BaseWindow doesnt show when electron app starts

import { app, BaseWindow } from "electron";

app.whenReady().then(() => {
  const window = new BaseWindow({
    title: "main",
    show: true,
    url: "https://www.google.com",
  });
  window.setBounds({
    x: 100,
    y: 100,
    width: 800,
    height: 600,
  });
});

I am expecting a window of specified size to show when i run electron.
intead it is giving me below error

> [email protected] start
> electron ./src/main.mjs --experimental-modules

/Users/arup/programming/JS/omnia/node_modules/electron/dist/Electron.app/Contents/MacOS/Electron exited with signal SIGSEGV

OmNxgRipple (NGXUI) full-screen wrapper blocking clicks on child elements

I am trying to create a wrapper component in Angular that shows a background ripple animation (using @omnedia/ngx-ripple) over the entire page, but leaves all inputs, links, and buttons in the foreground interactive. I have tried various solutions, but my content always gets stuck (clicks don’t propagate) or I never see the ripple. Below I describe how I set up the code and where I encounter the problem.

Context:

I am using Angular (v19) and Tailwind CSS for styles.

I installed @omnedia/ngx-ripple successfully (e.g., npm install @omnedia/ngx-ripple).

I want my entire “Coming Soon” page to be wrapped in a wrapper that shows the full-screen ripple, but does not block interactions on internal components (inputs, links, buttons, etc.).

I initially tried using directly as the parent of all content, but then the children are no longer clickable.

CODE:

coming-soon-page Template:

