How can I prevent my cookies being blocked as Third Party Cookies?

I have an authentication workflow as follows:

  1. From the client I send encrypted user and password credentials in x-authorization header in a request to API entpoint example.net/login
  2. the response of this request sends back authorization cookies set with set-cookie in the header.
  3. The cookies are used in a subsequent request to example.net/user, where the endpoint validates the cookies.

Now, with current and upcoming policies regarding Third Party Cookies, the cookies set and forwarded via first response get blocked by modern browsers (it seems) and the endpoint example.net/user returns a 401 status code. It works when the user enables third party cookies in their browser.

Is there still any way of cookie based authorization possible, or any alternative authorization flow at all, without forcing the user to enable cookies in their browsers?

I tried setting the cookies manually in the client via javascript, since the first request also has the cookies as json in its response data. But nothing works so far.

How to proxy fetch requests in chrome extensions?

I see the solution to this nowhere, and yet have the question:
How to proxy fetch requests in chrome extensions?

I have this code:

async makeRequest() {
    const postData = {
      // ..payload
    };

    const jsonData = JSON.stringify(postData);
    const url = "http://127.0.0.1:8000/endpoint/";
    try {
      // HERE I WANT TO USE PROXY!

      const response = await fetch(url, {
        method: "POST",
        headers: {
          "Content-Type": "application/json", 
        },
        body: jsonData,
      });

      return response;

    } catch (error) {
      console.error("Error during fetch:", error);
      return false;
    }
  }

My app is a webscrapping chrome extension, therefore the usage of proxies for my webscrapping purposes is fundamental.

Also saw that we can use the proxies manifest permission, but the problem that I run into using that implementation is that configures the Proxy for the WHOLE COMPUTER, and i only want it for the chrome extension requests.

Any solution?
Thanks!

Ready-Made Restaurant Ordering System with POS, Loyalty Programs, Third Party Delivery Integrations

This will probably get taken down but we are in urgent need and I am freaking out and I don’t know where else to go for a solution.

We urgently need a comprehensive restaurant ordering system, similar to Restoplus, with essential features like restaurant login/signup, customizable menus with item variations, a POS interface, and access to sales data. The system must support both in-store pickup and dine-in notifications via SMS, as well as integrate with delivery services like Uber/DoorDash. Additionally, it should include a robust rewards system for users, allowing them to earn points with purchases and redeem them, similar to major fast-food chains’ loyalty program. Instant receipt printing and order processing capabilities, mirroring the efficiency of modern restaurant system.

We are looking to purchase a ready-made solution immediately, with a strong preference for off-the-shelf systems to meet our critical timeline. We need at least a partial deployment within the next 2 days. If you have an existing solution that fits these requirements, please contact us ASAP. Speed is of the essence in this project.

We are looking for a ready-made solution that can be deployed immediately, with at least partial functionality within the next 2 days. The system must support a centralized website where we can manage client restaurants. We prioritize acquiring an off-the-shelf system due to the critical urgency of this project. Immediate responses are required to meet our timeline.

Look I’ll be honest we have a meeting with a client on Tuesday and we want a solution asap to make him believe in us or else we will loose him to another platform possibly who does all these for a monthly fee. We will also charge a monthly fee from restaurants via Stripe.

If anyone has a similar site we are happy to book a meeting and take a look at it.

I tried Fiverr, freelander and upwork, then though that this site has the most developers working on it also someone might have a similar system already built for us to take a look at.

Thanks,
Sasuke.

How to Extract Digital Signatures from a PDF Using Node.js?

I’m trying to extract information about all the digital signatures in a PDF file using Node.js. I found a way to obtain some data that appears to contain this information, but it seems to be jumbled.

Here is my current code:

const forge = require("node-forge");
const fs = require("fs");
const { Buffer } = require("buffer");


