Chrome throwing an error for a line that has been commented out already

The following line is commented out, but still throwing an error. Why would console still throw an error for a line that is already commented out? I have commented it out using // as well as `/…../

I have tried with both literal strings

// asdf = `<text>...${var}` 

inside the comment block as well as concatenated strings.

I have checked in Firefox and Chrome.

The specific error thrown in the console is Error: <textPath> attribute startOffset: Expected length, "'+offset+'%".

The following are various minimal reproducible examples of what I mean:

test.svg

<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="500px" height="500px" viewBox="0 0 500 500" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<script>
//  asdf += '<text font-family="sans-serif" font-size="14" fill="#1a202c"><textPath startOffset="'+offset+'%" xlink:href="#weeks-path">'+i+'</textPath></text>';
/*  asdf += '<text font-family="sans-serif" font-size="14" fill="#1a202c"><textPath startOffset="'+offset+'%" xlink:href="#weeks-path">'+i+'</textPath></text>';*/
</script>
</svg>

test.html

<!DOCTYPE html>
<html>
<svg width="500px" height="500px" viewBox="0 0 500 500" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<script>
//  asdf += '<text font-family="sans-serif" font-size="14" fill="#1a202c"><textPath startOffset="'+offset+'%" xlink:href="#weeks-path">'+i+'</textPath></text>';
/*  asdf += '<text font-family="sans-serif" font-size="14" fill="#1a202c"><textPath startOffset="'+offset+'%" xlink:href="#weeks-path">'+i+'</textPath></text>';*/
</script>
</svg>
</html>

Do ALL HTTPS requests in the browser derive from XMLHttpRequest and fetch API?

I’m trying to make a “nearly universal interceptor” package that can intercept all outgoing requests (coming soon…).

I added interceptors for fetch API and XMLHttpRequest, and then got ready to search for more types of HTTPS requests. However, I only found packages like Axios and Alova.

If I intercept every fetch request and XMLHttpRequest request, then can I say that I am intercepting ALL outgoing requests from the browser? If not, what is the closest way to reach a “universal interceptor”?

The trigger disappears due to a conflict between two ScrollTriggers

I’m currently creating a horizontal scroll for my website. At the very end of this horizontal scroll, I also set up a ScrollTrigger for stacking effects. However, strangely, the trigger for the stacking effects, #facts, disappears from the viewport once the user enters the onLeave area. This is very odd.

function createScrollTriggerMD() {
  ScrollTrigger.create({
    trigger: "#scroll-container",
    start: "top top",
    end: () => `+=${getScrollAmount() * -1}`,
    pin: "#scroll-container",
    animation: tween,
    scrub: 1,
    onUpdate: (e) => {
      let scale;
      let y;
      if (e.progress <= 0.5) {
        scale = gsap.utils.mapRange(0, 0.5, 1, 0.6, e.progress);
        y = gsap.utils.mapRange(0, 0.5, 0, -150, e.progress);
      } else {
        scale = gsap.utils.mapRange(0.5, 1, 0.6, 1, e.progress);
        y = gsap.utils.mapRange(0.5, 1, -150, -150, e.progress);
      }

      gsap.to("#red-bubble", {
        y,
        scale,
        x: `-${e.progress * 40}%`,
        overwrite: "auto",
        duration: 0.1,
      });
    },
    onLeave: () => {
      const cards = document.querySelectorAll(".protection-card");
      const header = document.querySelector("#facts");
      const animation = gsap.timeline();
      let cardHeight;

      function initCards() {
        animation.clear();
        cardHeight = cards[0].offsetHeight;
        console.log("initCards()", cardHeight);
        cards.forEach((card, index) => {
          if (index > 0) {
            //increment y value of each card by cardHeight
            gsap.set(card, { y: index * cardHeight });
            //animate each card back to 0 (for stacking)
            animation.to(
              card,
              { y: index * 10, duration: index * 0.5, ease: "none" },
              0
            );
          }
        });
      }

      initCards();

      ScrollTrigger.create({
        trigger: "#facts",
        start: "top top",
        pin: true,
        end: () => `+=${cards.length * cardHeight + header.offsetHeight}`,
        scrub: true,
        animation: animation,
        markers: true,
        invalidateOnRefresh: true,
      });

      ScrollTrigger.addEventListener("refreshInit", initCards);
    },
    invalidateOnRefresh: true,
  });
}

My goal is simple: how can I combine these two ScrollTriggers so that the stacking effects ScrollTrigger only runs after the horizontal scroll ScrollTrigger has finished?

Why are Socket.io or WebSockets used in React applications?

Socket.io or WebSockets are used in React applications for **real-time
communication Normally, React fetches data using HTTP requests (GET, POST), which work on a request-response cycle.

But for features like:
Chat applications
Live notifications
Real-time dashboards
Multiplayer games

HTTP requests become inefficient because the client has to keep asking the server for updates.

Socket.io/WebSockets solve this by creating a persistent connection between the server and client:

The server can push data to the client instantly.
The client can receive updates without sending repeated requests.
Latency is reduced, and data stays real-time synced

Example:

// Client-side React
import { useEffect } from 'react';
import io from 'socket.io-client';

const socket = io('http://localhost:3000');

function Chat() {
  useEffect(() => {
    socket.on('message', (msg) => {
      console.log('New message:', msg);
    });

    return () => socket.disconnect();
  }, []);

  return <div>Chat component running...</div>;
}






1. What you tried:

Describe the exact steps you took, including code changes, commands, or tools used.
Be precise and concise so someone else can replicate it.

Example:

> “I tried updating the React component to use Socket.io for real-time messaging. I imported `io` from `socket.io-client` and established a connection in a `useEffect` hook, then listened for the `message` event.”

2. What you expected:

 Explain the expected outcome if everything worked correctly.
 Be specific about the behavior, output, or UI change.


valueOf() changes after Object.create() on changed prototype. Why?

I observe strange behavior of valueOf() after Object.create() on changed prototype.

  1. reassign prototype.
  2. create two similar objects.
  3. one of them is used as prototype with Object.create()
  4. it changes its valueOf()!

I use VS Code.

function Animal(name) {
    this.name = name;
}

function Rabbit(name) {
    this.name = name;
}

let animal = new Animal("Bob");

Rabbit.prototype = animal;

// if we reassign constructor here, then odd_rabbit keeps its - valueof() - as Rabbit.
// but we comment it to see odd behavior later...
// Rabbit.prototype.constructor = Rabbit; // <-- this line fixes problem

let rabbit1 = new Rabbit("Tom");
let odd_rabbit = new Rabbit("Odd rabbit");

// rabbit1.valueOf() - Rabbit - first object is Ok
// odd_rabbit.valueOf() - Rabbit - second is still fine here

// After this line everything changes...
let rabbit2 = Object.create(odd_rabbit);

// rabbit1.valueOf() - Rabbit
// odd_rabbit.valueOf() - Animal - Why???

Why did odd_rabbit has changed its valueOf() after being used as a prototype of Object.create(odd_rabbit)? Or did I make a silly mistake?

Why does my div element display and then disappear after clicking the submit button?

I add an addEventListener so that when the user clicks on the “post” button, a new div with the user input should appear above it. But it disappears as soon as it appears. I have attached a live example to better illustrate the problem.

const form = document.getElementById('form');
form.style.visibility = 'hidden';

function comment() {
  const postLink = document.getElementById('postLink');
  postLink.style.visibility = 'hidden';

  if (form.style.visibility === 'hidden') {
    form.style.visibility = 'visible';
  } else {
    form.style.visibility = 'hidden';
  }
}

document.getElementById('button').addEventListener('click', function createPost() {
  userInput();
});

function userInput() {
  const textarea = document.getElementById('textarea').value;
  if (textarea.length > 0) {
    const cards = document.getElementById('cards');
    const div = document.createElement('div');
    cards.appendChild(div);
    div.textContent = textarea;
  }
}
.cards {
  display: grid;
  grid-template-columns: repeat(1, minmax(100px, 1fr));
  gap: 40px;
  justify-content: center;
}

.cards>div {
  border-top-style: solid;
  border-width: 5px 1px 0px 0px;
  box-shadow: 5px 5px 20px #e0dfdf;
  justify-self: center;
  padding: 10px;
}
<div class="cards" id="cards">
  <div>Type anything you want here and it will keep expanding.</div>
</div>
<p id="postLink"><a onclick='comment()' href="#">post</a></p>
<form id="form">
  <label for="textarea"></label>
  <textarea name="post" id="textarea" rows="8" cols="50" placeholder="start typing your essay..."></textarea>
  <div><button type="submit" id="button">post</button></div>
</form>
</div>

</div>
<script src="script.js"></script>

Audio preloading and sprite flicker issues in my HTML5 canvas space shooter—how to fix?

I made a browser-based space shooter game text in HTML5 and JavaScript. Here’s a minimal code example where I preload audio assets:

const hitSound = new Audio(‘hit.mp3’);
hitSound.preload = ‘auto’;

Yet when enemies die, the first hit is silent or delayed. Also, in full-screen mode, the spaceship sprite flickers badly. Here’s my drawing loop…

I’ve tried using requestAnimationFrame, double-buffering, and forcing audio.play() multiple times, but the problems persist. What am I missing?

THREE.js depth-map parallax looks “off” / swimming—how do I correctly align depth with the texture?

I’m building a layered parallax effect in React + THREE.js where each PNG texture has a matching grayscale depth map. The scene renders and the mouse parallax works, but the motion looks unnatural—almost like the depth map is slightly misregistered with the color, causing features to “swim” when I move the mouse.

What I’m doing

  • React + THREE WebGLRenderer with an OrthographicCamera so layers keep their size; parallax comes from sampling the depth map in the fragment shader.
  • Each layer has a color texture and a depth map; both are PNGs with the same aspect and (as far as I can tell) the same pixel dimensions and alignment.
  • I draw one full-screen plane per layer (plane size = viewport width × height) and sort by textureZ.
  • Displacement is computed from the depth map and the mouse position; I allow per-layer tuning with textureZ and depthZ.

