Context-sensitive functions, type and generic inference issues in TypeScript

There is a problem with the typing. In abc, a function is passed that can accept 3 parameters and return an object. If a function without parameters is passed into abc, TypeScript can handle the typing and will output in

test:{ 
    isLoading: boolean,
    setIsLoading: () => {
        isLoading: boolean
    }
}

But if you pass any props into the function, as I understand it, TypeScript starts considering this function as context-sensitive, and during the first compilation phase, it cannot determine what type to assign to the prop. I tried to apply static typing to the props, but TypeScript still doesn’t understand. What am I doing wrong?

Working code:

const test = abc(() => {
    return {
        isLoading: false,
        setIsLoading: () => ({ isLoading: false }),
    };
});

Non-working code:

const test = abc((set) => {
    return {
        isLoading: false,
        setIsLoading: () => ({ isLoading: false }),
    };
});

All code:

export type TestStateCreator<T> = (
    setState: StoreApi<T>["setState"],
    getState: StoreApi<T>["getState"],
    store: StoreApi<T>,
) => T extends (...args: any) => any ? ReturnType<T> : T;

type abcType = <
    T,
    U =
        | T
        | ((
              set: (...args: any) => void,
              get: (...args: any) => void,
              store: (...args: any) => any,
          ) => object),
>(
    init: TestStateCreator<U>,
) => U;

const abc: abcType = (value) => {
    return value;
};

const test = abc(() => {
    return {
        isLoading: false,
        setIsLoading: () => ({ isLoading: false }),
    };
});

error: Uncaught TypeError: Failed to execute ‘appendChild’ on ‘Node’: parameter 1 is not of type ‘Node’ [closed]

var c = Math.floor(Math.random()*3);
function b() {
c = Math.floor(Math.random()*3);
  //ther//
  // normal//
if (c === 2) {
  const h1 = document.createElement("input");
  const bob = h1.classList.add("asije");
  const sjwk = h1.setAttribute('type',"button");
  

const textNode = document.createTextNode("3");
h1.appendChild(textNode);
h1.appendChild(bob);
document.body.appendChild(h1);
  //ther//
  //normal//
} else if (c === 0) {
  const h1 = document.createElement("h1");
const textNode = document.createTextNode("2");
  const bob = h1.classList.add("asije");
  const sjwk = h1.setAttribute('type', "button");
h1.appendChild(bob);
h1.appendChild(textNode);
document.body.appendChild(h1);
  //ther//
  //normal//
} else if (c === 1) {
  const h1 = document.createElement("h1");
const textNode = document.createTextNode("1");
  const bob = h1.classList.add("asije");
  const sjwk = h1.setAttribute('type', "button");
h1.appendChild(bob);
h1.appendChild(textNode);
document.body.appendChild(h1);
}
};
body {
  background-color: #329A73;
}
.a {
  text-align: center;
  font-size: 60px;
  color: #41284B;
}
.b {
  text-align: center;
  color: #41284B;
}
.bob {
  
}
<body>
<h1 class="a">hi</h1>
  <h3 class="b">choo choo<h3>
    <input type="button" style="margin-left: auto; margin-right: auto; display: block;" onclick="b()">
</body>

trying to create a thing where you choose one out of three buttons, and one has a prize.

How can I keep my navbar from being obstructed? [closed]

I’m practicing building a website using just HTML, CSS, and JS and created a navigation bar following a guide from W3Schools. It sticks to the top of the screen like I want, but it isn’t on the most top layer as in scrolling past some elements causes it to go underneath like this photo carousel script I used.

let slideIndex = [1, 1, 1];
let slideId = ["Twice", "Blackpink", "Newjeans"]
showSlides(1, 0);
showSlides(1, 1);
showSlides(1, 2);

function plusSlides(n, no) {
  showSlides(slideIndex[no] += n, no);
}

