Unable to export Bar graph to EXCEL sheet

I am using ant design Bar graph , I am trying to export Bar graph to excel worksheet.
I tried to convert <Bar/> from UI to Object using html2canvas.

Currently I am getting the converted image URL instead of actual bar graph Image in the excel worksheet cell. Like below…

data:image/png;base64,iVBORw0k......

And I can see the actual bar graph image after visiting above URL in browser.

const exportToExcel=()=>{
    const workbook= XLSX2.utils.book_new();
    const chart = document.getElementById('myChart');
        html2canvas(chart).then((canvas) => {
          const imgData = canvas.toDataURL('image/png');
          const worksheet = XLSX.utils.aoa_to_sheet([['Chart'], [imgData]]);
          XLSX.utils.book_append_sheet(workbook, worksheet, "Chart");
          XLSX.writeFile(workbook, U_${formattedDate}.xlsx, { compression: true });
        });
      };

I want to export Bar graph to excel worksheet

Button not appearing in Angular app unless code is run in console after full render

I’m trying to dynamically add a “Help” button to an element in an Angular-based application that I don’t have direct control over.
The button should appear within a container with the class .submitanduserinfo, once it’s rendered on the page. Here’s the code I’m using:

<!DOCTYPE html>
<html lang="ja-EN">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Community</title>
    <style>
      .help-button {
        margin: 10px 0;
        padding: 8px 16px;
        background-color: #007bff;
        color: white;
        border: none;
        cursor: pointer;
        font-size: 16px;
      }
      .help-button:hover {
        background-color: #0056b3;
      }
    </style>
  </head>

  <body>
    <header>
      <h1>Welcome to Community</h1>
    </header>

    <main>
      <p>This is a community</p>
    </main>

    <script>
      function addHelpButton() {
        console.log('addHelpButton function is called');

        function insertHelpButton(submitContainer) {
          if (submitContainer.querySelector('.help-button')) return;

          const helpButton = document.createElement('button');
          helpButton.innerText = 'Help';
          helpButton.className = 'help-button';
          helpButton.addEventListener('click', () => alert("Help button clicked!"));

          const submitButton = submitContainer.querySelector('.btn-primary');
          if (submitButton) {
            submitContainer.insertBefore(helpButton, submitButton);
          } else {
            console.error('Submit button (.btn-primary) not found in submitContainer');
          }
        }

        setTimeout(() => {
          const observer = new MutationObserver((mutationsList, observer) => {
            const submitContainer = document.querySelector('.submitanduserinfo');
            if (submitContainer) {
              insertHelpButton(submitContainer);
              observer.disconnect();
            }
          });
          observer.observe(document.body, { childList: true, subtree: true });
        }, 5000);
      }

      window.addEventListener('DOMContentLoaded', addHelpButton);
    </script>
  </body>
</html>

Issue: The code only works when I run it in the browser console after the page fully renders. When included in the HTML, the MutationObserver doesn’t seem to detect .submitanduserinfo, and the button doesn’t appear.

Attempts So Far:

  1. Timeout Delays: I tried adding a delay (currently 5 seconds), but the timing is not working since Angular’s rendering can vary.

  2. MutationObserver: Even with subtree: true, the observer sometimes doesn’t detect the .submitanduserinfo element when it finally loads.

  3. Polling with setInterval: Polling not worked felt inefficient and occasionally caused duplicate buttons.

Question: What’s the best way to add this button reliably when I`your text` can’t modify the Angular code? Is there a more efficient or reliable method that works with dynamically loaded elements in Angular apps?

How to implement HKDF with CryptoJS?

I am trying to implement HKDF with CryptoJS. (It’s not allowed to use native crypto in my case.) The output of my implementation is different from the output from CyberChef, so I think my implementation is wrong somewhere. I cannot figure out what is wrong. Below is my code:

function toUint8Array(wordArray) {
  // copy from: https://gist.github.com/lettergram/ba6733a854f835bca22b
  var words = wordArray.words;
  var sigBytes = wordArray.sigBytes;
  var u8 = new Uint8Array(sigBytes);
  for (var i = 0; i < sigBytes; i++) {
      var byte = (words[i >>> 2] >>> (24 - (i % 4) * 8)) & 0xff;
      u8[i]=byte;
  }
  return u8;
}

/**
 * HKDF (HMAC-based Key Derivation Function) implementation.
 *
 * @param {Uint8Array} salt - The salt value used in the extraction phase.
 * @param {Uint8Array} ikm - The input key material.
 * @param {Uint8Array} info - Contextual information for the extraction.
 * @param {number} length - The desired length of the output key material in bytes.
 * @returns {Uint8Array} The derived key material
 */
function hkdfSha256(salt, ikm, info, length) {
  const prk = CryptoJS.HmacSHA256(CryptoJS.lib.WordArray.create(ikm), CryptoJS.lib.WordArray.create(salt)); // HKDF-Extract
  let okm = CryptoJS.lib.WordArray.create();
  let previousBlock = CryptoJS.lib.WordArray.create();
  const wordArrayInfo = CryptoJS.lib.WordArray.create(info)

  for (let i = 1; okm.sigBytes < length; i++) {
    previousBlock = CryptoJS.HmacSHA256(previousBlock.concat(wordArrayInfo).concat(CryptoJS.lib.WordArray.create([i], 1)), prk);
    okm.concat(previousBlock);
  }

  return toUint8Array(okm);
  // return new Uint8Array(new Int32Array(okm.words).buffer, 0, length);
}

function main() {
  const salt = CryptoJS.enc.Hex.parse('f339a9b6f339a9b6');
  const ikm = CryptoJS.enc.Utf8.parse('Hello');
  const info = CryptoJS.enc.Hex.parse('');
  const length = 32;

  let outputKeyMaterial = hkdfSha256(toUint8Array(salt), toUint8Array(ikm), toUint8Array(info), length);
  console.log(CryptoJS.lib.WordArray.create(outputKeyMaterial).toString());
  // output:    4ac2a7fe494a5920aaac2f4771ec73468a14f8af1d49bf3d11ce75c8fda8f4e1
  // CyberChef: 3d18bc7eccb941ded1260bef702b94d899f4defa0365a49ee83543c59f336fe6
}