Minimal shader (fragment):

uniform sampler2D u_image;
uniform sampler2D u_depth;
uniform vec2 u_mouse;     // normalized [0..1]
uniform float u_strength; // 0.15
uniform float u_texZ;     // per-layer
uniform float u_depthZ;   // per-layer
varying vec2 vUv;

void main() {
  float d = texture2D(u_depth, vUv).r;   // grayscale depth
  float zFactor = (u_texZ - u_depthZ) * 0.057; // tuning constant
  vec2 center = u_mouse;
  vec2 disp = (vUv - center) * u_strength * (1.0 - d) * zFactor;
  vec2 uv = vUv + disp;
  gl_FragColor = texture2D(u_image, uv);
}

Full component (React + THREE) is included below for reference.

What “off” looks like

  • Edges and high-contrast details appear to slide relative to their color as I move the mouse.
  • Flat objects (e.g., a picture frame) bend or shear subtly rather than staying rigid.
  • The parallax direction is mostly right, but the magnitude seems inconsistent across the image (some areas over-displace, others under-displace).

Environment

  • React 18, THREE r1xx (via three NPM).
  • Textures and depth maps are PNG, linear filtering.
  • Renderer: antialias: true, alpha: true, sRGBEncoding not explicitly set.
  • Reproduces in Chrome and Firefox on desktop (Windows + macOS).

Things I’ve already checked / tried

  1. Same resolution & aspect for texture and depth map: verified in an image editor.
  2. UVs: using a single full-screen plane; vUv is standard [0..1].
  3. Filtering: LinearFilter for min/mag; still swims.
  4. Wrap mode: not explicitly set; defaults apply.
  5. Depth polarity: tried d vs 1.0 - d; only changes the direction, not the “swim.”
  6. Displacement scale: reduced u_strength and zFactor; effect is smaller but still looks misaligned.
  7. Z sorting: layers are sorted far→near; visually correct stacking, but the artifact persists.
  8. Mouse math: normalized to the canvas rect; seems correct.

Suspicions

  • Color space mismatch: the color texture might be sampled in sRGB, depth in linear, leading to nonlinear depth response. I haven’t set renderer.outputEncoding or texture.encoding.
  • Texture wrap/clamp: lack of ClampToEdgeWrapping could cause edge bleeding when uv goes out of [0..1].
  • Depth map generation: the depth may not be metrically consistent (e.g., not linearized), causing local over/under-displacement.
  • Incorrect center: using u_mouse as the parallax center may produce perspective that feels wrong for an ortho camera without a focal length model.
  • Plane scaling vs. image pixels: viewport-sized plane might stretch textures slightly compared to their native pixel grid, revealing minor registration errors.
  • Per-layer Z math: (u_texZ - u_depthZ) * 0.057 might double-count or mis-scale perceived depth.

Concrete questions

  1. What’s the correct way to ensure the depth map aligns perfectly with the color texture in this setup?

  2. Should I explicitly set encodings and wraps like:

    renderer.outputColorSpace = THREE.SRGBColorSpace;
    tex.colorSpace = THREE.SRGBColorSpace;
    depth.colorSpace = THREE.LinearSRGBColorSpace; // or leave linear?
    tex.wrapS = tex.wrapT = THREE.ClampToEdgeWrapping;
    depth.wrapS = depth.wrapT = THREE.ClampToEdgeWrapping;
    depth.minFilter = depth.magFilter = THREE.LinearFilter;
    
  3. Is there a known pattern for screen-space parallax that avoids UVs leaving [0..1] (e.g., uv = clamp(uv, 0.0, 1.0);) without introducing visible edge pinning?

  4. If a depth map is not metrically linear, is there a common remapping (gamma, curve, or per-layer scale) you use to stabilize the motion?

  5. Would switching to a perspective camera and computing parallax from a camera basis (instead of mouse delta in UV space) make the motion feel more natural?

Debugging steps I’m planning (open to better ideas)

  • Visualize the depth directly: gl_FragColor = vec4(vec3(d), 1.0) to confirm alignment.
  • Draw the Sobel edges of the depth and overlay the color to check registration.
  • Clamp UVs and compare: uv = clamp(uv, 0.0, 1.0) to test edge bleeding hypothesis.
  • Toggle color/depth encodings and verify with a test gradient depth map.
  • Add a single global scale slider and separate per-layer scales for displacement to see if “swim” is just nonlinearity.

Any advice on the correct encoding/wrap settings, depth remapping, or parallax math to eliminate the “swimming” would be hugely appreciated! If there’s a canonical sample that combines sRGB color + linear depth correctly, a pointer would be gold.

Type Error while trying to import page props in a next js form

Type error: Type '{ params: { type: string; }; }' does not satisfy the constraint 'PageProps'.
  Types of property 'params' are incompatible.
    Type '{ type: string; }' is missing the following properties from type 'Promise<any>': then, catch, finally, [Symbol.toStringTag]

this is the error i am getting while trying to import some props.

The goal of this below code is to import any from dynamically according to the url or the button pressed and display it accordingly. this is done to reduce the number of separate pages and make a uniform url format.

import {
    Breadcrumb,
    BreadcrumbItem,
    BreadcrumbLink,
    BreadcrumbList,
    BreadcrumbPage,
    BreadcrumbSeparator,
} from "@/components/ui/breadcrumb"
import * as form from "@/components/forms";

const formMap: Record<string, React.ComponentType> = {
    client: form.ClientForm,
    invoice: form.InvoiceForm,
};

export default async function DynamicFormPage({ params }: { params: { type: string } }) {
    const FormComponent =await formMap[params.type];

    return (
        <main className="mx-70 flex flex-col gap-y-15">
            <section>
                <Breadcrumb>
                <BreadcrumbList>
                    <BreadcrumbItem>
                        <BreadcrumbLink href="/">Home</BreadcrumbLink>
                    </BreadcrumbItem>
                    <BreadcrumbSeparator/>
                    <BreadcrumbItem>
                        <BreadcrumbLink>New</BreadcrumbLink>
                    </BreadcrumbItem>
                    <BreadcrumbSeparator/>
                    <BreadcrumbItem>
                        <BreadcrumbPage>{params.type}</BreadcrumbPage>
                    </BreadcrumbItem>
                </BreadcrumbList>
            </Breadcrumb>
            </section>
            <section>
                <FormComponent/>
            </section>
        </main>
    );
}

while the example form i am using is

"use client";

//frontend imports
import {
    Accordion,
    AccordionContent,
    AccordionItem,
    AccordionTrigger,
} from "@/components/ui/accordion";
import * as field from "@/components/forms/fields";
import RadioField from "@/components/forms/fields/RadioField";
import { Checkbox } from "@/components/ui/checkbox";
import { Label } from "@/components/ui/label";

//backend imports
import { useForm } from "react-hook-form";
import { z } from "zod";
import { zodResolver } from "@hookform/resolvers/zod";

const clientSchema = z.object({
    businessName: z.string().min(4, "Company name too short!!"),
})

