Using the OR operator correctly in a Rock, Paper, Scissors game [duplicate]

I am new to the programming world and new to stack overflow, so forgive my basic question here, but I couldn’t find an answer elsewhere. I am building a simple Rock, Paper, Scissors game for a project and can’t figure out what is wrong with my syntax here. I have Googled around but cannot determine what is wrong with my use of the logical OR operator. Can someone look at this code and tell me why my function is not returning an error message here and instead is returning ‘dog’. Thanks so much!

const getUserChoice = userInput => {
  userInput = userInput.toLowerCase();
  const paper = 'paper'
  const rock = 'rock'
  if (userInput === 'paper' || 'rock' || 'scissors') {
    return userInput
  } else {
    console.log(`Error ${userInput} does not match.`)
  }
}

console.log(getUserChoice('Dog')) // Returns: dog

How to set element value based on Another element in Adaptive Card

I have tried with CDN approach and attaching handler onParseElement on AdaptiveCard static method. However handler is never invoked.

i am trying the answer posted however it is not working Your answer

I am using CDN approach to load AdaptiveCards SDK JS using 3.0.5 version “https://unpkg.com/[email protected]/dist/adaptivecards.js”

Also tried with https://unpkg.com/[email protected]/dist/adaptivecards.js this version.

As pointed out in the documentation, there are breaking changes from version 2.0 and suggested to use SerializationContext.onParseElement as AdaptiveCard.onParseElement has been removed. But still it is not hitting the handler.

Could you please assist?

how to prevent input value lower then another

I have 2 inputs type=”number” : min and max

It should not be possible to put a value inside max input lower then the value in min input.

In example below you can select the value in max input and type per example 9. This should not be possible.
How can i prevent that?

<span class="input-group-text pretext">Min:</span>          
<input min="" max="" type="number" class="form-control min-input" name="price_min" value="12">
<br />                              
<span class="input-group-text pretext">Max:</span>
<input min="" max="" type="number" class="form-control max-input" name="price_max" value="25">

js:

$(".min-input, .max-input").on("input", function(e) {
    var minInput = $(".min-input").val();
    var maxInput = $(".max-input").val();
    if(maxInput < minInput) {
        $(".max-input").val(minInput);      
    }
});

Fiddle