This is the recipe of the CyberChef

Hiding parent div with javascript

How do I hide a div with a nested label class using javascript? For example I have the code below and I want to hide all the div.nbd-xlabel-wrap with the nested class label.nbo-disabled-wrap.

I tried this script

function hideLabels() {
  const labels = document.querySelectorAll('.nbo-disabled-wrap');

  labels.forEach(label => {
    let currentElement = label;
    for (let i = 0; i < 5; i++) {
      if (currentElement.parentElement) {
        currentElement = currentElement.parentElement;
      } else {
        break; // Reached the top of the DOM tree
      }
    }

    const targetDiv = currentElement.querySelector('.nbd-xlabel-wrap');
    if (targetDiv) {
      targetDiv.style.display = 'none';
    }
  });
}

hideLabels();
<div class="nbd-xlabel-wrap">
  <div class="nbd-xlabel-value">
    <div class="nbd-xlabel-value-inner" title="Titanium">
      <input ng-change="check_valid();updateMapOptions('f1539147544370')" value="1" ng-model="nbd_fields['f1539147544370'].value" name="nbd-field[f1539147544370]" type="radio" id="nbd-field-f1539147544370-1" class="ng-pristine ng-untouched ng-valid ng-not-empty">
      <label class="nbd-xlabel ng-isolate-scope nbo-disabled-wrap" for="nbd-field-f1539147544370-1" nbo-disabled="!status_fields['f1539147544370'][1].enable" nbo-disabled-type="class"></label>
    </div>
  </div>
  <label for="nbd-field-f1539147544370-1"><b>Titanium</b></label>
</div>

Passing integer values connections in javascript [closed]

I am making a logic gate simulator and am struggling with the passing of values from one logic gate to another. I am not good at java script (or programming) and chat bots are not much help. I assume it is how the values are evaluated/parse from the initial coding blocks but not sure what to do to fix it.
here is the code: https://codepen.io/SEXYSEXY/pen/YzmjqWy

function evaluateCircuit() {

  const values = {};

  // Set initial input values
  document.querySelectorAll('.input').forEach(input => {
    const value = parseInt(input.dataset.value, 10);
    if (value !== undefined) {
      values[input.dataset.id] = value;
    } else {
      console.warn(`Input ${input.dataset.id} has no defined value.`);
    }
  });

  connections.forEach(conn => {
    const startId = conn.start.parentElement.dataset.id;
    const endId = conn.end.parentElement.dataset.id;
    if (!values[endId]) values[endId] = [];
    values[endId].push(values[startId]);
  });

  console.log('Connections:', connections);
  console.log('Initial Values:', values);

  document.querySelectorAll('.gate').forEach(gate => {
    const gateId = gate.dataset.id;
    const gateType = gate.dataset.type;
    let inputValues = values[gateId] || [];

    // Ensure inputValues is an array
    if (!Array.isArray(inputValues)) {
      inputValues = [inputValues];
    }

    console.log(`Evaluating gate ${gateId} of type ${gateType} with inputs:`, inputValues);

    let outputValue;

    switch (gateType) {
      case 'AND':
        outputValue = inputValues.reduce((a, b) => (a !== undefined && b !== undefined) ? a & b : 0, 1);
        break;
      case 'OR':
        outputValue = inputValues.reduce((a, b) => (a !== undefined && b !== undefined) ? a | b : 0, 0);
        break;
      case 'NOT':
        outputValue = inputValues.length ? 1 - inputValues[0] : 0;
        break;
      case 'NAND':
        outputValue = 1 - (inputValues.reduce((a, b) => (a !== undefined && b !== undefined) ? a & b : 0, 1));
        break;
      case 'NOR':
        outputValue = 1 - (inputValues.reduce((a, b) => (a !== undefined && b !== undefined) ? a | b : 0, 0));
        break;
      case 'XOR':
        outputValue = inputValues.reduce((a, b) => (a !== undefined && b !== undefined) ? a ^ b : 0, 0);
        break;
      case 'XNOR':
        outputValue = 1 - inputValues.reduce((a, b) => (a !== undefined && b !== undefined) ? a ^ b : 0, 0);
        break;
      default:
        outputValue = 0;
    }

    console.log(`Output of gate ${gateId} (${gateType}):`, outputValue);
    values[gateId] = [outputValue]; // Store output value for the gate
  });

  document.querySelectorAll('.output').forEach(output => {
    const outputId = output.dataset.id;
    const outputValue = values[outputId] ? values[outputId][0] : 0;
    console.log(`Output ${outputId}: ${outputValue}`);
  });
}

Adding decimal numbers instead of concatenating

I am trying to sum multiple decimals numbers together however when I console the result it is showing a concatenated result with an undefined in front of it

  for (let i = 0; i < this.performInternationalSwiftPaymentsService.bopSplit.length; i++) {
    this.totalZARForeign += this.performInternationalSwiftPaymentsService.bopSplit[i].randValue;
  }
  console.log(this.totalZARForeign)

console result –> undefined4752.861188.22

The result I want is for it to add 4752.86 and 1188.22 together in this example

Any idea what I am doing wrong. I also tried adding a parseFloat here this.totalZARForeign += parseFloat(this.performInternationalSwiftPaymentsService.bopSplit[i].randValue); but then I get NaN in the console result

How to handle an error thrown by an asynchronous function? [duplicate]

This is not a duplicate to this question since it discusses rejecting promises. This is about errors that are thrown. It is also worth mentioning that I can’t modify the behavior of the mpv.getProperty function. Please re-open this question.

I’m using an async function mpv.getProperty (see documentation here)