export default function ClientForm() {

    const {
        register,
        handleSubmit,
        formState: { errors },
    } = useForm({
        resolver: zodResolver(clientSchema),
        mode: "onBlur",
    });

    const onSubmit = (data: any) => {
        console.log("Valid data:", data);
    };

    return (
        <form onSubmit={handleSubmit(onSubmit)}>
            <Accordion
                type="single"
                collapsible
                defaultValue="item-1"
            >
                <AccordionItem value="item-1">
                    <AccordionTrigger className="text-xl !no-underline">Basic Information</AccordionTrigger>
                    <AccordionContent className="grid grid-cols-2 gap-4 text-balance">
                        <field.TextField
                            label="Business Name"
                            {...register("businessName")}
                            error={errors.businessName?.message}
                            required
                        />
                        <field.DropdownField
                            label="Business Type"
                            options={[
                                { value: "accounting", label: "Accounting" },
                                { value: "advertising", label: "Advertising" },
                                { value: "aerospace", label: "Aerospace & Defense" },
                                { value: "agriculture", label: "Agriculture" },
                                { value: "apparel", label: "Apparel & Fashion" },
                                { value: "architecture", label: "Architecture & Design" },
                                { value: "artificial_intelligence", label: "Artificial Intelligence" },
                                { value: "arts", label: "Arts & Culture" },
                                { value: "automotive", label: "Automotive" },
                                { value: "aviation", label: "Aviation" },
                                { value: "banking", label: "Banking" },
                                { value: "biotechnology", label: "Biotechnology" },
                                { value: "blockchain", label: "Blockchain" },
                                { value: "chemicals", label: "Chemicals" },
                                { value: "cloud_computing", label: "Cloud Computing" },
                                { value: "construction", label: "Construction" },
                                { value: "consulting", label: "Consulting" },
                                { value: "cybersecurity", label: "Cybersecurity" },
                                { value: "defense", label: "Defense" },
                                { value: "ecommerce", label: "E-commerce" },
                                { value: "education", label: "Education" },
                                { value: "edtech", label: "EdTech" },
                                { value: "electronics", label: "Electronics" },
                                { value: "energy", label: "Energy" },
                                { value: "environmental", label: "Environmental Services" },
                                { value: "farming", label: "Farming" },
                                { value: "financial_services", label: "Financial Services" },
                                { value: "fintech", label: "FinTech" },
                                { value: "fishing", label: "Fishing" },
                                { value: "film", label: "Film & TV" },
                                { value: "food_and_beverage", label: "Food & Beverage" },
                                { value: "forestry", label: "Forestry" },
                                { value: "gaming", label: "Gaming" },
                                { value: "government", label: "Government" },
                                { value: "healthcare", label: "Healthcare" },
                                { value: "hospitals", label: "Hospitals" },
                                { value: "hospitality", label: "Hospitality" },
                                { value: "human_resources", label: "Human Resources" },
                                { value: "insurance", label: "Insurance" },
                                { value: "investment", label: "Investment & Asset Management" },
                                { value: "it_services", label: "IT Services" },
                                { value: "jewelry", label: "Jewelry" },
                                { value: "legal", label: "Legal Services" },
                                { value: "logistics", label: "Logistics" },
                                { value: "luxury_goods", label: "Luxury Goods" },
                                { value: "manufacturing", label: "Manufacturing" },
                                { value: "marketing", label: "Marketing & PR" },
                                { value: "maritime", label: "Maritime" },
                                { value: "media", label: "Media & Entertainment" },
                                { value: "medical_devices", label: "Medical Devices" },
                                { value: "metaverse", label: "Metaverse" },
                                { value: "mining", label: "Mining" },
                                { value: "music", label: "Music" },
                                { value: "nonprofit", label: "Non-Profit" },
                                { value: "nuclear_energy", label: "Nuclear Energy" },
                                { value: "oil_and_gas", label: "Oil & Gas" },
                                { value: "pet_industry", label: "Pet Industry" },
                                { value: "pharmaceuticals", label: "Pharmaceuticals" },
                                { value: "printing", label: "Printing & Packaging" },
                                { value: "private_equity", label: "Private Equity" },
                                { value: "publishing", label: "Publishing" },
                                { value: "railways", label: "Railways" },
                                { value: "real_estate", label: "Real Estate" },
                                { value: "religious", label: "Religious Institutions" },
                                { value: "renewable_energy", label: "Renewable Energy" },
                                { value: "research", label: "Research & Development" },
                                { value: "restaurants", label: "Restaurants" },
                                { value: "retail", label: "Retail" },
                                { value: "semiconductors", label: "Semiconductors" },
                                { value: "shipping", label: "Shipping" },
                                { value: "software", label: "Software Development" },
                                { value: "space", label: "Space & Astronomy" },
                                { value: "sports", label: "Sports" },
                                { value: "telecommunications", label: "Telecommunications" },
                                { value: "textiles", label: "Textiles" },
                                { value: "toys", label: "Toys & Games" },
                                { value: "tourism", label: "Tourism" },
                                { value: "transportation", label: "Transportation" },
                                { value: "utilities", label: "Utilities" },
                                { value: "venture_capital", label: "Venture Capital" },
                                { value: "waste_management", label: "Waste Management" },
                                { value: "water_supply", label: "Water Supply" },
                                { value: "wholesale", label: "Wholesale" },
                            ]}
                        />
                        <field.DropdownField
                            label="Country"
                            required
                            options={[
                                { value: "argentina", label: "Argentina" },
                                { value: "australia", label: "Australia" },
                                { value: "brazil", label: "Brazil" },
                                { value: "canada", label: "Canada" },
                                { value: "china", label: "China" },
                                { value: "france", label: "France" },
                                { value: "germany", label: "Germany" },
                                { value: "india", label: "India" },
                                { value: "indonesia", label: "Indonesia" },
                                { value: "italy", label: "Italy" },
                                { value: "japan", label: "Japan" },
                                { value: "mexico", label: "Mexico" },
                                { value: "russia", label: "Russia" },
                                { value: "saudi_arabia", label: "Saudi Arabia" },
                                { value: "south_africa", label: "South Africa" },
                                { value: "south_korea", label: "South Korea" },
                                { value: "turkey", label: "Turkey" },
                                { value: "united_arab_emirates", label: "United Arab Emirates" },
                                { value: "united_kingdom", label: "United Kingdom" },
                                { value: "united_states", label: "United States" },
                            ]}
                        />
                        <field.TextField
                            label="City/Town"
                            name="cityTown"
                            required
                        />
                    </AccordionContent>
                </AccordionItem>
                <AccordionItem value="item-2">
                    <AccordionTrigger className="text-xl !no-underline">Tax Information (Optional)</AccordionTrigger>
                    <AccordionContent className="grid grid-cols-2 gap-4 text-balance">
                        <field.TextField
                            label="Business GSTIN"
                            name="gstin"
                        />
                        <field.TextField
                            label="Business PAN"
                            name="pan"
                        />
                        <RadioField
                            label="Payment Method"
                            name="payment"
                            tooltip="Important for filing GST reports"
                            orientation="horizontal"
                            className="col-span-2"
                            options={[
                                { value: "individual", label: "Individual" },
                                { value: "company", label: "Company" },
                            ]}
                        />
                        <field.DropdownField
                            label="Country"
                            required
                            className="col-span-2"
                            options={[
                                { value: "it", label: "IT Services" },
                                { value: "finance", label: "Finance" },
                                { value: "retail", label: "Retail" },
                            ]}
                        />
                    </AccordionContent>
                </AccordionItem>
                <AccordionItem value="item-3">
                    <AccordionTrigger className="text-xl !no-underline">Address (Optional)</AccordionTrigger>
                    <AccordionContent className="grid grid-cols-2 gap-4 text-balance">
                        <field.DropdownField
                            label="Country"
                            required
                            className="col-span-2"
                            options={[
                                { value: "it", label: "IT Services" },
                                { value: "finance", label: "Finance" },
                                { value: "retail", label: "Retail" },
                            ]}
                        />
                        <field.DropdownField
                            label="State/Province"
                            required
                            className="col-span-2"
                            options={[
                                { value: "it", label: "IT Services" },
                                { value: "finance", label: "Finance" },
                                { value: "retail", label: "Retail" },
                            ]}
                        />
                        <field.TextField
                            label="City/Town"
                            name="cityTown"
                        />
                        <field.TextField
                            label="Postal Code"
                            name="pincode"
                        />
                        <field.TextField
                            label="Street Address"
                            name="address"
                            className="col-span-2"
                        />
                    </AccordionContent>
                </AccordionItem>
                <AccordionItem value="item-4">
                    <AccordionTrigger className="text-xl !no-underline">Shipping Details (Optional)</AccordionTrigger>
                    <AccordionContent className="grid grid-cols-2 gap-4 text-balance">
                        <field.DropdownField
                            label="Country"
                            required
                            className="col-span-2"
                            options={[
                                { value: "it", label: "IT Services" },
                                { value: "finance", label: "Finance" },
                                { value: "retail", label: "Retail" },
                            ]}
                        />
                        <field.DropdownField
                            label="State/Province"
                            required
                            className="col-span-2"
                            options={[
                                { value: "it", label: "IT Services" },
                                { value: "finance", label: "Finance" },
                                { value: "retail", label: "Retail" },
                            ]}
                        />
                        <field.TextField
                            label="City/Town"
                            name="cityTown"
                        />
                        <field.TextField
                            label="Postal Code"
                            name="pincode"
                        />
                        <field.TextField
                            label="Street Address"
                            name="address"
                            className="col-span-2"
                        />
                    </AccordionContent>
                </AccordionItem>
                <AccordionItem value="item-5">
                    <AccordionTrigger className="text-xl !no-underline">Additional Details (Optional)</AccordionTrigger>
                    <AccordionContent className="grid grid-cols-2 gap-4 text-balance">
                        <field.TextField
                            label="Business Alias"
                            name="businessAlias"
                        />
                        <field.TextField
                            label="Unique Key"
                            name="uniqueKey"
                        />
                        <div className="flex items-center space-x-2">
                            <field.TextField
                                label="Email"
                                name="address"
                            />
                            <Checkbox
                                //checked={formData.showEmail}
                                //onCheckedChange={(val) => handleChange("showEmail", val === true)}
                            />
                            <Label>Show Email in Invoice</Label>
                        </div>
                        <field.TextField
                            label="Phone No."
                            name="phoneNumber"
                        />
                    </AccordionContent>
                </AccordionItem>
                <AccordionItem value="item-6">
                    <AccordionTrigger className="text-xl !no-underline">Account Details (Optional)</AccordionTrigger>
                    <AccordionContent className="grid grid-cols-2 gap-4 text-balance">
                        <field.TextField
                            label="Bank Name"
                            name="BankName"
                        />
                        <field.TextField
                            label="IFSC Code"
                            name="ifscCode"
                        />
                        <field.TextField
                            label="Account Number"
                            name="accountNumber"
                            className="col-span-2"
                        />
                    </AccordionContent>
                </AccordionItem>
            </Accordion>
        </form>
    );
}

(recreation guide: install breadcrumb and accordion component from shadcn and place the page code in a directory such as app/new/[type]/page.tsx and the form code in any directory with the correct path.)

the project is on nextjs 15+ and typescript.

i tried async await tho it should not be awaited. also asked a few AIs but none of them were able to solve the issue. you are also free to recommend other changes in the code apart from the issue as i am a new developer so I don’t know much about optimization and security.

Mobile chat widget panel shrinks and header/composer misaligns when keyboard opens (iOS Safari & Android Chrome)

I’m building a custom chat widget in JavaScript (similar to an in-page messenger). The widget attaches as a fixed panel with a sticky header, a scrollable message stream, and a composer at the bottom.

The problem happens on mobile when the keyboard opens:

On Android Chrome:

The panel shrinks when the keyboard opens.

Sometimes the underlying page becomes visible behind the panel.

If the address bar animates (top/bottom), the panel height jumps.

On iOS Safari:

The header (sticky) sometimes disappears when typing.

The panel height jiggles when the URL bar and keyboard animate.

Sometimes the composer is overshooting or undershooting the keyboard.

What I’ve tried

100vh, 100dvh, 100svh → panel still shrinks on keyboard open.

100lvh (Large Viewport Height) with a JS fallback:

const vv = window.visualViewport;
const large = vv.height + (vv.offsetTop || 0);
panel.style.setProperty('--lvh', (large/100) + 'px');