<app-ripple-background>
  <div class="bg-neutral-900">
    <app-topbar></app-topbar>
    <div class="min-h-screen flex flex-col items-center justify-center text-center bg-neutral-900 text-white px-4">
      <om-gradient-text [text]="'Coming Soon'"
                        [styleClass]="'mb-4 font-extrabold text-6xl md:text-8xl'"></om-gradient-text>
      <p class="text-lg md:text-xl mb-8 max-w-2xl mt-6">
        A smarter way to receive curated tech, development, and cybersecurity insights — powered by AI.
        <span class="inline-flex items-center mt-1">
        <svg height="24" width="24" fill="#FFFFFF" viewBox="0 0 24 24" data-name="Layer 1" id="Layer_1" class="sparkle">
          <path
            d="M10,21.236,6.755,14.745.264,11.5,6.755,8.255,10,1.764l3.245,6.491L19.736,11.5l-6.491,3.245ZM18,21l1.5,3L21,21l3-1.5L21,18l-1.5-3L18,18l-3,1.5ZM19.333,4.667,20.5,7l1.167-2.333L24,3.5,21.667,2.333,20.5,0,19.333,2.333,17,3.5Z"></path>
        </svg>
      </span>
      </p>
      <form class="flex flex-col sm:flex-row items-center sm:items-start gap-2 w-full max-w-md mx-auto">
        <input
          type="email"
          placeholder="Enter your email"
          class="p-3 rounded-lg text-white w-full bg-neutral-800"
          required
        />
        <button type="submit" class="notify-btn">
          <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" class="bel-2" viewBox="0 0 256 256">
            <path fill="#000"
                  d="M224 71.1a8 8 0 0 1-10.78-3.42a94.13 94.13 0 0 0-33.46-36.91a8 8 0 1 1 8.54-13.54a111.46 111.46 0 0 1 39.12 43.09A8 8 0 0 1 224 71.1M35.71 72a8 8 0 0 0 7.1-4.32a94.13 94.13 0 0 1 33.46-36.91a8 8 0 1 0-8.54-13.54a111.46 111.46 0 0 0-39.12 43.09A8 8 0 0 0 35.71 72m186.1 103.94A16 16 0 0 1 208 200h-40.8a40 40 0 0 1-78.4 0H48a16 16 0 0 1-13.79-24.06C43.22 160.39 48 138.28 48 112a80 80 0 0 1 160 0c0 26.27 4.78 48.38 13.81 63.94M150.62 200h-45.24a24 24 0 0 0 45.24 0M208 184c-10.64-18.27-16-42.49-16-72a64 64 0 0 0-128 0c0 29.52-5.38 53.74-16 72Z"/>
          </svg>
          <span class="text">Notify Me</span>
          <span class="circle"></span>
          <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" class="bel-1" viewBox="0 0 256 256">
            <path fill="#fff"
                  d="M224 71.1a8 8 0 0 1-10.78-3.42a94.13 94.13 0 0 0-33.46-36.91a8 8 0 1 1 8.54-13.54a111.46 111.46 0 0 1 39.12 43.09A8 8 0 0 1 224 71.1M35.71 72a8 8 0 0 0 7.1-4.32a94.13 94.13 0 0 1 33.46-36.91a8 8 0 1 0-8.54-13.54a111.46 111.46 0 0 0-39.12 43.09A8 8 0 0 0 35.71 72m186.1 103.94A16 16 0 0 1 208 200h-40.8a40 40 0 0 1-78.4 0H48a16 16 0 0 1-13.79-24.06C43.22 160.39 48 138.28 48 112a80 80 0 0 1 160 0c0 26.27 4.78 48.38 13.81 63.94M150.62 200h-45.24a24 24 0 0 0 45.24 0M208 184c-10.64-18.27-16-42.49-16-72a64 64 0 0 0-128 0c0 29.52-5.38 53.74-16 72Z"/>
          </svg>
        </button>
      </form>
      <div class="flex items-center justify-center text-center mt-8 gap-2">
        <a href="https://github.com/C0MPL3XDEV" target="_blank">
          <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
            <g fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2">
              <path stroke-dasharray="32" stroke-dashoffset="32"
                    d="M12 4c1.67 0 2.61 0.4 3 0.5c0.53 -0.43 1.94 -1.5 3.5 -1.5c0.34 1 0.29 2.22 0 3c0.75 1 1 2 1 3.5c0 2.19 -0.48 3.58 -1.5 4.5c-1.02 0.92 -2.11 1.37 -3.5 1.5c0.65 0.54 0.5 1.87 0.5 2.5c0 0.73 0 3 0 3M12 4c-1.67 0 -2.61 0.4 -3 0.5c-0.53 -0.43 -1.94 -1.5 -3.5 -1.5c-0.34 1 -0.29 2.22 0 3c-0.75 1 -1 2 -1 3.5c0 2.19 0.48 3.58 1.5 4.5c1.02 0.92 2.11 1.37 3.5 1.5c-0.65 0.54 -0.5 1.87 -0.5 2.5c0 0.73 0 3 0 3">
                <animate fill="freeze" attributeName="stroke-dashoffset" dur="0.7s" values="32;0"/>
              </path>
              <path stroke-dasharray="10" stroke-dashoffset="10"
                    d="M9 19c-1.41 0 -2.84 -0.56 -3.69 -1.19c-0.84 -0.63 -1.09 -1.66 -2.31 -2.31">
                <animate fill="freeze" attributeName="stroke-dashoffset" begin="0.8s" dur="0.2s" values="10;0"/>
              </path>
            </g>
          </svg>
        </a>
        <a href="https://instagram.com/carmine.developer" target="_blank">
          <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
            <circle cx="17" cy="7" r="1.5" fill="currentColor" fill-opacity="0">
              <animate fill="freeze" attributeName="fill-opacity" begin="1.3s" dur="0.15s" values="0;1"/>
            </circle>
            <g fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2">
              <path stroke-dasharray="72" stroke-dashoffset="72"
                    d="M16 3c2.76 0 5 2.24 5 5v8c0 2.76 -2.24 5 -5 5h-8c-2.76 0 -5 -2.24 -5 -5v-8c0 -2.76 2.24 -5 5 -5h4Z">
                <animate fill="freeze" attributeName="stroke-dashoffset" dur="0.6s" values="72;0"/>
              </path>
              <path stroke-dasharray="28" stroke-dashoffset="28"
                    d="M12 8c2.21 0 4 1.79 4 4c0 2.21 -1.79 4 -4 4c-2.21 0 -4 -1.79 -4 -4c0 -2.21 1.79 -4 4 -4">
                <animate fill="freeze" attributeName="stroke-dashoffset" begin="0.7s" dur="0.6s" values="28;0"/>
              </path>
            </g>
          </svg>
        </a>
      </div>
      <footer class="mt-12 text-sm text-gray-400">
        &copy; {{ date.getFullYear() }}  C0MPL3XDEV — All rights reserved.
      </footer>
    </div>
  </div>