messageDeleted` not called when a message is deleted in WhatsApp Web (via `WKScriptMessageHandler`)

I’m developing an iOS app that uses a WKWebView to display WhatsApp Web (https://web.whatsapp.com). I need to detect when a message is deleted in the WhatsApp Web interface and handle the event in my app using the WKScriptMessageHandler. However, the messageDeleted event is not being triggered when a message is deleted in the WhatsApp Web UI.

Here is the relevant code where I handle the messages in the WKScriptMessageHandler:

extension WhatsWebVC: WKScriptMessageHandler {
    @objc func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
        guard let body = message.body as? [String: Any],
              let type = body["type"] as? String,
              let data = body["data"] as? [String: Any] else { return }
        
        switch type {
        case "messageDeleted":
            handleDeletedMessage(data)  // This function is not being called
        case "mediaMessage":
            handleMediaMessage(data)
        case "wsReceive":
            handleWebSocketMessage(data)
        case "wsSend":
            print("Outgoing WS message:", data)
        default:
            print("Unknown message type received:", type)
        }
    }
}

In my WebView’s JavaScript injection, I monitor when a message is deleted using a MutationObserver on the WhatsApp Web chat container. When a message is deleted, I send the messageDeleted event back to the iOS app using window.webkit.messageHandlers.messageObserver.postMessage().

Here’s the JavaScript code that I inject into WhatsApp Web:

(function() {
    let messageCache = new Map();
    function extractMessageContent(element) {
        let messageContainer = element.querySelector('[data-pre-plain-text]');
        let messageText = element.querySelector('.selectable-text');
        let mediaContainer = element.querySelector('.media-container');
        let timestampElement = element.querySelector('div[data-pre-plain-text]');
        let timestamp = '';
        let sender = '';
        let mediaUrl = '';
        let mediaName = '';
        
        if (timestampElement) {
            let preText = timestampElement.getAttribute('data-pre-plain-text');
            if (preText) {
                let matches = preText.match(/\[(.*?)\].*?([^:]+):/);
                if (matches) {
                    timestamp = matches[1];
                    sender = matches[2].trim();
                }
            }
        }
        if (mediaContainer) {
            let mediaElement = mediaContainer.querySelector('img, video');
            if (mediaElement) {
                mediaUrl = mediaElement.src;
                mediaName = mediaElement.alt || mediaElement.src.split('/').pop();
            }
        }
        return {
            id: element.getAttribute('data-id'),
            text: messageText ? messageText.innerText : '',
            sender: sender,
            timestamp: timestamp,
            hasMedia: !!mediaContainer,
            mediaUrl: mediaUrl,
            mediaName: mediaName
        };
    }

    const messageObserver = new MutationObserver((mutations) => {
        mutations.forEach((mutation) => {
            if (mutation.type === 'childList') {
                mutation.removedNodes.forEach((node) => {
                    if (node.nodeType === Node.ELEMENT_NODE) {
                        let messageElement = node.querySelector('[data-id]');
                        if (messageElement) {
                            let messageId = messageElement.getAttribute('data-id');
                            window.webkit.messageHandlers.messageObserver.postMessage({
                                type: 'messageDeleted',
                                data: extractMessageContent(messageElement)
                            });
                        }
                    }
                });
            }
        });
    });

    function observeChat() {
        const chatContainer = document.querySelector('#main div.copyable-area');
        if (chatContainer) {
            messageObserver.observe(chatContainer, {
                childList: true,
                subtree: true
            });
        } else {
            setTimeout(observeChat, 1000);
        }
    }

    function initObserver() {
        if (document.querySelector('#app')) {
            observeChat();
        } else {
            setTimeout(initObserver, 1000);
        }
    }

    initObserver();
})();

In this JavaScript code:

  • A MutationObserver listens for changes in the chat container and specifically checks when messages are removed.
  • If a message is deleted, I call window.webkit.messageHandlers.messageObserver.postMessage() to notify the app with the messageDeleted type and the corresponding message data.

What I’ve tried:

  1. Ensure the JavaScript is injected: I’ve confirmed that the JavaScript is properly injected into the WKWebView. The observer is firing when elements are removed from the DOM, but the messageDeleted message never reaches the userContentController(_:didReceive:) method in the iOS app.

  2. Message type and data: I added print statements in the app to log incoming messages, but the “messageDeleted” case does not get triggered, even though the WebView is correctly executing the JavaScript.

  3. WebView configuration: I ensure that the WebView’s WKUserContentController is properly configured to handle messages:

    let userContentController = WKUserContentController()
    userContentController.add(self, name: "messageObserver")
    let config = WKWebViewConfiguration()
    config.userContentController = userContentController
    let webView = WKWebView(frame: .zero, configuration: config)
    
  4. Injected JavaScript: I double-checked that the JavaScript executes correctly and that the postMessage function is called with the expected data.

Question:

Why is the messageDeleted case not being called? Are there any issues with how the JavaScript is communicating with the iOS app, or with how I’ve set up the message handler in WKWebView? What could be causing this problem, and how can I fix it? Any suggestions would be greatly appreciated!

Can this IF statement that has an OR operator be simplified further?

I have this code that I’m trying to simplify, but feels like its as simple as it can get.

if (index == string.lastIndexOf(word) || word != wordArr[0]) 
  {
  k = 0;
  wordArr = []
  }
else
  {
  // other code
  }

if (index == string.lastIndexOf(word)) 
  {
  notify.innerHTML = 'End of search!'
  }

I’m not sure if its possible to change the innerHTML of the notify element only if the ìndex variable matches the last index, without checking the wordArr Array, and then checking if both the last index matches the index variable and the word variable is not equal to the wordArr[0] element, to reset k and the array. Id rather not repeat the if (index == string.lastIndexOf(word)) twice and just use the first one to change the innerHTML.

Basically how do you split the code block to be executed so that only part of it gets executed for part of the conditional?

Is it possible to swap input value with htmx?

If we have an input element like:

<input type="text" id="search-query" name="search_query">

I want to use htmx to update the input value when the value of another input element changes. This is what’s in my mind:

<input
    type="text"
    id="search-query"
    name="search_query"
    hx-get="/get-search-query-value"
    hx-trigger="otherInputChange from:#brand-search"
    hx-include="[data-brand-id]"
    hx-target="this"
    hx-swap="value"
/>

The problem is that htmx docs don’t list value as a possible option for hx-swap.

Is there a recommended way to achieve this with htmx or we need to resort to JavaScript for that?

Vue3 compiling removes function’s parameters

I need to send the index and the $event but Vite or Vuejs keep removes the parameters for a button when compiling.

Here all the tests

<script setup>
function imageAdd (index, ev) {
    console.log(index, ev);
}
</script>

<template>
<button class="button" type="button" @click="imageAdd('test1', 'test2')">b1</button>
<button class="button" type="button" @click="imageAdd(index, $event)">b2</button> // index is declared in a v-for loop
<button class="button" type="button" @click="imageAdd($event)">b3</button>
<button class="button" type="button" @click="imageAdd()">b4</button>
<button class="button" type="button" @click="imageAdd">b5</button> // the only test which send $event
</template>

and a part of the compiled js code, all buttons are the same without parameters

createBaseVNode("button", {
  class: "button",
  type: "button",
  onClick: ($event) => imageAdd()

How to extract text from scanned PDF files, which could work in both web workers and NodeJS too

I want to extract text from pdf files but particularly only those which are made up of scanned images, I tried to use pdfjs methods with Tesseract.js OCR, but it won’t work in web workers, although this is quite expected because document or any DOM elements are not available in web workers. The single most reason I can’t do this on main thread or in main script modules, is because of performance, as the browser can get freezed or even crash while extracting large pdfs or containing many pages.

This is the code I have currently:

import * as pdfjsLib from 'pdfjs-dist';
import Tesseract from 'tesseract.js';

pdfjsLib.GlobalWorkerOptions.workerSrc = 'pdfjs-dist/build/pdf.worker.js'; // Important!

async function extractTextFromPDF(file) {
   
  const fileReader = new FileReader();
    fileReader.readAsArrayBuffer(file);

    const arrayBuffer = await new Promise((resolve, reject) => {
      fileReader.onload = event => resolve(event.target.result);
      fileReader.onerror = error => reject(error);
    });

  const pdf = await pdfjsLib.getDocument(arrayBuffer).promise;
  const page = await pdf.getPage(1); // Get the first page

  const viewport = page.getViewport({ scale: 1.0 });
  const canvas = document.createElement('canvas');
  const context = canvas.getContext('2d');
  canvas.height = viewport.height;
  canvas.width = viewport.width;

  await page.render({ canvasContext: context, viewport: viewport }).promise;

  const { data: { text } } = await Tesseract.recognize(
    canvas,
    'eng', // Language
    { logger: m => console.log(m) } // Optional logging
  );

  console.log(text);
  return text;
}

extractTextFromPDF('your_pdf.pdf');

As discussed this can’t work due to unavailability of document element

What can I do to make it work in both web worker as well as in Node.js environments? I couldn’t find any solutions or guides online or anywhere.
Help, would be really appreciated.

I have tried Tesseract OCR but it doesn’t work nor does pdfjs.

How to get the IP of the server in NextJs 15.1.1?

I would my client login page to have access to the IP the server is running on for making requests. I have a Scala webserver running on the same machine that the webpage needs to send requests to.

The idea is:

  • The user goes to https://{serverIP}/ -> works

  • nginx redirects to Next https://{serverIP}:3000 using proxy_pass -> works

  • The login page loads, and somehow extracts the IP address from the request, so the rest of the website can make requests to https://{serverIP}/ to be redirected by nginx to the scala webserver

I believe this would have to be somewhere in my middleware.js so it can capture the information when nginx does the redirect to Next, but what I want to know:

  1. How do I extract the IP from the incoming request?
  2. How do I then make it available so that the components have access to it when they do a fetch?

I have tried req.ip, req.connection.remoteAddress, req.socket.remoteAddress, all of which seem to have been removed and are undefined.

I also tried req.headers['x-forwarded-for'] and req.headers["x-real-ip"] but again, I get an empty result.

Am I missing something? I am not a React/JS developer so I’m going on what I can find online, which seems mostly out of date for NextJS 15.

Await multiple promises in parallel, but return early if they take too long, once first 2 have resolved

I’m working with promises in JavaScript. I need to call a promise that returns a number 3 times. These conditions must be met:

  • The promises must be run in parallel, not one after the other.
  • If all the promises resolve in less than 50ms, then return the sum of all 3.
  • If any of the promises take over 50ms, then return the sum of the first 2, regardless of how long they take.

I’ve made a start but I don’t know how to return early if the promises take too long:

function getPromise(): Promise<number> {
  return new Promise(resolve => {
    setTimeout(()=>{
      resolve(Math.round(Math.random() * 10))
    }, Math.random() * 100);
  })
};

const TIMEOUT_MS = 50;

async function foo(){
  const promises = [getPromise(), getPromise(), getPromise()];
  const timeBefore = new Date().getTime()
  const results: number[] = await Promise.all(promises);
  const timeAfter = new Date().getTime();
  const duration = timeAfter - timeBefore;

  // if the duration is within 50ms then return the sum of all 3
  if(duration <= TIMEOUT_MS) {
    const sum: number = results.reduce((acc, current ) => acc + current, 0);
    return sum
  }

  // todo
}

SVG path, stroke-width is inconsistent. How to make it uniform

I am creating a loading screen using an SVG path. there is a grey path to represent the unloaded bar, and a white path to represent the percentage loaded.

document.addEventListener("DOMContentLoaded", () => {
  const loadingScreen = document.getElementById("loading-screen");
  const loadingPercentage = document.getElementById("loading-percentage");
  const progressPath = document.getElementById("progress-path");

  let progress = 0; // Current progress
  const minDisplayTime = 1750; // Minimum display time in milliseconds
  const fadeDelay = 500; // Duration of fade-out animation (in ms)
  const delayAfterComplete = 750; // Delay after hitting 100% (in ms)
  const startTime = Date.now(); // Record when loading starts
  const totalLength = 360; // Total length of the SVG path

  // Set the initial stroke-dasharray and stroke-dashoffset for the white bar
  progressPath.style.strokeDasharray = totalLength;
  progressPath.style.strokeDashoffset = totalLength;

  // Function to update progress
  function updateProgress() {
    const elapsedTime = Date.now() - startTime;

    // Calculate the progress as a percentage based on time
    if (elapsedTime < minDisplayTime) {
      progress = Math.min((elapsedTime / minDisplayTime) * 100, 100);
    } else {
      progress = 100; // Ensure progress reaches 100% after minimum display time
    }

    // Update percentage text
    loadingPercentage.textContent = `${Math.floor(progress)}%`;

    // Update progress bar position
    const offset = totalLength * (1 - progress / 100);
    progressPath.style.strokeDashoffset = offset;

    console.log(`Loading progress: ${progress}%`);

    // Trigger fade-out when progress hits 100%
    if (progress === 100) {
      const remainingTime = minDisplayTime - elapsedTime; // Ensure minimum display time
      setTimeout(() => {
        // Add a 0.75-second delay after hitting 100% before starting fade-out
        setTimeout(() => {
          loadingScreen.style.opacity = "0"; // Trigger fade-out animation

          // Completely hide the loading screen after the fade-out
          setTimeout(() => {
            loadingScreen.style.display = "none";
          }, fadeDelay); // Match the CSS transition duration
        }, delayAfterComplete); // 0.75-second delay after hitting 100%
      }, Math.max(remainingTime, 0)); // Wait for any remaining time if necessary
    } else {
      // Continue updating progress until it reaches 100%
      requestAnimationFrame(updateProgress);
    }
  }

  // Start the progress update loop
  updateProgress();
});
#loading-screen {
  position: fixed;
  top: 0;
  left: 0;
  width: 100vw;
  height: 100vh;
  background-color: #222;
  /* Dark background */
  display: flex;
  justify-content: center;
  align-items: center;
  z-index: 9999;
  /* Overlay all content */
  overflow: hidden;
  transition: opacity 0.5s ease;
  /* Fade-out effect */
}

/* Logo and percentage container */
#loading-content {
  position: absolute;
  display: flex;
  flex-direction: column;
  align-items: center;
  z-index: 1;
  /* Above the loading bar */
}

/* Logo styling */
#ws-logo {
  width: 15%;
  max-width: 100px;
  height: auto;
  margin-bottom: 10px;
}

/* Percentage text styling */
#loading-percentage {
  font-size: 1.5em;
  color: #fff;
  font-family: Arial, sans-serif;
}

/* SVG loading bar */
#loading-bar {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  z-index: 0;
  /* Behind content */
  padding: 0;
  /* Ensure no internal spacing */
  margin: 0;
  /* Remove any external margin */
  box-sizing: border-box;
  /* Include border in dimensions */
}

#loading-bar path {
  vector-effect: ;
}

#progress-path {
  transition: stroke-dashoffset 0.2s ease-out;
  /* Smooth animation for the progress bar */
}
<!-- Loading Screen -->
<div id="loading-screen">
  <div id="loading-content">
    <img id="ws-logo" src="ws-logo.png" alt="WS Logo">
    <div id="loading-percentage">0%</div>
  </div>
  <svg id="loading-bar" width="100%" height="100%" viewBox="0 0 100 100" preserveAspectRatio="none">
          <!-- Grey background path -->
          <path
            d="M5 5 L5 95 L95 95 L95 5 Z"
            stroke="#666"
            stroke-width="1"
            stroke-linecap="square"
            fill="none"
          />
          <!-- White progress path -->
          <path
            id="progress-path"
            d="M5 5 L5 95 L95 95 L95 5 Z"
            stroke="#fff"
            stroke-width="1"
            stroke-linecap="square"
            fill="none"
            stroke-dasharray="0"
            stroke-dashoffset="0"
          />
        </svg>
</div>

here is a CodePen with what i’ve created: https://codepen.io/Ramon-117/pen/QwLrxvb

The concept:
the loading bar will resemble a grey box border. As the site loads, the progress bar will grow white starting from the top right corner (0%), down to the bottom left corner (25%), to the bottom right corner (50%), up to the top right corner (75%), and back to the top left corner (100%).

The issue:
I have everything working except for a key issue. If the viewheight is larger than the viewwidth, then then the top and bottom widths will be thicker than the left and right and vise-versa.

What I want:
I want the stroke to have an even thickness throughout the path no matter the viewport size. I also want to be able to adjust said thickness to account for mobile devices.

What I’ve tried:

  • stroke-width=”1″ *doesnt work

  • stroke-width=”1px” *doesnt work

  • stroke-width=”1%” *doesnt work

  • stroke-width=”1vmin” *doesnt work

  • vector-effect:non-scaling-stroke; *breaks the animation

  • vector-effect:non-scaling-stroke; AND vector-effect:non-rotation;

  • dynamically setting the width based on viewport with JavaScript (i dont have this code anymore)

How to avoid HTML cutting the overflow only on IOS

I’m building a React component that uses <svg> to display text with a gradient fill and stroke. On iOS (iPhone, iPad, Safari), the text is partially cut off near the top and bottom—almost like the bounding box or stroke area is getting clipped. However, on desktop browsers (Chrome, Brave, Firefox) and on Android devices, the text renders perfectly without any clipping.

Probably part of the problem is due to the italic font but, as you can see, accent marks like “~” are also being cut.

Edges and accent marks being cut

I work on Ubuntu and I can’t check it directly from a MacIOS system, but the text boundaries looks like this in Brave:
Text in Brave

The site is for a client and it’s still being developed, but I provided it for test in: https://museclub-teste.rerunsset.com/

I’ve tried several common fixes without success:

  1. Increasing the viewBox dimensions significantly (adding extra padding around the text).
  2. Inserting an invisible <rect> to expand the bounding box.
  3. Setting overflow=”visible” on both the <svg> and <text> elements.
  4. Changing dominantBaseline from “middle” to “central”, “hanging”, or other baselines.
  5. Removing or altering fontStyle=”italic” and adjusting line-height or leading-none.

Despite these attempts, the text still gets truncated only on iOS Safari. I expected the text to render fully (with no cutting on top or sides), just like it does on other platforms. Does anyone know how to reliably prevent <text> clipping in <svg> on iOS devices?

Versions:

  • React 18
  • NextJS 14.2

FeaturedTextSVG.tsx:

import React, { ComponentPropsWithoutRef, ReactNode } from "react";
import { cn } from "@/utils/classMerge";

type GradientStop = {
  offset: string;
  stopColor: string;
};

type GradientData = {
  fillID: string;
  strokeID: string;
  fillStops: GradientStop[];
  strokeStops: GradientStop[];
};

type GradientMap = Record<'dark', GradientData>;

/**
 * Map containing the fill and stroke gradient definitions
 * for each theme variant.
 */
const GRADIENT_MAP: GradientMap = {
  dark: {
    fillID: "fillGradientDark",
    strokeID: "strokeGradientDark",
    fillStops: [
      { offset: "0%", stopColor: "#DB98A5" },
      { offset: "50%", stopColor: "#C96981" },
      { offset: "100%", stopColor: "#91314A" },
    ],
    strokeStops: [
      { offset: "0%", stopColor: "#472B2D" },
      { offset: "5%", stopColor: "#7C4A4F" },
      { offset: "10%", stopColor: "#965A61" },
      { offset: "15%", stopColor: "#BC707B" },
      { offset: "51%", stopColor: "#EFBFC7" },
      { offset: "61%", stopColor: "#EFC6CA" },
      { offset: "69.5%", stopColor: "#D9959F" },
      { offset: "90%", stopColor: "#948184" },
      { offset: "100%", stopColor: "#615254" },
    ],
  },
};

/**
 * Props for FeaturedTextSVG component.
 */
type FeaturedTextSVGProps = {
  children: ReactNode; // The text to display
  width?: number | string;
  height?: number | string;
  fontSize?: number | string;
  strokeWidth?: number;
  className?: string;
  textClassName?: string;
  textX?: string;
} & Pick<ComponentPropsWithoutRef<'text'>, 'textAnchor' | 'fontStyle' | 'fontWeight'>;

/**
 * Renders text with both fill and stroke gradients via SVG.
 * The stroke precisely follows the shape of each letter.
 */
export function FeaturedTextSVG({
  children,
  width = 500,
  height = 100,
  strokeWidth = 3,
  className,
  textAnchor = 'middle',
  fontStyle = 'italic',
  fontWeight = '800',
  textX = "50%"
}: FeaturedTextSVGProps): ReactNode {
  // Retrieve gradient definitions from the map
  const gradients = GRADIENT_MAP['dark']; // dark is default so far

  return (
    <svg
      overflow={'visible'}
      width={width}
      height={height}
      viewBox={`0 0 ${width} ${height}`}
      style={{ display: "block" }}
      className={cn("maw-w-[500px] px-2 lg:maw-w-[700px] max-lg:v", className)}
    >
      <defs>
        {/* Fill gradient */}
        <linearGradient
          id={gradients.fillID}
          gradientUnits="objectBoundingBox"
          x1="0" y1="0"
          x2="0" y2="1"
        >
          {gradients.fillStops.map((stop, idx) => (
            <stop
              key={idx}
              offset={stop.offset}
              stopColor={stop.stopColor}
            />
          ))}
        </linearGradient>

        {/* Stroke gradient */}
        <linearGradient
          id={gradients.strokeID}
          gradientUnits="objectBoundingBox"
          x1="0" y1="0"
          x2="1" y2="0"
          gradientTransform="rotate(100)"
        >
          {gradients.strokeStops.map((stop, idx) => (
            <stop
              key={idx}
              offset={stop.offset}
              stopColor={stop.stopColor}
            />
          ))}
        </linearGradient>
      </defs>
      <text
        x={textX}
        y={parseFloat(height as string) / 2 + strokeWidth / 2}
        dominantBaseline='central'
        textAnchor={textAnchor}
        fontWeight={fontWeight}
        fontStyle={fontStyle}
        fill={`url(#${gradients.fillID})`}
        stroke={`url(#${gradients.strokeID})`}
        strokeWidth={strokeWidth}
        strokeLinejoin="round"
        style={{ overflow: 'visible', paintOrder: "stroke" }}
        strokeLinecap="round"
        className={cn("uppercase pr-4 max-[350px]:text-5xl text-[3.25rem] leading-none md:text-6xl lg:text-8xl")}
      >
        {children}
      </text>
    </svg>
  );
};