Locking page scroll while widget is open.

Raising the composer with a –kb CSS variable computed from visualViewport deltas.

This works better, but I still see edge cases:

On Android Chrome, panel briefly shrinks when the address bar animates.

On iOS Safari, header sometimes stops being sticky, and the panel still jiggles.

Goal

Panel should always cover the full viewport (no background page visible), even when the keyboard is open.

Composer should rise above the keyboard without overshooting.

Should work on both Android Chrome (address bar top/bottom) and iOS Safari (new & older versions).

Question

What’s the most robust pattern (CSS + JS) to keep a fixed chat widget panel:

Full height independent of the keyboard,

With a sticky header and bottom composer that adjust correctly,

On both Android Chrome and iOS Safari,

Without relying on UA-sniffing hacks?

here is my code

<div id="panel" class="panel">
  <div class="head">OAT Clinic</div>
  <div id="stream" class="stream">
    <!-- messages -->
  </div>
  <div id="composer" class="composer">
    <textarea id="msg" placeholder="How can we help you today?"></textarea>
  </div>
</div>
css
Copy code
:root {
  /* Large viewport height (JS sets this var) */
  --lvh: 1vh;
  /* Keyboard overlap (JS sets this var) */
  --kb: 0px;
}

/* Fullscreen panel that should NOT shrink when keyboard opens */
.panel {
  position: fixed;
  inset: 0;
  height: calc(var(--lvh) * 100);   /* prefer LVH when available */
  display: flex;
  flex-direction: column;
  background: #f7f8fb;
  overflow: hidden;
}

.head {
  position: sticky;
  top: 0;
  z-index: 1;
  padding: 9px 13px;
  background: white;
  border-bottom: 1px solid #e5e7eb;
}

.stream {
  flex: 1 1 auto;
  min-height: 0;                  /* critical for mobile scrolling */
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
}

.composer {
  position: sticky;               /* stays at bottom of panel */
  bottom: 0;
  border-top: 1px solid #e5e7eb;
  background: #f7f8fb;
  /* Lift above keyboard (JS sets --kb) */
  transform: translateY(calc(-1 * var(--kb)));
}

textarea {
  width: 100%;
  min-height: 54px;
  max-height: 120px;
  border: 1px solid #E1E1E1;
  border-radius: 12px;
  margin: 8px;
  padding: 8px 10px;
  resize: none;
}
js
Copy code
// Robust LVH + keyboard offset calculation
(function () {
  const panel = document.getElementById('panel');
  const composer = document.getElementById('composer');
  const msg = document.getElementById('msg');

  // Use Large Viewport Height when supported; JS fallback otherwise.
  function setLVH() {
    const vv = window.visualViewport;
    const large = vv ? (vv.height + (vv.offsetTop || 0)) : window.innerHeight;

    // Extra fallback using physical screen size for iOS quirks
    const alt = (window.screen && window.screen.height && window.devicePixelRatio)
      ? (window.screen.height / window.devicePixelRatio)
      : large;

    const lvh = Math.max(large, alt) / 100; // 1% unit
    panel.style.setProperty('--lvh', lvh + 'px');
  }

  let baseVVH = null; // visible height baseline (without keyboard)
  function setBaseVVH() {
    const vv = window.visualViewport;
    baseVVH = vv ? vv.height : window.innerHeight;
  }

  function computeKeyboardOffset() {
    const vv = window.visualViewport;
    let kb = 0;

    if (vv) {
      // How much of the window is occluded by the keyboard / chrome
      const occluded = Math.max(0, Math.round(window.innerHeight - vv.height - (vv.offsetTop || 0)));
      // Is the composer currently below the visible bottom?
      const visBottom = vv.height + (vv.offsetTop || 0);
      const compBottom = composer.getBoundingClientRect().bottom;
      const overlap = Math.max(0, Math.round(compBottom - visBottom));
      // Visible height delta vs baseline (helps with iOS “jiggle”)
      const delta = Math.max(0, Math.round((baseVVH || vv.height) - vv.height));

      kb = Math.max(occluded, overlap, delta);
    }

    // Thresholds to ignore small URL bar animations
    const IS_IOS = /iPad|iPhone|iPod/.test(navigator.userAgent);
    const THRESH = IS_IOS ? 120 : 80;
    if (kb < THRESH) kb = 0;

    // Cap to prevent overshoot
    const maxKb = Math.max(0, Math.round(panel.getBoundingClientRect().height - 56));
    kb = Math.min(kb, maxKb);

    panel.style.setProperty('--kb', kb + 'px');
  }

  function relayout() {
    setLVH();
    computeKeyboardOffset();
  }

  // Init
  setBaseVVH();
  setLVH();

  // Recalculate on viewport changes (keyboard / URL bar animation)
  if (window.visualViewport) {
    let timer = null;
    const onVV = () => {
      clearTimeout(timer);
      // Debounce to avoid rapid jiggle
      timer = setTimeout(() => {
        relayout();
      }, 50);
    };
    visualViewport.addEventListener('resize', onVV);
    visualViewport.addEventListener('scroll', onVV);
  }

  window.addEventListener('resize', relayout);
  window.addEventListener('orientationchange', () => setTimeout(relayout, 250));

  // Update baseline around focus/blur to track keyboard state changes
  msg.addEventListener('focus', () => { setBaseVVH(); computeKeyboardOffset(); });
  msg.addEventListener('blur', () => {
    panel.style.setProperty('--kb', '0px');
    setBaseVVH();
  });
})();

Whatsapp user initiated calling not working on live

I’ve implemented WhatsApp user initiated calling using WebRTC, nodeJS, ReactJS. Its working properly on local but not working on live, the i’m getting on both ends seems similar and normal, But on live the call the is getting auto hungup on after 20 seconds. On local its working Fine. Following is the code to handle user initiated calls from WhatsApp.

I’m following this documentation

https://developers.facebook.com/docs/whatsapp/cloud-api/calling/user-initiated-calls

const handleUserInitiatedCallRequest = async ({ req, res }) => {
  let db;
  try {
    // Extract and validate webhook data
    const change = req.body.entry?.[0]?.changes?.[0] || {};
    const call = change?.value?.calls?.[0] || {};
    const callId = call?.id;
    const receivedSdp = call.session?.sdp;
    const WHATSAPP_BUSINESS_ACCOUNT_ID =
      change.value?.metadata?.phone_number_id;

    let tenantIdRes = await getTenantIdFromUserMetaData(
      `whatsapp_id`,
      WHATSAPP_BUSINESS_ACCOUNT_ID
    );

    tenant_id = tenantIdRes?.tenant_id;

    const io = getIO();

    db = await getUserDBfromRequest({ tenant_id });

    let contactDetails =
      (await getChatUserDetailsById(db, call?.from, {
        platform: "whatsapp",
      })) || {};

    if (!callId || !receivedSdp || !WHATSAPP_BUSINESS_ACCOUNT_ID) {
      console.error("Missing required call data:", {
        callId,
        receivedSdp,
        WHATSAPP_BUSINESS_ACCOUNT_ID,
        chat_user: contactDetails,
      });
      return;
    }

    const callerName = call?.from || "Unknown";
    const callerNumber = call?.from || "Unknown";

    console.log(`Incoming WhatsApp call from ${callerName} (${callerNumber})`);
    io.emit(`whatsapp_calling_incoming_request_${tenant_id}`, {
      callId,
      callerName,
      callerNumber,
      chat_user: contactDetails,
    });

    setActiveCalls({
      callId,
      value: {
        whatsappOfferSdp: receivedSdp,
        phone_number_id: WHATSAPP_BUSINESS_ACCOUNT_ID,
      },
    });

    await initiateWebRTCBridge({ callId });
  } catch (error) {
    if (db) db.destroy();
    console.error("Error handling call request:", getAxiosError(error));
  }
};