This function sometimes throws an error and not a rejection to the promise, so I cannot simply use a .catch block after the async call.

I’ve tried wrapping it around a try-catch block but that didn’t work. I also tried writing a wrapper for it and calling it instead of the function directly as so:

app.get('/filename', (req, res) => {
    async function getFilenameProperty() {
        try {
            return await mpv.getProperty("filename")
        } catch (error) {
            console.log(error)
        }
    }

    getFilenameProperty().then((f) => {
        res.status(200).send(f)
    }).catch((error) => {
        console.log(error)
        res.status(400).send(`Error getting filename`)
    })
})
}

Why isn’t this working? What’s the best practice way to handle this error?

To reproduce this error, create an express server with the node-mpv library imported including the /filename endpoint as shown above:

const mpv = new mpvAPI({"verbose": true}, ["--fullscreen"])
const app = express()

If you perform a GET request to the endpoint, the server crashes instead of handling the error gracefully.

Thanks!

Edit: this is the error being thrown if that gives any clue as to how the error can be handled:

node:events:495
      throw er; // Unhandled 'error' event
      ^

Error [ERR_SOCKET_CLOSED]: Socket is closed
    at new NodeError (node:internal/errors:405:5)
    at Socket._writeGeneric (node:net:953:8)
    at Socket._write (node:net:975:8)
    at writeOrBuffer (node:internal/streams/writable:392:12)
    at _write (node:internal/streams/writable:333:10)
    at Writable.write (node:internal/streams/writable:337:10)
    at /hot/GitHub/remotetv-fullstack-project/back/node_modules/node-mpv/lib/ipcInterface/ipcInterface.js:209:17
    at new Promise (<anonymous>)
    at ipcInterface.send (/hot/GitHub/remotetv-fullstack-project/back/node_modules/node-mpv/lib/ipcInterface/ipcInterface.js:190:10)
    at ipcInterface.getProperty (/hot/GitHub/remotetv-fullstack-project/back/node_modules/node-mpv/lib/ipcInterface/ipcInterface.js:117:15)
Emitted 'error' event on Socket instance at:
    at emitErrorNT (node:internal/streams/destroy:151:8)
    at emitErrorCloseNT (node:internal/streams/destroy:116:3)
    at process.processTicksAndRejections (node:internal/process/task_queues:82:21) {
  code: 'ERR_SOCKET_CLOSED'
}

Next does not recognize changes happening in custom server unless I re-run the application

I am using Express.js on backend, and Next typescript on frontend, in order to properly connect next with a custom server, I followed the instructions in this documentation page:
Configuring: Custom Server

Here is my app.js code in express side:

const express = require('express')
//const proxy = require('express-http-proxy')
const parser = require('body-parser')
const session = require('express-session')
const dotenv = require('dotenv').config()
const {pool} = require('./routes/routes')

const pgSessionStore = require('connect-pg-simple')(session);


function nextAppWrapper(nextApp){

const app = express()
const port = 3000

const {router}  = require('./routes/routes')
const cors = require('cors')

corsConfig = {
  methods:'*',
  credentials:true
}


app.set('trust proxy', 1) // trust first proxy




app.listen(port, () => {
  console.log(`Example app listening on port ${port}`)
})


app.use(cors(corsConfig))

app.use(session(
  {
  store: new pgSessionStore({
    pool:pool,
    tableName:'session',
    createTableIfMissing:true
    
  }),
  secret: process.env.SESSION_SECRET,
  resave: true,
  cookie: { maxAge: 365 * 24 * 60 * 60 * 1000,httpOnly: true , domain:'127.0.0.1:3000'},
  saveUninitialized: true,
}))




app.use(parser.urlencoded({extended:false}))
app.use(parser.json())
app.use('/api',router)
//app.use(proxy('http://127.0.0.1:3000'))

const handle = nextApp.getRequestHandler()

app.all('*', (req, res) => {
  return handle(req, res);
});


}

module.exports = nextAppWrapper

here is my code for server.ts file on Next side:

const nextAppWrapper = require('../backend/app')
const next = require('next')


const dev = process.env.NODE_ENV !== 'production';
const nextApp = next({dev})
nextApp.prepare().then(()=>{
    nextAppWrapper(nextApp)

})

So every-time I try to run npm run dev in console, and do a small change in backend, that change does not take effect unless I execute npm run dev again,

here is my package.json dep-list for express:


 "dependencies": {
    "@aws-sdk/client-dynamodb": "^3.651.1",
    "@aws-sdk/client-s3": "^3.651.1",
    "@aws-sdk/client-ses": "^3.651.1",
    "bcryptjs": "^2.4.3",
    "body-parser": "^1.20.3",
    "connect-pg-simple": "^10.0.0",
    "dotenv": "^16.4.5",
    "express": "^4.21.0",
    "express-http-proxy": "^2.1.1",
    "express-session": "^1.18.0",
    "jest": "^29.7.0",
    "nodemailer": "^6.9.15",
    "nodemon": "^3.1.4",
    "pg": "^8.12.0",
    "pg-pool": "^3.6.2",
    "rewire": "^7.0.0",
    "sinon": "^19.0.2",
    "slugify": "^1.6.6",
    "socket.io": "^4.7.5",
    "supertest": "^7.0.0",
    "uuid": "^10.0.0"
}

here is my package.json dep-list on next side:


"dependencies": {
    "@nextui-org/react": "^2.4.8",
    "@nextui-org/tooltip": "^2.0.41",
    "dompurify": "^3.1.7",
    "express-http-proxy": "^2.1.1",
    "hugeicons-react": "^0.3.0",
    "markdown-it": "^14.1.0",
    "markdown-it-jsx": "^1.1.0",
    "markdown-to-jsx": "^7.5.0",
    "moment": "^2.30.1",
    "next": "14.2.10",
    "react": "^18",
    "react-dom": "^18",
    "socket.io": "^4.7.5"
  },
  "devDependencies": {
    "@types/dompurify": "^3.0.5",
    "@types/markdown-it": "^14.1.2",
    "@types/node": "^20",
    "@types/react": "^18",
    "@types/react-dom": "^18",
    "eslint": "^8",
    "eslint-config-next": "14.2.10",
    "postcss": "^8",
    "tailwindcss": "^3.4.1",
    "typescript": "^5"
  }

