Create permanent route using React

I started with React, read some docs but I can’t find a solution, maybe I’m wrong

I have a HomePage in src/app/page.tsx

export default function HomePage() {
  const [loggedIn, setLoggedIn] = useState(false)
  const [email, setEmail] = useState('')

  return (
    <div className="App">
    <BrowserRouter>
      <Routes>
        <Route path="/" element={<Home email={email} loggedIn={loggedIn} />} />
        <Route path="/login" element={<Login setLoggedIn={setLoggedIn} setEmail={setEmail} />} />
      </Routes>
    </BrowserRouter>
    </div>
  )
}

In Home() method, I show a button

const onButtonClick = () => {
  navigate('/login')
}
[...]
<input
  type="button"
  onClick={onButtonClick}
  value={loggedIn ? 'Log out' : 'Log in'}
/>

When I click on the button, I can see my Login form.

I saw that my url is now localhost:3000/login

If I do a refresh (F5) I have a 404 http error

How I can create a permanent route ?
I thought that all calls what triggered by my HomePage ?

Is there any client-side storage that is safe from browser extensions?

LocalStorage, SessionStorage and IndexedDB can all be easily accessed by browser extensions through content scripts. Yes, the extensions need user permission, but users are dumb enough to give extensions access to all websites.

So is there any client-side storage that is actually secure and can be accessed by your JavaScript, e.g. one where you can safely store the user’s private key for an end-to-end encrypted web app?

(I know HttpOnly cookies can’t be accessed by extensions, but my JavaScript can’t access them either.)

Items are not in order ReactJS

When I add the items for the section Included and Not Included the items are getting added as expected, but when I refresh the page, the items are not in order as added.

When I add the first item, it should be first in the list, and the last item should be last, but the list is getting ordered randomly.

Included part

import { ItemList } from "../ItemList";
import { useInfo } from "../../context";

export const IncludesPart = () => {
  const { state, addIncludes, editIncludes, deleteIncludes } = useInfo();

  return (
    <ItemList
   
      title="What's Included?"
      items={state.includes}
      onAdd={addIncludes}
      onEdit={editIncludes}
      onDelete={deleteIncludes}
    />
  );
};

Item input

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

export const ItemInputs = ({
  setAddIncludesItem,
  values,
  setValues,
  handleSave
}) => {
  const divRef = useRef(null);

  return (
    <div className="item_inputs_wrapper" ref={divRef}>
      <div className="item_input_wrapper">
        <input
          placeholder="Item title"
          className="input_style"
          type="text"
          value={values.title}
          maxLength="24"
          onChange={(e) => setValues({ ...values, title: e.target.value })}
          // onBlur={handleSave}  // Handle save when focus out
        />
        <p className="characters_remaining">{24 - values.title.length}</p>
      </div>
      <div className="item_input_wrapper">
        <input
          placeholder="Item description"
          className="input_style"
          type="text"
          value={values.description}
          maxLength="200"
          onChange={(e) => setValues({ ...values, description: e.target.value })}
          onBlur={handleSave}  // Handle save when focus out
        />
        <p className="characters_remaining">
          {200 - values.description.length}
        </p>
      </div>
      <div style={{ display: "flex" }}>
        <div className="done_icon" onClick={handleSave}></div>
        <div
          className="delete_icon"
          onClick={() => {
            setAddIncludesItem(false);
            setValues({
              title: "",
              description: "",
            });
          }}
        ></div>
      </div>
    </div>
  );
};

Item list

import "./style.css";

import { AddButton } from "../AddButton";
import { ItemInputs } from "../ItemInputs";
import { useState } from "react";

