pass utf8 string from javascript’s formData object to php by POST

I’m trying to pass a utf8 string from javascript to php through formData and POST.

My javascript code:

let formData = new FormData();
formData.append("downloadzip", zipFilename);

// send the request to php
let request = new XMLHttpRequest();
let url = window.location.origin + window.location.pathname;
request.onreadystatechange = function() {
    if (this.readyState === 4) {
        if (this.status >= 200 && this.status < 300) {
            $("#downloading-and-zipping").fadeOut(2000);
        } else {
            $("#error-downloading").show();
        }
    }
};
request.open("POST", url, true);
request.send(formData);

The php code that reads the POST data:

if (! empty($_POST) && ! empty($_POST["downloadzip"])) {
    error_log("ORIGINAL " . $_POST["downloadzip"]);
}

Now, the problem is: if javascript‘s zipFilename == "Misión", in php $_POST["downloadzip"] == "Misixc3xb3n".

Why is the string transformed?

How do I get the original string?

Add Full screen mode for Embla Slide

I’m using Embla Carousel, TailwindCSS and ShaDCN for React Typescript.
I have implemented a default carousel here.

Now I want to implement a full-screen carousel modal when any item is clicked, please let me know how I can do that.

I have tried this example but it only shows a single image.

how to open external links in the default browser ( Electron Js )

i want to open this link in a new default browser instead of Electron window.

Html :

<a href="https://https://www.youtube.com" target="_blank" >Youtube</a>

Main.Js :

 // Open external links in the default browser
 mainWindow.webContents.on('will-redirect', function (event, newUrl) {
  event.preventDefault();
  shell.openExternal(newUrl);
});

child’s css interfering with the parent’s css

I have a component that is called by the app component, but when you include margin-top in the child component, it interferes with the parent component, causing the parent component to take the margin instead of only the child component getting margin-top

import "../src/App.css";
import CardComponent from "./components/CardComponent";

function App() {
  return (
    <div className="App">
    <div className="card"></div>
      <CardComponent />
    </div>
  );
}

export default App;
function CardComponent() {
  return (
    <div className="card-component-wraper">
      <div> FAQs </div>
      <div>
        <div> What is Frontend Mentor, and how will it help me? </div>
        Frontend Mentor offers realistic coding challenges to help developers
        improve their frontend coding skills with projects in HTML, CSS, and
        JavaScript. It's suitable for all levels and ideal for portfolio
        building.
      </div>
    </div>
  );
}

export default CardComponent;
* {
  margin: 0;
  padding: 0;
}

.App {
  background-color: hsl(275, 100%, 97%);
  background-image: url("../assets/images/background-pattern-desktop.svg");
  background-size: 100%;
  background-repeat:repeat-x;
  width: 100%;
  height: 100vh;
}
.card-component-wraper {
    background-color: hsl(0, 0%, 100%);
    width: 20%;
    height: auto;
    border-radius: 10px;
    margin-left: 40%;
    margin-top: 10%;
}

Vscode duplicates files. I can’t connect any of the files

Please help me solve the problem. The files are duplicated and I can’t do anything. I tried creating other folders with different paths, but they still duplicate the files.
enter image description here

There are no hidden files in the folder itself.

enter image description here

Here are the extensions installed

enter image description here

Please help, I reinstalled everything. I checked all the settings.

the same error appeared later:

[Info - 6:27:20 PM] ESLint server is starting.
[Info - 6:27:20 PM] ESLint server running in node v18.15.0
[Info - 6:27:20 PM] ESLint server is running.
[Warn - 6:28:12 PM] Detected package manager() differs from the one in the deprecated packageManager setting(npm). We will honor this setting until it is removed.
[object Object]
[Info - 6:28:12 PM]
Failed to load the ESLint library for the document c:PortfolioCalculatorindex.js

To use ESLint please install eslint by running npm install eslint in the workspace folder Calculator
or globally using 'npm install -g eslint'. You need to reopen the workspace after installing eslint.