also, scripts

  "scripts": {
    "dev": "node server.ts",
    "build": "next build",
    "start": "next start",
    "lint": "next lint"
  }

Please note that I am using 127.0.0.1 host with port 3000

How to use a Mule payload to structure an HTML for email body purpose?

We have a payload as below:

{
  "API1": "UP",
  "API2": "DOWN",
  "API3": "UP"
}

We need to structure this in HTML and read(using parse template) to send it in email body as Table with 2 columns and ‘n’ rows.
We cannot hardcode this payload, it needs to be dynamic and read as payload in the flow because there might be ‘n’ number of APIs.
How to read payload in the template using HTML or JS?

How can I inject a whatsapp web session to stay logged in with selenium?

I am trying to write a python wrapper for selenium to send and receive messages on whatsapp web. However, I don’t want people to have to scan the qr authentication code every single time they run the program.

From what I’ve read online, the session data is stored in indexeddb with the name “wawc” and syncs that data to local storage. I have written js scripts to extract the indexeddb keys and values and to inject these into local storage and indexeddb on start up. These appear to work when I look at the chrome dev tools but on reloading the page, I get a logging out screen and then the indexeddb gets cleared.

I’ve seen that some people get around this by specifying the user-data-dir argument in ChromeOptions but I’d rather do this manually as I’d prefer user data only to be saved for web.whatsapp.com not any other sites.

extract_session.js:

function requestPromise(request) {
    return new Promise((resolve, reject) => {
        request.onsuccess = () => resolve(request.result);
        request.onerror = () => reject(request.error);
    });
}

async function openDatabase(dbName) {
    const request = indexedDB.open(dbName);
    return requestPromise(request);
}

async function getAllFromStore(db, storeName) {
    const transaction = db.transaction(storeName, "readonly");
    const objectStore = transaction.objectStore(storeName);
    return requestPromise(objectStore.getAll());
}

try {
    const db = await openDatabase(arguments[0]);
    const data = await getAllFromStore(db, arguments[1]);
    return JSON.stringify(data);
} catch (error) {
    console.log("Failed to extract session:", error)
    return null;
}

inject_session.js:

function requestPromise(request) {
    return new Promise((resolve, reject) => {
        request.onsuccess = () => resolve(request.result);
        request.onerror = () => reject(request.error);
    });
}

async function openDatabase(dbName) {
    const request = indexedDB.open(dbName);
    return requestPromise(request);
}

async function putInStore(db, storeName, data) {
    const transaction = db.transaction(storeName, "readwrite");
    const objectStore = transaction.objectStore(storeName);
    for (const item of data) {
        const request = objectStore.put(item);
        await requestPromise(request);
    }
}

try {
    const session = JSON.parse(arguments[2]);
    const db = await openDatabase(arguments[0]);
    await putInStore(db, arguments[1], session);
    localStorage.clear()
    for (const item of session) {
        localStorage.setItem(item.key, item.value);
    }
} catch (error) {
    console.error("Failed to inject session:", error);
}

Minimal code to recreate the problem:

from selenium.webdriver import Chrome, ChromeOptions
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.common.exceptions import TimeoutException
from selenium.webdriver.common.by import By

import os

def _handle_await(parent, locator, timeout, poll_freq):
    try:
        return WebDriverWait(parent,
                             timeout,
                             poll_frequency=poll_freq
                             ).until(EC.presence_of_element_located(locator))
    except TimeoutException:
        return None

def await_element(parent, locator, timeout=0, poll_freq=0.05):

    if timeout == 0:
        while True:
            res = _handle_await(parent, locator, timeout, poll_freq)
            if res is not None:
                return res
    else:
        return _handle_await(parent, locator, timeout, poll_freq)

QR_CODE = (By.CSS_SELECTOR, "canvas[role='img']")
LOGGED_IN = (By.CSS_SELECTOR, "div[title='Chats']")

options = ChromeOptions()
options.set_capability("goog:loggingPrefs", {"browser": "ALL"})

driver = Chrome(options=options)
driver.get("https://web.whatsapp.com/")

await_element(driver, QR_CODE)

if os.path.isfile("session.wa"):

    js_code = open("inject_session.js", "r").read()
    with open("session.wa", "r", encoding="utf-8") as file:
        driver.execute_script(js_code, "wawc", "user", file.read())

    driver.refresh()
    input()

else:

    await_element(driver, LOGGED_IN)

    js_code = open("extract_session.js", "r").read()
    session_data = driver.execute_script(js_code, "wawc", "user")

    with open("session.wa", "w", encoding="utf-8") as file:
        file.write(str(session_data))

    input()

The first time the code is run, the session.wa file is created and looks fine. Once the code is run again, the local storage and indexeddb appear to be updated correctly but once the page is reloaded, I get this screen:
Whatsapp Logout Image
And then I’m redirected to the main web.whatsapp.com screen with the QR code for login.

How to solve “Missing X server or $DISPLAY” when starting an ElectronJs App on Ubuntu 24 (X11)?

When I try to launch an ElectonJs application in development, I get the error [13117:1104/071616.998450:ERROR:ozone_platform_x11.cc(245)] Missing X server or $DISPLAY. The system used is Ubuntu 24.04.1 LTS and the windowing system is X11.

I get this error even with a minimum of code, just two files (main.js and index.html):

main.js

const { app, BrowserWindow } = require("electron");

const createWindow = () => {
    const win = new BrowserWindow({
        width: 800,
        height: 600,
    });

    win.loadFile("index.html");
};

app.whenReady().then(() => {
    createWindow();
});

