React handle multiple clicks on mobile at the same time

I am building telegram mini app, and there you can’t click on object with more than one finger, however i would like to make that possible.

I’m using last react with nextjs. Tailwindcss for styles.

Right now my setup look’s like this:

const handleClick = () => {
    console.log(e.detail);

    const card = e.currentTarget;
    const rect = card.getBoundingClientRect();
    const x = e.clientX - rect.left - rect.width / 2;
    const y = e.clientY - rect.top - rect.height / 2;

}

<div className="cursor-pointer" onClick={handleClick}></div>

For example when user tap’s with 2-3-4 finger’s at the same time and handle this tap’s.

When user moves mouse (on desktop) and still can click. (Don’t have to wait to stop moving)

Get info about coordinates of this click’s. (2-3-4 at the same time)

If you know how to do any of these – please share with me! Thanks!

I try to set up 'cursor-pointer', tried to handle e.detail.

Don’t know what to do.

Fresh NextJS project cannot hit root route, keep getting redirected to home

Pretty straight forward. Inside the app folder there is page.tsx with the default vercel stuff.

If it try and hit http://localhost:3000/ i get redirected to http://localhost:3000/home.

If i put a home folder in the app directory and put page.tsx inside it I cant see the page contents when i navigate to /home.

But even putting a new page.tsx inside app and accessing the root directory / I still get redirected to /home

Can’t add event listener to window error event in module

I have been trying to add an error handler to the window object in my module class and no matter what I’ve tried it doesn’t work. The same code works when it is on the HTML page but not in a module. This is from a module:

class MyModule {
   showErrorsInDialog() {
      var output = "";
      window.addEventListener('error', this.errorHandler);
      
      window.onerror = (message, url, lineNumber, columnNumber, error) => {
         !isNaN(lineNumber) ? output += "Line " + lineNumber + " " : null;
         !isNaN(columnNumber) ? output += "Column " + columnNumber + " " : null;
         output += message;
         url!=null ? output += " at " + url + " " : null;
         output += "n";
         console.log(output);
      }
   }

   errorHandler(event) {
      console.log("error event" + event)
   }
}

My page is slightly different but this might be the HTML. I haven’t used inline modules:

<script type="module">
var myModule = new MyModule();
</script>

Is there a reason I can’t add an event handler on the error object? Other events seem to work fine.

await the latest observable value

I’m completely new to rxjs and trying to accomplish one task – essentially I need a Promise-like API with the following differences:

  1. Unlike the standard Promise my API should be able to resolve multiple times.
  2. When calling await/then the last resolved value should be used.
  3. If my API was never resolved the await/then should hang, just like the standard Promise.
  4. Additionally I need a reset method which will be resetting my API object so the following await/then calls will hang like in the point 3.

How can I implement the needed behaviour? I think rxjs Observable and lastValueFrom is what I need, but I just can’t figure out how to use it.

Pseudocode example usage:

const myAuthObservable = new MyObservableApi<Auth>((resolve) =>
  subscribe(
    (s) => s.auth,
    (auth) => {
      if (auth) {
        resolve(auth); // this can be called multiple times
      }
    }
  )
);

emitter.on("start", async () => {
  // always the last auth will be returned
  // or the api will hang until the first auth is emitted
  const auth = await myAuthObservable;
  myAuthObservable.reset();
});

How do I go about making my popup element appear over the publications page, similar to how google scholar’s cite button popup works?

I was working on a publications page and wanted to have the bibtex be a popup, kind of like how google scholar’s cite button works (NOT their bibtex button which links to a new page).

The issue is that I can’t get the popup to overlay on top of the page. I’ve tried moving the popup out of the block, or out of the div element, even into a new file and then importing to Publications.js, but none of it works.

It is true that this moves around the popup (either above/below the p section or the entire main section) but it doesn’t make it get on top of everything else like the google scholars version does. I think perhaps this is due to how my container is defined? Also, I already tried things like adjusting the top, bottom, etc., and changing the z value.

Here is my code below, for the publications main section js and cs files, publications.js, popup.js and popup.css.

Google Scholars Popup

My popup

PublicationsMain.js

import React, {useState} from 'react';
import Popup from './pages/Popup';
import './PublicationsMain.css';

function PublicationsMain() {
  const [firstButtonPopup, setFirstButtonPopup]=useState(false);
  return (

<> <div className='publications-main-container'>
      <p className="firstp">random text[
            <button onClick={()=>setFirstButtonPopup(true)}>bibtex</button>] 
              <Popup trigger={firstButtonPopup} setTrigger={setFirstButtonPopup}>
              <h3>bibtex</h3>
              <p>Here is my bibtex</p>
              </Popup>
              </p>
    </div>
    </>
  );
}