export const ItemList = ({
  title,
  items,
  onAdd,
  onEdit,
  onDelete,
}) => {
  const [values, setValues] = useState({ title: "", description: "" });
  const [isAdding, setIsAdding] = useState(false);
  const [editingIndex, setEditingIndex] = useState(-1);

  const handleAdd = () => {
    setIsAdding(true);
    setValues({ title: "", description: "" });
  };

  const handleSave = () => {
    if (editingIndex >= 0) {
      onEdit(values, editingIndex);
      setEditingIndex(-1);
    } else {
      onAdd({
        ...values,
        order: items.length
      });
      setIsAdding(false);
    }
    setValues({ title: "", description: "" });
  };

  const handleEdit = (index) => {
    setEditingIndex(index);
    setValues(items[index]);
  };

  const handleCancel = () => {
    setIsAdding(false);
    setEditingIndex(-1);
    setValues({ title: "", description: "" });
  };

  const sortedItems = [...items].map((item, index) => ({
    ...item,
    originalIndex: index
  }));

  return (
    <div className="part_wrapper">
      <h2 className="question_title">{title}</h2>
      
      {sortedItems.map((item) => (
        <div key={item.originalIndex}>
          {editingIndex === item.originalIndex ? (
            <ItemInputs
              values={values}
              setValues={setValues}
              handleSave={handleSave}
              setAddIncludesItem={handleCancel}
            />
          ) : (
            <div className="includes_item">
              <div className="includes_main_part_wrapper">
                <p className="includes_title">{item.title}</p>
                <p className="includes_description">{item.description}</p>
              </div>
              <div className="event_icons">
                <div 
                  className="edit_icon" 
                  onClick={() => handleEdit(item.originalIndex)}
                />
                <div 
                  className="delete_icon" 
                  onClick={() => onDelete(item.originalIndex)}
                />
              </div>
            </div>
          )}
        </div>
      ))}

      <div className="edit_wrapper">
        {isAdding && (
          <ItemInputs
            values={values}
            setValues={setValues}
            handleSave={handleSave}
            setAddIncludesItem={handleCancel}
          />
        )}
        {!isAdding && editingIndex === -1 && (
          <AddButton
            text={`Add ${title.toLowerCase()} item`}
            onClick={handleAdd}
          />
        )}
      </div>
    </div>
  );
}; 

Not included

import { ItemList } from "../ItemList";
import { useInfo } from "../../context";

export const NotIncludesPart = () => {
  const { state, addNotIncludes, editNotIncludes, deleteNotIncludes } = useInfo();

  return (
    <ItemList
      title="What's not Included?"
      items={state.notIncludes}
      onAdd={addNotIncludes}
      onEdit={editNotIncludes}
      onDelete={deleteNotIncludes}
    />
  );
};

CryptoJS – decrypt PBEWithHMACSHA512AndAES_256

I’d like to decrypt strings encrypted with algorithm PBEWithHMACSHA512AndAES_256 using CryptoJS.

Encrypted strings are meant for a Java Spring Jasypt application and are created in this way:

    var passphrase = "XxxXXXXxX";
    var saltWA = CryptoJS.lib.WordArray.random(128/8);
    var ivWA = CryptoJS.lib.WordArray.random(128/8);
    var iterations = 1000;
    var plaintext = "some text";

    var keyWA = CryptoJS.PBKDF2(passphrase, saltWA, {keySize: 256/32, iterations: iterations, hasher: CryptoJS.algo.SHA512});

    //ENCRYPT
    var ciphertextCP = CryptoJS.AES.encrypt(plaintext, keyWA, {iv: ivWA});
    var ciphertextHex = ciphertextCP.ciphertext.toString(); 

    // Concatenate
    var encryptedData = saltWA.clone().concat(ivWA).concat(ciphertextCP.ciphertext);  //     Concatenate on binary level
    var encryptedDataB64 = encryptedData.toString(CryptoJS.enc.Base64);  

This works but you have to pass the ciphertext used during encryption

    var decrypted = CryptoJS.AES.decrypt(ciphertextCP, keyWA, {iv: ivWA});
    var decryptedString = decrypted.toString(CryptoJS.enc.Utf8);

I would like to have a different function in order to get plain content from an encrypted string. Unfortunately this doesn’t work

   var decrypted = CryptoJS.AES.decrypt({ciphertext: 
   CryptoJS.enc.Hex.parse(encryptedDataB64)}, passphrase);

Encrypted data example: PvQalMekYBNW2Kl5QWSjZNGgycJ2Ato+ISx7L1i2IA9BaCzwEPq55FbSq71U6gT5

any suggestion?
Thanks in advance

Code not working on website (working fine on Codepen)

I have some code for rotating circular text on my website that was working fine until recently. Now I am getting some error messages and the text is just displaying as normal static, horizontal text. I can’t figure out how the code can be working fine in Codepen but on the website it is not working. What is also weird is that in the Elementor editor on the website, the circular rotating text is working fine but on the live site it’s broken?!