index.html

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8" />
        <title>Hello World!</title>
    </head>
    <body>
        <div>Hello World from Humans !</div>
    </body>
</html>

Before the Missing X server or $DISPLAY error, I was getting the error [16018:1104/074700.492381:FATAL:setuid_sandbox_host.cc(163)] The SUID sandbox helper binary was found, but is not configured correctly.
But I solved it by executing in the terminal:

sudo sysctl -w kernel.apparmor_restrict_unprivileged_userns=1

I don’t know if this is the cause, it’s more detailed here The SUID sandbox helper binary was found, but is not configured correctly

I tried to set the $DISPLAY environment variable by adding to the end of the ~/.bashrc file :

export DISPLAY=127.0.0.1:0.0

As descript here Electron: Missing X server or $DISPLAY, but with no result

Getting wrong number of response render on intial rendering

I have written a Reactjs code . Here the first api is rendering the list of job ids . and in next api each job id is rendering the job detail of that id . here is the example .

api 1 - https://hacker-news.firebaseio.com/v0/jobstories.json 
o/p 1 - [35908337, 35904973, 35900922, 35893439, 35890114, 35880345, ...]
api 2 - https://hacker-news.firebaseio.com/v0/item/35908337.json
o/p 2 - {
  "by": "jamilbk",
  "id": 35908337,
  "score": 1,
  "time": 1683838872,
  "title": "Firezone (YC W22) is hiring Elixir and Rust engineers",
  "type": "job",
  "url": "https://www.ycombinator.com/companies/firezone/jobs"
} 

Now I have wriiten a react js code for it to achieve the same .


import { useEffect, useState } from "react";
import "./App.css";

function App() {
  const [jobId, setJobId] = useState([]);
  const [jobData, setJobData] = useState([]);
  const [pages, SetPages] = useState(0);
  const [hasMore, setHasMore] = useState(true);   
  const [loading, setLoading] = useState(false);
  const No_Of_Pages = 6;
  useEffect(() => {
    fetchJobId();
  }, []);

  useEffect(() => {
    if (jobId.length > 0) fetchJobData();
  }, [pages, jobId]);

  const fetchJobId = async () => {
    const response = await fetch(
      "https://hacker-news.firebaseio.com/v0/jobstories.json"
    );
    const data = await response.json();
    setJobId(data);
  };

  const fetchJobData = async () => {
    setLoading(true);
    const JobrangeId = jobId.slice(
      pages * No_Of_Pages,
      (pages + 1) * No_Of_Pages
    ); // 0-6 , 6-12 , 12-18 ...
    const JobDataPromise = JobrangeId.map(async (id) => {
      const response = await fetch(
        `https://hacker-news.firebaseio.com/v0/item/${id}.json`
      );
      const data = await response.json();
      return data;
    });
    const jobInfo = await Promise.all(JobDataPromise);
    setJobData((prevjob) => [...prevjob, ...jobInfo]);
    setHasMore((pages + 1) * No_Of_Pages < jobData.length);
    setLoading(false);
  };
  return (
    <div className="">
      <div className="h-[500px] w-[100%]  relative p-4 bg-gray-50 overflow-y-scroll">
        <div className="flex flex-col w-[100%] h-[100%] items-center ">
          <p className="text-orange-400 font-bold text-2xl">
            {" "}
            Hacker News Jobs Board
          </p>
          {jobData.length > 0
            ? jobData.map((ele, index) => (
                <div
                  className="w-5/6 h-16 border-[1.5px] border-gray-300 m-3 p-1.5 bg-white"
                  key={index}
                >
                  <div className="flex flex-col ">
                    <div>
                      <p className="font-bold text-black text-xl">
                        {ele?.title}
                      </p>
                    </div>
                    <div className="flex justify-start gap-2">
                      <p className="font-normal text-base">By {ele?.by}</p>
                      <p>-</p>
                      <p>{ele?.time}</p>
                    </div>
                  </div>
                </div>
              ))
            : null}
          <div className="w-5/6 flex justify-start">
            <button
              className="p-3 bg-orange-400 text-white rounded-md"
              onClick={() => SetPages(pages + 1)}
              disabled={hasMore}
            >
              {loading ? "Loading..." : "Load more"}
            </button>
          </div>
        </div>
      </div>
    </div>
  );
}

export default App;

The error I am getting here is on intial render it is rendering 12 job details instead of 6 . In 12 the last 6 are the same to that of first 6 . in subsequent rendering on click of load more button it is rendering correctly . Why it is happening like that ? What is wrong in my code ? Thanks in advance .

Facing the problem of uploading the member ID while uploading the data to multiple tables through a single form/click

I have a form with multiple fields to upload data and fetch the member’s data to the front end. In the front end, some sections have multiple points so I have created separate tables for them. To fetch data from different tables we need to create a foreign key and for this, I have made the member name a foreign key. In this, I have a problem if the backend user uploads data then he should not upload the same member name, for this, I need to make a foreign key a numeric number, but a numeric number foreign key is also a primary key so that it becomes auto_increment. But in tables like Qualification, Career, Achievement, and Issue, the member’s data will get separated because of auto_increment. So is there any way to make the foreign key numeric so that the foreign key will not get separated from the tables like Qualification, Career, Achievement, and Issue?

Following are my form-

function addQua() {
var container = document.getElementById('qua-container');
var newQua = document.createElement('div');
newQua.className = 'qua';
newQua.innerHTML = `
<input type="text" name="qua[]" required placeholder="Qualification">
<button type="button" class="btn-remove" onclick="removeQua(this)">Remove</button>
`;
container.appendChild(newQua);
}

function removeQua(button) {
var qua = button.parentElement;
qua.remove();
}



function addCar() {
var container = document.getElementById('car-container');
var newCar = document.createElement('div');
newCar.className = 'car';
newCar.innerHTML = `
<input type="text" name="car[]" required placeholder="Career">
<input type="text" name="date[]" required placeholder="Year">
<button type="button" class="btn-remove" onclick="removeCar(this)">Remove</button>
`;
container.appendChild(newCar);
}