function GetSignaturesByteRange(FileBuffer) {

    const ByteRangeList = [];

    let ByteRangeStart = 0;

    while ((ByteRangeStart = FileBuffer.indexOf("/ByteRange [", ByteRangeStart)) !== -1) {

        const ByteRangeEnd = FileBuffer.indexOf("]", ByteRangeStart);
        const ByteRange = FileBuffer.slice(ByteRangeStart, ByteRangeEnd + 1).toString();

        const ByteRangeString = /(d+) +(d+) +(d+) +(d+)/.exec(ByteRange);
        const ByteRangeArray = ByteRangeString.slice(1, 5).map(Number); // Convert to integers

        // Add the ByteRange to the list
        ByteRangeList.push(ByteRangeArray);

        // Move past the current ByteRange
        ByteRangeStart = ByteRangeEnd + 1;

    }

    return ByteRangeList;
}

function GetSignatureData(FileBuffer, ByteRange) {

    // Extract the specified range from the buffer
    let ByteRangeBuffer = FileBuffer.slice(ByteRange[1] + 1, ByteRange[2] - 1)

    // Remove the zeroes from the end of the buffer
    let EndIndex = ByteRangeBuffer.length;
    while (EndIndex > 0 && ByteRangeBuffer[EndIndex - 1] === 0x30) {
        EndIndex--;
    }

    ByteRangeBuffer = ByteRangeBuffer.slice(0, EndIndex);

    return ByteRangeBuffer.toString("binary");
}

const InputFile = fs.readFileSync("./signed.pdf");
const AllByteRanges = GetSignaturesByteRange(InputFile);

let SignatureBuffer = GetSignatureData(InputFile, AllByteRanges[0]);


console.log(SignatureBuffer);

fs.writeFileSync("Sigature.bin", Buffer.from(SignatureBuffer, "hex"));

The Signature.bin file produced by this code contains some data such as my name and city from when I digitally signed the PDF, but it is surrounded by what seems to be garbage data.

How can I properly extract and clean up the digital signature information from the PDF? Any advice or improvements to my code would be greatly appreciated!

Styling dropdown that is created with react-select

This is my first time using react-select and I have created the dropdown as below (I want this dropdown to be a re-usable component)

//import libraries
import React from 'react';
import Select, { components } from 'react-select';
import classNames from 'classnames';

//import some svg icons using svgr
import Twitter from '@/assets/images/icon-twitter.svg';
import Linkedin from '@/assets/images/icon-linkedin.svg';
import Youtube from '@/assets/images/icon-youtube.svg';


export const PlatformDropdown = (listProps: any) => {
const options = [           
        { label: 'Twitter', value: 'Twitter', icon: <Twitter /> },
        { label: 'Linkedin', value: 'Linkedin', icon: <Linkedin /> },
        { label: 'YouTube', value: 'YouTube', icon: <Youtube /> },
        { label: 'Facebook', value: 'Facebook', icon: <Facebook /> },       
    ];
const { Option } = components;

const IconOption = (props: any) => (
        <Option {...props}>
            <div className="flex items-center gap-2">
                <div>{props.data.icon}</div>
                {props.data.label}
            </div>
        </Option>
    );

const handleChange = (e: any) => {
        listProps.setValue(e.value.toLowerCase());
    };

return (
        <Select
            options={options}
            components={{ Option: IconOption }}
            className="w-40 mx-auto"
            unstyled
            isClearable
            onChange={handleChange}
            value={listProps.value}
            classNames={{
                control: ({ isFocused }) => 'border border-gray-300 rounded-md',
                option: ({ isDisabled, isFocused, isSelected }) =>
                    classNames(
                        isSelected && 'text-purple [&_svg]:fill-purple',                        
                    )
            }}
        />
    );
};

The dropdown is working fine but as you can see in the first pic, the icons show on the list for selection. But the icon is NOT seen on the selected item. Can anyone help me fix this issue so that icon is seen on the selected value as well?

[![List][1]][1]


  [1]: https://i.sstatic.net/Z4P5IV7m.png