export default PublicationsMain;

PublicationsMain.css

 :root {
    --font-size: 31px;
}

.publications-main-container {
    width: 100%;
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: center;
    object-fit: contain;
}


.publications-main-container > p {
    color: #fff;
    font-size: var(--font-size);
    font-family: 'Trebuchet MS', 'Lucida Sans Unicode', 
    'Lucida Grande', 'Lucida Sans', Arial, sans-serif;
    font-weight:bold;
    padding:3rem;
}

.publications-main-container > p.firstp {
    background-color: #2c3e50;
}

.publications-main-container > p.secondp {
    background-color: #2e557f;
}

.publications-main-container > p.thirdp {
    background-color: #2c3e50;
}

.publications-main-container > p.fourthp {
    background-color: #2e557f;
}

.publications-main-container > p > span {
    color: #fff;
    font-style: italic;
    font-family: 'Trebuchet MS', 'Lucida Sans Unicode', 
    'Lucida Grande', 'Lucida Sans', Arial, sans-serif;
}

.publications-main-container > p > a {
    color: #fff;
    font-family: 'Trebuchet MS', 'Lucida Sans Unicode', 
    'Lucida Grande', 'Lucida Sans', Arial, sans-serif;
}


.publications-main-container > p > button {
    background: none!important;
    border: none;
    padding: 0!important;
    font-size: var(--font-size);
    font-weight: bold;
    color: #fff;
    text-decoration: underline;
    font-family: 'Trebuchet MS', 'Lucida Sans Unicode', 
    'Lucida Grande', 'Lucida Sans', Arial, sans-serif;
    cursor: pointer;
}

Popup {
    position: fixed;
    bottom:0;
    top:0;
    left:0;
    right:0;
    width: 100%;
    height: 100vh;
    background-color: rgba(255, 0, 0, 0.2);
    display: flex;
    justify-content: center;
    align-items: center;
    z-index: 1000000000;
}



@media screen and (max-width: 1093px) {
    /* .publications-main-container > h1 {
        font-size: 80px;
    } */
}
@media screen and (max-width: 978px) {
    /* .publications-main-container > h1 {
        font-size: 60px;
    } */
    :root {
        --font-size: 27px;
    }
}

@media screen and (max-width: 784px) {
    /* .publications-main-container > h1 {
        font-size: 55px;
    } */

    :root {
        --font-size: 23px;
    }
}

@media screen and (max-width: 701px) {
    /* .publications-main-container > h1 {
        font-size: 47px;
    } */
}

Publications.js

import PublicationsHero from '../PublicationsHero';
import PublicationsMain from '../PublicationsMain';

function Publications() {
  return (
    <>
      <PublicationsHero />
      <PublicationsMain />
    </>
  );
}

export default Publications;

Popup.js

import React from 'react'
import './Popup.css';

function Popup(props) {
  return (props.trigger) ? (
    <div className="Popup">
        <div className="popup-inner">
            <button className="close-btn" onClick={()=>props.setTrigger(false)}>&#x2715; 
            &#x00d7; </button>
            {props.children}
        </div>
    </div>
  ) : "";
}

export default Popup;

Popup.css

.popup {
    position: fixed;
    top:0;
    left:0;
    width: 100%;
    height: 100vh;
    background-color: rgba(255, 0, 0, 0.2);
    display: flex;
    justify-content: center;
    align-items: center;
}

.popup-inner{
    position:relative;
    padding:32px;
    width:100%;
    max-width: 640px;
    background-color: #fff;
}

.popup-inner .close-btn {
    position: absolute;
    top:16px;
    right:16px;
}

Color gradiant beween red, white and green in javascript

I am trying to create a function like this:


function colorCell(current, min=-100, max=100) {
    current = Math.max(min, Math.min(current, max));

    return 'hsl(' + ((max + current) * 135 / (max - min)) + ", 100%, 50%)";
}

If current = 0, color should be white. If current is between 0 and min, color should move from light red to dark red. If color <= min, it should return same dark red.

Then it repeats the same thing between 0 and max but green color gradiant here.

Shopify GraphQL API – Is it possible to get all company orders over the last 30 days?

I’m looking into fetching all orders for a B2B company from the last 30 days.

After checking out the documentation for both B2B company and orders, I see that it’s not possible to use a query on a company order and it’s not possible to query for the company specifically when accessing orders directly.