Usage:

<BigText
    size={'mini'}
    className="title-text-shadow text-center font-[600]"
  >
    Seja a mulher <br /> que você nasceu
  </BigText>
  <FeaturedTextSVG
    width={600}
    height={60}
    fontSize={80}
    strokeWidth={1.2}
    textAnchor="middle"
    className="title-drop-shadow mt-1 md:mt-4 lg:mt-8 text-[3.6rem]"
  >
    para ser!
  </FeaturedTextSVG>
</div>

Respond to delay of fetch without break fetch in javascript

I use videojs for display film and depend of time of video I display description from backend what is required for this project.
In case of problem with download decription on time (but no with buffer store of video) I’d like stop video, for example after 3 seconds delay, and continue video when fetch will finish download data.

I do not sure I can use wraped setTimeout and fetch with Promise for solution this problem.

Is it better repeat fetch after stop video by AbortController, but is it properly?

It is what I use for download data without setTimeout and start/stop video:

const player = videojs('my-video');
player.on('timeupdate', async function(){
        //...
        const verset = await checkVerset(zone);
        //...
});
async function checkVerset(zone) {  
    let zoneRes;
    await connectFetch('./in.php', zone ).then(resolve =>{ 
        zoneRes = resolve;
        console.log(zoneRes);   
    }).catch(error => console.log( 'Error of details: ', error));
    return zoneRes; 
}
async function connectFetch (url, text) {
    const response = await fetch(url, { 
        method:'post', 
        mode:'cors',
        credentials:'same-origin',
        headers:{'Content-type':'text/plain;charset=UTF-8'}, 
        body: JSON.stringify(text) 
    })
    if(!response.ok){
        const message = 'Error: ${response.status}';
        throw new Error(message);
    }
    const resolve  = response.text();
    return resolve;
}
//player.pause();
//player.play();