enter image description here

jQuery(document).ready(function($) {
const text = document.querySelector(".circular-text .contact-text")
const rotate = new CircleType(text).radius(40)
window.addEventListener("scroll", function() {
  text.style.transform = `rotate(${window.scrollY * 0.15}deg)`
  });

  });
.circle-text { 
overflow: hidden; 
    
}

.circle-text text { 
    font-family: "Alliance No 2", Sans-serif; 
    font-size: 17.2px; 
    font-weight: 500; 
    
}

.circle-text svg { 
    position: relative;
left: 0; 
top: 0; 
width: 100%; 
height: 220px;

  -webkit-animation-name: rotate;
     -moz-animation-name: rotate;
      -ms-animation-name: rotate;
       -o-animation-name: rotate;
          animation-name: rotate;
  -webkit-animation-duration: 5s;
     -moz-animation-duration: 5s;
      -ms-animation-duration: 5s;
       -o-animation-duration: 5s;
          animation-duration: 5s;
  -webkit-animation-iteration-count: infinite;
     -moz-animation-iteration-count: infinite;
      -ms-animation-iteration-count: infinite;
       -o-animation-iteration-count: infinite;
          animation-iteration-count: infinite;
  -webkit-animation-timing-function: linear;
     -moz-animation-timing-function: linear;
      -ms-animation-timing-function: linear;
       -o-animation-timing-function: linear;
          animation-timing-function: linear;

}