My query currently looks like

  query GetCompanyOrders(
    $query: String
  ) {
      orders(first: 50, query: "created_at:>=2024-07-01 AND company_id:gid://shopify/Company/123456789") {
      nodes {
        id
        displayFulfillmentStatus
        name
        createdAt
        totalPriceSet {
          shopMoney {
            amount
            currencyCode
          }
        }
        lineItems(first: 100) {
          nodes {
            name
            id
            variant {
              sku
            }
            image {
              url
              width
              height
              altText
            }
          }
        }
        shippingAddress {
          formatted
        }
      }
    }
}

It would be great to see if anyone else has run into a similar issue.

Any help would be great. Thanks!

Intermittent undefined response in commercetools SDK v3 inventory API endpoint

I’m running into a strange bug where the res value expected inside an internal function in the commercetools v3 sdk is coming back as undefined. It happens roughly half the time when making a basic get call:

const existingItem = (await getApiRoot()).inventory().withKey({ key }).get().execute()

When successful, it returns the expected { body } response with all expected values present. But randomly the execution will fail instead with the error message "Cannot read property 'error' of undefined".
There’s no difference between the calls or the values being passed, this is executing the code locally using the exact same key every time and it’s a dice roll whether it comes back successfully or throws the error when running it multiple times in a row.

The same code using the (soon to be end-of-lifed) v2 API doesn’t seem to trigger this issue, it’s only after to moving to v3 that it started happening.

The error is throwing from this file within the SDK library node_modules@commercetoolsts-clientdistcommercetools-ts-client.cjs.dev.js at line 1461, this is the block of code. Somehow res is coming back as undefined in the then statement:

const dispatch = compose(middlewares)(resolver.resolve);
  return {
    process: process$1,
    execute(request) {
      validate('exec', request);
      return new Promise((resolve, reject) => {
        dispatch({
          reject,
          resolve,
          ...request
        }).then(res => {
          if (res.error) {
            reject(res.error);
          } else {
            resolve(res);
          }
        }).catch(reject);
      });
    }
  };

After adding error logging to that block of code:

 dispatch({
      reject,
      resolve,
      ...request
    }).then(res => {
      console.log('this was the request: ', request)
      console.log('this is the res: ', typeof res, res)
      if (res.error) {
        reject(res.error);
      } else {
        resolve(res);
      }
    }).catch(reject);

we receive these logs when the error happens (sensitive values removed from request object here):

[2024-08-01T14:48:32.211Z] this was the request:  {
[2024-08-01T14:48:32.214Z]   baseUri,
[2024-08-01T14:48:32.216Z]   method: 'GET',
[2024-08-01T14:48:32.218Z]   uriTemplate: '/{projectKey}/inventory/key={key}',
[2024-08-01T14:48:32.219Z]   pathVariables: { projectKey, key },
[2024-08-01T14:48:32.221Z]   headers: {},
[2024-08-01T14:48:32.222Z]   queryParams: undefined,
[2024-08-01T14:48:32.222Z]   uri
[2024-08-01T14:48:32.223Z] }
[2024-08-01T14:48:32.223Z] this is the res:  undefined undefined
[2024-08-01T14:48:32.224Z] an issue occurred
[2024-08-01T14:48:32.225Z] Problem getting existing item Cannot read properties of undefined (reading 'error')

Has anyone else seen these intermittent failures with their inventory API or any others? The payment API call made in the same codebase seems to work consistently, the only difference being that this one queries by .withKey({ key }) and the payment one uses .withId({ ID: paymentId})

How do I troubleshoot an Amazon Lambda Skill Smart Home Alexa voice request?

So a colleague made a Lambda in Node.js 12.x which allows you to read and write data with vocal requests to some devices that operate in MQTT and which connects to AWS services

He gave me the code, and I was forced to migrate from Node.js 12.x to Node.js 20.x
I updated the dependencies (actions-on-google, Alexa-SDK, Ask-SDK, AWS-SDK, JSONWEBTOKEN, JWK-TO- PEM, UUID) which caused some problems

I was able to correct the problems related to the discovery reading and writing of the MQTT devices, except when it’s done with vocal requests

When I make a vocal request for this product, Alexa says, “hum, I have no answer to that.”
Or sometimes there is just a noise from Alexa, and in the chat it is written “<Audio only Response>”

I tried to use console.log() to understand what’s going on, but I have no return in Amazon Cloudwatch

My Lambda function is based on this sample : sample

I used some advices from this documentation too : docs

I tried some of the solutions presented here : debug-your-smart-home-ckill (but I couldn’t find anything)

Do you know a way to precisely troubleshoot why Alexa answers “hum, I have no answer to that.” or “<Audio only Response>” ?

Thank you

Expericing visual glitches in an infinite looping animation with React and Framer Motion