How to receive data in form from another component in ReactJS

I’m building a react weather app where users are allowed to enter their city name and the weather info is displayed back to the user.

The problem is, I’ve got the input and button in a form, and I want to receive data from another component called WeatherApp. I want the user to be able to enter their city and get the weather info using the form.

how do I link the two components

the form component

import '../App.css';
import Input from './Input';
import Button from './Button';
import { useState } from 'react';

const Form = ({handleQueryChange}) => {
    const [city, setCity] = useState('')

    const handleChange = (e) => {
        setCity(e.target.value)
       
    }

    const handleSubmit  = (e) => {
        e.preventDefault();
        handleQueryChange(city);
        
    }
   
    return (  
    <div>
        <form className="inputForm" onSubmit={handleSubmit}>
       <Input value={city} onChange={handleChange} />
       <Button/>
        </form>

    </div>);
}
 
export default Form;

the weatherapp component

import React from 'react';
import { BrowserRouter,  Routes,Route } from 'react-router-dom';
import { useState, useEffect } from 'react';
import { WiDaySunny,WiCloud, WiNightCloudy,WiHumidity, WiNightClear } from 'react-icons/wi';
import Layout from './Layout';
import Home from './Home';
import Minutecast from './Minutecast';
import Hourly from './Hourly';
import Today from './Today';
import '../App.css';