function showSlides(n, no) {
  let i;
  let x = document.getElementsByClassName(slideId[no]);
  if (n > x.length) {
    slideIndex[no] = 1
  }
  if (n < 1) {
    slideIndex[no] = x.length
  }
  for (i = 0; i < x.length; i++) {
    x[i].style.display = "none";
  }
  x[slideIndex[no] - 1].style.display = "block";
}
#navbar {
  overflow: hidden;
  position: sticky;
  top: 0;
}

#navbar a {
  float: left;
  text-decoration: none;
  padding: 12px;
  margin: auto;
}
<div id="navbar">
  <a href="index.html">Home</a>
  <a href="history.html">History</a>
  <a href="idols.html">Idols</a>
  <a href="releases.html">Releases</a>
</div>

Using JavaScript in Adobe Acrobat File

I am trying to use use Javascript in a file I am creating. I have a list box that when clicked, a user can select up to 7 options. They will all appear in the the box fine. I would also like these selected options to appear on different boxes in my file. I can’t get them to appear there. Can someone help me?

My code to pull the 7 options from the list box is:

var listBox = this.getField(“List Box6”);

if (typeof listBox.value==”string”) event.value = listBox.value;

else event.value = listBox.value.join(“n”);

The code I tried to use to use to get those options to appear in other boxes is:
if(event.willCommit)