Can anyone give me a specific or clear explanation that , when to use QUERY selector and ID selector in JavaScript?

I wanted to fetch the checkboxes from the html part through Id Selector but not getting the desired output. After that I tried through querySelector , then I get my desired output. So this is the confusion that when to use querySelector and ID selector. Please clarify.

const checkBoxElement = document.getElementById('checked');
const checkedBoxes = document.querySelectorAll('input[type="checkbox"]:checked');

these are the cases where I switch to querySelector from IdSelector.

I can’t make collisions work in p5js with circles

I have followed the instructions of a “TheCodingTrain” tutorial, it describes how to calculate the distance between two circles to emulate collisions. I have a lot more, but this is the code I have pertaining to my problem.

  playerPos = createVector(width * 0.2, height / 2, 60);
  enemyPos1 = createVector(width * 0.8, height / 2, 40);

  d = dist(playerPos.x,playerPos.y,enemyPos1.x,enemyPos1.y);

  circle(playerPos.x, playerPos.y, playerPos.z);
  circle(enemyPos1.x, enemyPos1.y, enemyPos1.z);

  if( d < playerPos.z/2 + enemyPos1.z/2){
     enemyPos1.x++
  }

I tried the code above, it did not make the position of the smaller circle change. I was expecting it to move. I have gone through and I haven’t identified any problems with the code.

How make a validator for a parent function?

Im making a web site which encrypt texts and decrypt them, already I managed asignning the funcionalities to the buttons and enclose this functions into a parent function with the finality that the user only can use the web site after do click in “aceppt thte terms of use” (with a checkbox), so all good at this point beacuse I bond this button as well but I found that after the first click in the button dosent matter if this isnt mark anymore the parent function dont “return”.

I wanna make a validator for this checkbox.

Well my first thought was made another parent function bellow all like this:

document.getElementId("MycheckboxButton").addEeventListener("change", validator);

function validator() {
  const terms = document.getElementId("MycheckboxButton").value
  if (check.checked) {}

But to be short i dont know exactly how do it wel… Can you help me please guys 🙂

How to fix my accordion button using HTML, CSS and Javascript

I am creating a FAQs page, and the accordion button doesn’t seem to be working. In this FAQs page, I have 5 “FAQs” div each containing the accordion button and a “panel” div. Now when i click on the accordion button, the panel div is supposed to be displayed but it is not working

HTML CODE 
<section id="FAQs">
        <div class="FAQs-container">
            <h1>Have any questions?</h1>
            <div class="FAQs">
                <button class="accordion">
                    What is the process of ordering furniture on urban oasis?
                    <i class="fa-solid fa-chevron-down"></i>
                </button>
                <div class="panel">
                    <p>
                        To order furniture from our ecommerce store, simply browse our product 
                        collection, select the desired items, and add them to your cart. Proceed 
                        to checkout, where you'll enter your shipping and payment information to confirm your order
                    </p>
                </div>
            </div>
            <div class="FAQs">
                <button class="accordion">
                    How do i know a furniture item will fit in my home?
                    <i class="fa-solid fa-chevron-down"></i>
                </button>
                <div class="panel">
                    <p>
                        To check if a furniture item will fit, measure your space and compare 
                        it with the product's dimensions. Ensure there's enough clearance for 
                        movement, and use room planning tools for a visual fit. Need help? Contact our customer service team!    
                    </p>
                </div>
            </div>
            <div class="FAQs">
                <button class="accordion">
                    Do you offer assembly services for furniture items?
                    <i class="fa-solid fa-chevron-down"></i>
                </button>
                <div class="panel">
                    <p>
                        Yes, we do offer assembly services for many of our furniture items. You can 
                        select this option during checkout, or contact our customer service team for 
                        more details and availability.    
                    </p>
                </div>
            </div>
            <div class="FAQs">
                <button class="accordion">
                    Can I customise the color or material of a furniture item?
                    <i class="fa-solid fa-chevron-down"></i>
                </button>
                <div class="panel">
                    <p>
                        Yes, you can customize the color and material of many furniture items! 
                        Simply use the “Customize” option in the navbar and click the “Customize Order” 
                        button  to explore your choices and create a piece that perfectly matches your style.
                    </p>
                </div>
            </div>
            <div class="FAQs">
                <button class="accordion">
                    What if my furniture item arrives damaged or defective?
                    <i class="fa-solid fa-chevron-down"></i>
                </button>
                <div class="panel">
                    <p>
                        If your furniture arrives damaged or defective, please contact our customer service team 
                        immediately. We'll guide you through the return or replacement process and ensure the issue 
                        is resolved quickly.
                    </p>
                </div>
            </div>
        </div>
    </section>

CSS 
#FAQs {
    background: var(--bg);
}