I’m trying to create an infinite looping animation for a list of items using React and Framer Motion. The intended sequence is:

  1. Left column items move down, with the last item fading out.
  2. The top item from the right column moves to the top of the left column.
  3. Right column items move up to fill the space, and a new item fades in at the bottom.

The animation works, but I’m encountering visual glitches where items flash or momentarily appear in the wrong order during the loop which is affecting the smoothness of the animation.

Expected behavior: Continuous, smooth transitions between states without any flashing or incorrect ordering.

Actual behavior: Items occasionally flash or appear out of order between loops.

Code:

import React, { useEffect, useState } from "react";
import { motion, useAnimationControls } from "framer-motion";

const ITEMS_LIST = [
  "Item 1",
  "Item 2",
  "Item 3",
  "Item 4",
  "Item 5",
  "Item 6",
  "Item 7",
  "Item 8",
  "Item 9",
  "Item 10",
  "Item 11",
  "Item 12",
];

function getItemAt(index: number) {
  // Handle positive and negative indices with modulo
  const adjustedIndex =
    ((index % ITEMS_LIST.length) + ITEMS_LIST.length) % ITEMS_LIST.length;
  return ITEMS_LIST[adjustedIndex];
}

export default function App() {
  const [loopIndex, setLoopIndex] = useState<number>(0);

  const controlsLeftItem1 = useAnimationControls();
  const controlsLeftItem2 = useAnimationControls();
  const controlsLeftItem3 = useAnimationControls();
  const controlsLeftItem4 = useAnimationControls();

  const controlsRightItem1 = useAnimationControls();
  const controlsRightItem2 = useAnimationControls();
  const controlsRightItem3 = useAnimationControls();
  const controlsRightItem4 = useAnimationControls();
  const controlsRightItem5 = useAnimationControls();
  const controlsRightItem6 = useAnimationControls();
  const controlsRightItem7 = useAnimationControls();
  const controlsRightItem8 = useAnimationControls();

  const leftItem1 = getItemAt(loopIndex - 1);
  const leftItem2 = getItemAt(loopIndex - 2);
  const leftItem3 = getItemAt(loopIndex - 3);
  const leftItem4 = getItemAt(loopIndex - 4);

  const rightItem1 = getItemAt(loopIndex);
  const rightItem2 = getItemAt(loopIndex + 1);
  const rightItem3 = getItemAt(loopIndex + 2);
  const rightItem4 = getItemAt(loopIndex + 3);
  const rightItem5 = getItemAt(loopIndex + 4);
  const rightItem6 = getItemAt(loopIndex + 5);
  const rightItem7 = getItemAt(loopIndex + 6);
  const rightItem8 = getItemAt(loopIndex + 7);

  useEffect(() => {
    Promise.all([
      // Animate left column
      controlsLeftItem1.start(
        { y: "calc(100% + 0.75rem)" },
        { type: "spring", duration: 1 }
      ),
      controlsLeftItem2.start(
        { y: "calc(100% + 0.75rem)" },
        { type: "spring", duration: 1 }
      ),
      controlsLeftItem3.start(
        { y: "calc(100% + 0.75rem)" },
        { type: "spring", duration: 1 }
      ),
      controlsLeftItem4.start(
        { y: "calc(100% + 0.75rem)", opacity: 0 },
        { type: "spring", duration: 1 }
      ),

      // Animate active item from right to left
      controlsRightItem1.start(
        { x: "calc((100% + 122px) * -1)" },
        { type: "spring", duration: 1, delay: 0.25 }
      ),

      // Animate right column
      controlsRightItem2.start(
        { y: "calc((100% + 0.75rem) * -1)" },
        { type: "spring", duration: 1, delay: 0.5 }
      ),
      controlsRightItem3.start(
        { y: "calc((100% + 0.75rem) * -1)" },
        { type: "spring", duration: 1, delay: 0.5 }
      ),
      controlsRightItem4.start(
        { y: "calc((100% + 0.75rem) * -1)" },
        { type: "spring", duration: 1, delay: 0.5 }
      ),
      controlsRightItem5.start(
        { y: "calc((100% + 0.75rem) * -1)" },
        { type: "spring", duration: 1, delay: 0.5 }
      ),
      controlsRightItem6.start(
        { y: "calc((100% + 0.75rem) * -1)" },
        { type: "spring", duration: 1, delay: 0.5 }
      ),
      controlsRightItem7.start(
        { y: "calc((100% + 0.75rem) * -1)" },
        { type: "spring", duration: 1, delay: 0.5 }
      ),
      controlsRightItem8.start(
        { y: "calc((100% + 0.75rem) * -1)", opacity: 1 },
        { type: "spring", duration: 1, delay: 1 }
      ),
    ]).then(() => {
      window.setTimeout(() => {
        setLoopIndex((old) => old + 1);

        window.setTimeout(() => {
          controlsLeftItem1.set({ y: "calc(0% + 0rem)" });
          controlsLeftItem2.set({ y: "calc(0% + 0rem)" });
          controlsLeftItem3.set({ y: "calc(0% + 0rem)" });
          controlsLeftItem4.set({ y: "calc(0% + 0rem)", opacity: 1 });

          controlsRightItem1.set({ x: "calc((0% + 0px) * -1)" });
          controlsRightItem2.set({ y: "calc((0% + 0rem) * -1)" });
          controlsRightItem3.set({ y: "calc((0% + 0rem) * -1)" });
          controlsRightItem4.set({ y: "calc((0% + 0rem) * -1)" });
          controlsRightItem5.set({ y: "calc((0% + 0rem) * -1)" });
          controlsRightItem6.set({ y: "calc((0% + 0rem) * -1)" });
          controlsRightItem7.set({ y: "calc((0% + 0rem) * -1)" });
          controlsRightItem8.set({ y: "calc((0% + 0rem) * -1)", opacity: 0 });
        });
      }, 1000);
    });
  }, [loopIndex]);

  return (
    <div className="relative w-[670px] pb-[3.75rem] pt-3">
      <div className="absolute right-0 top-0 bg-red-300 text-white">
        {loopIndex}
      </div>
      <div className="relative">
        <div className="absolute inset-0 z-0 rounded-3xl border-[5px] border-white/20 bg-white/35" />
        <div className="relative z-10 flex justify-between pr-6">
          <ul className="flex flex-col gap-3 p-7">
            <li className="pb-5 opacity-50">
              <Item label="Static 1" />
            </li>
            <motion.li animate={controlsLeftItem1}>
              <Item label={leftItem1} />
            </motion.li>
            <motion.li animate={controlsLeftItem2}>
              <Item label={leftItem2} />
            </motion.li>
            <motion.li animate={controlsLeftItem3}>
              <Item label={leftItem3} />
            </motion.li>
            <motion.li animate={controlsLeftItem4}>
              <Item label={leftItem4} />
            </motion.li>
            <li className="pt-5 opacity-50">
              <Item label="Static 2" />
            </li>
            <li className="opacity-50">
              <Item label="Static 3" />
            </li>
          </ul>
          <ul className="-mb-20 -mt-3 flex flex-col gap-3">
            <li className="opacity-50">
              <Item label="Static 1" />
            </li>
            <li className="opacity-50">
              <Item label="Static 2" />
            </li>
            <motion.li animate={controlsRightItem1}>
              <Item label={rightItem1} />
            </motion.li>
            <motion.li animate={controlsRightItem2}>
              <Item label={rightItem2} />
            </motion.li>
            <motion.li animate={controlsRightItem3}>
              <Item label={rightItem3} />
            </motion.li>
            <motion.li animate={controlsRightItem4}>
              <Item label={rightItem4} />
            </motion.li>
            <motion.li animate={controlsRightItem5}>
              <Item label={rightItem5} />
            </motion.li>
            <motion.li animate={controlsRightItem6}>
              <Item label={rightItem6} />
            </motion.li>
            <motion.li animate={controlsRightItem7}>
              <Item label={rightItem7} />
            </motion.li>
            <motion.li animate={controlsRightItem8}>
              <Item label={rightItem8} />
            </motion.li>
          </ul>
        </div>
      </div>
    </div>
  );
}