@-webkit-keyframes rotate {
    from { -webkit-transform: rotate(360deg); }
    to { -webkit-transform: rotate(0); }
}
@-moz-keyframes rotate {
    from { -moz-transform: rotate(360deg); }
    to { -moz-transform: rotate(0); }
}
@-ms-keyframes rotate {
    from { -ms-transform: rotate(360deg); }
    to { -ms-transform: rotate(0); }
}
@-o-keyframes rotate {
    from { -o-transform: rotate(360deg); }
    to { -o-transform: rotate(0); }
}
@keyframes rotate {
    from { transform: rotate(360deg); }
    to { transform: rotate(0); }
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.7.1/jquery.min.js"></script>
<div class="circle-text">
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="300px" height="100px" viewBox="0 0 300 300" enable-background="new 0 0 300 300" xml:space="preserve">
    <defs>
        <path id="circlePath" d="M 150, 150 m -60, 0 a 60,60 0 0,1 120,0 a 60,60 0 0,1 -120,0 "/>
    </defs>
    <circle cx="150" cy="100" r="75" fill="none"/>
    <g>
        <use xlink:href="#circlePath" fill="none"/>
        <text fill="#FB4D98">
            <textPath xlink:href="#circlePath">ROTATE . ROTATE . ROTATE . ROTATE . </textPath>
        </text>
    </g>
</svg>
</div>

How to generate a pdf using the print view using js

Okay so i have a webpage that is different when i click print. I can save the page to pdf using the print function. This looks good.

The problem is, i need to do this using js. I have a button (download as pdf) that should download the page exactly as shown in the print view.

Is this even possible? Is there a way to only use the print styling?

Hopefully anyone can help 😀

Software for visually impaired [closed]

What are the critical features, advanced functionalities, and innovative technologies that should be integrated into software to enable visually impaired individuals to navigate the web with ease, independence, and an enhanced user experience?


dividuals to navigate the web with ease, independence, and an enhanced user experience?

Angular directive & Storybook

Hi Have the following angular directive & I’m trying to add a storybook for it. But constantly getting error:

template.html:2 NG0303: Can’t bind to ‘uiSpinner’ since it isn’t a known property of ‘div’ (used in the ‘StorybookWrapperComponent’ component template).

  1. If ‘div’ is an Angular component and it has the ‘uiSpinner’ input, then verify that it is included in the ‘@Component.imports’ of this component.
  2. To allow any property add ‘NO_ERRORS_SCHEMA’ to the ‘@Component.schemas’ of this component.
import { Directive, effect, input, TemplateRef, ViewContainerRef } from '@angular/core';

@Directive({
  selector: '[uiSpinner]',
  standalone: true,
})
export class SpinnerDirective {
  isLoading = input<boolean>(false);

  constructor(
    private templateRef: TemplateRef<unknown>,
    private viewContainer: ViewContainerRef
  ) {
    effect(() => this.toggleSpinner());
  }

  private toggleSpinner(): void {
    this.viewContainer.clear();

    if (this.isLoading()) {
      const spinnerElement = document.createElement('div');
      spinnerElement.className = 'spinner-border text-primary';
      spinnerElement.setAttribute('role', 'status');

      const spinnerText = document.createElement('span');
      spinnerText.className = 'visually-hidden';
      spinnerText.textContent = 'Loading...';

      spinnerElement.appendChild(spinnerText);

      this.viewContainer.element.nativeElement.appendChild(spinnerElement);
    } else {
      this.viewContainer.createEmbeddedView(this.templateRef);
    }
  }
}

Storbook file:

import { Meta, moduleMetadata, StoryObj } from '@storybook/angular';

import { SpinnerDirective } from './spinner.directive';

const meta: Meta<SpinnerDirective> = {
  component: SpinnerDirective,
  title: 'SpinnerDirective',
  decorators: [
    moduleMetadata({
      imports: [SpinnerDirective],
    }),
  ],
  argTypes: {
    isLoading: {
      control: { type: 'boolean' },
      description: 'Controls whether the spinner is displayed.',
      table: {
        type: { summary: 'boolean' },
        defaultValue: { summary: 'false' },
      },
    },
  },
} as Meta<SpinnerDirective>;

export default meta;

export const DefaultSpinner: StoryObj<SpinnerDirective> = {
  args: {
    isLoading: false,
  },
  render: (args) => ({
    props: args,
    template: 
      <div class="card card-body" *uiSpinner="isLoading">
        <p>Content will be replaced by the spinner when loading.</p>
      </div>
    ,
  }),
};

I have tried adding NO_ERRORS_SCHEMA but couldn’t sovle the issue except hiding the error message from the console. What am I doing wrong? Appreciate any help on this, thanks!

How to Exclude Microphone Audio While Capturing Screen and System Audio Using JavaScript?

Description:
I am working on a project where I need to:

  • Capture screen content along with system audio (e.g., YouTube,
    videos, etc.).
  • Exclude microphone audio from the captured stream.
  • Optionally allow microphone audio to be included if explicitly
    enabled by the user but process it separately (e.g., send microphone
    audio in a different stream or handle it differently).

Currently, I use navigator.mediaDevices.getDisplayMedia to capture the screen and audio, but the resulting stream always includes both system audio and microphone audio, which interferes with the service functionality.

Here’s my current code:

let timerInterval;
let totalSeconds = 0;

window.startScreenSharing = async function () {
    try {
        const container = document.getElementById('sharedScreen');
        if (!container) {
            console.error('Element with ID "sharedScreen" not found');
            return false;
        }

        const stream = await navigator.mediaDevices.getDisplayMedia({
            video: true,
            audio: true
        });

        const videoElement = document.createElement('video');
        videoElement.srcObject = stream;
        videoElement.autoplay = true;
        videoElement.muted = true; 
        videoElement.controls = false;
        videoElement.style.width = '100%';
        videoElement.style.height = '100%';

        container.innerHTML = '';
        container.appendChild(videoElement);

        window.currentScreenStream = stream;

        startTimer();
        return true;
    } catch (err) {
        console.error('Screen capture error:', err);
        alert('Screen capture failed. Check your browser settings.');
        return false;
    }
};

window.stopScreenSharing = function () {
    try {
        if (window.currentScreenStream) {
            const tracks = window.currentScreenStream.getTracks();
            tracks.forEach(track => track.stop());
            window.currentScreenStream = null;
            console.log("Screen sharing completed.");
        }
        stopTimer();
    } catch (err) {
        console.error('Error ending screen sharing:', err);
    }
};

function startTimer() {
    if (timerInterval) {
        clearInterval(timerInterval);
    }
    const timerElement = document.getElementById('timer');
    totalSeconds = 0;
    timerInterval = setInterval(() => {
        totalSeconds++;
        const minutes = Math.floor(totalSeconds / 60);
        const seconds = totalSeconds % 60;
        timerElement.textContent = `${String(minutes).padStart(2, '0')}:${String(seconds).padStart(2, '0')}`;
    }, 1000);
}

function stopTimer() {
    clearInterval(timerInterval);
    timerInterval = null; 
    const timerElement = document.getElementById('timer');
    timerElement.textContent = "00:00";
}

What I’ve Tried:

  • Enumerating and Stopping Microphones: I attempted to enumerate all
    audioinput devices using navigator.mediaDevices.enumerateDevices()
    and manually stopped their streams using getUserMedia:
function stopAllMicrophoneTracks() {
    navigator.mediaDevices.enumerateDevices().then(devices => {
        devices.filter(device => device.kind === "audioinput").forEach(device => {
            navigator.mediaDevices.getUserMedia({ audio: { deviceId: device.deviceId } })
                .then(stream => {
                    stream.getTracks().forEach(track => track.stop());
                    console.log(`Microphone "${device.label}" stopped.`);
                })
                .catch(error => console.error(`Error stopping microphone: ${error}`));
        });
    });
}

While this does stop active microphone streams, it is problematic because:

  • It could disrupt other applications (e.g., meetings or calls) that
    rely on the microphone.
  • Stopping the microphone is not an ideal solution for separating it
    from the system audio in the shared stream.

Analyzing Streams: I tried analyzing audio streams with AudioContext to detect active audio tracks and distinguish between system audio and microphone audio. I logged audio track activity using:

const audioContext = new (window.AudioContext || window.webkitAudioContext)();
const source = audioContext.createMediaStreamSource(stream);
const analyser = audioContext.createAnalyser();
analyser.fftSize = 256;
const dataArray = new Uint8Array(analyser.frequencyBinCount);

setInterval(() => {
    analyser.getByteFrequencyData(dataArray);
    const volume = dataArray.reduce((sum, value) => sum + value, 0) / dataArray.length;

    if (volume > 10) {
        console.log(`Active stream: ${track.id}, volume: ${volume}`);
    } else {
        console.log(`Silence in stream: ${track.id}`);
    }
}, 100);

This helps detect audio activity, but I still cannot exclude microphone audio from the shared stream programmatically.

Current Challenges:

  • How can I exclude microphone audio entirely from the getDisplayMedia stream while keeping system audio?
  • If microphone audio must be included, how can I:
  • Separate it from system audio.
  • Handle it independently (e.g., in another stream or process it
    differently)?

3.Is there a way to dynamically toggle microphone audio inclusion without disrupting other applications or meeting software (e.g., Google Meet)?

Additional Context:

  • Mixed Audio: When I test with a YouTube video playing, the system
    correctly detects the video audio as part of the shared stream.
    However, my microphone audio is also included, even when I don’t want it.

Environment: This is part of a Blazor project, but the functionality relies on JavaScript.

Ideal Outcome:
Default: Only system audio is captured in the shared stream (exclude microphone).
Optional: Add a toggle to enable/disable microphone audio dynamically.

Any guidance or suggestions for separating or excluding microphone audio would be greatly appreciated!

how can you change the background of an outer div after an observed event happens in the inner div?

i was thankfully helped in another post about changing the background of a div based on what month is called but i want it to change the container div rather than the calendar div itsself.

i tried modifying the code to observe the calendardivnode for the change but then alter the bgcontainerdivnode but its not working.

can anyone please help? this is using the semantic calendar from Adam Shaw

document.addEventListener('DOMContentLoaded', function() {
  var calendarEl = document.getElementById('calendar');
  var calendar = new FullCalendar.Calendar(calendarEl, {
    initialView: 'dayGridMonth'
  });
  calendar.render();

  // Select the node that will be observed for mutations
  const calendarDivNode = document.getElementById("calendar");


  // Options for the observer (which mutations to observe)
  const config = {
    attributes: true,
    childList: true,
    subtree: true
  };

  // Callback function to execute when mutations are observed
  const callback = (mutationList, observer) => {
    let monthFromElement = document.getElementById("fc-dom-1").innerHTML;
    let month = monthFromElement.replace(/[0-9]/g, "").trim();
    changeBackground(month);
  };

  // Create an observer instance linked to the callback function
  const observer = new MutationObserver(callback);

  // Start observing the target node for configured mutations
  observer.observe(calendarDivNode, config);

  // Function to change background
  function changeBackground(month) {
    const colors = {
      January: "url('https://placehold.co/600x400/orange/white')",
      February: "url('assets/images/pgs/month2.png')",
      March: "url('assets/images/pgs/month3.png')",
      April: "url('assets/images/pgs/month4.png')",
      May: "url('assets/images/pgs/month5.png')",
      June: "url('assets/images/pgs/months01.png')",
      July: "url('assets/images/pgs/months01.png')",
      August: "url('assets/images/pgs/months01.png')",
      September: "url('assets/images/pgs/months01.png')",
      October: "url('assets/images/pgs/months01.png')",
      November: "url('assets/images/pgs/months01.png')",
      December: "url('https://placehold.co/600x400/red/green')"
    };

    calendarDivNode.style.backgroundImage = colors[month];
    calendarDivNode.style.backgroundRepeat = "no-repeat";
    calendarDivNode.style.backgroundSize = "100%";
    calendarDivNode.style.backgroundPosition = "right";

  }
  changeBackground(Object.keys(new Date().getMonth()));
});
<script src='https://cdn.jsdelivr.net/npm/[email protected]/index.global.min.js'></script>

<!-- div bg container for calendar -->

<div class="bgcontainer">


  <div id='calendar'></div>

  <!-- end of div bg container for calendar -->


</div>

Unexpected result is return by document.getElementsByTagName and javascript behaviour

HTML :

<html>
   <body>
       <div id="a">
       </div>
   </body>
</html>

Above is my simple html given and i wrote a function to add a children div in each div.

 function appendChildren() {
       var allDivs = document.getElementsByTagName("div");
       console.log(allDivs) // [div#a, a: div#a]
       console.log(allDivs.length) // 1
       for (let i = 0; i < allDivs.length; i++) {
           let newDiv = document.createElement("div");
           allDivs[i].appendChild(newDiv);
       }
   }
   appendChildren();

I was expecting above function will add div in each div but it not working as expected after calling appendChildren() it went to infinite loop and keep load. Help me out to understand how and why its happen it will help me and others who learning javascript. Thanks!!!

How to position text that is left aligned in the middle – animated text

I have to have the text left aligned so that when it animates, the text stays ‘anchored’ and doesn’t push to the left which is what happens if I use text-align: center;

So, while this works, this issue is that I can only get it to work if I set a fixed width on loader-container. It basically needs to be the same width as the text. You can see from this example that the text is not in the middle.

This will also vary as I plan to make the text dynamic so the width will not always be the same. I tried using flex box and some other ideas but could not get it right.

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Dynamic Text Animation</title>
    <style>
        body {
            background-color: #010101;
        }

        .loader-container {
            position: absolute;
            top: 50%;
            left: 50%;
            width: 800px;
            text-align: left;
            transform: translate(-50%, -50%);
        }

        .loader {
            color: #fff;
            font-size: 50px;
            font-weight: 700;
            text-transform: uppercase;
            display: inline-block;
            transition: all 0.2s ease-in-out;
        }

        .glitch {
            opacity: 0.5;
            animation: glitch 0.1s infinite alternate;
        }

        @keyframes glitch {
            0% {
                transform: translateX(0);
            }

            50% {
                transform: translateX(-10px);
            }

            100% {
                transform: translateX(10px);
            }
        }
    </style>
</head>

<body>
    <div class="loader-container">
        <div class="loader" id="loader"></div>
    </div>

    <script>
        var words = ['PRIVACY POLICY'];
        var letters = "dxyhtfgq",
            speed = 150,
            steps = 2,
            loader = document.querySelector('#loader');

        function getRandomWord() {
            var randomWord = words[Math.floor(Math.random() * words.length)];
            return randomWord;
        }

        function getRandomLetter() {
            var randomLetter = letters[Math.floor(Math.random() * letters.length)];
            return randomLetter;
        }

        function randomWordLoop() {
            var word = getRandomWord();
            var textLength = word.length;

            for (var i = 0; i < textLength; i++) {
                (function(i, word) {
                    letterAppear(i, word);
                })(i, word);
            }

            function letterAppear(i, word) {
                setTimeout(function() {
                    randomLetters(i, word);
                }, speed * i);
            }

            function randomLetters(i, word) {
                for (var j = 0; j <= steps; j++) {
                    charsAnim(i, word, j);
                }
            }

            function charsAnim(i, word, j) {
                setTimeout(function() {
                    if (j < steps) {
                        randomChar(i);
                    } else {
                        goodChar(i, word);
                    }
                }, (speed / steps) * j - speed / steps);
            }

            function randomChar(i) {
                var letter = getRandomLetter();
                var oldText = loader.textContent.slice(0, i);
                loader.innerHTML = oldText + `<span class="glitch">${letter}</span>`;
            }

            function goodChar(i, word) {
                var oldText = loader.textContent.slice(0, i);
                loader.innerHTML = oldText + word[i];
            }
        }

        randomWordLoop();
    </script>
</body>

</html>

How to use text from clipboard in JavasScript variable [duplicate]

I am trying to use text from clipboard in JavasScript variable. I read lots of articles but nothing worked.

let myText = 'The text from clipboard is: ';
navigator.clipboard.readText()
.then(text => { myText = myText + ' ' + text; });
myText = myText.toUpperCase();
alert(myText); // THE TEXT FROM CLIPBOARD IS: ...

Maybe it is not working because readText() is asynchronous function?

But it looks like there is no synchronous function for pasting from clipboard… and I need to use text from clipboard in lots of code after it is assigned to variable.

Unable to re render my component in react native

PREMISE
ok so this is my code in a screen named sliding dashboard which is a child component in chatScreen which I used to call all data sources and render a dropdown with these data sources

CODE

const SlidingDashboard = () => {
  const [dashboardData, setDashboardData] = useState(null);
  const [dataSources, setDataSources] = useState([]);
  const [isDropDownDisabled, setIsDropDownDisabled] = useState(false);
  const [dropdownData, setDropdownData] = useState([]);
  const [defaultDropdownValue, setDefaultDropdownValue] = useState(null);
  const [loading, setLoading] = useState(true);
  const [jwtToken, setjwtToken] = useState();
  console.log(jwtToken);
  const [isDropDownLoading, setIsDropDownLoading] = useState(true);
  const [error, setError] = useState(null);
  const [stepsLoading, setStepsLoading] = useState(true);
  const [caloriesLoading, setCaloriesLoading] = useState(true);
  const [heartLoading, setHeartLoading] = useState(true);
  const [isDragged, setIsDragged] = useState(false);
  const slideAnim = useRef(new Animated.Value(height - fixedDistanceFromBottom)).current; // Start at the bottom

  useEffect(() => {
    const fetchMyData = async () => {
      try {
        setLoading(true);
        setIsDropDownLoading(true);
        const token = await AsyncStorage.getItem("jwtToken");
        setjwtToken(token);
        // console.log('Fetched token:', token);
        const sourceResp = await fetch(`${BACKEND_URL}/user/userSources`, {
          method: "GET",
          headers: {
            Authorization: `Bearer ${token}`,
            "Content-Type": "application/json",
          },
        });
        const sourceJson = await sourceResp.json();
        const { success, message } = sourceJson || {};
        // console.log('sourceJson:', sourceJson);
        if (!success) {
          console.log("error 1");
          setError(message || "An error occurred while fetching data");
          return;
        }

        const { data } = sourceJson.data || {};
        if (data && data.sources) {
          const sourceDetails = data.sources.map(({ id, defaultSource }) => ({
            id,
            defaultSource,
          }));
          setDataSources(sourceDetails);

          if (!data.sources.length) {
            setIsDropDownDisabled(true);
            return;
          } else {
            setIsDropDownDisabled(false);
            const serviceMapping = {
              "66f61ffb-7493-49ff-8e64-ce130f4d693b": {
                label: "Connected to Health Connect",
                value: "health connect",
              },
              "86619ffb-b8f6-4a97-a6f9-fda30bca20cd": {
                label: "Connected to Fitbit",
                value: "fitbit",
              },
            };
            const dropdownOptions = sourceDetails.map((source) => ({
              label: serviceMapping[source.id]?.label || "Unknown",
              value: serviceMapping[source.id]?.value || "unknown",
              id: source.id,
            }));
            setDropdownData(dropdownOptions);

            const defaultSource = sourceDetails.find((source) => source.defaultSource);
            // console.log('default source is', defaultSource);
            const defaultValue = defaultSource ? serviceMapping[defaultSource.id]?.value || null : null;
            // console.log('defaultValue is', defaultValue);
            setDefaultDropdownValue(defaultValue);
            setIsDropDownLoading(false);
            const sourceId = defaultSource ? defaultSource.id : sourceDetails[0]?.id;
            // console.log('source id is', sourceId);
            if (sourceId) {
              const dashBoardResp = await fetch(`${BACKEND_URL}/user/dashboard/${sourceId}`, {
                method: "GET",
                headers: {
                  Authorization: `Bearer ${token}`,
                  "Content-Type": "application/json",
                },
              });
              const dashBoardJson = await dashBoardResp.json();
              if (dashBoardJson.success) {
                setDashboardData(dashBoardJson.data);
                setStepsLoading(false);
                setCaloriesLoading(false);
                setHeartLoading(false);
                // console.log('dashboard dataz is', dashBoardJson);
              } else {
                setError(dashBoardJson.message || "Failed to fetch data");
                console.log("API response error:", dashBoardJson.message || "Unknown error");
              }
            }
          }
        } else {
          setIsDropDownDisabled(true); // Handle case where sources key is missing
          setError("No sources available");
        }
      } catch (error) {
        setError("An error occurred while fetching data");
        console.log("Fetch error:", error.message);
      } finally {
        setLoading(false);
        setIsDropDownLoading(false);
      }
    };
    fetchMyData();
  }, []);

  // useEffect(() => {
  //   if (dataSources.length > 0) {
  //     setIsDropDownDisabled(false);
  //   } else {
  //     setIsDropDownDisabled(true);
  //   }
  // }, [dataSources]);

  const getServiceData = async (sourceID, tok) => {
    try {
      setLoading(true);
      setStepsLoading(true);
      setCaloriesLoading(true);
      setHeartLoading(true);
      const dashBoardResp = await fetch(`${BACKEND_URL}/user/dashboard/${sourceID}`, {
        method: "GET",
        headers: {
          Authorization: `Bearer ${tok}`,
          "Content-Type": "application/json",
        },
      });
      const dashBoardJson = await dashBoardResp.json();
      if (dashBoardJson.success) {
        setDashboardData(dashBoardJson.data);
        setStepsLoading(false);
        setCaloriesLoading(false);
        setHeartLoading(false);
        // console.log('dashboard dataz is', dashBoardJson);
      } else {
        setError(dashBoardJson.message || "Failed to fetch data");
        console.log("API response error:", dashBoardJson.message || "Unknown error");
      }
    } catch (error) {
      setError("An error occurred while fetching data");
      console.log("Fetch error:", error.message);
    } finally {
      setLoading(false);
    }
  };
  const panResponder = useRef(
    PanResponder.create({
      onMoveShouldSetPanResponder: (evt, gestureState) => {
        const { dx, dy } = gestureState;
        return Math.abs(dy) > 10;
      },
      onPanResponderMove: (evt, gestureState) => {
        slideAnim.setValue(Math.max(0, Math.min(height - fixedDistanceFromBottom, gestureState.moveY)));
      },
      onPanResponderRelease: (evt, gestureState) => {
        if (dropdownRef.current && typeof dropdownRef.current.close === "function") {
          dropdownRef.current.close(); // Close the dropdown
        }
        const newPosition = gestureState.moveY < height / 2 ? 0 : height - fixedDistanceFromBottom;
        Animated.spring(slideAnim, {
          toValue: newPosition,
          useNativeDriver: false,
        }).start();
      },
    }),
  ).current;
  // ...
};

ISSUE
When I go to Add new device screen and successfully add a new device data sources increase and my dashboard should show this data but this doesnt happen and I have to press r to reload in dev mode or logout and login again in my app to see the new device data ie the screen has to re render once to show correct data

THINGS I TRIED

  1. added dependencies of dataSources to useEffect and hit trial of other dependencies

    Result: no effect of dataSources and other sometimes cause infinite re render

  2. used useFocusEffect from react navigation so that when user focuses on screen then data is fetched

    Result: No effect as even when screen comes in focus data is not refetched

  3. used propDrilling: I thought if screen is not coming in focus and not re rendering so let me pass —data from parent component ChatScreen

    Result: Infinite re render app is not readable: Error: Maximum update depth exceeded. This can happen when a component calls setState inside useEffect,

  4. I thought of one more fix that when dashboard is dragged to height/2 then call the api by modifying the pan responder

    Result: Api doesnt even fetch and only my loading placeholders are shown

So what should I do now to fix or debug this problem