const WeatherApp = () => {
const [data, setData] = useState([]);
const [query, setQuery] = useState('Accra');

const handleQueryChange = (data) => {
    setQuery(data.location.name);

}

const getWeatherIcons = (description) =>{
    switch(description.toLowerCase()) {
        case 'sunny':
            return <WiDaySunny size='100px'/>;
        case 'cloud':
                return <WiCloud  size='100px'/>;
        case 'clear':
                return <WiNightClear size='100px'/>;
        case 'partly cloudy':
            
                return <WiNightCloudy size='150px' color='blue' />;
        default:
                return <WiDaySunny color='red' size='100px' />;

    }
}

const convertToWhole = (tem) =>{
  const whole = Math.trunc(tem);
  return whole;


}

useEffect(()=>{
    
const fetchWeatherData = async () => {
  try {
    const response = await fetch(`https://api.weatherapi.com/v1/forecast.json?key=95f0ddb3a06a4a358cf223933242311&q=${query}&days=10&aqi=yes&alerts=no`);
    const result = await response.json();
    setData(result);

  console.log(result);
  } catch (error) {
    console.error("Error fetching weather data:", error);
  }
 
};
fetchWeatherData();
}, [data]);



    return ( <>
    <div className="formContainer">
    {/* <Form onSubmit={handleQueryChange} /> */}
    </div>
    <BrowserRouter>
    <Routes>
       <Route path ='/'  element={< Layout />}>
       <Route index element={<Home  data={data} getWeatherIcons={getWeatherIcons} convertToWhole={convertToWhole}/>} />
       <Route path='minutecast' element={<Minutecast />}/>
       <Route path='hourly' element={<Hourly data={data} convertToWhole={convertToWhole}/>}/>
       <Route path='today'element={<Today data={data} />}/>
     </Route>
     </Routes>
   </BrowserRouter>
  
    </>
    )
   
}
 
export default WeatherApp;