Issue with useNavigate() Hook in Custom React-Admin Application

I’m facing a challenging issue in my React-Admin application. When I try to use the useNavigate() hook within my custom login component (MyLoginPage), I’m getting the following error:

Error: useNavigate() may be used only in the context of a <Router> component.

Problematic Behavior:
The error occurs exclusively within MyLoginPage, which is set as the loginPage prop in the <Admin> component of React-Admin, suggesting it should inherently have routing context.

Setup:

Shell Component: Acts as a wrapper around React-Admin’s <Admin> for Firebase auth state handling.
MyLoginPage component: Custom login component using useNavigate() for post-login redirects.
Here’s a snippet from MyLoginPage where useNavigate() is invoked:

MyLoginPage component

import { useNavigate } from "react-router-dom";
// ... other imports

const MyLoginPage = () => {
  const navigate = useNavigate(); // this line triggers the error
  // ... rest of the component
};

And here’s how MyLoginPage is used within the app structure:

App component

import { Admin } from "react-admin";
import MyLoginPage from "./MyLoginPage";
import { Shell } from "./Shell";

const App = () => {
  return (
    <Shell>
      <Admin loginPage={MyLoginPage} /* ... other props ... */>
        {/* ... resources ... */}
      </Admin>
    </Shell>
  );
};

Attempts to Resolve:

  • Ensured MyLoginPage is rendered as a child of <Admin>.
  • Checked for additional <Router> instances that might conflict with React-Admin’s router context.

I’m stumped as to why useNavigate() is losing context within MyLoginPage. Could this be an issue with the order in which components are mounted? Any advice or insights would be greatly appreciated!

How to set “date” and “category” axes one below another in amChart4

I am trying to place two axes below the chart, one that will display the name of the “part”, in this example “Part_1”, and below it the corresponding date. As in the example below.

This is how it looks with provided code

And this is what I’m trying to achive

Here I have a working example with data and everything:

    am4core.useTheme(am4themes_animated);

    var chart = am4core.create("chartdiv", am4charts.XYChart);

    var data = [
                  {
                    "Part_1_bad": 20,
                    "Part_2_bad": 20,
                    "Part_1_good": 20,
                    "Part_2_good": 40,
                    "date": "2023-11-23",
                    "name": "Part 1"
                  },
                  {
                    "Part_1_bad": 20,
                    "Part_2_bad": 30,
                    "Part_1_good": 30,
                    "Part_2_good": 50,
                    "date": "2023-11-24",
                    "name": "Part 2"
                  },
                  {
                    "Part_1_bad": 20,
                    "Part_2_bad": 10,
                    "Part_1_good": 25,
                    "Part_2_good": 60,
                    "date": "2023-11-25",
                    "name": "Part 3"
                  }
                ];

    var part_names = ["Part_1", "Part_2"];

    chart.data = data;

    var dateAxis = chart.xAxes.push(new am4charts.DateAxis());
    dateAxis.renderer.labels.template.dy = 30

    var valueAxis = chart.yAxes.push(new am4charts.ValueAxis());
    valueAxis.tooltip.disabled = true;


    var createSeries = function (part_name) {

      var series_good = chart.series.push(new am4charts.ColumnSeries());
      series_good.data = this.chartData;
      series_good.dataFields.valueY = part_name.concat("_good");
      series_good.dataFields.dateX = "date";
      series_good.fillOpacity = 0.5;
      series_good.columns.template.column.strokeWidth = 1.5;
      series_good.columns.template.column.strokeOpacity = 1.0;
      series_good.columns.template.column.stroke = am4core.color("#008000");
      series_good.columns.template.column.fill = am4core.color("#008000");

      var series_bad = chart.series.push(new am4charts.ColumnSeries());
      series_bad.data = this.chartData;
      series_bad.dataFields.valueY = part_name.concat("_bad");
      series_bad.dataFields.dateX = "date";
      series_bad.fillOpacity = 0.5;
      series_bad.columns.template.column.strokeWidth = 1.5;
      series_bad.columns.template.column.strokeOpacity = 1.0;
      series_bad.columns.template.column.stroke = am4core.color("#ff0000");
      series_bad.columns.template.column.fill = am4core.color("#ff0000");
      series_bad.stacked = true;

    }

    part_names.forEach(function (part_name) {
      createSeries(part_name);
    });