function Item({ label }: { label: string }) {
  return (
    <div className="flex h-12 w-[248px] flex-shrink-0 flex-grow-0 items-center gap-4 rounded-xl bg-white/50 px-4">
      <span className="flex-shrink-0 flex-grow-0">
        <div className="w-6 h-6 rounded-full bg-white" />
      </span>
      <span className="flex-1 text-sm font-medium uppercase leading-none tracking-widest">
        {label}
      </span>
    </div>
  );
}

You can see the issue in action here:

enter image description here

Here’s a link to the CodeSandbox:

https://codesandbox.io/p/sandbox/quizzical-heisenberg-lyr7ct

Questions:

  • What might be causing these flashes or glitches?
  • Are there specific techniques in Framer Motion or React to prevent such issues?
  • Any tips for managing state or animations in this context to ensure smooth transitions?

Any advice would be greatly appreciated! I’m relatively new to React, so if there are more “React-like” approaches to handle this, please tell me!

I’ve had this error “Property ‘$t’ does not exist on type ‘ComponentCustomProperties'” since I updated the vue-router package, how can I resolve it?

enter image description here

enter image description here

I’ve updated my Vue Router package, and since then, I’ve encountered this error. I considered reverting the changes, but I need to keep my npm packages updated to ensure compatibility and take advantage of the latest features and fixes.