</app-ripple-background>```

background component template:

    <om-ripple
  [rippleBorderColor]="'rgba(255, 255, 255, 0.7)'"
  [rippleColor]="'rgba(174, 174, 174, 0.54)'">
  <ng-content></ng-content>
</om-ripple>

scrollIntoView – React working but is scrolling to the center of the element before its clicked (need it to center after click)

I am continuing to work on this and get better at REACT. I’ve spent a few days trying to figure out why it’s doing this so I’m here to ask for any insight- how would I go about triggering the executeScroll function I made to perform after the element has been clicked instead of centering the element before it was clicked?

Or am I just targeting the wrong element? It’s a gallery page that shows images of art and when you click on one of the images it pops open a modal – and the modal that pops up is the one I want to center on the page to scrollTo. Any insight is very much appreciated – thank you!!

(also I will remove the excessive console.log lines once I figure this out)

import { useState, useRef } from "react";
import { PropTypes } from "prop-types";
import GalleryData from "../data/GalleryData";
import styles from "../components/GalleryList.module.css";

function GalleryList() {
    return (
        <div className={styles.gallery}>
            <div className={styles.overlayNone}>
                {GalleryData.map((gallery) => (
                    <Gallery galleryObj={gallery} key={gallery.name} />
                ))}
            </div>
        </div>
    );
}

function Gallery({ galleryObj }) {
    const [isOpenModal, setIsOpenModal] = useState(null);

    Gallery.propTypes = {
        galleryObj: PropTypes.shape({
            name: PropTypes.string.isRequired,
            description: PropTypes.string.isRequired,
            bulletName: PropTypes.string.isRequired,
            bulletPoints: PropTypes.string.isRequired,
            bulletPoints2: PropTypes.string.isRequired,
            imagePath: PropTypes.bool.isRequired,
        }),
    };
    const myRef = useRef(null);

    const executeScroll = () => {
        const returnScroll = document.body.scrollHeight / 2;
        // console.log(returnScroll);
        const test = document.getElementById("box");
        let testBox = test.getBoundingClientRect();
        let testBoxHeight = testBox.height;
        console.log(testBox);
        console.log(returnScroll);
        let testPreview = returnScroll - testBoxHeight;
        console.log(testPreview);
        let testAgain = returnScroll - window.scrollY;
        console.log(testAgain);
        let finalExam = returnScroll + testAgain;
        console.log(finalExam);
        console.log(myRef);
        myRef.current.scrollIntoView({ behavior: 'smooth', block: 'center',})    // window.scrollTo({ top: testAgain, behavior: "smooth" });

// test.scrollIntoView({ behavior: 'smooth', block: 'center' });
// its currently centering div placement before it clicks open. need to find a way to center it AFTER modal opens
    }

    return (
        <div id="box"
            onClick={() => setIsOpenModal(!isOpenModal)}
            className={`${isOpenModal ? styles["overlay"] : styles["overlayNone"]}`}
            ref={myRef}

        >
            <div
                className={`${
                    isOpenModal
                        ? styles["modalBackground"]
                        : styles["modalBackgroundNone"]
                }`}
                onClick={executeScroll}


            >
                <img
                    src={galleryObj.imagePath}
                    alt={galleryObj.name}
                    className={`${
                        isOpenModal ? styles["galleryPrevModal"] : styles["galleryPrev"]
                    }`}
                />
                <div
                    className={`${isOpenModal ? styles["modalText"] : styles["none"]}`}
                >
                    <h2 className={`${isOpenModal ? styles["modalh2"] : styles["none"]}`}>
                        {galleryObj.name}
                    </h2>
                    <p className={`${isOpenModal ? styles["modalp"] : styles["none"]}`}>
                        {galleryObj.description}
                    </p>
                    <h3 className={`${isOpenModal ? styles["modalh3"] : styles["none"]}`}>
                        {galleryObj.bulletName}
                    </h3>                   
                    <ul className={`${isOpenModal ? styles["modalBullet"] : styles["none"]}`}>
                        <li>
                        {galleryObj.bulletPoints}
                        </li>
                        <li>
                        {galleryObj.bulletPoints2}
                        </li>
                    </ul>
                </div>
            </div>
        </div>
    );
}

export default GalleryList;

How do I use Parameterized configuration with Firebase Functions onSchedule?

I am trying to use environment variables with onSchedule. But it only accepts a string, not an Expression<string> or similar. Although value() makes it compile, it will not actually deploy.

Can I use onSchedule with Parameterized configuration as recommended in the docs? Or do I need to fall back to environment variables?

import { onSchedule } from "firebase-functions/v2/scheduler";
import { defineString} from "firebase-functions/params";

const schedule = defineString("REFRESH_SCHEDULE");

export const refreshSchedule = onSchedule(
  {
    schedule: schedule, // Adding .value() makes it compile, but then it doesn't deploy.
  },
  async () => {
    // Do Stuff
  }
);

Why doesn’t my JavaScript function add a new to-do item to the list? [closed]

I’m creating a simple to-do list using HTML, CSS, and JavaScript.
When I click the “Add” button, I expect the new task to appear in the list, but nothing happens.
Here’s my code:

<input type="text" id="todo-input" placeholder="Add a task" />
<button onclick="addTodo()">Add</button>
<ul id="todo-list"></ul>

<script>
  function addTodo() {
    const input = document.getElementById("todo-input");
    const list = document.getElementById("todo-list");

    const item = document.createElement("li");
    item.textContent = input.value;

    list.appendChild(item);
  }
</script>

I don’t see any errors in the console, but the list stays empty.
What am I doing wrong?

How to find same property value in an object [duplicate]

I am trying to group objects by property, I mean same property value, using if and else condition not ternary operator. I do not know how to match the property value from the object.

let ars = [
{name:"raj", age:21},
{name:"mraj", age:26},
{name:"kraj", age:21},
{name:"draj", age:26},
{name:"wraj", age:21},
{name:"sraj", age:29},
];

var result = ars.reduce(function(a,c) {
   let key = c.age;
     if (a[key]) {

     } else {
     a[key]=c;
   }
   return a;
 }, {});

console.log(result);

Now I am getting like this:

 {
   '21': [ { name: 'raj', age: 21 } ],
   '26': [ { name: 'mraj', age: 26 } ],
   '29': [ { name: 'sraj', age: 29 } ]
 }

Output should be like:

{
  '21': [ { name: 'raj', age: 21 }, { name: 'kraj', age: 21 }, { name: 'wraj', age: 21 } ],
  '26': [ { name: 'draj', age: 26 }, { name: 'mraj', age: 26 } ],
  '29': [ { name: 'sraj', age: 29 } ]
}

How can I extract session slot IDs from HTML or fetch responses in a dashboard with no public API?

How can I extract session slot IDs from HTML or fetch responses in a dashboard with no public API?

I’m working on a private automation script for syncing availability across platforms. One of the platforms I use has a dashboard that shows class sessions (dates, available spots), but does not have a public API.

I’ve already figured out how to send updates to the backend using a PATCH request that modifies session spots — but to do that, I need to know the session slot IDs in advance.

I’ve tried:

Watching DevTools > Network for any XHR/fetch response that returns a list of sessions with IDs. Nothing obvious so far.

Searching the HTML DOM for data-session-id, input name=”session_id”, or inline JSON in tags. Haven’t found the ID array yet.

Question:

Is there a consistent or recommended method to extract internal IDs from a site like this, without using a headless browser?

Any direction on how to identify fetch/XHR responses or embedded data would help — especially if I can parse it with Python or JavaScript.

Not pulling in the supervisor name, it just says your supervisor twice

In the below script, I’m having an issue with the script removing Miguel or Linnea if they are the receipient of this email and where it says “Contact your supervisor ${supDisplay}, Miguel, or Linnea for assistance.” it’s not pulling in the supervisor name it just says your supervisor twice.

/**
 * sendNotifications
 * -----------------
 * Sends one email per staffer with Status = "Incomplete".
 * • Reads Staff List (columns A=Staff Name, E=Supervisor, F=Email).
 * • Builds an in-memory map keyed by lowercased staff name.
 * • Looks up each person’s email and supervisor name & email from that map.
 * • CCs: supervisor, Miguel, Linnea (filtered by normalized local-part).
 * • Inserts the exact supervisor name (as spelled in Staff List) into the body.
 */
function sendNotifications() {
  const ss         = SpreadsheetApp.getActive();
  const ui         = SpreadsheetApp.getUi();
  const dbSheet    = ss.getSheetByName('Centralized Database');
  const staffSheet = ss.getSheetByName('Staff List');
  const mandSheet  = ss.getSheetByName('Mandatory Trainings');
  if (!dbSheet || !staffSheet || !mandSheet) {
    ui.alert('Error: Missing one or more required sheets.');
    return;
  }

  // Build header maps
  const dbMap  = getHeaderMap(dbSheet);
  const stMap  = getHeaderMap(staffSheet);
  const mdMap  = getHeaderMap(mandSheet);

  // 1) Build staffInfo map: 
  //    key = lowercased staffName, 
  //    value = { email, supervisorName (raw from column E) }
  const staffInfo = {};
  const staffData = staffSheet
    .getRange(2, 1, staffSheet.getLastRow() - 1, staffSheet.getLastColumn())
    .getValues();
  staffData.forEach(row => {
    const rawName  = (row[stMap['Staff Name']]   || '').toString().trim();
    const rawSup   = (row[stMap['Supervsior']]   || '').toString().trim(); // exact header spelling
    const rawEmail = (row[stMap['Email']]        || '').toString().trim();
    if (rawName && rawEmail) {
      const key = rawName.toLowerCase();
      staffInfo[key] = {
        email:      rawEmail.trim().toLowerCase(),
        supervisor: rawSup  // store exactly what’s in column E
      };
    }
  });

  // 2) Build a Set of mandatory titles (for labeling)
  const mandatoryList = mandSheet
    .getRange(2, mdMap['Mandatory Trainings'] + 1, mandSheet.getLastRow() - 1, 1)
    .getValues()
    .flat()
    .filter(String);

  // 3) Group all "Incomplete" trainings by lowercased staff name
  const incompleteMap = {}; // { "alice smith": ["Course A (Mandatory)", "Course B", ...], ... }
  const dbRows = dbSheet
    .getRange(2, 1, dbSheet.getLastRow() - 1, dbSheet.getLastColumn())
    .getValues();
  dbRows.forEach(r => {
    const status = (r[dbMap['Status']] || '').toString().trim();
    if (status !== 'Incomplete') return;

    const rawName  = (r[dbMap['Staff Name']]    || '').toString().trim();
    const title    = (r[dbMap['Training Title']]|| '').toString().trim();
    if (!rawName) return;

    const key       = rawName.toLowerCase();
    const label     = mandatoryList.includes(title)
      ? `${title} (Mandatory)`
      : title;

    if (!incompleteMap[key]) {
      incompleteMap[key] = [];
    }
    incompleteMap[key].push(label);
  });

  // 4) CC constants & helper to get local-part
  const MIGUEL = '[email protected]';
  const LINNEA = '[email protected]';
  function localPart(email) {
    return (email || '').toString().split('@')[0].toLowerCase().trim();
  }

  // 5) Send one email per staffName key
  Object.entries(incompleteMap).forEach(([staffKey, trainings]) => {
    // a) Lookup this staff’s info
    const info = staffInfo[staffKey];
    if (!info || !info.email) {
      console.warn(`Skipping "${staffKey}"—no email found in Staff List.`);
      return;
    }
    const toEmailNorm = info.email;            // already lowercased + trimmed
    const supNameRaw  = info.supervisor || '';  // exact text from column E
    const supKey      = supNameRaw.toLowerCase();
    const supEmailNorm = staffInfo[supKey]
      ? staffInfo[supKey].email
      : '';

    // b) Build CC list, dropping any whose local-part matches the recipient’s
    const ccList = [supEmailNorm, MIGUEL, LINNEA]
      .filter(addr => addr)                                // drop blanks
      .filter(addr => localPart(addr) !== localPart(toEmailNorm))  // drop if same local-part
      .filter((addr, i, arr) => arr.indexOf(addr) === i);  // dedupe

    // c) Build HTML bullet list
    const listHtml = trainings.map(t => `<li>${t}</li>`).join('n');

    // d) Supervisor display fallback
    const supDisplay = supNameRaw || 'your supervisor';

    // e) Compose the HTML body
    const htmlBody = `