{

if(event.value !=”item1″) {

this.getField(“field1”).display = display.visible;

this.getField(“field2”).display = display.hidden;

this.getField(“field3”).display = display.hidden;

this.getField(“field4”).display = display.hidden;

this.getField(“field5”).display = display.hidden;

this.getField(“field6”).display = display.hidden;

}

else if (event.value !=”item2″){

this.getField(“field1”).display = display.hidden;

this.getField(“field2”).display = display.visible;

this.getField(“field3”).display = display.hidden;

this.getField(“field4”).display = display.hidden;

this.getField(“field5”).display = display.hidden;

this.getField(“field6”).display = display.hidden;

}

else if (event.value !=”item3″){

this.getField(“field1”).display = display.hidden;

this.getField(“field2”).display = display.hidden;

this.getField(“field3”).display = display.visible;

this.getField(“field4”).display = display.hidden;

this.getField(“field5”).display = display.hidden;

this.getField(“field6”).display = display.hidden;

}

else if (event.value !=”item4″){

this.getField(“field1”).display = display.hidden;

this.getField(“field2”).display = display.hidden;

this.getField(“field3”).display = display.hidden;

this.getField(“field4”).display = display.visible;

this.getField(“field5”).display = display.hidden;

this.getField(“field6”).display = display.hidden;

}

else if (event.value !=”item5″){

this.getField(“field1”).display = display.hidden;

this.getField(“field2”).display = display.hidden;

this.getField(“field3”).display = display.hidden;

this.getField(“field4”).display = display.hidden;

this.getField(“field5”).display = display.visible;

this.getField(“field6”).display = display.hidden;

}

else if (event.value !=”item6″){

this.getField(“field1”).display = display.hidden;

this.getField(“field2”).display = display.hidden;

this.getField(“field3”).display = display.hidden;

this.getField(“field4”).display = display.hidden;

this.getField(“field5”).display = display.hidden;

this.getField(“field6”).display = display.visible;

}

Websocket failing on real domain

I am developing a turn based game with websocket communication. It all works on localhost, and it actually worked on my previous domain on the same server I am at now. But now when I changed domain I suddenly started to get error in console: WebSocket connection to 'wss://example.com/socket.io/?EIO=4&transport=websocket' failed: createSocket @ index-WoxGCKpd.js:26....

I know there were lots of work back and forth with my openlitespeed.conf settings but I copied over what I had before to my new domain with the same server code. U have the following in my openlitespeed.conf, and same for -443:

virtualHost example.com-80 {
ProxyPass / http://127.0.0.1:5000/
ProxyPassReverse / http://127.0.0.1:5000/
ProxyPass /socket.io/ ws://127.0.0.1:5000/socket.io/
ProxyPassReverse /socket.io/ ws://127.0.0.1:5000/socket.io/
  user                    admin
  ...
  #VirtualHost config settings
  ...
  rewrite  {
    enable                  1
    autoLoadHtaccess        1
    RewriteCond %{HTTP:X-Forwarded-Proto} https [NC]
    RewriteRule . - [E=HTTPS:on]
    RewriteCond %{HTTPS} !=on
    RewriteCond %{HTTP:X-Forwarded-Proto} !https [NC]
    RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
    # Mail auto configuration (Thunderbird)
    RewriteRule ^/.well-known/autoconfig/mail/config-v1.1.xml$ http://dainternal/$0 [P,L]
  }
  # include aliases
  include /usr/local/lsws/conf/httpd-alias.conf
  extprocessor nodejs{
type proxy
address 127.0.0.1:5000
maxConns 2000
initTimeout 20
retryTimeout 0
respBuffer 0
}
context / {
type proxy
handler nodejs
addDefaultCharset off
}
context /socket.io {
    type proxy
    handler nodejs
    location 127.0.0.1:5000
    allowBrowse 1
    addResponseHeader Connection "Upgrade, Keep-Alive"
    addResponseHeader Upgrade "websocket"
    proxySetHeader Upgrade $http_upgrade;
    proxySetHeader Connection "Upgrade";
    proxySetHeader Host $host;
    proxySetHeader X-Real-IP $remote_addr;
    proxySetHeader X-Forwarded-For $proxy_add_x_forwarded_for;
    proxySetHeader X-Forwarded-Proto $scheme;
    websocket 1
}
}

I tried a lot of different configurations but can’t get the error to fix. What I fixed and tested so far:

  1. SSL on the domain which works
  2. Still works on localhost as normal
  3. Updated CORS settings to allow my origin for both localhost and example.com
  4. My host says there are no other settings to fix such as fire walls or opening of ports

I have no clue where to start looking, any ideas?

How to avoid umping Issue using ShadCN Carousel with Server-Side Pagination NextJS?

I’m using the ShadCN Carousel in my Next.js app and trying to integrate it with server-side paginated API data.

The issue I’m facing is that the scrolling is not smooth—whenever new data is loaded, I notice a UI jump or flicker. It seems like the carousel recalculates the item sizes, causing an abrupt shift instead of a seamless transition.

Has anyone experienced this before? Is there a known solution or best practice for handling pagination smoothly in the ShadCN carousel?

Thanks in advance!

const PaginatedCarousel = ({ initialData, type }) => {
  const [data, setData] = useState(initialData?.results || [])
  const [currentPage, setCurrentPage] = useState(1)
  const [carouselApi, setCarouselApi] = useState(null)
  const [isPending, startTransition] = useTransition()
  const page_count = initialData?.page_count

  useEffect(() => {
    if (!carouselApi) return

    const handleSelect = async () => {
      const currentIndex = carouselApi.selectedScrollSnap()
      const totalSlides = carouselApi.scrollSnapList().length

      if (
        currentIndex >= totalSlides - 3 &&
        currentPage < page_count &&
        !isPending
      ) {
        const newPage = currentPage + 1
        startTransition(async () => {
          const newData = await fetchMoreCourses({ type, page: newPage })

          if (newData?.results?.length) {
            setData((prev) => [...prev, ...newData.results])
            setCurrentPage(newPage)
          }
        })
      }
    }

    carouselApi.on('select', handleSelect)

    return () => {
      carouselApi.off('select', handleSelect)
    }
  }, [carouselApi, data, currentPage, type, page_count, isPending])

  return (
    <div className="flex flex-col gap-12 w-11/12">
      <div className="flex items-center justify-between">
        <span className="m:text-2xl text-xl text-neutrals-50 font-clash not-italic leading-9 font-extramedium">
          {MAPPED_TITLE[type]}
        </span>

        <div className="flex items-center gap-5">
          <Image
            width={11}
            height={18}
            src={'/images/prevArrow.svg'}
            alt={'prev-arrow'}
            className={'cursor-pointer'}
            onClick={() => carouselApi && carouselApi.scrollPrev()}
          />
          <Image
            width={11}
            height={18}
            src={'/images/nextArrow.svg'}
            alt={'next-arrow'}
            className={'cursor-pointer'}
            onClick={() => carouselApi && carouselApi.scrollNext()}
          />
        </div>
      </div>

      <div className="w-full overflow-hidden">
        <Carousel className="w-full relative" setApi={setCarouselApi}>
          <CarouselContent className="flex space-x-2">
            {data.map((course) => (
              <CardsOrchestrator course={course} type={type} key={course.id} />
            ))}

            {isPending && <SkeletonCard type={type} />}
          </CarouselContent>
        </Carousel>
      </div>
    </div>
  )
}

react component is not displayed with react router v7

I do

function PrivateRoutes() {
  const user = useAuth();
  return user.token ? <Outlet /> : <Navigate to="/login" replace />;
}

const routes = (isInstalled: boolean) => [
        element: <PrivateRoutes />,
        children: [
          {
            path: "admin",
            element: <Dashboard />,
            children: [
              { index: true, element: <Index /> },
              { path: "foo", element: <Foo/> },
              { path: "bar", element: <Bar/> },
            ],
          },
        ],
      },
    ],