I have upgraded from version 4.4.0 to version 4.4.2 of the dependencies

Bootstrap desktop device “col” turn into (for mobile devices only) flex-row with horizontal scroll bar

I have some images in bootstrap “row” & “col” div. For Mobile devices I want to turn this into flex-row with horizontal scroll bar.

The caveat is it need to preserve “col” & “row” for desktop devices

Here is sample code for desktop devices

    <div class="row">
        <div class="col-2 setwidth bg-success">Card</div>
        <div class="col-2 setwidth bg-danger">Card</div>
        <div class="col-2 setwidth bg-info">Card</div>
        <div class="col-2 setwidth bg-warning">Card</div>
        <div class="col-2 setwidth ">Card</div>
    </div>

Desktop cols
For mobile devices

    <div class="d-flex flex-row flex-nowrap">
        <div class="col-2 setwidth bg-success">Card</div>
        <div class="col-2 setwidth bg-danger">Card</div>
        <div class="col-2 setwidth bg-info">Card</div>
        <div class="col-2 setwidth bg-warning">Card</div>
        <div class="col-2 setwidth ">Card</div>
    </div>

Mobile cols with horizontal scrollbar

Is there any css solution available.

First I thought two separate “div” for mobile & desktop, It contains images and I don’t know if both the “div” download images twice ?

Second solution I though was using javascript to detect device type and swap “row” class to “d-flex flex-row flex-nowrap” on load, if there is no css solution.

WebRTC is adding the remote video without clicking on answer button