function removeCar(button) {
var car = button.parentElement;
car.remove();
}



function addAchi() {
var container = document.getElementById('achi-container');
var newAchi = document.createElement('div');
newAchi.className = 'achi';
newAchi.innerHTML = `
<input type="text" name="achi[]" required placeholder="Achievement">
<button type="button" class="btn-remove" onclick="removeAchi(this)">Remove</button>
`;
container.appendChild(newAchi);
}

function removeAchi(button) {
var achi = button.parentElement;
achi.remove();
}



function addIss() {
var container = document.getElementById('iss-container');
var newIss = document.createElement('div');
newIss.className = 'iss';
newIss.innerHTML = `
<input type="text" name="iss[]" required placeholder="Issues">
<button type="button" class="btn-remove" onclick="removeIss(this)">Remove</button>
`;
container.appendChild(newIss);
}

function removeIss(button) {
var iss = button.parentElement;
iss.remove();
}
<div class="member_form_main_container">
    <div class="member_form_sub_container">
        <form action="handle_member_form" method="post" id="form" enctype="multipart/form-data">
            <div class="box">
                <span>image</span>
                <div class="input">
                    <input type="file" name="image" id="image">
                </div>
            </div>

            <div class="box">
                <span>full name</span>
                <div class="input">
                    <input type="text" name="name" id="name">
                </div>
            </div>

            <div class="box">
                <span>place of birth</span>
                <div class="input">
                    <input type="text" name="pob" id="pob">
                </div>
            </div>

            <div class="box">
                <span>date of birth</span>
                <div class="input">
                    <input type="date" name="dob" id="dob">
                </div>
            </div>

            <div class="box">
                <span>father's name</span>
                <div class="input">
                    <input type="text" name="father" id="father">
                </div>
            </div>

            <div class="box">
                <span>mother's name</span>
                <div class="input">
                    <input type="text" name="mother" id="mother">
                </div>
            </div>

            <div class="box qua">
                <span>qualification</span>
                <div class="input qua_input">
                    <div id="qua-container" class="formQua">
                        <div class="qua">
                            <input type="text" name="qua[]" required placeholder="Qualification">
                        </div>
                    </div>
                    <button type="button" class="btn-qua" onclick="addQua()">Add Qualification</button>
                </div>
            </div>

            <div class="box car">
                <span>career</span>
                <div class="input car_input">
                    <div id="car-container" class="formCar">
                        <div class="car">
                            <input type="text" name="car[]" required placeholder="Career">
                            <input type="text" name="date[]" required placeholder="Year">
                        </div>
                    </div>
                    <button type="button" class="btn-car" onclick="addCar()">Add Career</button>
                </div>
            </div>

            <div class="box achi">
                <span>achievements</span>
                <div class="input achi_input">
                    <div id="achi-container" class="formAchi">
                        <div class="achi">
                            <input type="text" name="achi[]" required placeholder="Achievements">
                        </div>
                    </div>
                    <button type="button" class="btn-achi" onclick="addAchi()">Add Achievements</button>
                </div>
            </div>

            <div class="box iss">
                <span>issues</span>
                <div class="input iss_input">
                    <div id="iss-container" class="formIss">
                        <div class="iss">
                            <input type="text" name="iss[]" required placeholder="Issues">
                        </div>
                    </div>
                    <button type="button" class="btn-iss" onclick="addIss()">Add Issues</button>
                </div>
            </div>

            <div class="button">
                <button type="submit">submit</button>
            </div>

        </form>
    </div>
</div>

The following scripts are for handling the form-

<?php
    include "../partials/dbconnect.php"
?>