async function initiateWebRTCBridge({ callId }) {
  try {
    const { getIO } = require("../../../../../sockets");
    let io = getIO();
    let browserOfferSdp = activeCalls[callId]?.browserOfferSdp;
    let whatsappOfferSdp = activeCalls[callId]?.whatsappOfferSdp;
    let browserSocket = io;
    let whatsappPc = activeCalls[callId]?.whatsappPc;
    if (!browserOfferSdp || !whatsappOfferSdp || !browserSocket) return;

    // --- Setup browser peer connection ---
    activeCalls[callId].browserPc = new RTCPeerConnection({
      iceServers: STUN_SERVERS,
    });
    activeCalls[callId].browserStream = new MediaStream();

    activeCalls[callId].browserPc.ontrack = (event) => {
      console.log("Audio track received from browser.");
      event.streams[0]
        .getTracks()
        .forEach((track) => activeCalls[callId].browserStream.addTrack(track));
    };

    activeCalls[callId].browserPc.onicecandidate = (event) => {
      if (event.candidate) {
        browserSocket.emit("whatsapp-calling-browser-candidate", {
          candidate: event.candidate,
          callId,
        });
      }
    };

    try {
      sdpTransform.parse(sanitizeSdp(browserOfferSdp)); // pinpoints the bad line
    } catch (e) {
      console.error("Bad SDP from browser:", e);
    }

    const cleanSdp = sanitizeSdp(browserOfferSdp);

    await activeCalls[callId].browserPc.setRemoteDescription(
      new RTCSessionDescription(cleanSdp, "offer")
    );
    console.log("Browser offer SDP set as remote description.");

    // --- Setup WhatsApp peer connection ---
    whatsappPc = new RTCPeerConnection({ iceServers: STUN_SERVERS });

    const waTrackPromise = new Promise((resolve, reject) => {
      const timeout = setTimeout(
        () => reject("Timed out waiting for WhatsApp track"),
        10000
      );
      whatsappPc.ontrack = (event) => {
        clearTimeout(timeout);
        console.log("Audio track received from WhatsApp.");
        whatsappStream = event.streams[0];
        resolve();
      };

      whatsappPc.onicecandidate = (e) => {
        console.log(
          "[WA-PC] cand:",
          e.candidate?.candidate || "end-of-candidates"
        );
      };
      whatsappPc.oniceconnectionstatechange = () => {
        console.log("[WA-PC] ice:", whatsappPc.iceConnectionState);
      };
    });

    await whatsappPc.setRemoteDescription(
      new RTCSessionDescription(whatsappOfferSdp, "offer")
    );
    console.log("WhatsApp offer SDP set as remote description.");

    // Forward browser mic to WhatsApp
    activeCalls[callId].browserStream?.getAudioTracks().forEach((track) => {
      console.log(track, "<<<<<<<<<<<<<<<< sending track to whatsapp");
      whatsappPc.addTrack(track, activeCalls[callId].browserStream);
    });
    console.log("Forwarded browser audio to WhatsApp.");

    // Wait for WhatsApp to send audio
    await waTrackPromise;

    // Forward WhatsApp audio to browser
    whatsappStream?.getAudioTracks().forEach((track) => {
      console.log(track, "<<<<<<<<<<<<<<<< sending track to browser");
      activeCalls[callId].browserPc.addTrack(track, whatsappStream);
    });

    // --- Create SDP answers for both peers ---
    const browserAnswer = await activeCalls[callId].browserPc.createAnswer();
    await activeCalls[callId].browserPc.setLocalDescription(browserAnswer);
    browserSocket.emit("whatsapp-calling-browser-answer", {
      sdp: browserAnswer.sdp,
      callId,
    });
    console.log("Browser answer SDP created and sent.");

    const waAnswer = await whatsappPc.createAnswer();
    await whatsappPc.setLocalDescription(waAnswer);
    const finalWaSdp = waAnswer.sdp.replace(
      "a=setup:actpass",
      "a=setup:active"
    );
    console.log("WhatsApp answer SDP prepared.");

    // Send pre-accept, and only proceed with accept if successful
    const preAcceptSuccess = await answerCallToWhatsApp(
      callId,
      finalWaSdp,
      "pre_accept",
      activeCalls?.[callId]?.phone_number_id
    );

    if (preAcceptSuccess) {
      await Promise.race([
        new Promise((r) => {
          const h = () => {
            if (
              ["connected", "completed"].includes(whatsappPc.iceConnectionState)
            ) {
              whatsappPc.removeEventListener("iceconnectionstatechange", h);
              r(true);
            }
          };
          whatsappPc.addEventListener("iceconnectionstatechange", h);
        }),
        waitForOutboundAudio(whatsappPc, 12000),
        new Promise((r) => setTimeout(r, 12000)),
      ]);

      setTimeout(async () => {
        const acceptSuccess = await answerCallToWhatsApp(
          callId,
          finalWaSdp,
          "accept",
          activeCalls?.[callId]?.phone_number_id
        );
        if (acceptSuccess && browserSocket) {
          browserSocket.emit("start-browser-timer");
        }
      }, 10);
    } else {
      console.error("Pre-accept failed. Aborting accept step.");
    }

    // Reset session state
    browserOfferSdp = null;
    whatsappOfferSdp = null;
  } catch (error) {
    console.error("Error initiating WebRTC bridge:", getAxiosError(error));
  }
}


async function waitForOutboundAudio(pc, ms = 12000) {
  const start = Date.now();
  while (Date.now() - start < ms) {
    const stats = await pc.getStats();
    for (const r of stats.values()) {
      if (
        r.type === "outbound-rtp" &&
        r.kind === "audio" &&
        (r.packetsSent || r.bytesSent)
      )
        return true;
    }
    await new Promise((r) => setTimeout(r, 300));
  }
  return false;
}

Following are the logs from live server