Only the /admin/foo and /admin/bar are reachable and react component are displayed

/admin route render only the layout. component is not rendered.

Into console, I get

You rendered descendant <Routes> (or called `useRoutes()`) at "/admin" (under <Route path="admin">) but the parent route path has no trailing "*". This means if you navigate deeper, the parent won't match anymore and therefore the child routes will never render.

Please change the parent <Route path="admin"> to <Route path="admin/*">. react-router-dom.js:1197:49

If I do admin/*, On each click to a button, the segment is add. I can see /foo/bar/foo/bar …

I don’t understand what is wrong

How do I style Modal MUI component with TailwindCSS?

I have setup my app propely to make things work but i have problem with modal component.
When i do

<Button classname="bg-red-600">Click</Button>

Everything works fine. Same on other components but not modal
How do i make styling work on this component?

import * as React from "react";
import Box from "@mui/material/Box";
import Typography from "@mui/material/Typography";
import Modal from "@mui/material/Modal";

export default function ModalLogin({ modalShow, onClose }) {
    const [open, setOpen] = React.useState(false);

    React.useEffect(() => {
        setOpen(modalShow);
    }, [modalShow]);

    const handleClose = () => {
        setOpen(false);
        if (onClose) {
            onClose(false);
        }
    };

    return (
        <div>
            <Modal
                open={open}
                onClose={handleClose}
                aria-labelledby="modal-modal-title"
                aria-describedby="modal-modal-description"
            >
                <Box className="absolute top-1/2 left-1/2 w-64 bg-white border-solid border-2 border-black p-4">
                    <Typography id="modal-modal-title" variant="h6" component="h2">
                        Text in a modal
                    </Typography>
                    <Typography id="modal-modal-description" sx={{ mt: 2 }}>
                        Duis mollis, est non commodo luctus, nisi erat porttitor ligula.
                    </Typography>
                </Box>
            </Modal>
        </div>
    );
}

How can I make a Dynamic Grid?

So currently my code iterates over an object to list all user items based on type when I am using the grid property of display each row gap is dependent on the largest item in the previous row. This means I want each element to have only a set row gap independent of what the largest item is in that row.

<div className={styles.profileGrid}>
          {investmentTypes.map(({ category, subtypes }) => (
            <div key={category} className={styles.block5}>
              <div className={styles.row6}>
                <div className={styles.info6}>{category}</div>
                <Button onClick={() => handleAddEntry(category)} className={styles.addButton}  >
                  +
                </Button>
              </div>
              {investmentEntries
                .filter((entry) => entry.category === category)
                .map((entry) => {
                  const selectedSubtype = subtypes.find((sub) => sub.name === entry.subtype) || {
                    inputs: []
                  };
                  return (
                    <div key={entry.id} className={styles.row8}>
                      <div className={styles.row1}>
                      <Select
                        value={entry.subtype}
                        onChange={(e) => handleEntryChange(entry.id, "subtype", e.target.value)}
                        displayEmpty
                        className={styles.inputName}
                        inputProps={{ "data-testid": `subtype-select-${entry.id}` }}
                      >
                        <MenuItem value="" disabled>
                          Select Subtype
                        </MenuItem>
                        {subtypes.map((subtype) => (
                          <MenuItem key={subtype.name} value={subtype.name}>
                            {subtype.name}
                          </MenuItem>
                        ))}
                      </Select>
                      <Button
                        onClick={() => handleRemoveEntry(entry.id)}
                        className={styles.removeButton}
                      >
                        -
                      </Button>
                      </div>

                      <TextField
                        type="text"
                        name="description"
                        className={styles['input-name']}
                        placeholder="Description"
                        value={entry.description || ""}
                        onChange={(e) => handleEntryChange(entry.id, "description", e.target.value)}
                      />
                      {selectedSubtype.inputs.map((input) => (
                        <TextField
                          key={input}
                          type="number"
                          name={input}
                          className={styles['input-name']}
                          placeholder={input}
                          value={entry.inputs[input] || ""}
                          onChange={(e) => handleInputChange(entry.id, input, e.target.value)}
                        />
                      ))}
                      
                    </div>
                  );
                })}
            </div>'''

My css for the classes look like this

.profileGrid {
  display: grid;
  align-content: center;
  margin: 0px 0px 0px 5%;

  min-width: max-content;
  font: $font-family-primary; 
  justify-content: center;
  grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
  grid-auto-rows: min-content; 
  
  @include md {
    column-gap: 32px;
  }

  @include lg {
    grid-template-columns: repeat(1, minmax(0, 1fr)); 
  }

  @include xs {
    column-gap: 16px;
    grid-template-columns: repeat(1, minmax(0, 1fr)); 
  }
} 

Is it possible to know if a is already loaded?

I can attach an event listener for the load event, but if the link is already loaded it will never trigger. Is there any way to check if it already loaded?

For images there is an .complete attribute that will make the trick and for <link rel="stylesheet"> there is .sheet, but I could find nothing for the preload link.

Chart.js streaming showing time (HH:MM:SS – 24 hour clock) on xAxis

I have seen a very similar question already, that concerns chart.js, but I am using the chart.js streaming plugin(https://nagix.github.io/chartjs-plugin-streaming/latest/). Therefore my code looks like this:

scales: {
  xAxes: [{
    type: 'realtime'
  }]
}

Adopting a solutions from this problem: Chart.js showing time (HH:MM:SS – 24 hour clock) on xAxis doesn’t seem to work because of this.

What other way is there to have a 24h format on the x-axis with this plugin?

Force grayscale rendering in Chrome’s built-in PDF viewer via URL parameter? [duplicate]

I’m working on a project where we need PDFs to display in grayscale (e.g., to save battery on OLED devices) when viewed in Chrome’s native PDF viewer. I attempted to append a parameter like #grayscale=1 to the PDF URL, but it seems to be completely ignored.

Here’s my minimal test case:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Grayscale PDF Test</title>
</head>
<body>
  <iframe src="https://example.com/document.pdf#grayscale=1" width="800" height="600"></iframe>
</body>
</html>

Despite the parameter, the PDF always renders in full colour.

Is there any documented or even undocumented URL parameter or workaround to force Chrome’s built-in PDF viewer to render PDFs in grayscale? Any suggestion, even if they involve flags or non-standard approaches, would be highly appreciated.

I’ve updated the post based on further discussion. My original idea to use #grayscale=1 was solely based on a coworker’s offhand suggestion—with no supporting documentation. In fact, as referenced (e.g. this answer and the Chromium source), while Chrome’s PDF viewer supports parameters for page number or zoom level, there is no documented or hidden parameter to force grayscale rendering.

CORS request successful if password is complex enough, however username throws an undefined error? [closed]

Here’s the long and the short of it, building a uni project and utilizing steps from the coursework / tutorials to finish it, because the coursework is out of date having to navigate it in modern react.

The Problem:

Onto the error I am getting, i’ve narrowed it down to the front end component in question based on the behaviour I have observed. I’m still trying to narrow it further but this is what I have so far:

  • The state for setting the signup data (username but i assume all of them are the same) is coming back as defined
  • I am getting a 400 bad request if the password is too simple
  • Due to the error the code is not activating the navigator hook

The Code:

There are two pieces of code I am working with that I think the problem can be stemming from, i’ll list them and the reasoning why I’m using them and go from there:

import axios from "axios";

axios.defaults.baseURL =
  "<Heroku app link>";
axios.defaults.headers.post["Content-Type"] = "multipart/form-data";
axios.defaults.withCredentials = true;

This is my axiosDefaults.js file that is imported into my App.js, according to the tutorials and the coursework i set up this defaults file so I don’t need to specify it everytime I want to create an axios call. (As an aside a possible solution I found was change multiform to application/json, however i’m working with images so I need to keep it like this apparently)

const SignUpForm = () => {
  const [signUpData, setSignUpData] = useState({
    username: "",
    password1: "",
    password2: "",
  });
  const { username, password1, password2 } = signUpData;

  const [errors, setErrors] = useState({
    username: [],
    password1: [],
    password2: [],
    non_field_errors: [], // For general errors
  });

  const navigate = useNavigate();

  const handleChange = (event) => {
    setSignUpData({
      ...signUpData,
      [event.target.name]: event.target.value,
    });
  };

  const validateForm = (data) => {
    const errors = {};

    // Username validation
    if (!data.username) {
      errors.username = ["Username is required."];
    }

    // Password validation
    if (!data.password1) {
      errors.password1 = ["Password is required."];
    } else if (data.password1.length < 8) {
      errors.password1 = ["Password must be at least 8 characters long."];
    }

    // Confirm password validation
    if (!data.password2) {
      errors.password2 = ["Confirm password is required."];
    } else if (data.password1 !== data.password2) {
      errors.password2 = ["Passwords do not match."];
    }

    return errors;
  };

  const renderErrors = (field) => {
    return errors[field]?.map((message, idx) => (
      <Alert variant="warning" key={idx}>
        {message}
      </Alert>
    ));
  };

  const handleSubmit = async (event) => {
    event.preventDefault();

    // Validate the form
    const validationErrors = validateForm(signUpData);
    if (Object.keys(validationErrors).length > 0) {
      setErrors(validationErrors);
      return;
    }

    // Submit the form
    const formData = new FormData();
    formData.append("username", username);
    formData.append("password1", password1);
    formData.append("password2", password2);

    try {
      const response = await axios.post(
        "/dj-rest-auth/registration/",
        formData
      );
      console.log("Response:", response.data); // Debugging line
      setSignUpData({ username: "", password1: "", password2: "" });
      setErrors({});
      console.log("Navigating to /signin"); // Debugging line
      navigate("/signin");
    } catch (err) {
      console.error("Error:", err.response?.data); // Debugging line
      setErrors({
        username: err.response?.data?.username || [],
        password1: err.response?.data?.password1 || [],
        password2: err.response?.data?.password2 || [],
        non_field_errors: err.response?.data?.non_field_errors || [],
      });
    }
  };

This is the main portion of my component based on suggestions I was under the assumption that I should format it to form data, and then pass it into the axios request, then any errors generated match them to common errors. It was this change that enabled the request to succeed, even if the code still errors, before this it was just erroring and 400 bad requesting.

            <Form.Group controlId="password1">
              <Form.Label className="d-none">Password</Form.Label>
              <Form.Control
                className={css.Input}
                type="password"
                placeholder="Password"
                name="password1"
                value={password1}
                onChange={handleChange}
              />
            </Form.Group>
            {renderErrors("password1")}

Finally the jsx where the errors will be rendered.

What I’ve Tried:

So far as stated above i have tried changing how the data is processed, before I was sending the state object and now i’m sending it as form Data this fixed the initial 400 bad request if the password entered was complex enough but if I enter a simple password / already used username OR leave it blank it still errors out (400 bad request, username undefined)

As well as this I have thoroughly tested my backend, it works fine, I can create users in it via the terminal in app, heroku terminal and if i send an xcurl request, so it’s definitely a front end issue.

I think the error is coming from the error being generated or the state is stale and being referenced again, Im not sure and that’s why i’m here to get extra eyes / insight.

To Summarize:

  • Backend works fine, can create accounts via the app, heroku and xcurling requests from other terminals.
  • Frontend signup CAN signup only if it’s a new account name and a complex enough password
  • Error handling is based on common error validation and matching but I THINK the error could be caused here because it’s not getting proper responses from the backend
  • Other place I think the error is coming from is stale state. However seeing as i’m also using old course materials as it’s not been updated I’m not 100% sure on what i am missing
  • Even though application/json is a possible solution i need multipart/form-data to send images.

This API project is not authorized to use this API. Places API error: ApiNotActivatedMapError. It’s driving me mad

So I am trying to set up a autocomplete function on my application using Google Maps API.

I am using React.js, and in my index.html file I have put in the tags:

<script src="https://maps.googleapis.com/maps/api/js?libraries=places&key=*key*"></script>

Then I have stored the functionality on the client side under LocationTracker.js

/* global google */