<?php
    if ($_SERVER['REQUEST_METHOD']=='POST') {
        $upload_name = $_POST['name'];
        $upload_pob = $_POST['pob'];
        $upload_dob = $_POST['dob'];
        $upload_father = $_POST['father'];
        $upload_mother = $_POST['mother'];
        date_default_timezone_set('Asia/Kolkata');
        $date = date('Y-m-d H:i:s');

        // File upload handling
        if (isset($_FILES['image']) && $_FILES['image']['error'] === UPLOAD_ERR_OK) {
            $fileTmpPath = $_FILES['image']['tmp_name'];
            $fileName = $_FILES['image']['name'];
            $fileNameCmps = explode(".", $fileName);
            $fileExtension = strtolower(end($fileNameCmps));

            // Allowed file extensions
            $allowedfileExtensions = array('jpg', 'jpeg', 'png', 'avif', 'webp');

            if (in_array($fileExtension, $allowedfileExtensions)) {
                // Directory in which the file will be saved
                $uploadFileDir = '../member_images/';
                $dest_path = $uploadFileDir.$fileName;

                if (move_uploaded_file($fileTmpPath, $dest_path)) {
                    $sql_member_profile = "INSERT INTO `member_profile` (`member_image`, `member_name`, `birth_place`, `birthday`, `father`, `mother`) VALUES ('$fileName', '$upload_name', '$upload_pob', '$upload_dob', '$upload_father', '$upload_mother')";
                    $result_member_profile = mysqli_query($conn, $sql_member_profile);

                    if ($result_member_profile) {
                        echo 'Image upload successfully';
                    }

                    
                    // start
                    // Qualification start
                    // Get the qualification data
                    $quas = $_POST['qua'];

                    // Prepare SQL statement to insert data into table "member_telephone"
                    $sqlQua = "INSERT INTO member_qualifications (member_name, member_qualification, date_upload) VALUES (?, ?, ?)";
                    $stmt1 = $conn->prepare($sqlQua);

                    // Insert each qualification and date into the table
                    for ($i = 0; $i < count($quas); $i++) {
                        $stmt1->bind_param("sss", $upload_name, $quas[$i], $date);
                        $stmt1->execute();
                    }
                    // Qualification end


                    // Career start
                    // Get the career data
                    $cars = $_POST['car'];
                    $dates = $_POST['date'];

                    // Prepare SQL statement to insert data into table "member_telephone"
                    $sqlCar = "INSERT INTO member_careers (member_name, member_career_year, member_career_context, date_upload) VALUES (?, ?, ?, ?)";
                    $stmt2 = $conn->prepare($sqlCar);

                    // Insert each qualification and date into the table
                    for ($i = 0; $i < count($cars); $i++) {
                        $stmt2->bind_param("ssss", $upload_name, $dates[$i], $cars[$i], $date);
                        $stmt2->execute();
                    }
                    // Career end


                    // Achievements start
                    // Get the achievement data
                    $achis = $_POST['achi'];

                    // Prepare SQL statement to insert data into table "member_telephone"
                    $sqlAchi = "INSERT INTO member_achievements (member_name, member_achievement, date_upload) VALUES (?, ?, ?)";
                    $stmt3 = $conn->prepare($sqlAchi);

                    // Insert each achievement and date into the table
                    for ($i = 0; $i < count($achis); $i++) {
                        $stmt3->bind_param("sss", $upload_name, $achis[$i], $date);
                        $stmt3->execute();
                    }
                    // Achievements end


                    // Issues start
                    // Get the issue data
                    $isss = $_POST['iss'];

                    // Prepare SQL statement to insert data into table "member_telephone"
                    $sqlIss = "INSERT INTO member_issues (member_name, member_issue, date_upload) VALUES (?, ?, ?)";
                    $stmt4 = $conn->prepare($sqlIss);

                    // Insert each issue and date into the table
                    for ($i = 0; $i < count($isss); $i++) {
                        $stmt4->bind_param("sss", $upload_name, $isss[$i], $date);
                        $stmt4->execute();
                    }
                    // Issues end


                    // Close the statement and connection
                    $stmt1->close();
                    $stmt2->close();
                    $stmt3->close();
                    $stmt4->close();


                    echo "File is successfully uploaded.";
                }else {
                    echo "There was some error moving the file to upload directory.";
                }
            }else {
                echo "Upload failed. Allowed file types: " . implode(',', $allowedfileExtensions);
            }
        }else {
            if (isset($_FILES['image']) && $_FILES['image']['error'] == UPLOAD_ERR_NO_FILE) {
                $sql_member_profile = "INSERT INTO `member_profile` (`member_image`, `member_name`, `birth_place`, `birthday`, `father`, `mother`) VALUES ('user.png', '$upload_name', '$upload_pob', '$upload_dob', '$upload_father', '$upload_mother')";
                $result_member_profile = mysqli_query($conn, $sql_member_profile);

                if ($result_member_profile) {
                    echo 'Image upload successfully';
                }


                // start
                // Qualification start
                // Get the qualification data
                $quas = $_POST['qua'];

                // Prepare SQL statement to insert data into table "member_telephone"
                $sqlQua = "INSERT INTO member_qualifications (member_name, member_qualification, date_upload) VALUES (?, ?, ?)";
                $stmt1 = $conn->prepare($sqlQua);

                // Insert each qualification and date into the table
                for ($i = 0; $i < count($quas); $i++) {
                    $stmt1->bind_param("sss", $upload_name, $quas[$i], $date);
                    $stmt1->execute();
                }
                // Qualification end


                // Career start
                // Get the career data
                $cars = $_POST['car'];
                $dates = $_POST['date'];

                // Prepare SQL statement to insert data into table "member_telephone"
                $sqlCar = "INSERT INTO member_careers (member_name, member_career_year, member_career_context, date_upload) VALUES (?, ?, ?, ?)";
                $stmt2 = $conn->prepare($sqlCar);

                // Insert each qualification and date into the table
                for ($i = 0; $i < count($cars); $i++) {
                    $stmt2->bind_param("ssss", $upload_name, $dates[$i], $cars[$i], $date);
                    $stmt2->execute();
                }
                // Career end


                // Achievements start
                // Get the achievement data
                $achis = $_POST['achi'];

                // Prepare SQL statement to insert data into table "member_telephone"
                $sqlAchi = "INSERT INTO member_achievements (member_name, member_achievement, date_upload) VALUES (?, ?, ?)";
                $stmt3 = $conn->prepare($sqlAchi);

                // Insert each achievement and date into the table
                for ($i = 0; $i < count($achis); $i++) {
                    $stmt3->bind_param("sss", $upload_name, $achis[$i], $date);
                    $stmt3->execute();
                    }
                // Achievements end


                // Issues start
                // Get the issue data
                $isss = $_POST['iss'];

                // Prepare SQL statement to insert data into table "member_telephone"
                $sqlIss = "INSERT INTO member_issues (member_name, member_issue, date_upload) VALUES (?, ?, ?)";
                $stmt4 = $conn->prepare($sqlIss);

                // Insert each issue and date into the table
                for ($i = 0; $i < count($isss); $i++) {
                    $stmt4->bind_param("sss", $upload_name, $isss[$i], $date);
                    $stmt4->execute();
                }
                // Issues end


                // Close the statement and connection
                $stmt1->close();
                $stmt2->close();
                $stmt3->close();
                $stmt4->close();

                
                echo "File is successfully uploaded.";
            }else {
                echo "There was an error with the file upload. Error code: " . $_FILES['image']['error'];            
            }
        }
    }
?>

How can I empty the “ field after submitting while keeping it as a server component?

Here I am using server component for Search form but to able to empty the input field when user click the cancel button I import a <SearchReset/> which is a client component but i cant reset or empty the form.

SearchForm.tsx

;<Form
  action="/search"
  className="search-form input input-bordered flex items-center gap-2 bg-white py-2 px-4 max-w-md mx-auto rounded border-2"