Incoming WhatsApp call from 9180975xxxxx (9180975xxxxx)
Received SDP offer from browser.
Audio track received from browser.
Browser offer SDP set as remote description.
Audio track received from WhatsApp.
WhatsApp offer SDP set as remote description.
MediaStreamTrack {
 _events: [Object: null prototype] {},
 _eventsCount: 0,
 _maxListeners: undefined,
 addEventListener: [Function: value],
 removeEventListener: [Function: value],
 uuid: 'c156af26-535c-492d-a2b1-75bcf2859547',
 streamId: '50ae6e2f-314a-45f4-9fd1-2b8ce773f552',
 remote: true,
 label: 'remote audio',
 kind: 'audio',
 id: 'c0e95fa9-f787-48a3-a31e-8e5f1a26beea',
 ssrc: 77909064,
 rid: undefined,
 header: undefined,
 codec: RTCRtpCodecParameters {
  payloadType: 111,
  mimeType: 'audio/opus',
  clockRate: 48000,
  channels: 2,
  rtcpFeedback: [ [RTCRtcpFeedback] ],
  parameters: 'minptime=10;useinbandfec=1',
  direction: 'all'
 },
 enabled: true,
 onReceiveRtp: Event {
  event: { stack: [Array], promiseStack: [], eventId: 1 },
  ended: false,
  onended: undefined,
  onerror: [Function: value],
  execute: [Function: value],
  complete: [Function: value],
  error: [Function: value],
  allUnsubscribe: [Function: value],
  subscribe: [Function: value],
  queuingSubscribe: [Function: value],
  once: [Function: value],
  watch: [Function: value],
  asPromise: [Function: value]
 },
 onReceiveRtcp: Event {
  event: { stack: [], promiseStack: [], eventId: 0 },
  ended: false,
  onended: undefined,
  onerror: [Function: value],
  execute: [Function: value],
  complete: [Function: value],
  error: [Function: value],
  allUnsubscribe: [Function: value],
  subscribe: [Function: value],
  queuingSubscribe: [Function: value],
  once: [Function: value],
  watch: [Function: value],
  asPromise: [Function: value]
 },
 onSourceChanged: Event {
  event: { stack: [], promiseStack: [], eventId: 0 },
  ended: false,
  onended: undefined,
  onerror: [Function: value],
  execute: [Function: value],
  complete: [Function: value],
  error: [Function: value],
  allUnsubscribe: [Function: value],
  subscribe: [Function: value],
  queuingSubscribe: [Function: value],
  once: [Function: value],
  watch: [Function: value],
  asPromise: [Function: value]
 },
 stopped: false,
 muted: true,
 stop: [Function: value],
 writeRtp: [Function: value],
 Symbol(shapeMode): false,
 Symbol(kCapture): false
} <<<<<<<<<<<<<<<< sending track to whatsapp
Forwarded browser audio to WhatsApp.
MediaStreamTrack {
 _events: [Object: null prototype] {},
 _eventsCount: 0,
 _maxListeners: undefined,
 addEventListener: [Function: value],
 removeEventListener: [Function: value],
 uuid: '58d00710-efb0-46d8-826c-2d6bdc94e0e2',
 streamId: undefined,
 remote: true,
 label: 'remote audio',
 kind: 'audio',
 id: '23ce1f0e-c369-41c0-8086-bdc092f1daa6',
 ssrc: 2795528785,
 rid: undefined,
 header: undefined,
 codec: RTCRtpCodecParameters {
  payloadType: 111,
  mimeType: 'audio/opus',
  clockRate: 48000,
  channels: 2,
  rtcpFeedback: [ [RTCRtcpFeedback] ],
  parameters: 'maxaveragebitrate=20000;maxplaybackrate=16000;minptime=20;sprop-maxcapturerate=16000;useinbandfec=1',
  direction: 'all'
 },
 enabled: true,
 onReceiveRtp: Event {
  event: { stack: [Array], promiseStack: [], eventId: 1 },
  ended: false,
  onended: undefined,
  onerror: [Function: value],
  execute: [Function: value],
  complete: [Function: value],
  error: [Function: value],
  allUnsubscribe: [Function: value],
  subscribe: [Function: value],
  queuingSubscribe: [Function: value],
  once: [Function: value],
  watch: [Function: value],
  asPromise: [Function: value]
 },
 onReceiveRtcp: Event {
  event: { stack: [], promiseStack: [], eventId: 0 },
  ended: false,
  onended: undefined,
  onerror: [Function: value],
  execute: [Function: value],
  complete: [Function: value],
  error: [Function: value],
  allUnsubscribe: [Function: value],
  subscribe: [Function: value],
  queuingSubscribe: [Function: value],
  once: [Function: value],
  watch: [Function: value],
  asPromise: [Function: value]
 },
 onSourceChanged: Event {
  event: { stack: [], promiseStack: [], eventId: 0 },
  ended: false,
  onended: undefined,
  onerror: [Function: value],
  execute: [Function: value],
  complete: [Function: value],
  error: [Function: value],
  allUnsubscribe: [Function: value],
  subscribe: [Function: value],
  queuingSubscribe: [Function: value],
  once: [Function: value],
  watch: [Function: value],
  asPromise: [Function: value]
 },
 stopped: false,
 muted: true,
 stop: [Function: value],
 writeRtp: [Function: value],
 Symbol(shapeMode): false,
 Symbol(kCapture): false
} <<<<<<<<<<<<<<<< sending track to browser
Received browser-candidate from browser. {
 candidate: 'candidate:1995127518 1 udp 2122260223 192.168.1.17 62065 typ host generation 0 ufrag PKLr network-id 1 network-cost 10',
 sdpMid: '0',
 sdpMLineIndex: 0,
 usernameFragment: 'PKLr'
} wacid.HBgMOTE4MDk3NTM0Njg0FQIAEhggOUU2RUM3QzM0NkQzQ0ZGRjZBNzk1NEE5NDY4OUVCOUYcGAw5MTkxNjk5NTk5NTkVAgAVAgA=
Received browser-candidate from browser. {
 candidate: 'candidate:884647390 1 udp 41885695 172.237.33.131 41118 typ relay raddr 116.72.105.227 rport 62065 generation 0 ufrag PKLr network-id 1 network-cost 10',
 sdpMid: '0',
 sdpMLineIndex: 0,
 usernameFragment: 'PKLr'
} wacid.HBgMOTE4MDk3NTM0Njg0FQIAEhggOUU2RUM3QzM0NkQzQ0ZGRjZBNzk1NEE5NDY4OUVCOUYcGAw5MTkxNjk5NTk5NTkVAgAVAgA=
Received browser-candidate from browser. {
 candidate: 'candidate:136632390 1 tcp 1518280447 192.168.1.17 9 typ host tcptype active generation 0 ufrag PKLr network-id 1 network-cost 10',
 sdpMid: '0',
 sdpMLineIndex: 0,
 usernameFragment: 'PKLr'
} wacid.HBgMOTE4MDk3NTM0Njg0FQIAEhggOUU2RUM3QzM0NkQzQ0ZGRjZBNzk1NEE5NDY4OUVCOUYcGAw5MTkxNjk5NTk5NTkVAgAVAgA=
Browser answer SDP created and sent.
Received browser-candidate from browser. {
 candidate: 'candidate:907102327 1 udp 1686052607 116.72.105.227 62065 typ srflx raddr 192.168.1.17 rport 62065 generation 0 ufrag PKLr network-id 1 network-cost 10',
 sdpMid: '0',
 sdpMLineIndex: 0,
 usernameFragment: 'PKLr'
} wacid.HBgMOTE4MDk3NTM0Njg0FQIAEhggOUU2RUM3QzM0NkQzQ0ZGRjZBNzk1NEE5NDY4OUVCOUYcGAw5MTkxNjk5NTk5NTkVAgAVAgA=
WhatsApp answer SDP prepared.
WhatsApp API Pre-accept Request Payload: {
 url: 'https://graph.facebook.com/v21.0/115017851530658/calls',
 method: 'POST',
 data: {
  messaging_product: 'whatsapp',
  call_id: 'wacid.HBgMOTE4MDk3NTM0Njg0FQIAEhggOUU2RUM3QzM0NkQzQ0ZGRjZBNzk1NEE5NDY4OUVCOUYcGAw5MTkxNjk5NTk5NTkVAgAVAgA=',
  action: 'pre_accept',
  session: {
   sdp_type: 'answer',
   sdp: 'v=0rn' +
    'o=- 59754882 0 IN IP4 0.0.0.0rn' +
    's=-rn' +
    't=0 0rn' +
    'a=group:BUNDLE audiorn' +
    'a=extmap-allow-mixedrn' +
    'a=msid-semantic:WMS *rn' +
    'm=audio 9 UDP/TLS/RTP/SAVPF 111rn' +
    'c=IN IP4 0.0.0.0rn' +
    'a=ice-ufrag:1ba9rn' +
    'a=ice-pwd:1b204f1058a8ccc5068917rn' +
    'a=ice-options:tricklern' +
    'a=fingerprint:sha-256 18:21:C7:E5:37:E6:AE:D3:DE:C5:DE:08:55:9D:13:CE:F8:46:AE:0F:54:18:84:00:A6:5C:60:FE:DE:C1:8D:A6rn' +
    'a=setup:activern' +
    'a=sendrecvrn' +
    'a=mid:audiorn' +
    'a=msid:7e5d7d63-467d-4bd2-b41c-8d08d08b1220 23ce1f0e-c369-41c0-8086-bdc092f1daa6rn' +
    'a=rtcp:9 IN IP4 0.0.0.0rn' +
    'a=rtcp-muxrn' +
    'a=ssrc:4129580503 cname:c6837d9e-0285-4fb2-81ac-f684d95751a9rn' +
    'a=rtpmap:111 opus/48000/2rn' +
    'a=rtcp-fb:111 transport-ccrn' +
    'a=fmtp:111 maxaveragebitrate=20000;maxplaybackrate=16000;minptime=20;sprop-maxcapturerate=16000;useinbandfec=1rn'
  }
 }
}
Pre-accept API Response: { messaging_product: 'whatsapp', success: true }
WhatsApp API Pre-accept Request Payload: {
 url: 'https://graph.facebook.com/v21.0/115017851530658/calls',
 method: 'POST',
 data: {
  messaging_product: 'whatsapp',
  call_id: 'wacid.HBgMOTE4MDk3NTM0Njg0FQIAEhggOUU2RUM3QzM0NkQzQ0ZGRjZBNzk1NEE5NDY4OUVCOUYcGAw5MTkxNjk5NTk5NTkVAgAVAgA=',
  action: 'accept',
  session: {
   sdp_type: 'answer',
   sdp: 'v=0rn' +
    'o=- 59754882 0 IN IP4 0.0.0.0rn' +
    's=-rn' +
    't=0 0rn' +
    'a=group:BUNDLE audiorn' +
    'a=extmap-allow-mixedrn' +
    'a=msid-semantic:WMS *rn' +
    'm=audio 9 UDP/TLS/RTP/SAVPF 111rn' +
    'c=IN IP4 0.0.0.0rn' +
    'a=ice-ufrag:1ba9rn' +
    'a=ice-pwd:1b204f1058a8ccc5068917rn' +
    'a=ice-options:tricklern' +
    'a=fingerprint:sha-256 18:21:C7:E5:37:E6:AE:D3:DE:C5:DE:08:55:9D:13:CE:F8:46:AE:0F:54:18:84:00:A6:5C:60:FE:DE:C1:8D:A6rn' +
    'a=setup:activern' +
    'a=sendrecvrn' +
    'a=mid:audiorn' +
    'a=msid:7e5d7d63-467d-4bd2-b41c-8d08d08b1220 23ce1f0e-c369-41c0-8086-bdc092f1daa6rn' +
    'a=rtcp:9 IN IP4 0.0.0.0rn' +
    'a=rtcp-muxrn' +
    'a=ssrc:4129580503 cname:c6837d9e-0285-4fb2-81ac-f684d95751a9rn' +
    'a=rtpmap:111 opus/48000/2rn' +
    'a=rtcp-fb:111 transport-ccrn' +
    'a=fmtp:111 maxaveragebitrate=20000;maxplaybackrate=16000;minptime=20;sprop-maxcapturerate=16000;useinbandfec=1rn'
  }
 }
}
Pre-accept API Response: { messaging_product: 'whatsapp', success: true }

Following are the logs i’m getting on local