I am working on a WebRTC application using JavaScript and WebSockets. The issue I am encountering is that the remote video stream is being added automatically without the user clicking the “Answer” button. I need the remote video to only be added after the “Answer” button is clicked.I am using websoket to handle signaling in django framework.Any advice is acceptable,thanks in advance.

  const url = "ws://127.0.0.1:8000/ws/wc/?group=manish";
  const socket = new WebSocket(url);
  let localVideo = document.getElementById("localVideo");
  let remoteVideo = document.getElementById("remoteVideo");
  let peerConnection;
  let iceCandidatesQueue = [];
  let awaitingAnswer = false;

  function createPeerConnection() {
    peerConnection = new RTCPeerConnection();

    peerConnection.onicecandidate = (event) => {
      if (event.candidate) {
        console.log("Sending ICE candidate:", event.candidate);
        socket.send(JSON.stringify({ type: "ice", ice: event.candidate }));
      }
    };

    peerConnection.ontrack = (event) => {
      console.log("Received remote track:", event.track);
      if (event.track.kind === "video") {
        console.log("Received video track");
        if (remoteVideo.srcObject !== event.streams[0]) {
          remoteVideo.srcObject = event.streams[0];
          console.log("Remote video stream added.");
        }
      }
    };

    peerConnection.oniceconnectionstatechange = () => {
      console.log("ICE connection state:", peerConnection.iceConnectionState);
    };

    peerConnection.onsignalingstatechange = () => {
      console.log("Signaling state:", peerConnection.signalingState);
    };
  }

  function getUserMediaAndAddTracks() {
    navigator.mediaDevices
      .getUserMedia({ video: true, audio: false })
      .then((stream) => {
        localVideo.srcObject = stream;
        stream
          .getTracks()
          .forEach((track) => peerConnection.addTrack(track, stream));
      })
      .catch((error) => {
        console.error("Error accessing media devices:", error);
      });
  }

  socket.onopen = (e) => {
    console.log("Connection opened:", e);
    createPeerConnection();
    getUserMediaAndAddTracks();
  };

  socket.onmessage = (event) => {
    const data = JSON.parse(event.data);
    console.log("Data received:", data);

    if (data.type === "sdp") {
      const sdp = new RTCSessionDescription(data.sdp);
      console.log("SDP received:", sdp);

      if (sdp.type === "offer") {
        handleOffer(sdp);
      } else if (sdp.type === "answer") {
        handleAnswer(sdp);
      }
    } else if (data.type === "ice") {
      handleIce(data.ice);
    }
  };

  socket.onclose = (e) => {
    console.log("Connection closed:", e);
  };

  socket.onerror = (e) => {
    console.error("WebSocket error:", e);
  };

  document
    .getElementById("send_message_btn")
    .addEventListener("click", function (e) {
      socket.send(JSON.stringify({ message: "Hello World", type: "message" }));
    });

  document.getElementById("sdp_btn").addEventListener("click", function (e) {
    if (peerConnection.signalingState === "stable") {
      peerConnection
        .createOffer()
        .then((offer) => peerConnection.setLocalDescription(offer))
        .then(() => {
          console.log("Sending SDP offer...");
          socket.send(
            JSON.stringify({
              type: "sdp",
              sdp: peerConnection.localDescription,
            })
          );
        })
        .catch((error) => {
          console.error("Error creating offer:", error);
        });
    } else {
      console.warn(
        "Cannot create offer in signaling state:",
        peerConnection.signalingState
      );
    }
  });

  document.getElementById("answer").addEventListener("click", function (e) {
    if (peerConnection.signalingState === "have-remote-offer") {
      peerConnection
        .createAnswer()
        .then((answer) => peerConnection.setLocalDescription(answer))
        .then(() => {
          console.log("Sending SDP answer...");
          socket.send(
            JSON.stringify({
              type: "sdp",
              sdp: peerConnection.localDescription,
            })
          );
        })
        .catch((error) => {
          console.error("Error creating answer:", error);
        });
    } else {
      console.warn(
        "Cannot create answer in signaling state:",
        peerConnection.signalingState
      );
    }
  });

  function handleOffer(offer) {
    if (peerConnection.signalingState === "stable") {
      peerConnection
        .setRemoteDescription(offer)
        .then(() => {
          console.log("Remote description set, creating answer...");
          return peerConnection.createAnswer();
        })
        .then((answer) => {
          console.log("Answer created, setting local description...");
          return peerConnection.setLocalDescription(answer);
        })
        .then(() => {
          console.log("Local description set, sending SDP answer...");
          socket.send(
            JSON.stringify({
              type: "sdp",
              sdp: peerConnection.localDescription,
            })
          );
          processIceCandidates();
        })
        .catch((error) => {
          console.error("Error handling offer:", error);
        });
    } else {
      console.warn(
        "Received offer in invalid state:",
        peerConnection.signalingState
      );
    }
  }

  function handleAnswer(answer) {
    if (peerConnection.signalingState === "have-local-offer") {
      peerConnection
        .setRemoteDescription(answer)
        .then(() => {
          console.log(
            "Remote description set from answer, processing ICE candidates..."
          );
          processIceCandidates();
        })
        .catch((error) => {
          console.error("Error handling answer:", error);
        });
    } else {
      console.warn(
        "Received answer in invalid state:",
        peerConnection.signalingState
      );
    }
  }

  function handleIce(candidate) {
    console.log("Handling ICE candidate:", candidate);
    if (peerConnection.remoteDescription) {
      peerConnection
        .addIceCandidate(new RTCIceCandidate(candidate))
        .catch((error) => {
          console.error("Error adding ICE candidate:", error);
        });
    } else {
      iceCandidatesQueue.push(candidate);
    }
  }

  function processIceCandidates() {
    while (iceCandidatesQueue.length) {
      const candidate = iceCandidatesQueue.shift();
      peerConnection
        .addIceCandidate(new RTCIceCandidate(candidate))
        .catch((error) => {
          console.error("Error adding queued ICE candidate:", error);
        });
    }
  }
});

Receiving and Sending JSON from node.js server to html

I am been working on setting up a server in node.js and creating a website that can send and receive information from the server. This is my code

// server.js
const express = require('express');
const bodyParser = require('body-parser');
const cors = require('cors');  // Import the cors package
const { GoogleGenerativeAI } = require('@google/generative-ai');

const app = express();
const port = 3000;

const apiKey = 'MYAPIKEYTHATISCORRECT';
const genAI = new GoogleGenerativeAI(apiKey);

app.use(cors());
app.use(bodyParser.json());

app.post('/chat', async (req, res) => {
    const { past_conversations } = req.body;

    // Validate past_conversations structure
    if (!Array.isArray(past_conversations) || !past_conversations.every(
        convo => convo.role && convo.parts && Array.isArray(convo.parts) && convo.parts.every(part => part.text)
    )) {
        return res.status(400).json({ error: 'Invalid conversation structure' });
    }

    const userInputValue = past_conversations[past_conversations.length - 1].parts[0].text;

    try {
        const model = genAI.getGenerativeModel({
            model: "gemini-1.5-pro",
            systemInstruction: `Output the feelling for the sentence given, like happy, sad, fear or angry`,
        });

        const generationConfig = {
            temperature: 0,
            topP: 1,
            topK: 128,
            maxOutputTokens: 256,
            responseMimeType: "text/plain",
        };

        const chatSession = model.startChat({
            generationConfig,
            history: past_conversations
        });

        const result = await chatSession.sendMessage(userInputValue);
        const aiResponse = await result.response.text();

        res.json({ output: aiResponse });
    } catch (error) {
        console.error('Error during chat processing:', error);
        res.status(500).json({ error: 'Internal Server Error', details: error.message });
    }
});