#FAQs .FAQs-container {
    max-width: 75%;
    margin: auto;
}

#FAQs .FAQs-container h1 {
    margin: 1.5rem 0;
    text-align: center;
    letter-spacing: 3px;
}

#FAQs .FAQs-container .FAQs .accordion {
    background-color: var(--white);
    color: rgba(0, 0, 0, 0.8);
    cursor: pointer;
    font-size: 1.2rem;
    width: 100%;
    padding: 2rem 2.5rem;
    outline: none;
    border: none;
    transition: 0.4s;
    display: flex;
    justify-content: space-between;
    align-items: center;
    font-weight: bold;
}

#FAQs .FAQs-container .FAQs .accordion i {
    font-size: 1.6rem;
}

#FAQs .FAQs-container .FAQs .accordion .active,
#FAQs .FAQs-container .FAQs .accordion:hover {
    background-color: #f1f7f5;
}

#FAQs .FAQs-container .FAQs .panel {
    padding: 0 2rem 2.5rem 2rem;
    background-color: var(--white);
    overflow: hidden;
    background-color: #f1f7f5;
    display: none;
}

#FAQs .FAQs-container .FAQs {
    border: 1px solid rgba(0, 0, 0, 0.2);
    margin: 10px 0px;
}

#FAQs .FAQs-container .FAQs .active {
    border: none;
}

#FAQs .FAQs-container .FAQs .panel p{
    color: rgba(0, 0, 0, 0.7);
    font-size: 1.2rem;
    line-height: 1.4;
}

JAVASCRIPT

var acc = document.getElementsByClassName("accordion");
var i;