import { useState, useEffect } from "react";
import axios from "axios";
import "./LocationTracker.css";
import { IoLocationOutline } from "react-icons/io5";
import { FaSpinner } from "react-icons/fa"; // Import spinner icon

export default function LocationTracker() {
    const apiKey = process.env.REACT_APP_GOOGLE_MAPS_API_KEY;

// React state for address, error, and loading
const [address, setAddress] = useState("");
const [error, setError] = useState(false);
const [loading, setLoading] = useState(false);

useEffect(() => {
    if (window.google && window.google.maps) {
        // Make sure google.maps is available before trying to use it
        new google.maps.places.Autocomplete(
            document.getElementById("autocomplete")
        );
    }
}, []); // Empty array ensures this runs only once after component mounts

const getAddressFrom = (lat, long) => {
    setLoading(true); // Start loading

    axios.get(`https://maps.googleapis.com/maps/api/geocode/json?latlng=${lat},${long}&key=${apiKey}`)
        .then(response => {
            if (response.data.error_message) {
                console.log(response.data.error_message);
                setError(true);
            } else {
                setAddress(response.data.results[0].formatted_address);
                setError(false);
            }
        })
        .catch(() => {
            setError(true);
        })
        .finally(() => {
            setLoading(false); // Stop loading
        });
};

const findLocation = () => {
    if (navigator.geolocation) {
        setError(false);
        setLoading(true); // Start loading when clicking the button
        navigator.geolocation.getCurrentPosition(
            position => {
                getAddressFrom(position.coords.latitude, position.coords.longitude);
            },
            () => {
                setError(true);
                setLoading(false); // Stop loading on error
            }
        );
    } else {
        setError(true);
    }
};

const handleInputChange = (event) => {
    setAddress(event.target.value);
};

return (
    <div id="locationPg">
        <h1>Location Tracker</h1>

        <div id="locationTrackerContainer">
            {error && (
                <div id="failedGeolocationContainer">
                    <h2>Geolocation is not permitted</h2>
                </div>
            )}

            <div id="locationInputContainer">
                <input 
                    type="text"
                    placeholder="Enter address"
                    value={address}
                    onChange={handleInputChange}
                    id="autocomplete"
                />

                {/* Change icon based on loading state */}
                {loading ? (
                    <FaSpinner className="spinner-icon" />
                ) : (
                    <IoLocationOutline onClick={findLocation} id="locationButtonIcon" />
                )}
            </div>
        </div>
    </div>
);

}

I also have another function that allows users with the press of a button (and when location is enabled) to show their location in the input bar. This works perfectly

I have also ensured that my

Maps JavaScript API
Places API (New)
Geolocation API
Geocoding API

are all enabled on my Google Cloud Console.

I have also set up billing for the project that this api key is part of, and these apis are all enabled.

why then when i try and use the autocomplete does it always say in my console

This API project is not authorized to use this API. Places API error: ApiNotActivatedMapError