Incoming WhatsApp call from 91809xxxxxxx (91809xxxxxxx)
Received SDP offer from browser.
Audio track received from browser.
Browser offer SDP set as remote description.
Audio track received from WhatsApp.
WhatsApp offer SDP set as remote description.
MediaStreamTrack {
 _events: [Object: null prototype] {},
 _eventsCount: 0,
 _maxListeners: undefined,
 addEventListener: [Function: value],
 removeEventListener: [Function: value],
 uuid: 'c156af26-535c-492d-a2b1-75bcf2859547',
 streamId: '50ae6e2f-314a-45f4-9fd1-2b8ce773f552',
 remote: true,
 label: 'remote audio',
 kind: 'audio',
 id: 'c0e95fa9-f787-48a3-a31e-8e5f1a26beea',
 ssrc: 77909064,
 rid: undefined,
 header: undefined,
 codec: RTCRtpCodecParameters {
  payloadType: 111,
  mimeType: 'audio/opus',
  clockRate: 48000,
  channels: 2,
  rtcpFeedback: [ [RTCRtcpFeedback] ],
  parameters: 'minptime=10;useinbandfec=1',
  direction: 'all'
 },
 enabled: true,
 onReceiveRtp: Event {
  event: { stack: [Array], promiseStack: [], eventId: 1 },
  ended: false,
  onended: undefined,
  onerror: [Function: value],
  execute: [Function: value],
  complete: [Function: value],
  error: [Function: value],
  allUnsubscribe: [Function: value],
  subscribe: [Function: value],
  queuingSubscribe: [Function: value],
  once: [Function: value],
  watch: [Function: value],
  asPromise: [Function: value]
 },
 onReceiveRtcp: Event {
  event: { stack: [], promiseStack: [], eventId: 0 },
  ended: false,
  onended: undefined,
  onerror: [Function: value],
  execute: [Function: value],
  complete: [Function: value],
  error: [Function: value],
  allUnsubscribe: [Function: value],
  subscribe: [Function: value],
  queuingSubscribe: [Function: value],
  once: [Function: value],
  watch: [Function: value],
  asPromise: [Function: value]
 },
 onSourceChanged: Event {
  event: { stack: [], promiseStack: [], eventId: 0 },
  ended: false,
  onended: undefined,
  onerror: [Function: value],
  execute: [Function: value],
  complete: [Function: value],
  error: [Function: value],
  allUnsubscribe: [Function: value],
  subscribe: [Function: value],
  queuingSubscribe: [Function: value],
  once: [Function: value],
  watch: [Function: value],
  asPromise: [Function: value]
 },
 stopped: false,
 muted: true,
 stop: [Function: value],
 writeRtp: [Function: value],
 Symbol(shapeMode): false,
 Symbol(kCapture): false
} <<<<<<<<<<<<<<<< sending track to whatsapp
Forwarded browser audio to WhatsApp.
MediaStreamTrack {
 _events: [Object: null prototype] {},
 _eventsCount: 0,
 _maxListeners: undefined,
 addEventListener: [Function: value],
 removeEventListener: [Function: value],
 uuid: '58d00710-efb0-46d8-826c-2d6bdc94e0e2',
 streamId: undefined,
 remote: true,
 label: 'remote audio',
 kind: 'audio',
 id: '23ce1f0e-c369-41c0-8086-bdc092f1daa6',
 ssrc: 2795528785,
 rid: undefined,
 header: undefined,
 codec: RTCRtpCodecParameters {
  payloadType: 111,
  mimeType: 'audio/opus',
  clockRate: 48000,
  channels: 2,
  rtcpFeedback: [ [RTCRtcpFeedback] ],
  parameters: 'maxaveragebitrate=20000;maxplaybackrate=16000;minptime=20;sprop-maxcapturerate=16000;useinbandfec=1',
  direction: 'all'
 },
 enabled: true,
 onReceiveRtp: Event {
  event: { stack: [Array], promiseStack: [], eventId: 1 },
  ended: false,
  onended: undefined,
  onerror: [Function: value],
  execute: [Function: value],
  complete: [Function: value],
  error: [Function: value],
  allUnsubscribe: [Function: value],
  subscribe: [Function: value],
  queuingSubscribe: [Function: value],
  once: [Function: value],
  watch: [Function: value],
  asPromise: [Function: value]
 },
 onReceiveRtcp: Event {
  event: { stack: [], promiseStack: [], eventId: 0 },
  ended: false,
  onended: undefined,
  onerror: [Function: value],
  execute: [Function: value],
  complete: [Function: value],
  error: [Function: value],
  allUnsubscribe: [Function: value],
  subscribe: [Function: value],
  queuingSubscribe: [Function: value],
  once: [Function: value],
  watch: [Function: value],
  asPromise: [Function: value]
 },
 onSourceChanged: Event {
  event: { stack: [], promiseStack: [], eventId: 0 },
  ended: false,
  onended: undefined,
  onerror: [Function: value],
  execute: [Function: value],
  complete: [Function: value],
  error: [Function: value],
  allUnsubscribe: [Function: value],
  subscribe: [Function: value],
  queuingSubscribe: [Function: value],
  once: [Function: value],
  watch: [Function: value],
  asPromise: [Function: value]
 },
 stopped: false,
 muted: true,
 stop: [Function: value],
 writeRtp: [Function: value],
 Symbol(shapeMode): false,
 Symbol(kCapture): false
} <<<<<<<<<<<<<<<< sending track to browser
Received browser-candidate from browser. {
 candidate: 'candidate:1995127518 1 udp 2122260223 192.168.1.17 62065 typ host generation 0 ufrag PKLr network-id 1 network-cost 10',
 sdpMid: '0',
 sdpMLineIndex: 0,
 usernameFragment: 'PKLr'
} wacid.HBgMOTE4MDk3NTM0Njg0FQIAEhggOUU2RUM3QzM0NkQzQ0ZGRjZBNzk1NEE5NDY4OUVCOUYcGAw5MTkxNjk5NTk5NTkVAgAVAgA=
Received browser-candidate from browser. {
 candidate: 'candidate:884647390 1 udp 41885695 172.237.33.131 41118 typ relay raddr 116.72.105.227 rport 62065 generation 0 ufrag PKLr network-id 1 network-cost 10',
 sdpMid: '0',
 sdpMLineIndex: 0,
 usernameFragment: 'PKLr'
} wacid.HBgMOTE4MDk3NTM0Njg0FQIAEhggOUU2RUM3QzM0NkQzQ0ZGRjZBNzk1NEE5NDY4OUVCOUYcGAw5MTkxNjk5NTk5NTkVAgAVAgA=
Received browser-candidate from browser. {
 candidate: 'candidate:136632390 1 tcp 1518280447 192.168.1.17 9 typ host tcptype active generation 0 ufrag PKLr network-id 1 network-cost 10',
 sdpMid: '0',
 sdpMLineIndex: 0,
 usernameFragment: 'PKLr'
} wacid.HBgMOTE4MDk3NTM0Njg0FQIAEhggOUU2RUM3QzM0NkQzQ0ZGRjZBNzk1NEE5NDY4OUVCOUYcGAw5MTkxNjk5NTk5NTkVAgAVAgA=
Browser answer SDP created and sent.
Received browser-candidate from browser. {
 candidate: 'candidate:907102327 1 udp 1686052607 116.72.105.227 62065 typ srflx raddr 192.168.1.17 rport 62065 generation 0 ufrag PKLr network-id 1 network-cost 10',
 sdpMid: '0',
 sdpMLineIndex: 0,
 usernameFragment: 'PKLr'
} wacid.HBgMOTE4MDk3NTM0Njg0FQIAEhggOUU2RUM3QzM0NkQzQ0ZGRjZBNzk1NEE5NDY4OUVCOUYcGAw5MTkxNjk5NTk5NTkVAgAVAgA=
WhatsApp answer SDP prepared.
WhatsApp API Pre-accept Request Payload: {
 url: 'https://graph.facebook.com/v21.0/115017851530658/calls',
 method: 'POST',
 data: {
  messaging_product: 'whatsapp',
  call_id: 'wacid.HBgMOTE4MDk3NTM0Njg0FQIAEhggOUU2RUM3QzM0NkQzQ0ZGRjZBNzk1NEE5NDY4OUVCOUYcGAw5MTkxNjk5NTk5NTkVAgAVAgA=',
  action: 'pre_accept',
  session: {
   sdp_type: 'answer',
   sdp: 'v=0rn' +
    'o=- 59754882 0 IN IP4 0.0.0.0rn' +
    's=-rn' +
    't=0 0rn' +
    'a=group:BUNDLE audiorn' +
    'a=extmap-allow-mixedrn' +
    'a=msid-semantic:WMS *rn' +
    'm=audio 9 UDP/TLS/RTP/SAVPF 111rn' +
    'c=IN IP4 0.0.0.0rn' +
    'a=ice-ufrag:1ba9rn' +
    'a=ice-pwd:1b204f1058a8ccc5068917rn' +
    'a=ice-options:tricklern' +
    'a=fingerprint:sha-256 18:21:C7:E5:37:E6:AE:D3:DE:C5:DE:08:55:9D:13:CE:F8:46:AE:0F:54:18:84:00:A6:5C:60:FE:DE:C1:8D:A6rn' +
    'a=setup:activern' +
    'a=sendrecvrn' +
    'a=mid:audiorn' +
    'a=msid:7e5d7d63-467d-4bd2-b41c-8d08d08b1220 23ce1f0e-c369-41c0-8086-bdc092f1daa6rn' +
    'a=rtcp:9 IN IP4 0.0.0.0rn' +
    'a=rtcp-muxrn' +
    'a=ssrc:4129580503 cname:c6837d9e-0285-4fb2-81ac-f684d95751a9rn' +
    'a=rtpmap:111 opus/48000/2rn' +
    'a=rtcp-fb:111 transport-ccrn' +
    'a=fmtp:111 maxaveragebitrate=20000;maxplaybackrate=16000;minptime=20;sprop-maxcapturerate=16000;useinbandfec=1rn'
  }
 }
}
Pre-accept API Response: { messaging_product: 'whatsapp', success: true }
WhatsApp API Pre-accept Request Payload: {
 url: 'https://graph.facebook.com/v21.0/115017851530658/calls',
 method: 'POST',
 data: {
  messaging_product: 'whatsapp',
  call_id: 'wacid.HBgMOTE4MDk3NTM0Njg0FQIAEhggOUU2RUM3QzM0NkQzQ0ZGRjZBNzk1NEE5NDY4OUVCOUYcGAw5MTkxNjk5NTk5NTkVAgAVAgA=',
  action: 'accept',
  session: {
   sdp_type: 'answer',
   sdp: 'v=0rn' +
    'o=- 59754882 0 IN IP4 0.0.0.0rn' +
    's=-rn' +
    't=0 0rn' +
    'a=group:BUNDLE audiorn' +
    'a=extmap-allow-mixedrn' +
    'a=msid-semantic:WMS *rn' +
    'm=audio 9 UDP/TLS/RTP/SAVPF 111rn' +
    'c=IN IP4 0.0.0.0rn' +
    'a=ice-ufrag:1ba9rn' +
    'a=ice-pwd:1b204f1058a8ccc5068917rn' +
    'a=ice-options:tricklern' +
    'a=fingerprint:sha-256 18:21:C7:E5:37:E6:AE:D3:DE:C5:DE:08:55:9D:13:CE:F8:46:AE:0F:54:18:84:00:A6:5C:60:FE:DE:C1:8D:A6rn' +
    'a=setup:activern' +
    'a=sendrecvrn' +
    'a=mid:audiorn' +
    'a=msid:7e5d7d63-467d-4bd2-b41c-8d08d08b1220 23ce1f0e-c369-41c0-8086-bdc092f1daa6rn' +
    'a=rtcp:9 IN IP4 0.0.0.0rn' +
    'a=rtcp-muxrn' +
    'a=ssrc:4129580503 cname:c6837d9e-0285-4fb2-81ac-f684d95751a9rn' +
    'a=rtpmap:111 opus/48000/2rn' +
    'a=rtcp-fb:111 transport-ccrn' +
    'a=fmtp:111 maxaveragebitrate=20000;maxplaybackrate=16000;minptime=20;sprop-maxcapturerate=16000;useinbandfec=1rn'
  }
 }
}
Pre-accept API Response: { messaging_product: 'whatsapp', success: true }

How can I make my Ajax add_to_cart work in nested async function

I have out of stock products for which customer can place a preorder. Initialy I am doing this by creating a duplicate product through ajax request by sending product id. Then i am adding this duplicate product (using its id) after response is received by changing add_to_cart button href (the old way). This works correctly. However I wanted to add a notification that shows after checking if the product is in the cart. Could not do that using this method as page reloads in this case. Here is the first working method:

        if(e.target.closest("button[name='pre-order-confirmation-btn']")){
            e.preventDefault()
            e.target.setAttribute('disabled', '')
            const notif_wrapper_in_use = document.querySelector('.stock-notif- wrapper.in-use')
            let btn_clicked = e.target.closest("button[name='pre-order-confirmation-btn']")
            let value = btn_clicked.value
            let a_add_to_cart = notif_wrapper_in_use.querySelector(`a[data-type = ${value}]`)
            let product_id = btn_clicked.dataset.productId
            send_request_create_preorder_product(make_duplicate_preorder_object.ajax_url,'post', product_id, a_add_to_cart, btn_clicked )       
        }