CodePen exemple

How do i use a conditional statement to style a react anchorlink tag

i am trying to style my anchorlink tags for navigation using a conditional statement while also adding the hover and transition effect, it seems i am not getting the syntax right.

i want to apply the styling effect if the selected page matches the id of the navlink which will be in lower case, here is a snippet of what it looks like below

interface Props  {
    page: string;
    selectedPage: string;
    setSelectedPage: (value:string) => void;
}

function Link({page,selectedPage,setSelectedPage}: Props) {
    const lowerCasePage = page.toLowerCase().replace(/ /g, "")
  return (
    <AnchorLink
    className={'${selectedPage === lowerCasePage ? "text-primary-500" : ""}
    transition duration-500 hover:text-primary-300
    '}
    href={'#${lowerCasePage}'}
    onClick={}
    >
        {page}
    </AnchorLink>
  )
}

export default Link

Selected number matching Random Numbers

I am creating a lottery game and I am facing some problems. The player can choose 5 numbers and as soon as the player sends the 5 lottery numbers, the machine generates 5 random numbers. numbers 2, 3, 4, and 5 are the winning numbers. The problem is that when I select 5 numbers and there is the same number among the random generated numbers, there is no Match. The order does not matter, if there is a matching number, the player should win. Can you help what is missing? `

import { useEffect, useState } from "react";
import useLottoInfo from "./useLottoInfo";
import usePlayerInfo from "./usePlayerInfo";

const useGameLogic = () => {
  const { playerName, playerBalance, setPlayerName, setPlayerBalance } =
    usePlayerInfo();

  const {
    selectedNumbers,
    lottoNumbers,
    prize,
    ticketList,
    generatedNumbers,
    hasResult,
    setHasResult,
    setSelectedNumbers,
    setGeneratedNumbers,
    setLottoNumbers,
    setPrize,
    setTicketList,
  } = useLottoInfo();

  const [numbersGenerated, setNumbersGenerated] = useState(false);
  const [isGeneratingNumbers, setIsGeneratingNumbers] = useState(false);

  useEffect(() => {
    setLottoNumbers(generateRandomNumbers());
  }, []);

  const generateRandomNumbers = () => {
    const numbers = [];
    while (numbers.length < 5) {
      const randomNum = Math.floor(Math.random() * 39) + 1;
      if (!numbers.includes(randomNum)) {
        numbers.push(randomNum);
      }
    }
    return numbers;
  };

  const handleSelectNumber = (number) => {
    if (selectedNumbers.length < 5 && !selectedNumbers.includes(number)) {
      setSelectedNumbers([...selectedNumbers, number]);
    }
  };

  const handleGenerateNumbers = () => {
    if (isGeneratingNumbers || numbersGenerated) {
      alert("You have already generated numbers for this ticket.");
      return;
    }

    if (
      playerBalance >= 500 &&
      selectedNumbers.length === 5 &&
      !hasResult &&
      !numbersGenerated
    ) {
      const matchingNumbers = selectedNumbers.filter((num) =>
        lottoNumbers.some(
          (lottoNum) =>
            lottoNum === num &&
            lottoNumbers.filter((n) => n === num).length === 1
        )
      );

      let currentPrize = 0;

      switch (matchingNumbers.length) {
        case 1:
          currentPrize = 200;
          break;
        case 2:
          currentPrize = 400;
          break;
        case 3:
          currentPrize = 600;
          break;
        case 4:
          currentPrize = 1000;
          break;
        case 5:
          currentPrize = 10000;
          break;
        default:
          currentPrize = 0;
      }

      const newTicket = {
        numbers: selectedNumbers,
        matchingNumbers: matchingNumbers.length,
        prize: currentPrize,
      };

      setTicketList([...ticketList, newTicket]);

      setPlayerBalance(playerBalance + currentPrize - 500);
      setGeneratedNumbers(generateRandomNumbers());
      setHasResult(true);
      setSelectedNumbers([]);
      setIsGeneratingNumbers(true);
      setNumbersGenerated(true);
    } else {
      alert("Please select exactly 5 numbers to generate your lottery ticket.");
    }
  };

  const handleNewTicket = () => {
    setNumbersGenerated(false);
    setHasResult(false);
    setIsGeneratingNumbers(false);
  };

  return {
    playerName,
    playerBalance,
    selectedNumbers,
    lottoNumbers,
    prize,
    ticketList,
    generatedNumbers,
    hasResult,
    setHasResult,
    setPlayerName,
    setPlayerBalance,
    setSelectedNumbers,
    setGeneratedNumbers,
    setLottoNumbers,
    setPrize,
    setTicketList,
    handleSelectNumber,
    handleGenerateNumbers,
    handleNewTicket,
  };
};

export default useGameLogic;

D3 bar chart on MouseMove display Y value

I have included my R code and my D3JS code. I’m trying to create a normal distribution in R-Studio, and using D3 to visualize the results, the R code is as follows, and was created to be replicable. I want the MouseMove code to show the Y-axis value on MouseMove, but currently it’s not working. Any tips is appreciated.

Happy Thanksgiving!

library(r2d3)
# Generate standard normal distribution data
set.seed(123)
df <- rnorm(n = 10000, mean = 0, sd = 1)
# Bin the data to create a histogram
binned_df <- hist(df, plot = FALSE, breaks = 770)
# Convert the binned data to a data frame
df <- data.frame(mid = binned_df$mids, count = binned_df$counts)
rm(list=setdiff(ls(), "df")) # Clear enviroment
# Use r2d3 to pass the data to D3.js
r2d3(data = df, script = "~/Desktop/D3Test.js")

The D3 code is:

// D3 code to create an interactive histogram with varying shades of blue, tooltips, and bar height display on mouseover
r2d3.onRender(function(data, svg, width, height) {
  // Set margins
  var margin = { top: 20, right: 20, bottom: 30, left: 40 },
    width = width - margin.left - margin.right,
    height = height - margin.top - margin.bottom;

  // Set the scales
  var x = d3
    .scaleLinear()
    .rangeRound([0, width])
    .domain(d3.extent(data, function(d) {
      return d.mid;
    }));

  var y = d3
    .scaleLinear()
    .rangeRound([height, 0])
    .domain([0, d3.max(data, function(d) {
      return d.count;
    })]);

  // Append the svg object to the body of the page
  var g = svg.append("g").attr("transform", "translate(" + margin.left + "," + margin.top + ")");

  // Define a color scale for varying shades of blue
  var colorScale = d3.scaleSequential(d3.interpolateBlues)
    .domain([0, d3.max(data, function(d) {
      return d.count;
    })]);

  // Create a tooltip
  var tooltip = d3.select("body")
    .append("div")
    .attr("class", "tooltip")
    .style("opacity", 0);

  // Add the bars
  g.selectAll(".bar")
    .data(data)
    .enter()
    .append("rect")
    .attr("class", "bar")
    .attr("x", function(d) {
      return x(d.mid);
    })
    .attr("y", function(d) {
      return y(d.count);
    })
    .attr("width", 10) // fixed width for each bar
    .attr("height", function(d) {
      return height - y(d.count);
    })
    .style("fill", function(d) {
      return colorScale(d.count); // Vary shades of blue based on count
    })
    .on("mouseover", mouseover)
    .on("mousemove", mousemove) // Updated mousemove function
    .on("mouseout", mouseout);

  // Tooltip functions
  function mouseover(d) {
    tooltip
      .style("opacity", 1);
    d3.select(this)
      .style("stroke", "black")
      .style("opacity", 1);
  }
  
/////////////////////////////////////////////////////////////////////////////
function mousemove(d) {
  const tooltipContent = `Value: ${d.count}<br>Mid: ${d.mid}`;
  tooltip
    .html(tooltipContent)
    .style("left", (d3.event.pageX + 10) + "px") // Adjust the left offset as needed
    .style("top", (d3.event.pageY - 28) + "px"); // Adjust the top offset as needed

  // Add text for bar height at the top of the bar
  const barHeightText = g.selectAll(".bar-height-text").data([d]);
  barHeightText
    .enter()
    .append("text")
    .attr("class", "bar-height-text")
    .attr("x", x(d.mid) + 5) // Adjust the positioning as needed
    .attr("y", y(d.count) - 5) // Adjust the positioning as needed
    .text(`Height: ${d.count}`)
    .style("fill", "black");

  barHeightText
    .merge(barHeightText) // Update existing text
    .text(`Height: ${d.count}`);
}
/////////////////////////////////////////////////////////////////////////////


  function mouseout(d) {
    tooltip
      .style("opacity", 0);
    d3.select(this)
      .style("stroke", "none")
      .style("opacity", 0.7);
  }

  // Add the x-axis
  g.append("g")
    .attr("transform", "translate(0," + height + ")")
    .call(d3.axisBottom(x));

  // Add the y-axis
  g.append("g").call(d3.axisLeft(y));

  // Append text labels and arrows to the x-axis
  var xAxis = g.append("g")
    .attr("transform", "translate(0," + height + ")")
    .call(d3.axisBottom(x));

  xAxis.append("text")
    .attr("x", width)
    .attr("y", 30) // Adjust the y-coordinate for vertical positioning
    .attr("text-anchor", "end")
    .text("More Conservative");

  xAxis.append("text")
    .attr("x", 0)
    .attr("y", 30) // Adjust the y-coordinate for vertical positioning
    .attr("text-anchor", "start")
    .text("More Liberal");

  // Append arrows (optional)
  var arrowSize = 10;
  xAxis.append("polygon")
    .attr("points", "0,0 " + arrowSize + ",0 " + arrowSize / 2 + "," + arrowSize)
    .attr("transform", "translate(0, " + (arrowSize + 25) + ")")
    .style("fill", "black"); // Adjust arrow styling as needed

  xAxis.append("polygon")
    .attr("points", "0,0 -" + arrowSize + ",0 -" + arrowSize / 2 + "," + arrowSize)
    .attr("transform", "translate(" + width + ", " + (arrowSize + 25) + ")")
    .style("fill", "black"); // Adjust arrow styling as needed
});

Javascript + Vuex issue: how to access a Vuex boolean in a `v-if`

While working in a team project, my teammates wish me to display a div only when a certain boolean is true. However, I do not know how to access said boolean in the html.


App.vue:

<template>
  <div>
    <div v-if="store.state.initSession">If true</div>
  </div>
</template>

<script>
import { store } from '../store'
...
</script>

store.js:

import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex)

export const store =  new Vuex.Store({
  state: {
    initSession: false,
  },
...

Yet I get the following error:

[Vue warn]: Property or method "store" is not defined on the instance but referenced during render.

The error has been discussed in this post, but I continue not to know how to solve it.

Regex to Extract Environment, Domain, and Hostname from URL with Variable Subdomains

I am working on a project where I need to extract specific information from URLs, specifically the environment, domain, and hostname. The URLs have variable subdomains, and I’m having difficulty constructing a regex pattern to capture the required groups.

Here are some examples of the URLs I’m working with:

I need help crafting a regex pattern that can efficiently capture the following groups:

Group 1: Environment (e.g., test, stage, qa)

Group 2: Domain (e.g., example, ops-cert-qa-beta)

Group 3: Hostname (e.g., hostname)

const regex = /.*?(?<env>(qa|stage|dev|preprod|test)).*?.(?<host>[w]+).(?<domain>w+)$/;

function extractInfoFromURL(url) {
    const match = url.match(regex);
    
    if (match) {
        const environment = match.groups.env;
        const domain = match.groups.domain;
        const hostname = match.groups.host;
        
        return { environment, domain, hostname };
    } else {
        return null; // URL didn't match the pattern
    }
}

const testUrls = [
    "https://example.test.qa.sub.hostname.com",
    "https://example.test.stage.coonect.hostname.com",
    "https://example.qa.hostname.com",
    "https://example.hostname.com",
    "https://example.stage.hostname.com",
    "https://example.test.hostname.com",
    "https://ops-cert-stage-beta.apps.sub-test.minor.qa.test.sub.hostname.com",
    "https://ops-cert-qa-beta.apps.sub-test.minor.qa.test.sub.hostname.com",
    "https://ops-cert-qa.apps.sub-test.minor.qa.test.sub.hostname.com",
    "https://ops-cert-stage.apps.sub-test.minor.qa.test.sub.hostname.com"
];

testUrls.forEach((url, index) => {
    const result = extractInfoFromURL(url);
    
    if (result) {
        console.log(`Result for URL ${index + 1}:`, result);
    } else {
        console.log(`URL ${url} did not match the pattern.`);
    }
});

Check for Result 3, 1&2 are working fine.

Why is this array.length return 1 for an empty array?

Using:

<input id="selectedRecords" name="selectedRecords" type="hidden" />

Executing this code:

var keyValues = $('#selectedRecords').val().split(",").map(item => item.trim());

console.log('$(#selectedRecords).val(): [' + $('#selectedRecords').val() + ']');
console.log('keyValues: [' + keyValues + ']');
console.log('keyValues.length: [' + keyValues.length + ']');

Gives this console readout (copy pasted from console window in Brave browser):

$(#selectedRecords).val(): []
keyValues: []
keyValues.length: [1]

Why is keyValues.length returning a count of 1 ?

PDO func insert and multiplilcation

im trying to make function that take every row from column inv by user id multiply it by 0,015 and then insert this value to zhod with same user id.

i have this but im lost already. if someone can help or simplify it ill be glad.

public function updateZhod($id) {
   $sql = "UPDATE users SET zhod = inv * 0.015 WHERE id = :id AND verified = 1";
    $stmt = $this->conn->prepare($sql);
    $stmt->bindParam(':id', $id);
    $stmt->execute();
}
if (isset($_POST['action']) && $_POST['action'] == 'fetchAllUsersInv') {
    $output = '';
    $data = $admin->fetchAllUsersInv(0);
    if ($data) {
        $output .= '<table class="table table-striped table-bordered text-center">
                        <thead>
                            <tr>
                                <th>ID</th>
                                <th>Inv</th>
                <th>Zhod</th>
                            </tr>
                        </thead>
                        <tbody>';

        foreach ($data as $row) {
            $zhodValue = $row['inv'] * 0.015;

            $output .= '<tr>
                            <td>' . $row['id'] . '</td>
                            <td>' . $row['inv'] . '</td>
                            <td>' . $zhodValue . '</td>
                        </tr>';
        }

        $output .= '</tbody>
                    </table>';

        echo $output;
    } else {
        echo '<h3 class="text-center text-secondary">:( No inv</h3>';
    }
}


if (isset($_POST['action']) && $_POST['action'] == 'updateZhod') {
    $admin->updateZhod();

    echo 'Zhod values updated successfully!';
}
<script>
    $(document).ready(function() {
        $("#zhodLed").click(function() {
            $.ajax({
                url: 'assets/php/admin-action.php',
                type: 'POST',
                data: {
                    action: 'updateZhod'
                },
                dataType: 'json',
                success: function(response) {
                    if (response.success) {
                        $("#invValue").text(response.newValue.toFixed(2) + " ...");
                    } else {
                        alert("Error: Failed to update zhod value.");
                    }
                },
                error: function(jqXHR, textStatus, errorThrown) {
                    console.error("AJAX Error:", textStatus, errorThrown);
                    alert("Error: Unable to make the AJAX request.");
                }
            });
        });
    });
</script>

this should be simple func that take one value from inv multiply it by 0,015 and insert it to zhod but its probably behind my skills

How to refresh usestate with keydown event listeners in react JS

I am making a drum machine that is supposed to activate audios when specific keys are pressed and then display the name of the sound. However, everytime the keys are pressed the if statements are not functioning properly because the useStates are not updating when the function / eventlistener is called. I am trying to use useEffect but I’m struggling and it is driving me insane.

To clarify: I am using a function component and not a class object component

  useEffect(()=>{
    document.addEventListener('keydown',handleKey)
  }, [bank, power, volume])

  function handleKey(e){
    e.stopImmediatePropagation() // Stops the function from firing 2+ times
    if (power){               // if the drum machine is on 
      if(bank === true) {const clip = audiosBank.find((clip) => clip.keyCode === e.which); // bank is boolean representing the second audio set
      if (!clip) return;    // clip eg: {keyCode: x, letter: x, name: x, src: x}
      let csound = new Audio(clip.src)
      csound.volume = volume  // Volume is a useState connected to a input element with type range
      csound.play()
      setValue(prev => prev = clip.name)  // Displays the audio name      
}
  }}

The problem is that power,bank,and volume are set to their default state, which is true, false, and 0.7 and they are not updating.
Can anyone please tell me the issue that I am not seeing.

I want to split my web app into 2 parts using react router. however iam using a router inside of one of the previously mentioned routes. Its nested

/src
|-- /components
|   |-- /signin
|       |-- SignIn.js
|       |-- /home
|           |-- Home.js
|
|           |-- /dashboard
|               |-- Dashboard.js
|    |-- /assignee
|-- /App.js
|-- /index.js

As you can see i want to split into 2 parts(signin(adimin part), assignee(user part)).
I am using router for signin and assignee
Also i want to use router for home page, to display dashboard and other pages
How do i make it possible

///////////////////////////////////////////////////////////////

function App() {
  return (
    <Router>
      <div className="maindiv">
        <Routes>
          <Route path="/" element={<SignIn />} />
          <Route path="/assignment" element={<AssigneePage />} />
        </Routes>
      </div>
    </Router>
  );
}

///////////////////////////////////////////////////////////////

function Home() {
  return (
    <div>
      <Container className="content">
        <div className="side-nav">
          <Nav />
        </div>
        <div className="main-content">
          <Routes>
            <Route path="/dashboard" element={<Dashboard />} />
            <Route path="/review" element={<Review />} />
          </Routes>
        </div>
      </Container>
    </div>
  );
}

//////////////////////////////////////////////////////////////////

Home is stacked inside Signup

When i try http://localhost:3000/dashboard it gives me this error
history.ts:501 No routes matched location “/dashboard”

How to specify date ranges with “Now Playing” TMDB API

I’m fetching the nowPlaying movies from the API but no movies are displayed. I believe it is because it has a max and min date in the URL. However, I have tried to enter some dates but nothing has changed.

This is the URL

`https://api.themoviedb.org/3/discover/movie?api_key=${process.env.REACT_APP_TMDB_KEY}&include_adult=false&include_video=false&language=en-US&page=1&sort_by=popularity.desc&with_release_type=2|3&release_date.gte={min_date}&release_date.lte={max_date}`

Next.js external script not loading properly, second client component won’t display

I am trying to learn React by creating a small and simple web app with Next.js, but I am seeing some very strange bugs.

The app uses a node package to display charts from data that comes from a database. It sets a javascript interval to refresh its data. I could write this app without React in 20 minutes, but trying to use React to develop it has taken a week and it still isn’t working. I’ll explain the problems below.

Here are my 3 source files. (To save space, I removed the SQL queries. They are well-tested and are not causing these problems.)

page.tsx

import Chart from './Chart.tsx';

const ServerComponent = () => {
    return (
        <div>
            <Chart divID="xau-usd-candlestick" refreshMinutes="5" chartType="candlestick" currencyFrom="xau" currencyTo="usd" decimalPlaces="2" />
            <Chart divID="cny-usd-candlestick" refreshMinutes="5" chartType="candlestick" currencyFrom="cny" currencyTo="usd" decimalPlaces="4" />
            <Chart divID="try-usd-candlestick" refreshMinutes="5" chartType="candlestick" currencyFrom="try" currencyTo="usd" decimalPlaces="6" />
            <Chart divID="irr-usd-candlestick" refreshMinutes="5" chartType="candlestick" currencyFrom="irr" currencyTo="usd" decimalPlaces="8" />
            <Chart divID="btc-usd-candlestick" refreshMinutes="5" chartType="candlestick" currencyFrom="btc" currencyTo="usd" decimalPlaces="2" />
        </div>
    );
};

export default ServerComponent;

Chart.tsx

'use client'

import styles from './page.module.css';
import { useState, useEffect } from 'react';
import Script from 'next/script'

async function renderChart (divID, chartType, currencyFrom, currencyTo, decimalPlaces)
{
    let url = 'http://localhost:3000/api?chart-type=' + chartType;
    url += '&cur-from=' + currencyFrom + '&cur-to=' + currencyTo + '&decimal-places=' + decimalPlaces;

    await fetch (url)
        .then ((response) => { return response.text (); })
        .then ((data) => { Highcharts.stockChart (divID, JSON.parse (data).data); })
        .catch ((error) => { console.log (error, currencyFrom); });
}

function Chart (props)
{
    if (typeof props.refreshMinutes != 'undefined' && props.refreshMinutes > 0)
    {
        useEffect (() => {
            const interval = setInterval (renderChart, props.refreshMinutes * 60000, props.divID, props.chartType, props.currencyFrom, props.currencyTo, props.decimalPlaces);
            return () => { clearInterval (interval); };
        }, []);
    }

    let css = `${styles.chart}`;

    return (
        <div className={styles.main}>
            <div id={props.divID} className={css}>
            </div>
            <Script
                src = "https://code.highcharts.com/stock/highstock.js"
                onReady = { () => { renderChart (props.divID, props.chartType, props.currencyFrom, props.currencyTo, props.decimalPlaces); }}
            />
        </div>
    );
}

export default Chart;

api/route.ts

const { Client } = require ('pg');

const pg_client =
{
  host: '127.0.0.1',
  port: 5432,
  database: 'db_name',
  user: 'xxxxx',
  password: 'xxxxx'
};

const db_client = new Client (pg_client);
async function connect () {
    await db_client.connect ();
}
await connect ();

async function getCandlestickData (cur_from, cur_to, decimal_places)
{
    return new Promise (async (resolve, reject) =>
    {
        var query = 'select .....';
        await db_client.query (query)
            .then ((db_result) =>
            {
                for (let i = 0; i < db_result.rows.length; i++)
                {
                    db_result.rows [i].x = Number (db_result.rows [i].x) * 1000;
                    db_result.rows [i].open = Number (Number (db_result.rows [i].open).toFixed (decimal_places));
                    db_result.rows [i].close = Number (Number (db_result.rows [i].close).toFixed (decimal_places));
                    db_result.rows [i].low = Number (Number (db_result.rows [i].low).toFixed (decimal_places));
                    db_result.rows [i].high = Number (Number (db_result.rows [i].high).toFixed (decimal_places));
                }

                let result =
                {
                    plotOptions: {
                        candlestick: {
                            color: 'pink',
                            lineColor: 'red',
                            upColor: 'lightgreen',
                            upLineColor: 'green'
                        }
                    },
                    rangeSelector: { selected: 1 },
                    title: { text: cur_from + '-' + cur_to },
                    series: [
                                {
                                    type: 'candlestick',
                                    name: cur_from + '-' + cur_to,
                                    data: db_result.rows
                                }
                            ]
                };

                resolve (result);
            })
            .catch ((error) => { reject (error); });
    });
}


export async function GET (request: Request) {

    let data;
    let url = new URL (request.url);
    let chartType = url.searchParams.get ('chart-type');

    if (chartType == 'candlestick')
    {
        let currencyFrom = url.searchParams.get ('cur-from').toUpperCase ();
        let currencyTo = url.searchParams.get ('cur-to').toUpperCase ();
        let decimalPlaces = url.searchParams.get ('decimal-places').toUpperCase ();
        await getCandlestickData (currencyFrom, currencyTo, decimalPlaces).then ((result) => { data = result; });
    }
    return Response.json({ data });
}

There are several problems I’m seeing, but here are the main two:

The weirdest thing I am noticing is that the second chart in the list does not display. If I rearrange the <Chart> elements in page.tsx, it is still the second one that doesn’t display. It seems like the onReady function for the <Script> element never gets called but I have no idea why. It works fine for the other elements, but never for the second one.

At random times, I get the error Highcharts is not defined. So the code is trying to use the Highcharts object before it is fully loaded? I thought the onReady event was supposed to prevent that. Is there something wrong with the way I am using the <Script> tag? Is there a better way to load an external script than the way I am doing it?