If you are using yarn or pnpm instead of npm set the setting eslint.packageManager to either yarn or pnpm
Alternatively you can disable ESLint for the workspace folder Calculator by executing the 'Disable ESLint' command.`

After installing ESlint into the project, the files are still duplicated

How to use Nuxt 3 layout transitions with JavaScript hooks not CSS

I’m looking to use JavaScript hooks in layout transitions in Nuxt 3 to create an advance layout transition with GSAP. However, there are no examples of layout transitions with JavaScript hooks in the docs.

Where/how should I write my layout transitions to make use of JavaScript hooks, similar to how they are used in the page transition example.

pages/some-page.vue

<script setup lang="ts">
definePageMeta({
  pageTransition: {
    name: 'custom-flip',
    mode: 'out-in',
    onBeforeEnter: (el) => {
      console.log('Before enter...')
    },
    onEnter: (el, done) => {},
    onAfterEnter: (el) => {}
  }
})
</script>

Centering and evenly spacing multiple objects in Canvas

For a new game I’m making, I need to have 3 rectangles centered and evenly spaced apart along the bottom of the canvas, but I need to be able to add more rectangles, and have them evenly spaced as well, (probably no more than 5 though)

I started by just taking the width of the canvas, dividing it by (NumberOfBoxes), and setting the x to that plus half the width, but this results in them having a bigger gap between the right wall and the right-most box, than the left wall and the left-most box.

class Box {   
constructor(game, x){     
this.game = game;     
this.width = 150;     
this.height = 75;     
this.x = this.game.width/this.game.numberOfBoxes*x;     
this.y = this.game.height - this.height;   
}  

draw(context){     
context.fillRect(this.x + this.width/2, this.y, this.width, this.height); 
} 

(the x being pulled in is the variable telling each box which fraction of the canvas to sit in)

I also tried using mod to get the remaining space after the boxes, then adding part to each box’s x-pos, but this also did not work.

Using react context with inner component

I have a root file inside that I have OuterComponent component, I wrap my first provider around the OuterComponent and I pass userId to it, so the FirstContext can use it to fetch user data.
Then I wrap my SecondProvider around InnerComponent component and pass nodeId to the 2nd SecondContext so I can fetch the node using that. is this wrong practice to do in react?

import { FirstProvider } from './FirstContext';
import OuterComponent from './OuterComponent';

const App = () => {
  return (
    <FirstProvider userId={userId}>
        <OuterComponent />
    </FirstProvider>
  );
};

export default App;


// OuterComponent.js
import React from 'react';
import InnerComponent from './InnerComponent';
import { SecondProvider } from './SecondContext';

const OuterComponent = () => {
  return (
    <div>
      <p>Outer Component</p>
      <SecondProvider nodeId={nodeId}>
      <InnerComponent />
      </SecondProvider>
    </div>
  );
};

export default OuterComponent;

I want to understand if its a best practice in react to use it so

Chrome extension sending message by clicking event from popup to background, then fetch data and return to popup. only one of the click events works

I’m a student who has just started to learn javascript. I wrote an extension that can visualize the history data of the user.

So what I made was a Chrome extension sending message by clicking event from popup to background, then fetch data and return to popup. But I encountered some problem during the process of clicking event.

There are three different buttons that users can click, which can set the period of data to the corresponding time (”last hour”, “last 24 hours” and “last week”). I tested each click event individually. All of which works when alone. But when I put three buttons together, only one of them works.

I’m wondering why is that happening, and how should I fix that? Thank you very much.

I included here the part of code which isn’t working

popup.js

//buttons that send mmesages
document.addEventListener('DOMContentLoaded', function () {

    const lastHourbtn = document.getElementById('lastHour');
    lastHourbtn.addEventListener('click', function () {
        console.log('test 1');
        historyDiv.innerHTML = '';
        chrome.runtime.sendMessage({ action: 'getLastHour' }, function (response) {
            generateVisual(response);
        });
    });
    const lastDaybtn = document.getElementById('last24Hours');
    lastDaybtn.addEventListener('click', function () {
        historyDiv.innerHTML = '';
        chrome.runtime.sendMessage({ action: 'getLast24Hour' }, function (response) {
            generateVisual(response);
        });
    });
    const lastWeekbtn = document.getElementById('lastWeek');
    lastWeekbtn.addEventListener('click', function () {
        historyDiv.innerHTML = '';
        chrome.runtime.sendMessage({ action: 'getLastWeek' }, function (response) {
            generateVisual(response);
        });
    });

});

background.js

chrome.runtime.onMessage.addListener(function(request, sender, sendResponse) {
  if (request.action === 'getLastHour') {
      const thisHour = new Date().getTime() - ( 60 * 60 * 1000);
      chrome.history.search({ text: '', startTime: thisHour, maxResults: 1000 }, function (historyItems) {
          sendResponse({ historyItems });
    });
  }else if (request.action === 'getLast24Hour') {
    const today = new Date().getTime() - ( 24 * 60 * 60 * 1000); 
    chrome.history.search({ text: '', startTime: today, maxResults: 1000 }, function (historyItems) {
        sendResponse({ historyItems });
  });
} else if (request.action === 'getLastWeek') {
  const thisWeek = new Date().getTime() - ( 7 * 24 * 60 * 60 * 1000);
  chrome.history.search({ text: '', startTime: thisWeek, maxResults: 1000 }, function (historyItems) {
      sendResponse({ historyItems });
});
}
return true;
});

OR_BIBED_06 error in Google Pay test environtment

I’m trying to set up Google Pay in test mode for a website (not for an Android app). My Processor is Fiserv – CardPointe which says to use CARDCONNCT as the gateway. When the Google Pay window pops up it displays this error.

Something went wrong
This merchant is having trouble accepting your payment right now. Try using a different payment method. [OR_BIBED_06] OR_BIBED_06

I’m not seeing a lot about this error on Google. But I’m thinking this is a problem with Fiserv. Here is my code

<script>
    function googlePayLoaded() {
        googlePayClient = new google.payments.api.PaymentsClient({ environment: 'TEST' });
        console.log("Google Pay Client loaded");
    }
</script>
<script id="googlePay" src="https://pay.google.com/gp/p/js/pay.js" async onload="googlePayLoaded()"></script>

And the code that runs on the Donation page at start up and creates the button

const allowedPaymentMethods = ["CARD", "TOKENIZED_CARD"];
const allowedCardNetworks = ["AMEX", "DISCOVER", "INTERAC", "JCB", "MASTERCARD", "VISA"];
googlePayMerchantID = settingValue(settings, "GooglePayMerchantID");
googlePayMerchantName = settingValue(settings, "GooglePayMerchantName");
// also called IsReadyToPayRequest in the docs
googlePayConfig = {
    apiVersion: 2,
    apiVersionMinor: 0,
    allowedPaymentMethods: allowedPaymentMethods
}
paymentDataRequest = Object.assign({}, googlePayConfig);
// currency code is ISO 4217 code
// country code is ISO 3166-1 alpha-2 code for where the transaction is processed
paymentDataRequest.transactionInfo = {
    totalPriceStatus: "FINAL",
    totalPrice: 0,  // will change this later
    currencyCode: "USD",
    countryCode: "US"
}
paymentDataRequest.merchantInfo = {
    merchantId: googlePayMerchantID,
    merchantName: googlePayMerchantName
}
const tokenizationSpec = {
    type: "PAYMENT_GATEWAY",
    paramters: {
        gateway: 'CARDCONNECT',
        gatewayMerchantId: CardPointeMerchantID
    }
}
const cardPaymentMethod = {
    type: "CARD",
    tokenizationSpecification: tokenizationSpec,
    parameters: {
        allowedCardNetworks: allowedCardNetworks,
        allowedAuthMethods: ["PAN_ONLY", "CRYPOGRAM_3DS"],
        //billingAddressParamters: {
        //    format: "FULL",
        //    phoneNumberRequired: false
        //}
    }
}
paymentDataRequest.shippingAddressRequired = false;
paymentDataRequest.allowedPaymentMethods = [cardPaymentMethod];

googlePayClient.isReadyToPay(googlePayConfig).then(function (response) {
    if (response.result) {
        vm.showGooglePayOption = true;
        const googlePayButton = googlePayClient.createButton({
            buttonColor: "default",
            buttonType: "donate",
            onClick: donateWithGooglePay
            //allowedPaymentMethods: [cardPaymentMethod]
        });
        $("#googlePayButton").html(googlePayButton);
    } else {
        console.log("Google Pay not ready");
    }
}).catch(function (error) {
    console.log(error);
});

And then when you click the button it does this

function donateWithGooglePay2() {
    paymentDataRequest.transactionInfo.totalPrice = vm.data.amount;
    googlePayClient.loadPaymentData(paymentDataRequest).then((paymentData) => {
        token = paymentData.paymentMethodData.tokenizationData.token;
        if (vm.paymentProcessor === "CardPointe") {
            tokenized = true;
            donate2();  // this uses the token to authorize a payment 
        }
    }).catch((error) => {
        // errors will be displayed in the Google Pay window
        console.log(error);
        return;
    });
}

Any thoughts?

How to find query url in NextJs 14

Im trying to get query url from my url http://localhost:3000/products/edit/6578dc752bb3c50101a76644

so before was with router.query but with new version (params) im trying without result.

const params = useParams()
    const { id } = params

    useEffect(() => {
        if(!id) {
            return;
        }
        axios.get('/api/products?id='+id).then(response => {
            setProductInfo(response.data)
        })
    }, [id])

and the problem is here I think:

export const GET = async (req) => {
    await mongooseConnect()

    if (req.query?.id) {
        Response.json(await Product.findOne({_id:req.query.id}));
        
    } else {
        return Response.json(await Product.find())
    }
}

Thank you!

Why does Javscript custom cursor extend the page into infinity?

I am trying to use this sparkle custom cursor from CodePen: https://codepen.io/sarahwfox/pen/pNrYGb

var colour="random"; // "random" can be replaced with any valid colour ie: "red"...
var sparkles=100;// increase of decrease for number of sparkles falling

var x=ox=400;
var y=oy=300;
var swide=800;
var shigh=600;
var sleft=sdown=0;
var tiny=new Array();
var star=new Array();
var starv=new Array();
var starx=new Array();
var stary=new Array();
var tinyx=new Array();
var tinyy=new Array();
var tinyv=new Array();

colours=new Array('#ff0000','#00ff00','#ffffff','#ff00ff','#ffa500','#ffff00','#00ff00','#ffffff','ff00ff')

n = 10;
y = 0;
x = 0;
n6=(document.getElementById&&!document.all);
ns=(document.layers);
ie=(document.all);
d=(ns||ie)?'document.':'document.getElementById("';
a=(ns||n6)?'':'all.';
n6r=(n6)?'")':'';
s=(ns)?'':'.style';

if (ns){
    for (i = 0; i < n; i++)
        document.write('<layer name="dots'+i+'" top=0 left=0 width='+i/2+' height='+i/2+' bgcolor=#ff0000></layer>');
}

if (ie)
    document.write('<div id="con" style="position:absolute;top:0px;left:0px"><div style="position:relative">');

if (ie||n6){
    for (i = 0; i < n; i++)
        document.write('<div id="dots'+i+'" style="position:absolute;top:0px;left:0px;width:'+i/2+'px;height:'+i/2+'px;background:#ff0000;font-size:'+i/2+'"></div>');
}

if (ie)
    document.write('</div></div>');
(ns||n6)?window.captureEvents(Event.MOUSEMOVE):0;

function Mouse(evnt){

    y = (ns||n6)?evnt.pageY+4 - window.pageYOffset:event.y+4;
    x = (ns||n6)?evnt.pageX+1:event.x+1;
}

(ns)?window.onMouseMove=Mouse:document.onmousemove=Mouse;

function animate(){

    o=(ns||n6)?window.pageYOffset:0;

    if (ie)con.style.top=document.body.scrollTop + 'px';

    for (i = 0; i < n; i++){

        var temp1 = eval(d+a+"dots"+i+n6r+s);

        randcolours = colours[Math.floor(Math.random()*colours.length)];

        (ns)?temp1.bgColor = randcolours:temp1.background = randcolours; 

        if (i < n-1){

            var temp2 = eval(d+a+"dots"+(i+1)+n6r+s);
            temp1.top = parseInt(temp2.top) + 'px';
            temp1.left = parseInt(temp2.left) + 'px';

        } 
        else{

            temp1.top = y+o + 'px';
            temp1.left = x + 'px';
        }
    }

    setTimeout("animate()",10);
}

animate();

window.onload=function() { if (document.getElementById) {
    var i, rats, rlef, rdow;
    for (var i=0; i<sparkles; i++) {
        var rats=createDiv(3, 3);
        rats.style.visibility="hidden";
        rats.style.zIndex="999";
        document.body.appendChild(tiny[i]=rats);
        starv[i]=0;
        tinyv[i]=0;
        var rats=createDiv(5, 5);
        rats.style.backgroundColor="transparent";
        rats.style.visibility="hidden";
        rats.style.zIndex="999";
        var rlef=createDiv(1, 5);
        var rdow=createDiv(5, 1);
        rats.appendChild(rlef);
        rats.appendChild(rdow);
        rlef.style.top="2px";
        rlef.style.left="0px";
        rdow.style.top="0px";
        rdow.style.left="2px";
        document.body.appendChild(star[i]=rats);
    }
    set_width();
    sparkle();
}}

function sparkle() {
    var c;
    if (Math.abs(x-ox)>1 || Math.abs(y-oy)>1) {
        ox=x;
        oy=y;
        for (c=0; c<sparkles; c++) if (!starv[c]) {
            star[c].style.left=(starx[c]=x)+"px";
            star[c].style.top=(stary[c]=y+1)+"px";
            star[c].style.clip="rect(0px, 5px, 5px, 0px)";
            star[c].childNodes[0].style.backgroundColor=star[c].childNodes[1].style.backgroundColor=(colour=="random")?newColour():colour;
            star[c].style.visibility="visible";
            starv[c]=50;
            break;
        }
    }
    for (c=0; c<sparkles; c++) {
        if (starv[c]) update_star(c);
        if (tinyv[c]) update_tiny(c);
    }
    setTimeout("sparkle()", 40);
}

function update_star(i) {
    if (--starv[i]==25) star[i].style.clip="rect(1px, 4px, 4px, 1px)";
    if (starv[i]) {
        stary[i]+=1+Math.random()*3;
        starx[i]+=(i%5-2)/5;
        if (stary[i]<shigh+sdown) {
            star[i].style.top=stary[i]+"px";
            star[i].style.left=starx[i]+"px";
        }
        else {
            star[i].style.visibility="hidden";
            starv[i]=0;
            return;
        }
    }
    else {
        tinyv[i]=50;
        tiny[i].style.top=(tinyy[i]=stary[i])+"px";
        tiny[i].style.left=(tinyx[i]=starx[i])+"px";
        tiny[i].style.width="2px";
        tiny[i].style.height="2px";
        tiny[i].style.backgroundColor=star[i].childNodes[0].style.backgroundColor;
        star[i].style.visibility="hidden";
        tiny[i].style.visibility="visible"
    }
}

function update_tiny(i) {
    if (--tinyv[i]==25) {
        tiny[i].style.width="1px";
        tiny[i].style.height="1px";
    }
    if (tinyv[i]) {
        tinyy[i]+=1+Math.random()*3;
        tinyx[i]+=(i%5-2)/5;
        if (tinyy[i]<shigh+sdown) {
            tiny[i].style.top=tinyy[i]+"px";
            tiny[i].style.left=tinyx[i]+"px";
        }
        else {
            tiny[i].style.visibility="hidden";
            tinyv[i]=0;
            return;
        }
    }
    else tiny[i].style.visibility="hidden";
}

document.onmousemove=mouse;
function mouse(e) {
    if (e) {
        y=e.pageY;
        x=e.pageX;
    }
    else {
        set_scroll();
        y=event.y+sdown;
        x=event.x+sleft;
    }
}

window.onscroll=set_scroll;
function set_scroll() {
    if (typeof(self.pageYOffset)=='number') {
        sdown=self.pageYOffset;
        sleft=self.pageXOffset;
    }
    else if (document.body && (document.body.scrollTop || document.body.scrollLeft)) {
        sdown=document.body.scrollTop;
        sleft=document.body.scrollLeft;
    }
    else if (document.documentElement && (document.documentElement.scrollTop || document.documentElement.scrollLeft)) {
        sleft=document.documentElement.scrollLeft;
        sdown=document.documentElement.scrollTop;
    }
    else {
        sdown=0;
        sleft=0;
    }
}

window.onresize=set_width;
function set_width() {
    var sw_min=999999;
    var sh_min=999999;
    if (document.documentElement && document.documentElement.clientWidth) {
        if (document.documentElement.clientWidth>0) sw_min=document.documentElement.clientWidth;
        if (document.documentElement.clientHeight>0) sh_min=document.documentElement.clientHeight;
    }
    if (typeof(self.innerWidth)=='number' && self.innerWidth) {
        if (self.innerWidth>0 && self.innerWidth<sw_min) sw_min=self.innerWidth;
        if (self.innerHeight>0 && self.innerHeight<sh_min) sh_min=self.innerHeight;
    }
    if (document.body.clientWidth) {
        if (document.body.clientWidth>0 && document.body.clientWidth<sw_min) sw_min=document.body.clientWidth;
        if (document.body.clientHeight>0 && document.body.clientHeight<sh_min) sh_min=document.body.clientHeight;
    }
    if (sw_min==999999 || sh_min==999999) {
        sw_min=800;
        sh_min=600;
    }
    swide=sw_min;
    shigh=sh_min;
}

function createDiv(height, width) {
    var div=document.createElement("div");
    div.style.position="fixed";
    div.style.height=height+"px";
    div.style.width=width+"px";
    div.style.overflow="hidden";
    return (div);
}

function newColour() {
    var c=new Array();
    c[0]=255;
    c[1]=Math.floor(Math.random()*256);
    c[2]=Math.floor(Math.random()*(256-c[1]/2));
    c.sort(function(){return (0.5 - Math.random());});
    return ("rgb("+c[0]+", "+c[1]+", "+c[2]+")");
}
// ]]>

but when I add it to my site it will extend the page y axis into infinity. At first it looks normal with the y scroll stopping after the footer but if you put your mouse down there and scroll some more it will stretch the page down into infinity. It happens on the original example linked above as well.

I searched for an answer first and found a similar issue here: Prevent custom cursor to expand page

I tried changing absolute to fixed and it does work to prevent the page extending but it has undesirable effects on the cursor itself. It becomes more compact and the trailing stars are delayed which looks odd. That can be viewed here: https://codepen.io/jenniferannwalsh/pen/xxMvmvM

Any ideas on how to fix this?

Problems with assertions, specifically the negative lookahead assertion ‘x(?!y)’

So I have been practicing and reading about assertions, and ran into this problem:

const text14 = "123 456 7890";
const pattern12 = /d+(?!0)/g;

let matches12 = text14.match(pattern12);
console.log(matches12);

the output is supposed to be [‘123’, ‘456’]
Yet it isn’t.
its [‘123’, ‘456’, ‘7890’]

After tinkering with it a bit I realized that when I put a space on the assertion as well as on the string itself, it removed, yet only the 9.

const text14 = "123 456 789 0";
const pattern12 = /d+(?! 0)/g;

let matches12 = text14.match(pattern12);
console.log(matches12);

Ouput:

['123', '456', '78', '0']

This made me believe that there is a different way in which assertion works with numbers.
The desired outcome I’ve been trying to get is to turn the original “123 456 7890” into [‘123’, ‘456’] using the negative lookahead assertion: ‘x(?!y)’.

Clear cells returning invalid values

So I’ve written the code below (multiple dependent dropdowns) which is now working. I now want to build a final step into this script which will clear any invalid values entered. I’m not really finding many threads/guides/videos which touch on this.

The only other thread here is this – Clear Invalid Values from Spreadsheet, but from the looks of this code it can only clear specific values. When I need the script to clear anything invalid.

Any help would be greatly appreciated.

function dropdown() {
  var activeCell=SpreadsheetApp.getActiveRange();
  var activeRow=activeCell.getRow()
  var activeCol=activeCell.getColumn()
  var activeValue=activeCell.getValue()
  var activeSheet=activeCell.getSheet()

  if(activeSheet.getName()=="Main Sheet" && activeRow>1 && activeCol==3){
    var worksheet=SpreadsheetApp.getActiveSpreadsheet();
    var spreadsheet=worksheet.getSheetByName("Data")
    var data=spreadsheet.getDataRange().getValues();
    var list=data.filter(row=>row[0]==activeValue).map(row=>row[1])
    var validation=SpreadsheetApp.newDataValidation().requireValueInList(list).setAllowInvalid(false).build()
    activeCell.offset(0,1).setDataValidation(validation)
}
}

function onEdit(){
  dropdown()
}

react isLoading state not behaving correctly

I am trying to make a skeleton loading effect when isLoading state is true (its set to true on init), like this =>

{isLoading  ? (
            <div className="grid grid-cols-4 gap-3">
              {voiceData.voices.map((voice) => (
                <Skeleton key={voice.voice_id} className="w-[200px] h-[250px] rounded-md" />
              ))}
          </div>
          ) : <div id="dash-card-container" className="grid grid-cols-4 gap-3" >
                {voiceData.voices.map((voice) => (
                  <VoiceCard onClick={() => {
                    // Store the voice object in localStorage
                    localStorage.setItem("voice", JSON.stringify(voice));
                    console.log(localStorage.getItem("voice"));
                    // Navigate to the editor route
                    navigate("/create/editor");
                  }} key={voice.voice_id} img={voice.img} name={voice.name} category={voice.category} />
                ))}
            </div>
    }

But for some reason it’s not working when I reload the page, here is my useEffect for calling the api

// Fetching voices from api
  useEffect(() => {
    const fetchVoices = async () => {
      // async function to fetch voices
      try {
        setIsLoading(true);

        const response = await axios.get("http://localhost:3000/voices");
        const data = response.data;
        
        console.log("data:", data);
        setVoiceData(data);
        console.log("Voicedata fetched:", voiceData)
      } catch (error) {
        console.error("Error fetching voices", error)
        setIsLoading(false)
      } finally {
        setIsLoading(false);
      }
    };
    fetchVoices();
  }, []); 

I’ve tried to removing the “finally” block but this did not do it either

useEffect(() => {
    const fetchVoices = async () => {
      // async function to fetch voices
      try {
        setIsLoading(true);

        const response = await axios.get("http://localhost:3000/voices");
        const data = response.data;
        
        console.log("data:", data);
        setVoiceData(data);
        console.log("Voicedata fetched:", voiceData)
        setIsLoading(false)
      } catch (error) {
        console.error("Error fetching voices", error)
        setIsLoading(false)
      } 
    };
    fetchVoices();
  }, []);

I know my loading effect is working because if I never set setIsLoading => false it shows up.enter image description here

I’ve also tried console.logging both at the beginning of the try block where I set it to true and at the end where I set it to false and it’s the same value every time, either true or false, but this has no impact on rendering which I find weird.

I’m a bit new to this but I don’t think I have missed anything major. Any help would be greatly appriciated as I’ve banged my head for a while now.