<p>Hello ${staffKey.charAt(0).toUpperCase() + staffKey.slice(1)},</p>

<p>Our records show you have not completed the following trainings:</p>
<ul>
${listHtml}
</ul>

<p>We encourage you to complete these trainings at your earliest convenience, as they are pre-requisites for registering for future trainings and will ensure you stay aligned with professional development goals.</p>

<p>These trainings can be found on <a href="https://testing.litmos.com/account/Login">Litmos</a> —
please reach out to <a href="mailto:[email protected]">[email protected]</a>
if you have any issues accessing Litmos.</p>

<p>Contact your supervisor ${supDisplay}, Miguel, or Linnea for assistance.</p>

<p>Warmly,<br>
<strong>BJI Training Liaisons</strong></p>
`;

    // f) Send the email
    GmailApp.sendEmail(toEmailNorm, 'Incomplete Trainings Reminder', '', {
      htmlBody,
      cc: ccList.join(', ')
    });
  });

  ui.alert('sendNotifications: All incomplete reminders have been sent.');
}

Google Apps Script Having 2 mapping issues

In the below script, I’m having an issue with the script removing Miguel or Linnea if they are the receipient of this email and where it says “Contact your supervisor ${supDisplay}, Miguel, or Linnea for assistance.” it’s not pulling in the supervisor name it just says your supervisor twice. Help please!

/**
 * sendNotifications
 * -----------------
 * Sends one email per staffer with Status = "Incomplete".
 * • Reads Staff List (columns A=Staff Name, E=Supervisor, F=Email).
 * • Builds an in-memory map keyed by lowercased staff name.
 * • Looks up each person’s email and supervisor name & email from that map.
 * • CCs: supervisor, Miguel, Linnea (filtered by normalized local-part).
 * • Inserts the exact supervisor name (as spelled in Staff List) into the body.
 */
function sendNotifications() {
  const ss         = SpreadsheetApp.getActive();
  const ui         = SpreadsheetApp.getUi();
  const dbSheet    = ss.getSheetByName('Centralized Database');
  const staffSheet = ss.getSheetByName('Staff List');
  const mandSheet  = ss.getSheetByName('Mandatory Trainings');
  if (!dbSheet || !staffSheet || !mandSheet) {
    ui.alert('Error: Missing one or more required sheets.');
    return;
  }

  // Build header maps
  const dbMap  = getHeaderMap(dbSheet);
  const stMap  = getHeaderMap(staffSheet);
  const mdMap  = getHeaderMap(mandSheet);

  // 1) Build staffInfo map: 
  //    key = lowercased staffName, 
  //    value = { email, supervisorName (raw from column E) }
  const staffInfo = {};
  const staffData = staffSheet
    .getRange(2, 1, staffSheet.getLastRow() - 1, staffSheet.getLastColumn())
    .getValues();
  staffData.forEach(row => {
    const rawName  = (row[stMap['Staff Name']]   || '').toString().trim();
    const rawSup   = (row[stMap['Supervsior']]   || '').toString().trim(); // exact header spelling
    const rawEmail = (row[stMap['Email']]        || '').toString().trim();
    if (rawName && rawEmail) {
      const key = rawName.toLowerCase();
      staffInfo[key] = {
        email:      rawEmail.trim().toLowerCase(),
        supervisor: rawSup  // store exactly what’s in column E
      };
    }
  });

  // 2) Build a Set of mandatory titles (for labeling)
  const mandatoryList = mandSheet
    .getRange(2, mdMap['Mandatory Trainings'] + 1, mandSheet.getLastRow() - 1, 1)
    .getValues()
    .flat()
    .filter(String);

  // 3) Group all "Incomplete" trainings by lowercased staff name
  const incompleteMap = {}; // { "alice smith": ["Course A (Mandatory)", "Course B", ...], ... }
  const dbRows = dbSheet
    .getRange(2, 1, dbSheet.getLastRow() - 1, dbSheet.getLastColumn())
    .getValues();
  dbRows.forEach(r => {
    const status = (r[dbMap['Status']] || '').toString().trim();
    if (status !== 'Incomplete') return;

    const rawName  = (r[dbMap['Staff Name']]    || '').toString().trim();
    const title    = (r[dbMap['Training Title']]|| '').toString().trim();
    if (!rawName) return;

    const key       = rawName.toLowerCase();
    const label     = mandatoryList.includes(title)
      ? `${title} (Mandatory)`
      : title;

    if (!incompleteMap[key]) {
      incompleteMap[key] = [];
    }
    incompleteMap[key].push(label);
  });

  // 4) CC constants & helper to get local-part
  const MIGUEL = '[email protected]';
  const LINNEA = '[email protected]';
  function localPart(email) {
    return (email || '').toString().split('@')[0].toLowerCase().trim();
  }

  // 5) Send one email per staffName key
  Object.entries(incompleteMap).forEach(([staffKey, trainings]) => {
    // a) Lookup this staff’s info
    const info = staffInfo[staffKey];
    if (!info || !info.email) {
      console.warn(`Skipping "${staffKey}"—no email found in Staff List.`);
      return;
    }
    const toEmailNorm = info.email;            // already lowercased + trimmed
    const supNameRaw  = info.supervisor || '';  // exact text from column E
    const supKey      = supNameRaw.toLowerCase();
    const supEmailNorm = staffInfo[supKey]
      ? staffInfo[supKey].email
      : '';

    // b) Build CC list, dropping any whose local-part matches the recipient’s
    const ccList = [supEmailNorm, MIGUEL, LINNEA]
      .filter(addr => addr)                                // drop blanks
      .filter(addr => localPart(addr) !== localPart(toEmailNorm))  // drop if same local-part
      .filter((addr, i, arr) => arr.indexOf(addr) === i);  // dedupe

    // c) Build HTML bullet list
    const listHtml = trainings.map(t => `<li>${t}</li>`).join('n');

    // d) Supervisor display fallback
    const supDisplay = supNameRaw || 'your supervisor';

    // e) Compose the HTML body
    const htmlBody = `