app.listen(port, () => {
    console.log(`Server running at http://localhost:${port}/`);
});
// script.js
async function sendMessage() {
        const userInputValue = userInput.value;
        if (!userInputValue) return;
    
        const chatDiv = document.getElementById('chat');
        const userMessageDiv = document.createElement('div');
        userMessageDiv.classList.add('message', 'user');
        userMessageDiv.textContent = userInputValue;
        chatDiv.appendChild(userMessageDiv);
        chatDiv.scrollTop = chatDiv.scrollHeight;
    
        userInput.value = '';
    
        // Push user message to pastConversations
        pastConversations.push({ role: "user", parts: [{ text: userInputValue }] });
    
        try {
            const response = await fetch('http://localhost:3000/chat', {
                method: 'POST',
                headers: {
                    'Content-Type': 'application/json'
                },
                body: JSON.stringify({ past_conversations: pastConversations })
            });
    
            const data = await response.json();
    
            if (!response.ok) {
                throw new Error(data.error || 'Failed to get response from server');
            }
    
            const aiResponse = data.output;
    
            const aiMessageDiv = document.createElement('div');
            aiMessageDiv.classList.add('message', 'ai');
            aiMessageDiv.textContent = aiResponse;
            chatDiv.appendChild(aiMessageDiv);
            chatDiv.scrollTop = chatDiv.scrollHeight;
    
            // Push AI response to pastConversations
            pastConversations.push({ role: "model", parts: [{ text: aiResponse }] });
    
            aitext.push(aiResponse);
            speak(aiResponse);
        } catch (error) {
            console.error('Error:', error);
        }
    }

After the function sendMessage() is called, I got the error 500 Internal Server Error and SyntaxError: Unexpected token ‘T’, “TypeError:”… is not valid JSON. What should I do to fix it? ChatGPT didn’t give any useful suggestions.

Animation does not work in the mobile version of the site

Animation does not work in the mobile version of the site, although through the element explorer in the smartphone browser, everything is fine. On the phone, the video just turns off and that’s it, although it should increase and stand in the center of the screen when you click on the screensaver

I tried using js, but nothing comes out
html

<div class="bakctage">                                  
<div class="video__poster" tabindex="0">                                              
<video id="video" class="video" poster="assets/img/постеры к                
 подкастам/IMG_8742.JPG"src="assets/video/сладко.mp4" tabindex="0"></video>                                 <a href="#video" id="play__img" class="video__img"></a>                             
</div>                             
<div class="bakctage-info">                                 
<a>Фриц Ланг - М</a>                             
</div>                             
<div class="backstage_data">                                    
<a>Дата:</a> <a>29.06.2020</a>                              
</div>                          
</div>

CSS

.video__poster video {
        width: 230px;
        height: 140px;
    }
.video__poster video {
    display: block;
    padding: 0.5%;
    cursor: pointer; 
}
    .video__poster[tabindex="0"] {
    cursor: zoom-in;
    }
    
    .video__poster video[tabindex="0"]:focus {
        position: fixed;
        z-index: 90;
        top: 0;
        left: 0;
        bottom: 0;
        right: 0;
        width: auto;
        max-width: 90%;
        height: auto;
        max-height: 90%;
        margin: auto;
        box-shadow: 0 0 200px #000, 0 0 0 1000px rgba(0, 0, 0, .3);
        -webkit-box-shadow: 0 0 200px #000, 0 0 0 1000px rgba(0, 0, 0, .3);
        -moz-box-shadow: 0 0 200px #000, 0 0 0 1000px rgba(0, 0, 0, .3);
    }

    .video__poster video[tabindex="0"]:focus,
    .video__poster video[tabindex="0"]:focus~* {
    cursor: pointer;  
    }

JS

<script>
    const videos = document.querySelectorAll('.video');
    videos.forEach(video => {
        const playButton = video.parentElement.querySelector('.video__img');
        playButton.addEventListener('click', () => {
            if (video.paused) {
                videos.forEach(otherVideo => {
                    if (otherVideo !== video && !otherVideo.paused) {
                        otherVideo.pause();
                        otherVideo.parentElement.querySelector('.video__img').classList.remove('play__img-off');
                        otherVideo.removeAttribute("controls");
                    }
                });

                video.play();
                playButton.textContent = '';
                playButton.classList.add('play__img-off');
                video.setAttribute("controls", "controls");
            } else {
                video.pause();
                playButton.textContent = '';
                playButton.classList.remove('play__img-off');
                video.removeAttribute("controls");
            }
        });
    });
</script>