>
  <input
    name="query"
    defaultValue={query}
    className="search-input grow w-full focus:outline-none outline-none focus:ring-0 active:ring-0"
    placeholder="Seacrh Ideas"
  />

  {query ? (
    <SearchReset />
  ) : (
    <button type="submit" className="flex items-center">
      <Search className="text-secondary size-6" />
    </button>
  )}
</Form>

SearchReset.tsx

export default function SearchReset () {
  const reset = () => {
    const form = document.querySelector(".search-form") as HTMLFormElement
    console.log(form)
    if (form) {
      const input = form.querySelector(
        'input[name="query"]',
      ) as HTMLInputElement
      console.log(input) // this works
      if (input) {
        input.value = "" // this doesnt
      }
      form.reset()
    }
  }

  return (
    <button type="reset" className="flex items-center" onClick={reset}>
      <X className="text-black-200 size-4" />
    </button>
  )
}

I tried to access the form’s input field after I click the reset button which I can but when am trying to set it’s value empty or reset the form it’s not working

Google OAuth works in production but shows “origin_mismatch” error in development (localhost)

I’m setting up Google OAuth 2.0 for my app, and I’m encountering an issue where everything works perfectly in production (https://mywebsite.com), but in development (localhost), I get an “Error 400: origin_mismatch” error during the Google sign-in process.

Error Message

The error displayed in the Google sign-in modal is:

Access blocked: Authorization Error

[email protected]

You can't sign in to this app because it doesn't comply with Google's OAuth 2.0 policy.

If you're the app developer, register the JavaScript origin in the Google Cloud Console.
Error 400: origin_mismatch

Setup Details

  • Frontend: localhost:3000 (React)
  • Backend: localhost:8000 (Express with Node.js)

Google Cloud Console Configuration

I’ve configured my Google Cloud Console with the following:

  • Authorized JavaScript Origins:

    • http://localhost:3000
    • https://mywebsite.com (for production)
  • Authorized redirect URIs:

    • http://localhost:8000/api/callback (for development)
    • https://mywebsite.com/api/callback (for production)

Relevant Code

Backend OAuth Route (Express.js in auth.js file):

const express = require("express");
const router = express.Router();
const oauth2Client = require("../config/googleConfig");
const SCOPES = [
    'https://www.googleapis.com/auth/userinfo.profile',
    'https://www.googleapis.com/auth/userinfo.email'
];

// Redirect to Google's OAuth 2.0 server to initiate authentication
router.get('/google', (req, res) => {
    console.log(`/google called`);
    const authUrl = oauth2Client.generateAuthUrl({
        access_type: 'offline',
        scope: SCOPES,
        redirect_uri: 'http://localhost:8000/api/callback' // Explicitly set redirect URI for development
    });
    res.redirect(authUrl);
});

// Handle the OAuth 2.0 server response
router.get('/callback', async (req, res) => {
    console.log(`/callback req.query: `, req.query);
    const { code } = req.query;
    try {
        const { tokens } = await oauth2Client.getToken(code);
        oauth2Client.setCredentials(tokens);
        req.session.tokens = tokens;
        res.redirect('http://localhost:3000'); // Redirect back to frontend after successful login
    } catch (error) {
        console.error('Error during OAuth callback:', error.response ? error.response.data : error);
        res.status(500).send('Authentication failed');
    }
});

module.exports = router;

CORS Configuration (Express middleware in server.js):

// process.env.CLIENT_URL === http://localhost:3000

app.use(cors({ 
  origin: `${process.env.CLIENT_URL}`,
  credentials: true
}));

Session Configuration (Express express-session setup):

app.use(session({
    secret: process.env.SESSION_SECRET,
    resave: false,
    saveUninitialized: false,
    store: MongoStore.create({ mongoUrl: process.env.DATABASE }),
    cookie: {
        maxAge: 2 * 60 * 60 * 1000, // 2 hours
        httpOnly: true,
        secure: false, // Set to false in development
        sameSite: 'Lax' // Ensures cookies are accessible across localhost:3000 and localhost:8000
    }
}));

And now for the frontend code that is used to communicate with the backend.

Frontend React API Call function

export const googleSignIn = async (token) => { // not the JWT token, the google token
  try {
      const response = await fetch(`${API}/google-login`, {
          method: 'POST',
          headers: {
              Accept: 'application/json',
              'Content-Type': 'application/json',
          },
          credentials: 'include', // Ensure session cookie is included
          body: JSON.stringify({ idToken: token }),
      });
      return await response.json();
  } catch (err) {
      return { error: 'Google sign-in failed. Please try again.' };
  }
};

What I’ve Tried

  1. Verified Authorized JavaScript Origins and Redirect URIs: Double-checked that http://localhost:3000 is set as an authorized JavaScript origin and http://localhost:8000/api/callback as an authorized redirect URI in the Google Cloud Console for development.

  2. Explicitly Set Redirect URI in generateAuthUrl: Ensured that the redirect_uri is specified directly in the generateAuthUrl call to match what’s in the Google Console.

  3. Adjusted SCOPES: Initially, I used 'https://www.googleapis.com/auth/drive.file', but I changed it to:

    const SCOPES = [
        'https://www.googleapis.com/auth/userinfo.profile',
        'https://www.googleapis.com/auth/userinfo.email'
    ];
    

    This change was made to avoid potential scope conflicts, as I only need basic user info for authentication.

  4. Cleared Cache and Cookies: Cleared browser cache and cookies on localhost, and also tested in incognito mode to eliminate any caching issues.

  5. Console Logs and Network Activity: Inspected network logs in the browser developer tools. I verified that the authUrl generated in the /google route matches the redirect URI set in the Google Console.

Observed Behavior

  • Production: Works without issues on https://mywebsite.com, with users able to log in and authenticate.
  • Development: Returns “origin_mismatch” error during the last step of the Google OAuth process in the sign-in modal.

Question

Why is Google OAuth throwing an “origin_mismatch” error only in the development environment? Are there specific configurations for localhost that I might be overlooking? Any advice on how to fix this issue would be greatly appreciated!