<p>Hello ${staffKey.charAt(0).toUpperCase() + staffKey.slice(1)},</p>

<p>Our records show you have not completed the following trainings:</p>
<ul>
${listHtml}
</ul>

<p>We encourage you to complete these trainings at your earliest convenience, as they are pre-requisites for registering for future trainings and will ensure you stay aligned with professional development goals.</p>

<p>These trainings can be found on <a href="https://testing.litmos.com/account/Login">Litmos</a> —
please reach out to <a href="mailto:[email protected]">[email protected]</a>
if you have any issues accessing Litmos.</p>

<p>Contact your supervisor ${supDisplay}, Miguel, or Linnea for assistance.</p>

<p>Warmly,<br>
<strong>BJI Training Liaisons</strong></p>
`;

    // f) Send the email
    GmailApp.sendEmail(toEmailNorm, 'Incomplete Trainings Reminder', '', {
      htmlBody,
      cc: ccList.join(', ')
    });
  });

  ui.alert('sendNotifications: All incomplete reminders have been sent.');
}

Javascript JSON related TypeError

Workflow: Basically I want to update number of Pomodoro using this code:

backButton.addEventListener("click", async () => {
    remainingPomodoro = Math.max(0, noPomodoros - (pomoCount - 1)); // Result clamped to 0

    try {
        const response = await fetch("/updatetask", {
            method: "POST",
            headers: {
                "Content-type": "application/json"
            },
            body: JSON.stringify({
                taskId,
                updatedpomoCount: remainingPomodoro
            })
        });

        const rawText = await response.text();
        try {  // Read the response once
            result = JSON.parse(rawText);
            if (result.success) {
                window.location.href = "/task-tracker";
            }
            else {
                alert("Failed to update task.");
            }

        } catch (e) {
            const text = await response.text();
            console.error("Failed to parse JSON. Raw response:", text);
            alert("Server error. Check console for details.");
            return;
        }
    }

    catch (error) {
        console.error("Error updating task:", error);
        alert("Error contacting server.");
    }

This code will be transferred to flask backend to be processed:

@app.route("/updatetask", methods=["POST"])
def updatetask():
    if request.method == "POST":
        data = request.get_json()
        updated_pomocount = data.get("updatedpomoCount")
        id = data.get("taskId")

        db = get_db_connection()
        cursor = db.cursor()
        updated_task = cursor.execute("UPDATE tasks SET pomocount = ? WHERE id = ?", (updated_pomocount, id))
        db.commit()
        cursor.close()
        db.close()

        if updated_pomocount is None or id is None:
            return jsonify({"success": False, "error": "Missing data"}), 400
        return jsonify({"success": True})

However, I got this error:

Error updating task: TypeError: Failed to execute ‘text’ on ‘Response’: body stream already read
at HTMLButtonElement. (pomodoro.js:451:41)
(anonymous) @ pomodoro.js:459

Could somebody please help me to identify the root cause of the problem, why did I trigger the problem in the first place and the steps needed to fix this code.

The values are initialized in the following blocks of code

function addTask(taskName, noPomodoros, selectedDayIndex, taskId) {
  console.log(taskName, noPomodoros, selectedDayIndex, taskId)
  // Create a new task div
  const taskDiv = document.createElement("div");
  taskDiv.className = "task-div";
  taskDiv.innerHTML = 
  `<span>${taskName}</span>
  <p> Pomodoros: ${noPomodoros}</p>
  <button class="deleteTaskButton">delete</button>`;

  const deleteTaskButton = taskDiv.querySelector(".deleteTaskButton");

  // Initially hide the button via CSS (not with inline style)
  deleteTaskButton.style.opacity = "0";
  deleteTaskButton.style.visibility = "hidden";
  deleteTaskButton.style.transition = "all 0.3s ease;";

  // Show button on hover (only for this taskDiv)
  taskDiv.addEventListener("mouseenter", () => {
    deleteTaskButton.style.opacity = "1";
    deleteTaskButton.style.visibility = "visible";
  });
  taskDiv.addEventListener("mouseleave", () => {
    deleteTaskButton.style.opacity = "0";
    deleteTaskButton.style.visibility = "hidden";
  });

  // Add event listener to delete button
  deleteTaskButton.addEventListener("click", async (e) => {
    e.stopPropagation();
    new Audio('/static/button-click.mp3').play()
    try {
    const response = await fetch ('/deletetask', {
      method: 'DELETE',
      headers: {
        "Content-Type": "application/json",
      },
      body: JSON.stringify({
        task_id : taskId,
      }),
    });

    const result = await response.json();
    if (result.success) {
      taskDiv.remove();  
      alert("Task deleted successfully.");
    } else {
      alert("Failed to delete task.");
    }}
      catch (error) {
    console.error("Error deleting task:", error);
    alert("An error occurred.");
      }
  })
  // Insert the task div into the correct column above the add task button
  const targetColumn = document.querySelector(`.day-column[data-index="${selectedDayIndex}"]`)
  const addButton = targetColumn.querySelector(".add-task");
  targetColumn.insertBefore(taskDiv, addButton);

  taskDiv.addEventListener("click", async () => {
    const form = document.createElement("form");
    form.method = "POST";
    form.action = "/view-task";

    const data = {
      task_name: taskName,
      no_pomodoros: noPomodoros,
      day_idx: selectedDayIndex + 1,
    };

    for (const key in data) {
      const input = document.createElement("input");
      input.type = "hidden";
      input.name = key;
      input.value = data[key];
      form.appendChild(input);
    }

    localStorage.setItem("currentTask", JSON.stringify({
      taskName,
      noPomodoros,
      taskId,
      day_idx: selectedDayIndex
    }));

    document.body.appendChild(form);
    form.submit();
  })

  // Clear inputs and close popup
  document.getElementById('taskNameInput').value = '';
  document.getElementById('pomoCountInput').value = 1;
  closeTaskPopup();
}

taskFormPopup.addEventListener("submit", async function (e) {
  e.preventDefault(); // Prevent the form from submitting normally

  const taskName = document.getElementById("taskNameInput").value.trim(); 
  const noPomodoros = document.getElementById("pomoCountInput").value;
  const taskDayIdx = parseInt(document.getElementById("dayIndexInput").value);

  // Create a json object to send to flask serverside
  const response = await fetch('/addtask', {
    method: 'POST',
    headers: {
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      task_name: taskName,
      pomodoro_count: noPomodoros,
      day_index: taskDayIdx,
    }),
  });

  const data = await response.json();
  console.log(data);
  if (data.success) {
    taskId = data.task_id;
    addTask(taskName, noPomodoros, taskDayIdx, taskId);
    alert("Task added successfully!");
  }
  else {
    alert("Failed to add task. Please try again.")
  }
})

The other javascript file then receives the information here

const currentTask = JSON.parse(localStorage.getItem("currentTask"));
if (currentTask) {
    taskId = currentTask.taskId;
    noPomodoros = parseInt(currentTask.noPomodoros);
    taskName = currentTask.taskName;
    day_idx = currentTask.day_idx;
}

Any sort of guide and help is appreciated! Let me know if you still need any more information.

Dropdown buttons do not function correctly when NVDA screen reader is active

The dropdown buttons in the main menu are expected to open submenus when activated via the Enter or Space key. While this behavior works correctly during standard keyboard-only testing, it fails when NVDA is active: Instead of expanding the dropdown, pressing Enter or Space while focused on a dropdown item navigates to the linked product page. How can I fix this issue?

<button class="class1" tabindex="0" type="button" aria-controls="categoryList" aria-expanded="false"** aria-label="" aria-haspopup="true">

<span class="MuiBox-root css-0">Find Your Fit</span>

<span class="MuiTouchRipple-root css-w0pj6f"></span>
</button>

Users always get ERR_CONNECTION_CLOSED / ERR_CONNECTION_REFUSED error when using my website

I use php, javascript (for ajax), html and css to build my website on a web hosting.
However, when my users and I use the function of the website, we will get ERR_CONNECTION_CLOSED / ERR_CONNECTION_REFUSED error and got blocked for about 5 mins.
I asked the hosting provider and they say the server files are fine.

BTW, I have subdomains on the domain too.
When I got blocked, I change to use mobile network and the website comes back, but it will block me again if i use the website for a while.
the users have done clearing cache

upload image to firebase storage not working [closed]

I’m trying to upload image to firebase storage with this code

 const upLoadProfilePhoto = async () => {
let result = await ImagePicker.launchImageLibraryAsync({
  mediaTypes: ImagePicker.MediaTypeOptions.Images,
  allowsEditing: true,
  aspect: [1, 1],
  quality: 1,
});

console.log(result.assets[0].uri);

if (!result.cancelled) {
  setImage(result.assets[0].uri);
 await uploadData(result.assets[0].uri, 'image')
}
};

async function uploadData (uri, fileType) {
// just to confirm the uri got to the upload function
 console.log('uploading....'+ uri)

const response = await fetch(uri)
const blob = await response.blob()
const storag = ref(storage, 'data/' + new Date().getTime())
const uploadTask = uploadBytesResumable(storag, blob)

uploadTask.on('state_changed', (snapshot) => {
     const progress = (snapshot.bytesTransferred / snapshot.totalBytes) * 100
     console.log('upload progress: ' + progress + '%')
},
(error) => {
 console.log(error)
},
() => {
  getDownloadURL(uploadTask.snapshot.ref).then(async (downloadUrl) => {

   setImageUrl(downloadUrl)
   console.log('file available at: ' + downloadUrl)

  }).then(() => {
   // saveToFireStore()
   
  })
})
}

somehow the image does not get uploaded and nothing is being logged in the console. I have all the necessary imports and still yet nothing happens when I try to upload an image.