for (i = 0; i < acc.length; i++) {
    acc[i].addEventListener("click", function () {
        this.classList.toggle("active");
        this.parentElement.classList.toggle("active");

        var panel = this.nextElementSibling;

        if (panel.style.display === "block") {
            panel.style.display = "none";
        } else {
            panel.style.display = "block";
        }
    });
}
[FAQs page accordion not working](https://i.sstatic.net/YpCcLXx7.png)

I tried creating an accorion button that displays a paragraph when it is clicked on but it does not work.

Item Id not being passed to the async function in vue js

I have a vue file, where I have a checkbox for every row (corresponds to each object), which when clicked needs to toggle and hit the patch api. When clicked the checkbox, the item.id and checked=true needs to be passed in the async function. But when I check the console, the ItemId is undefined and also in network tab, the api has /undefined/ in the pk param.

The template is here..

<template>
  <div
    class="modal fade"
    id="manageLocationModal"
    tabindex="-1"
    aria-labelledby="manageLocationLabel"
    aria-hidden="true"
  >
    <div class="modal-dialog modal-dialog-centered modal-lg">
      <div class="modal-content">
        <div class="modal-header">
          <h5 class="modal-title" id="manageLocationModalLabel">
            Locations List
          </h5>
          <button
            type="button"
            class="btn-close"
            data-bs-dismiss="modal"
            aria-label="Close"
          ></button>
        </div>
        <div class="modal-body px-4">
          <div class="collapse mb-4 border p-4" id="editLocation">
            <location-edit-form
              :item="item"
              @updated="itemUpdated"
              @cancel="cancelUpdate"
            ></location-edit-form>
          </div>

          <table class="table table-bordered">
            <thead>
              <tr>
                <th>S/N</th>
                <th>Local Name</th>
                <th>Latitude</th>
                <th>Longitude</th>
                <th>Variable</th>
                <th>Altitude</th>
                <th>Municipality</th>
                <th>Owners Name</th>
                <th>Operational</th>
                <th>Ward</th>
                <th>Started Date</th>
                <th>End Date</th>
                <th>Uploaded At</th>
                <th class="text-center">Actions</th>
                <th>Publish</th>
              </tr>
            </thead>
            <tbody>
              <tr v-for="(item, index) in location" :key="item.id">
                <th scope="row" v-if="meta.currentPage > 1">
                  <p v-if="index !== 9">
                    {{ meta.currentPage - 1 }}{{ ++index }}
                  </p>
                  <p v-else>
                    {{ ++index * meta.currentPage }}
                  </p>
                </th>
                <th v-else scope="row">
                  {{ ++index }}
                </th>
                <td>{{ item.Localname }}</td>
                <td>{{ item.latitude }}</td>
                <td>{{ item.longitude }}</td>
                <td v-if="item.variable.length">
                  {{ item.variable | filterVariableName }}
                </td>
                <td v-else>N/A</td>
                <td>{{ item.Altitude }}</td>
                <td>{{ item.Municipality }}</td>
                <td>{{ item.owners_name }}</td>
                <td>{{ item.Operational }}</td>
                <td>{{ item.Ward }}</td>
                <td>{{ item.Started_date }}</td>
                <td>{{ item.End_date }}</td>
                <td>{{ item.uploaded_at }}</td>
                <td class="text-center">
                  <button
                    class="btn btn-primary btn-sm me-3 mb-3"
                    @click.prevent="editLocation(item)"
                    :disabled="isUpdating"
                    data-bs-toggle="tooltip"
                    data-bs-placement="top"
                    title="Edit"
                  >
                    <i class="bi bi-pencil-square"></i>
                  </button>
                  <button
                    class="btn btn-danger btn-sm"
                    :disabled="isUpdating"
                    @click.prevent="deleteLocation(item.location_id)"
                    data-bs-toggle="tooltip"
                    data-bs-placement="top"
                    title="Delete"
                  >
                    <i class="bi bi-trash-fill"></i>
                  </button>
                </td>
                <td class="text-center">
                  <input
                    type="checkbox"
                    v-model="item.selectedItems"
                    :value="item.id"
                    @change="handleCheckboxChange(item.id, $event.target.checked)"
                    :checked="selectedItems.includes(item.id)"
                  />                  
                </td>
              </tr>
            </tbody>
          </table>

          <nav>
            <ul class="pagination" v-if="meta.totalPages > 1">
              <li
                class="page-item"
                v-if="meta.currentPage !== 1 && meta.totalPages > 1"
              >
                <button
                  class="page-link"
                  @click.prevent="getData(--meta.currentPage)"
                  :disabled="meta.currentPage === 1"
                >
                  Previous
                </button>
              </li>
              <li
                v-for="i in meta.totalPages"
                class="page-item"
                :class="{ active: meta.currentPage === i }"
                :key="i"
              >
                <a class="page-link" href="#" @click.prevent="getData(i)">{{
                  i
                }}</a>
              </li>
              <li
                class="page-item"
                v-if="
                  meta.currentPage !== meta.totalPages && meta.totalPages > 1
                "
              >
                <button
                  class="page-link"
                  @click.prevent="getData(++meta.currentPage)"
                  :disabled="meta.currentPage >= meta.totalPages"
                >
                  Next
                </button>
              </li>
            </ul>
          </nav>
        </div>
        <div class="modal-footer">
          <button
            type="button"
            class="btn btn-secondary"
            data-bs-dismiss="modal"
          >
            Close
          </button>
        </div>
      </div>
    </div>
  </div>
</template>

<script>
import LocationEditForm from "../../components/forms/LocationEditForm.vue";

export default {
  name: "ManageLocationModal",
  components: { LocationEditForm },
  data() {
    return {
      editCollapse: null,
      isUpdating: false,
      location: [],
      selectedItems: [], // Array to store selected item IDs
      meta: {
        totalItems: 0,
        totalPages: 0,
        currentPage: 1,
        pageSize: 10,
      },
      item: null,
    };
  },
  mounted() {
    this.getData();
  },
  filters: {
    filterVariableName(val) {
      const variable = val.map((el) => {
        return el.variable;
      });
      return variable;
    },
  },
  methods: {
    collapseEditForm(type) {
      if (!this.editCollapse) {
        this.editCollapse = new this.$bootstrap.Collapse(
          document.getElementById("editLocation")
        );
      }
      if (type === "show") {
        this.editCollapse.show();
      } else {
        this.editCollapse.hide();
      }
    },
    collapseEditLocationForm() {
      this.collapseEditForm("hide");
      this.item = null;
      this.isUpdating = false;
    },
    itemUpdated() {
      this.collapseEditLocationForm();
      this.getData();
      this.$emit("itemUpdated");
    },
    cancelUpdate() {
      this.collapseEditLocationForm();
    },
    async deleteLocation(id) {
      await this.$confirm({
        message: `Are you sure?`,
        button: {
          no: "No",
          yes: "Yes",
        },
        callback: (confirm) => {
          if (confirm) {
            this.$repository.location
              .delete(id)
              .then(() => {
                this.getData();
                this.$emit("itemUpdated");
                this.$toast.success("Location deleted");
              })
              .catch(() => {
                this.$toast.error("Deletion failed");
              });
          }
        },
      });
    },
    editLocation(item) {
      this.isUpdating = true;
      this.item = item;
      this.collapseEditForm("show");
    },
    async getData(page = 1) {
      this.meta.currentPage = page;

      let params = `?page_size=${this.meta.pageSize}&ordering=-uploaded_at`;

      if (this.meta.currentPage > 1) {
        params += `&page=${this.meta.currentPage}`;
      }

      await this.$repository.location.filter(params).then((res) => {
        this.location = res.data.results;
        this.meta.totalItems = res.data.count;
        this.meta.totalPages = Math.ceil(res.data.count / 10);
      });
    },
    async handleCheckboxChange(itemId, isChecked) {
      console.log("Checkbox changed:", { itemId, isChecked });
      if (!itemId) {
        console.error("Item ID is undefined");
        return;
      }
      this.isUpdating = true;
      try {
        if (isChecked) {
          console.log("Checkbox checked. Item ID:", itemId);

          // Check if the item is already in the selectedItems list
          if (!this.selectedItems.includes(itemId)) {
            this.selectedItems.push(itemId);
          }

          // Publish the item if checked
          await this.$repository.location.edit({ in_draft: false }, itemId);
          this.$toast.success("Location published successfully.");
        } else {
          console.log("Checkbox unchecked. Item ID:", itemId);

          // Remove the item from the selectedItems list
          if (this.selectedItems.includes(itemId)) {
            this.selectedItems = this.selectedItems.filter(
              (id) => id !== itemId
            );
          }
        }
      } catch (error) {
        this.$toast.error(
          `Error: ${error.response?.data?.error || error.message}`
        );
      } finally {
        this.isUpdating = false;
      }
    },
  },
};
</script>

<style scoped>
.modal-dialog {
  max-width: 85%;
  overflow: initial !important;
}
.modal-body {
  height: 80vh;
  overflow-y: auto;
}
.actions {
  min-width: max-content;
}
</style>

The code snippet of focus here is :

<input
                type="checkbox"
                v-model="item.selectedItems"
                :value="item.id"
                @change="handleCheckboxChange(item.id, $event.target.checked)"
                :checked="selectedItems.includes(item.id)"
              />

And the async function handleCheckboxChange is called.

The screenshot of console is here.

Screenshot of Console and api

Google Picker API giving Null user before completing authorization

I am using the google picker api example code from https://developers.google.com/drive/picker/guides/sample and when I tried authenticating with google, it always gives me back a null access token before I even complete the authorization part. Here is the following code I used for authorizing:

let tokenClient;
let accessToken = null;
let pickerInited = false;
let gisInited = false;


document.getElementById('authorize_button').style.visibility = 'hidden';
document.getElementById('signout_button').style.visibility = 'hidden';

/**
 * Callback after api.js is loaded.
 */
function gapiLoaded() {
  gapi.load('client:picker', initializePicker);
}
/**
 * Callback after the API client is loaded. Loads the
 * discovery doc to initialize the API.
 */
async function initializePicker() {
   
  await gapi.client.load('https://www.googleapis.com/discovery/v1/apis/drive/v3/rest');
  pickerInited = true;
  maybeEnableButtons();
}

/**
 * Callback after Google Identity Services are loaded.
 */
function gisLoaded() {
  tokenClient = google.accounts.oauth2.initTokenClient({
    client_id: CLIENT_ID,
    scope: SCOPES,
    callback: '', // defined later
  });
  gisInited = true;
  maybeEnableButtons();
}

/**
 * Enables user interaction after all libraries are loaded.
 */
function maybeEnableButtons() {
  if (pickerInited && gisInited) {
    document.getElementById('authorize_button').style.visibility = 'visible';
  }
}

/**
 *  Sign in the user upon button click.
 **/
function handleAuthClick() {
  tokenClient.callback = async (response) => {
    if (response.error !== undefined) {
      throw (response);
    }
    accessToken = response.access_token;
    document.getElementById('signout_button').style.visibility = 'visible';
    document.getElementById('authorize_button').innerText = 'Refresh';
    await createPicker();
  };

  if (accessToken === null) {
    // Prompt the user to select a Google Account and ask for consent to share their data
    // when establishing a new session.
    tokenClient.requestAccessToken({prompt: 'consent'});
  } else {
    // Skip display of account chooser and consent dialog for an existing session.
    tokenClient.requestAccessToken({prompt: ''});
  }
  console.log(tokenClient);
}

/**
 *  Sign out the user upon button click.
 */
function handleSignoutClick() {
  if (accessToken) {
    accessToken = null;
    google.accounts.oauth2.revoke(accessToken);
    document.getElementById('content').innerText = '';
    document.getElementById('authorize_button').innerText = 'Authorize';
    document.getElementById('signout_button').style.visibility = 'hidden';
  }
}

/**
 *  Create and render a Picker object for searching images.
 */
function createPicker() {
  console.log("Create Picker");
  const view = new google.picker.View(google.picker.ViewId.DOCS);
  view.setMimeTypes('image/png,image/jpeg,image/jpg');
  const picker = new google.picker.PickerBuilder()
      .enableFeature(google.picker.Feature.NAV_HIDDEN)
      .enableFeature(google.picker.Feature.MULTISELECT_ENABLED)
      .setDeveloperKey(API_KEY)
      .setAppId(APP_ID)
      .setOAuthToken(accessToken)
      .addView(view)
      .addView(new google.picker.DocsUploadView())
      .setCallback(pickerCallback)
      .build();
  picker.setVisible(true);
}

/**
 * Displays the file details of the user's selection.
 * @param {object} data - Containers the user selection from the picker
 */
async function pickerCallback(data) {
  if (data.action === google.picker.Action.PICKED) {
    let text = `Picker response: n${JSON.stringify(data, null, 2)}n`;
    const document = data[google.picker.Response.DOCUMENTS][0];
    const fileId = document[google.picker.Document.ID];
    console.log(fileId);
    const res = await gapi.client.drive.files.get({
      'fileId': fileId,
      'fields': '*',
    });
    text += `Drive API response for first document: n${JSON.stringify(res.result, null, 2)}n`;
    window.document.getElementById('content').innerText = text;
  }
}

From this, I get the popupp to log into my google account but the picker does not show up after I complete my login and when I added another button to forcefully build the picker, I get error 403 saying they dont have access to the page. It also seems that the await createPicker(); is never called

I tried moving around async tag in my function but nothing could stop the function from continuing and giving me a null user. I am hosting this on a Django server and I am trying to use OAuth2. I also tried tinkering with the redirect URI in the google console which is currently set to http://127.0.0.1:8000 as my authorized javascript origin and http://127.0.0.1:8000/callback as my authorized redirect URI. It seems the tokenClient.callback = async (response) => { is never running as well so any ideas why would be great! Any info/help is appreciated!

handle calling function exported from custom hook inside a useEffect reactjs

I have the following function which is used in multiple components to refresh a token:

// useRefresh is a custom hook
const refresh = useRefresh()

I have the following useEffect that should only really run on mount:

useEffect(() => {
    const handleRefresh = async () => {
        if (!tokenExpired || !isOpen) return
        const token = await refresh()
        tokenRef.current = token
    }

    const fetchStories = async () => {
        if (isOpen === false) return

        try {
            const result = await axiosPrivate.get(`${BASE_URL}/api/users/stories/${userId}`, {
                headers: { "x-auth-token": tokenRef.current },
            })
            dispatch(setUserStories({ userId, stories: result?.data?.stories }))
        } catch (err) {
            console.log(err)
            return
        }
    }

    const handleMount = async () => {
        await handleRefresh()
        await fetchStories()
        setIsLoading(false)
    }
    handleMount()
}, [isOpen, dispatch, axiosPrivate, userId, tokenExpired, refresh])

The problem I have is that this effect is ran in an infinite loop. this is due to the refresh function being recreated again and again.

I don’t want to wrap useCallback around the refresh function inside the custom hook as the refresh function is consumed in numerous components. I tried extracting the handleRefresh function outside the useEffect, and wrapped it inside a useCallback with empty dependency array, however I got a warning saying refresh is missing dependency to useCallback, and when I add it, the function is recreated on every render, defeating the purpose.
Any ideas on how to fix this issue? Thanks.

How do I check the validity of a HTML form element without triggering the invalid event

In my snippet below you can see that I have a form where I wish to only enable the submit button after all input fields are correctly filled out.

I do this by adding a change event listener to the form itself and then calling the checkValidity() function on the inputs inside the form. (in this example I have only 1) If all the checkValidity() checks return true, I enable the button, if not I disable it.

However, I noticed that calling checkValidity() this also triggers the invalid event listener when the input is invalid which is not desireable. I am using the invalid event listener for other stuff like if the form gets submitted anyways via keyboard shortcuts or other means so I can display an appropriate error message for the input fields because the submit call also will check the validity and trigger the invalid event.

So is there a way to check the validity of the input without triggering the invalid event so I can keep my invalid event listener and not have to write a custom validity check function for every single input?

const form = document.getElementById("form");
const input = document.getElementById("input");
const button = document.getElementById("button");
const checkbox = document.getElementById("checkbox");

form.addEventListener("change", () => {
    if (!checkbox.checked) return;
    if (input.checkValidity()) {
        button.removeAttribute("disabled");
    } else {
        button.setAttribute("disabled", "");
    }
})

input.addEventListener("invalid", (e) => {
    e.preventDefault();
    console.log("Invalid");
});

form.addEventListener("submit", (e) => {
    e.preventDefault();
    console.log("submitted!");
});
button[disabled] {
    opacity: 0.5;
}
<form id="form">
  <input type="text" id="input" minLength="5">
  <button type="submit" id="button" disabled>Submit</button>
</form>
<br>
<label>
  <span>turn on change listener</span>
  <input type="checkbox" id="checkbox" checked>
</label>