async function send_request_create_preorder_product(url, post, product_id, add_to_cart_btn, btn_clicked){
    let formData = new FormData()
    formData.append('action','send_product_id_for_preorder');
    formData.append('product_id', product_id);
    const options = {
        method : post,
        body : formData
    }
    const response = await fetch(url, options)
    const result = await response.text()
    console.log(result)
    add_to_cart_btn.href = `?add-to-cart=${result}`
    add_to_cart_btn.classList.remove('hide')
    btn_clicked.style.display = 'none'

    /* Here I wanted to add the notification if product is indeed added to cart*/

    if(document.body.classList.contains('home') /*and product in cart*/){
        
/*show successful notification*/
    }

/* ajax function using using hooks wp_ajax and wp_ajax_nopriv*/

function ajax_create_duplicate_product_preorder(){
    if(isset($_POST['action']) && $_POST['action'] === 'send_product_id_for_preorder'){
        $original_product_id = $_POST['product_id'];
        $duplicate_product_id = add_notif_duplicate_wc_product($original_product_id);
        echo $duplicate_product_id;

    }
    wp_die();
}

function add_notif_duplicate_wc_product($product_id){
    $original_product = wc_get_product($product_id);
    if(!$original_product){
        return new WP_Error('invalid_product', 'Invalid product ID.');
    }
    $duplicate_product = new WC_Product_Simple();
    $duplicate_product->set_name($original_product->get_name().'-precommande');
    $duplicate_product->set_status('publish');
    $duplicate_product->set_description($original_product->get_description());
    $duplicate_product->set_short_description($original_product->get_short_description());
    $duplicate_product->set_price($original_product->get_price());
    $duplicate_product->set_regular_price($original_product->get_regular_price());
    $duplicate_product->set_sale_price($original_product->get_sale_price());
    $duplicate_product->set_catalog_visibility('hidden');
    $duplicate_product->set_manage_stock(false);
    $duplicate_product->set_stock_status('instock');
    $duplicate_product->set_virtual(true);
    $duplicate_product_id = $duplicate_product->save();
    $duplicate_product->set_name($duplicate_product->get_name() . '-' . $duplicate_product_id);
    $duplicate_product->save();
    wp_set_object_terms($duplicate_product_id,'preorders', 'product_cat', false);
    $thumbnail_id = get_post_thumbnail_id($product_id);
    if($thumbnail_id){
        set_post_thumbnail($duplicate_product_id, $thumbnail_id);
    }
    // echo $duplicate_product_id;
    return $duplicate_product_id;
}

so as an alternative I tried using this modified async function and woocommerce woocommerce_ajax_add_to_cart (I also removed the ‘post’ parameter in the above async function when called)

async function send_request_create_preorder_product(url, product_id, add_to_cart_btn, btn_clicked) {
    // Create the preorder product via AJAX
    const formData = new FormData();
    formData.append('action', 'send_product_id_for_preorder');
    formData.append('product_id', product_id);

    const response = await fetch(url, { method: 'POST', body: formData });
    const duplicateProductId = await response.text();
    console.log(duplicateProductId)

    if (!duplicateProductId) return;

    // Update the Add to Cart button
    add_to_cart_btn.dataset.productId = duplicateProductId; // store the new product ID
    add_to_cart_btn.classList.remove('hide');
    btn_clicked.style.display = 'none';

   // AJAX Add-to-Cart
    add_to_cart_btn.addEventListener('click', async (e) => {
        e.preventDefault(); // prevent page reload
        const addFormData = new FormData();
        addFormData.append('action', 'woocommerce_ajax_add_to_cart');
        addFormData.append('product_id', duplicateProductId);
        addFormData.append('quantity', 1);

        const addResponse = await fetch(url, { method: 'POST', body: addFormData });
        const addResult = await addResponse.json();
        console.log(addResult)
        if (addResult && addResult.added) {
            // Show notification
            let notifDiv = document.createElement('div');
            notifDiv.className = 'preorder-notif-div-homepage';
            notifDiv.textContent = 'Le produit précommandé a été ajouté au panier';
            document.body.appendChild(notifDiv);
        }
    }, { once: true });
}

The duplicate product_id is properly console logged but then I have a 400 (Bad Request) error on this line const addResponse = await fetch(url, { method: ‘POST’, body: addFormData });
I have been turning around to solve it for 2 days but did not find any working solution.

and this is the HTML form used

                    <div class='stock-notif-wrapper'>
                        <p><button type='button' name='show-add-notif-btn' data-notify-product-id='". $product->get_id(). "'>Pre-commander 24h</button></p>
                        <div class='stock-notif-form-wrapper'>
                            <div class='pre-order-questions-input'>
                                <label>
                                    <input type='radio' name='".$product->get_id()."-"."preorder-or-question[]' class='inputs radios' value='just-ask-date' checked>
                                    Voulez vous savoir quand le produit sera en stock?
                                </label>
                                <label> 
                                    <input type='radio' name='".$product->get_id()."-"."preorder-or-question[]' class='inputs radios' value='send-preorder'>
                                    Voulez-vous payer et pre commander directement?
                                </label>
                            </div>
                            <form action='' method='POST' data-type = 'just-ask-date'>
                                <div class='stock-notif-error-notif-div'></div>
                                <div id='recaptcha-container-". $product->get_id() ."'></div>
                                <div class='notify-inputs-wrapper'>
                                    <input type='email' name='stock-notif-email' class='inputs' placeholder='Email' required>
                                    <input type='tel' name='stock-notif-tel' class='inputs' placeholder='Mobile ex 22 222 222' required>
                                    <input type='hidden' name='notify_product_id' value='{$product->get_id()}'>
                                </div>
                                <div class='button-wrapper'>
                                    <button type='submit' name='stock-notif-submit-btn'>Envoyer</button>
                                    <button type='button' name='show-add-notif-shown-close-btn'>Fermer</button>
                                </div>
                                <div class='company_wrapper'>
                                    <div class='company-addition'>
                                        <input type='text' name='company-name'>
                                    </div>
                                </div>
                                <p class='info'>Vous recevrez un email ou SMS vous informant de la date de disponibilité sous 48h</p>
                            </form>
                            <div class='preorder-notif hide' data-type = 'send-preorder'>
                                <p class='pre-order-description-text'>Vous Allez payer la totalité du produit et nous vous enverrons votre code sous 24h par email si paiement en ligne ou sous 48h si paiement à la livraison</p>
                                <!--<form action='' metod='POST'>-->
                                <button name='pre-order-confirmation-btn' data-product-id ='".$product->get_id()."' value='pre-order-confirmation-add-to-cart'>Confirmer</button>
                                <!--</form>-->
                                <a href='". esc_url( "?add-to-cart=" . $product->get_id() ) . "' class='button' data-type='pre-order-confirmation-add-to-cart'>Pré-commander 24h</a>"."
                                <button type='button' name='show-add-notif-shown-close-btn'>Fermer</button>
                            </div>
                        </div>
                    </div>
                    ";

How externally fetched CSS can be used or it’s source code can be seen for more targeted use? [closed]

In my recent project I copied a CSS source link in my HTML source. Now, using just given class works in my project. But if we are able to read the code, then it we have some scope to fine tune as per our use. Now I have no idea how traditionally developers do ?

At this point I can only try to find out their documentations which I think is unnecessarily time consuming. Sometime it is difficult to find out documentation as well. My need is to look into the source if possible.

Error when importing HydratedRouter and RouterProvider from react-router/dom in TypeScript project

const router = createBrowserRouter([
  {
    path: "/",
    element: <Welcomepage />,
  },
  {
    path: "/signin",
    element: <Signin />,
  },
]);
C:UserschaitOneDriveDesktopdocument3_Coding4-Popxnode_modulesreact-router-domdistindex.mjs:13:48
12 | // index.ts
13 | import { HydratedRouter, RouterProvider } from "react-router/dom";
  >    |                                                ^^^^^^^^^^^^^^^^^^
14 | export * from "react-router";
15 | export {

@parcel/resolver-default: Cannot load file './dom' from module 'react-router'

I am working on a React project and trying to set up routing.
In my index.js file, I wrote:

import { createBrowserRouter, RouterProvider, Outlet } from "react-router";

But I am getting this error:

Error | // index.js > 13 | import { HydratedRouter, RouterProvider } from "react-router/dom";

I installed react-router-dom using:

npm install react-router-dom

function to match a input in array of JSON [closed]

looking for your help on JavaScript function where I want to pass 2 elements as input and expect a true or false as response back.

Scenario – I will be passing below 2 input in Javascript and need to check if value of variable varTaskID i.e. TaskID3 is matching with ExternalTaskId which is in JSON array structure.. if available return as true as simple say false. SO comparing varTaskID with ExternalTaskId element in complete array file.

Input Id – a variable as varTaskID which will have only 1 value like TaskID3
Input 2(A JSON structure where we have a repetitive structure)

{
  "items" :
  [
    {
      "ExternalParentTaskId" : "12345",
      "ExternalTaskId"       : "TaskID1"
    }, 
    {
      "ExternalParentTaskId" : "11111",
      "ExternalTaskId"       : "TaskID2"
    }, 
    {
      "ExternalParentTaskId" : "3456",
      "ExternalTaskId"       : "TaskID3"
    }, 
    {
      "ExternalParentTaskId" : "423423",
      "ExternalTaskId"       : "TaskID3"
    }, 
    {
      "ExternalParentTaskId" : "55666",
      "ExternalTaskId"       : "TaskID3"
    }
  ]
}