How to display All data with Angular mutual exclusion checkboxes

I’m trying to figure out how to display all identifier values(material table rows) if the ALL checkbox is checked. My current setup filters the rows based on identical values but the ‘ALL’ keyword is not an actual value in the material table.

I think the fix would need to happen here meaning if ALL is checked return […data]

 if (
   !this.identifierFilterValue ||
   this.identifierFilterValue.length === 0
    ) {
   console.log('No Identifier Filters are selected return full data');
   return [...data];
  }

How to test: When the page loads click the search button then toggle the ALL checkbox a few times. When it’s unchecked all rows appear. However I want all the rows to appear if ALL is checked.

Here is my stackblitz.

Alternative to MAC Address for Uniqueness in iOS Bluetooth Connection

I am developing a React Native app for a health monitoring device that connects via Bluetooth and streams live data on iOS. To ensure the uniqueness of the device, I initially planned to use the MAC address. However, I discovered that iOS does not provide access to the original MAC address due to privacy restrictions.
Is there an alternative approach to uniquely identifying a Bluetooth device in iOS? I need a reliable way to distinguish devices while maintaining secure and stable connections.
Any insights or best practices on handling this in iOS would be greatly appreciated.

DevExtreme DataGrid OnRowClick

I’m using a DevExtreme Data Grid inside a master-detail view. I want to open another component (or section) when a row is clicked inside the detail grid. To do this, I’m setting a variable (showAddHorario = true) inside the onRowClick event. However, it doesn’t always work on the first click—it sometimes requires multiple clicks before the state updates.

Here’s the relevant code:

  [dataSource]="salas"
  [showColumnLines]="true"
  [showBorders]="true"
  [rowAlternationEnabled]="true"
  [focusedRowEnabled]="false"
  [selection]="{ mode: 'none' }"
  [masterDetail]="{ enabled: true, autoExpandAll: true, template: 'detailTemplate' }">

//rest of code

  </div>
  <div *dxTemplate="let data of 'detailTemplate'">
    <dx-data-grid
      [dataSource]="data.data.horarios"
      [showBorders]="true"
      [hoverStateEnabled]="true"
      [selection]="{ mode: 'none' }"
      [focusedRowEnabled]="false"
      keyExpr="id"
      (onRowClick)="onRowClick($event, data.data)"
      class="detail-grid">
      <dxi-column dataField="startDate" caption="{{ label.DataInicio }}" [format]="{ type: 'date', format: 'dd/MM/yyyy' }"></dxi-column>
      <dxi-column dataField="endDate" caption="{{ label.DataFim }}" [format]="{ type: 'date', format: 'dd/MM/yyyy' }"></dxi-column>

      @for (day of daysOfWeek; track $index; let dayIndex = $index) {
        <dxi-column ="day" [calculateCellValue]="getScheduleCalculator(dayIndex)"></dxi-column>
      }
    </dx-data-grid>
  </div>

heres the function called:

onRowClick(event: RowClickEvent, sala: GetSalasByServiceResponse): void {
    const horario: GetSalasByServicoHorarioResponse = event.data;
    const horarioData: GetSalaByServicoHorarioDiarioResponse[] = event.data.horariosDiarios || [];
    this.selectedHorarioData = horario;
    this.horariosDiarios = horarioData;
    this.selectedSala = sala;
    this.showAddHorario = true;
  }

Reliably invalidating cache on new version of webpage and/or PWA in 2025

This problem isn’t new, I think it’s as old as browser caching and I’m aware of that from the number of sites I’ve trawled through looking for a solution but the problem remains and I’m a bit lost.

I’ve made a website that can be installed as a Progressive Web App and I want to ensure that users don’t have to do any manual work when I upload a new version of the site to the server.

I have iterated over several potential solutions for this, none of which appear to do anything – if I press f5 and look at my network activity, all the files that I’ve changed are still stubbornly the old versions (unless I clear the cache manually or toggle ‘disable cache’ in the dev options)

Firstly, I use the ‘manifest’ attribute in the HTML tag of my site’s main page.

<html lang="en" manifest="/games/safeword/appcache.php">

and that file’s contents look like this:

<?php 
    header("Cache-Control: max-age=0, no-cache, no-store, must-revalidate");
    header("Expires: Wed, 11 Jan 1984 05:00:00 GMT");
    header('Content-type: text/cache-manifest');
?>CACHE MANIFEST
v0.5.1323434
# Explicitly cached 'master entries'.
CACHE:
MyGame/assets/favicon.ico
Games/MyGame/index.php
dist/mainjs.js
css/main.css

However, as far as I can tell, this file does absolutely nothing – perhaps its been superseded by the PWA framework but I’ve found it difficult to find solid information on that other than a single line on the Wikipedia entry suggesting that this is an obsolete technology and this ought to be handled by the PWA framework (https://en.wikipedia.org/wiki/Cache_manifest_in_HTML5).

I also include several cache invalidation incantations that appear to also have no effect whatsoever:

  <meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate"> 
  <meta http-equiv='expires' content='0'>
  <meta http-equiv='pragma' content='no-cache'>

Assuming that’s the case, I’ve tried to also implement some sort of cache control within the PWA framework but the service worker I’ve written doesn’t seem to be called under normal website operation, so I’m not sure how that would help for checking if updates are available and to then apply those.

This is how I’m going about that in any case (within my web app’s initialisation function) :

if ("serviceWorker" in navigator) {
        navigator.serviceWorker.register("./scripts/install_game.js");        
      }

and the service worker itself looks something like this:

const cacheName = "MyGame";
const cacheContents = [    
    "/dist/webpackedmainfile.js",
    "../assets/someimage.png",
    "../assets/anotherimage.png"
];

self.addEventListener("install", (e) => {
    console.log("[Service Worker] Install");
    e.waitUntil(
      (async () => {
        const cache = await caches.open(cacheName);
        console.log("[Service Worker] Caching all: app shell and content");
        await cache.addAll(cacheContents);
      })(),
    );
  });

and the manifest file for the PWA looks like this:

{
    "id": "/games/mygame/index.php?version=v0.5.20",
    "name": "mygame",
    "start_url": ".",
    "screenshots": [
        {
            "src": "assets/screenshots/ss1.png",
            "sizes": "1280x720",
            "type": "image/png",
            "form_factor": "wide",
            "label": "crown and keyboard safe closed"
        }      
    ],
    "icons": [        
        {
            "src": "assets/logo144.png",
            "type": "image/png",
            "sizes": "144x144",
            "purpose": "maskable"
        },
        {
            "src": "assets/logo144.png",
            "type": "image/png",
            "sizes": "144x144",
            "purpose": "any"
        }
    ],
    "display": "standalone",
    "background_color": "#181200"
}

which actually does work: I can install the page as an app on all the platforms I’ve tested on. However, inspecting in chrome shows nothing cached under that cache name so I don’t think its worked as I intended – files are still cached, just not under my named cache. I’m also not sure what effect any of this has if the webpage isn’t installed as an app – I want a unified system that works for both and I don’t think that will ever update unless its forcibly reinstalled.

The flow I want is that I update my manfiest file’s version number and then something is triggered that either reinstalls everything or selectively reinstalls out of date files. I don’t mind handling that myself but I need to know how. I would like to know how to accomplish this for the PWA version and the website.

filter using react hook form not working?

I am creating a small list using React Hook Form with useFieldArray. I want to filter the list when the user types anything in the search field. However, the filtering is not working. Could you kindly suggest solutions?
Below is my code:
https://playcode.io/2322411

import React from 'react';
import { useForm, useFieldArray, Controller, useWatch } from 'react-hook-form';
import ReactDOM from 'react-dom';

let renderCount = 0;

export function App() {
  const { register, control, handleSubmit, reset, watch } = useForm({
    defaultValues: {
      test: [
        { firstName: 'Bill 1', lastName: 'Luo' },

        { firstName: 'hello2', lastName: 'Luo' },

        { firstName: 'test 3', lastName: 'Luo' },
        { firstName: 'test 4', lastName: 'Luo' },
      ],
    },
  });
  const { fields, append, prepend, remove, swap, move, insert, replace } =
    useFieldArray({
      control,
      name: 'test',
    });

  const onSubmit = data => console.log('data', data);

  const [searchQuery, setSearchQuery] = React.useState('');

  const handleSearchChange = event => {
    setSearchQuery(event.target.value);
  };

  const filteredRows = fields.filter(row =>
    row.firstName.toLowerCase().includes(searchQuery.toLowerCase())
  );

  console.log(JSON.stringify(filteredRows));
  return (
    <>
      <input onChange={handleSearchChange} value={searchQuery} />

      <form onSubmit={handleSubmit(onSubmit)}>
        <ul>
          {filteredRows.map((item, index) => {
            return (
              <li key={item.id}>
                <input
                  {...register(`test.${index}.firstName`, { required: true })}
                />

                <Controller
                  render={({ field }) => <input {...field} />}
                  name={`test.${index}.lastName`}
                  control={control}
                />
              </li>
            );
          })}
        </ul>
      </form>
    </>
  );
}

// Log to console
console.log('Hello console');

Issue is : when I searching “test” it is showing first two rows instead of last two rows .. don’t know why ?

Getting Maximum call stack size exceeded on dispatching API data

I am trying to fetch an API in my React Native project but everytime I try to fetch the API using dispatch, it gives me

Warning: RangeError: Maximum call stack size exceeded

Here is the call:

useEffect(() => {
    
    if (products.length === 0) {
      console.log('[HomeScreen] Dispatching fetchProducts...');
      dispatch(fetchSomeData());
    }
  }, [dispatch, products.length]);

And here is the fetch method:

export const fetchProducts = () => {
  return async dispatch => {
   
    console.log('[fetchProducts] Dispatching FETCH_PRODUCTS_REQUEST');
    dispatch({type: 'FETCH_PRODUCTS_REQUEST'});

    try {
      console.log('[fetchProducts] Fetching data from API...');
      const response = await fetch('https://fakestoreapi.com/products');
      const data = await response.json();

      console.log('[fetchProducts] API Response:', data.length, 'items');

      dispatch({type: 'FETCH_PRODUCTS_SUCCESS', payload: data});
    } catch (error) {
      console.error('[fetchProducts] Error fetching products:', error);
      dispatch({type: 'FETCH_PRODUCTS_FAILURE', error});
    }
  };
};

And here is the reducer:

const productReducer = (state = initialState, action) => {
  switch (action.type) {
    case FETCH_PRODUCTS_REQUEST:
      return {...state, loading: true};
    case FETCH_PRODUCTS_SUCCESS:
      return {...state, loading: false, products: action.payload};
    case FETCH_PRODUCTS_FAILURE:
      return {...state, loading: false, error: action.error};
    default:
      return state;
  }
};

I have also tried store.dispatch instead of just dispatch and I have also tried changing the whole fetchProducts() method by:

const client = axios.create({
  baseURL: 'https://fakestoreapi.com/', 
  timeout: 10000, 
  headers: {
    'Content-Type': 'application/json',
   
  },
});

export const fetchSomeData = (dispatch, getState) => {
  console.log('Fetching data from API...');
  
  try {
    client.get('products').then(data => {
      console.log('Number of todos before loading: ', getState().data.length);
      // Dispatch an action with the todos we received
      dispatch({type: 'FETCH_PRODUCTS_SUCCESS', payload: data});
      // Check the updated store state after dispatching
      const allTodos = getState().data;
      console.log('Number of todos after loading: ', allTodos.length);
    });
  } catch (error) {
    console.error('Error fetching data:', error);
  }
};

but still getting the same error, any ideas what might be going wrong?

Images array with random starting point and fade ins needs smoother transitions

I have a full screen slideshow of four images (in an array) that loads/starts at a random image then cycles through the rest of the images with fade ins. My problem is the fade ins do not fade over the previous image, but fades in from white (or a background color if/when added). I would like a crossfade wherein new image and current image fade smoothly in and out respectively, but I’m at a loss. I can create a crossfading slideshow without a random starting point, so I’m familiar with javascript to CSS, but the javascript code that I’ve stitched together for the added random start has me flailing. I’ve spent hours on stack overflow going through similar issues but none have done the job. My ignorance in javascript is definitely an issue, but I’m usually capable enough to get done what I need to get done. Any help is greatly appreciated, with JS fiddles and-or notes if possible. Thanks in advance, code as follows:

const images = [
  "hero-1.jpg",
  "hero-2.jpg",
  "hero-3.jpg",
  "hero-4.jpg",
];

const imgElement = document.getElementById("myImage");

let currentIndex;

function fadeInImage(index) {
  imgElement.style.opacity = 0;
  imgElement.src = images[index];
  let opacity = 0;
  imgElement.style.opacity = opacity;

  const intervalId = setInterval(() => {
    opacity += 0.01;
    imgElement.style.opacity = opacity;

    if (opacity >= 1) {
      clearInterval(intervalId);
    }

  }, 20);

  currentIndex = index;

}

function playImages() {
  let randomIndex = Math.floor(Math.random() * images.length);
  fadeInImage(randomIndex);

  setInterval(() => {
    currentIndex = (currentIndex + 1) % images.length;
    fadeInImage(currentIndex);
  }, 5000);
}

playImages();
body,
html {
  height: 100%;
  margin: 0;
  padding: 0px;
  outline: none;
  border: 0px;
}

.homehero {
  height: 100%;
}

.homehero img {
  height: 100%;
  width: 100%;
  object-fit: cover;
}
<div class="homehero"><img id="myImage" alt="" /></div>

I can not import any components from my own React component library

I am developing a component library for the components we use in common in our projects.For now only one button has been added.

-> main_folder -> lib -> Button -> index.jsx

export function Button(){
    return <button>Deneme</button>
}

-> main_folder -> lib -> main.js

export { Button } from './components/Button/index.jsx'

I’m getting build with Vite with library mode

-> main_folder -> vite.config.js

import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
import { resolve } from 'path';

// https://vite.dev/config/
export default defineConfig({
  plugins: [react()],
  build: {
    lib: {
      entry: resolve(__dirname, 'lib/main.js'),
      name: 'salaui',
      formats: ['es']
    },
    rollupOptions: {
      external: ['react', 'react-dom', 'react/jsx-runtime'],
    }
  }
})

and this is my package.json

{
  "name": "salaui",
  "private": true,
  "version": "0.0.0",
  "type": "module",
  "scripts": {
    "dev": "vite",
    "build": "vite build",
    "lint": "eslint .",
    "preview": "vite preview",
    "prepublishOnly": "npm run build"
  },
  "dependencies": {
    "react": "^19.0.0",
    "react-dom": "^19.0.0",
    "salaui": "file:"
  },
  "devDependencies": {
    "@eslint/js": "^9.21.0",
    "@types/react": "^19.0.10",
    "@types/react-dom": "^19.0.4",
    "@vitejs/plugin-react": "^4.3.4",
    "eslint": "^9.21.0",
    "eslint-plugin-react-hooks": "^5.1.0",
    "eslint-plugin-react-refresh": "^0.4.19",
    "globals": "^15.15.0",
    "vite": "^6.2.0"
  },
  "main": "dist/salaui.js",
  "files": [
    "dist"
  ]
}

I have a problem like this, when I add the button () I created to a project I created using vite, I can work smoothly, but when I add it to an old project, I cannot use it. I get the following error;

Objects are not valid as a React child (found: object with keys {$$typeof, type, key, props, _owner, _store}). If you meant to render a collection of children, use an array instead.

  • This is from old project (webpack)

enter image description here

this is webpack.dev.js used in this old project

const { merge } = require('webpack-merge');
const common = require('./webpack.common');

module.exports = merge(common, {
  mode: 'development',
  devtool: 'source-map',
  devServer: {
    port: 3100,
    https: true,
    host: 'localhost',
    historyApiFallback: true,
    hot: true,
    headers: {
      'Access-Control-Allow-Origin': '*',
      'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, PATCH, OPTIONS',
      'Access-Control-Allow-Headers': 'X-Requested-With, content-type, Authorization'
    }
  }
});
  • This is from new project (vite)

enter image description here

Could someone help me figure it out? Thanks a lot!

route optimization api shipmentIndex undefined

I’m using the Route Optimization API, but I’m noticing that I’m not getting all my points and that the missing delivery doesn’t have a shipmentIndex.

import { NextResponse } from 'next/server';
import { GoogleAuth } from 'google-auth-library';

const getOptimizedRoutes = async () => {
    try {
        // Setup autenticación para Google API
        const auth = new GoogleAuth();

        const projectId = process.env.GOOGLE_CLOUD_PROJECT_ID;
        const authClient = await auth.getClient();
        const token = await authClient.getAccessToken();

        // Coordenadas de Urvet México (punto de inicio/fin)
        const warehouseLat = 20.7014147;
        const warehouseLng = -103.4553225;

        // Clientes de ejemplo con coordenadas distribuidas en Guadalajara
        // Asegurando que ninguno tenga las mismas coordenadas que el almacén
        const exampleClients = [
            { id: 1, name: "Cliente 1", lat: 20.6597, lng: -103.3496 },  // Centro de Guadalajara
            { id: 2, name: "Cliente 2", lat: 20.6753, lng: -103.3868 },  // Zapopan
            { id: 3, name: "Cliente 3", lat: 20.6408, lng: -103.3249 },  // Tlaquepaque
            { id: 4, name: "Cliente 4", lat: 20.6169, lng: -103.2778 },  // Tonalá
            { id: 5, name: "Cliente 5", lat: 20.6934, lng: -103.4212 }   // Cerca de Urvet pero diferente
        ];

        // Log de clientes originales
        console.log('Clientes originales:', exampleClients.map(c => ({
            id: c.id,
            name: c.name,
            coordenadas: `${c.lat}, ${c.lng}`
        })));

        // Crear shipments con IDs únicos
        const shipments = exampleClients.map((client, index) => ({
            // ID único para cada shipment
            label: `Cliente-${client.id}`,
            deliveries: [
                {
                    arrivalLocation: {
                        latitude: client.lat,
                        longitude: client.lng
                    },
                    duration: "300s"
                }
            ],
            // Agregando algunos campos extras
            loadDemands: {
                weight: {
                    amount: "50"  // 50 kg
                }
            }
        }));

        // Crear vehículo con configuración adecuada
        const vehicles = [
            {
                startLocation: {
                    latitude: warehouseLat,
                    longitude: warehouseLng
                },
                endLocation: {
                    latitude: warehouseLat,
                    longitude: warehouseLng
                },
                // Campos adicionales para mejor optimización
                costPerKilometer: 1.0,
                costPerHour: 30.0,
                loadLimits: {
                    weight: {
                        maxLoad: "1000"  // 1000 kg
                    }
                }
            }
        ];

        const requestBody = {
            model: {
                shipments,
                vehicles,
                globalStartTime: {
                    seconds: Math.floor(Date.now() / 1000)
                },
                globalEndTime: {
                    seconds: Math.floor(Date.now() / 1000) + (8 * 60 * 60)
                }
            },
            // Opciones adicionales para mejor optimización
            considerRoadTraffic: true,
            populateTransitionPolylines: true,
            searchMode: "RETURN_FAST"
        };

        console.log('Request a la API:', JSON.stringify(requestBody, null, 2));

        const response = await fetch(
            `https://routeoptimization.googleapis.com/v1/projects/${projectId}:optimizeTours`,
            {
                method: 'POST',
                headers: {
                    'Authorization': `Bearer ${token.token}`,
                    'Content-Type': 'application/json',
                    'x-goog-user-project': projectId
                },
                body: JSON.stringify(requestBody)
            }
        );

        if (!response.ok) {
            const errorText = await response.text();
            throw new Error(`Error en la API de Google: ${response.status} - ${errorText}`);
        }

        const result = await response.json();
        
        // Log de la respuesta de la API para debug
        console.log('Respuesta de la API:', JSON.stringify(result, null, 2));
        
        // Mapear visitas de vuelta a los clientes usando los índices de shipment
        const clientsInRoutes = [];
        const visitedShipmentIndices = new Set();
        
        // Procesar todas las visitas de todas las rutas
        result.routes.forEach((route, routeIndex) => {
            console.log(`Ruta ${routeIndex + 1}:`);
            
            route.visits.forEach((visit, visitIndex) => {
                // Verificar si esta visita corresponde a un shipment (cliente)
                if (visit.shipmentIndex) {
                    const clientIndex = visit.shipmentIndex - 1;
                    if (clientIndex >= 0 && clientIndex < exampleClients.length) {
                        visitedShipmentIndices.add(clientIndex);
                        clientsInRoutes.push(exampleClients[clientIndex]);
                        
                        console.log(`  Visita ${visitIndex + 1}: Cliente ${exampleClients[clientIndex].id} (${exampleClients[clientIndex].name})`);
                    } else {
                        console.warn(`  Visita ${visitIndex + 1}: Índice de cliente inválido - ${clientIndex}`);
                    }
                } else {
                    console.warn(`  Visita ${visitIndex + 1}: No tiene shipmentIndex`);
                }
            });
        });
        
        // Encontrar clientes que no fueron visitados
        const missingClients = exampleClients.filter((client, index) => 
            !visitedShipmentIndices.has(index)
        );
        
        // Crear el formato de respuesta final
        const routes = result.routes.map((route, index) => {
            // Extraer solo los clientes de esta ruta basado en los shipmentIndex
            const routeClients = route.visits
                .filter(visit => visit.shipmentIndex)
                .map(visit => {
                    const clientIndex = visit.shipmentIndex - 1;
                    if (clientIndex >= 0 && clientIndex < exampleClients.length) {
                        return exampleClients[clientIndex];
                    }
                    return null;
                })
                .filter(Boolean);
                
            // Crear waypoints para esta ruta
            const waypoints = [
                // Punto inicial (depósito)
                {
                    location: [warehouseLng, warehouseLat],
                    client: "Urvet México",
                    weight: 0
                },
                // Clientes en esta ruta
                ...routeClients.map(client => ({
                    location: [client.lng, client.lat],
                    client: client.name,
                    id: client.id,
                    weight: 50 // Peso fijo de ejemplo
                })),
                // Punto final (depósito)
                {
                    location: [warehouseLng, warehouseLat],
                    client: "Urvet México",
                    weight: 0
                }
            ];
            
            return {
                vehicle_id: `Vehículo ${index + 1}`,
                waypoints: waypoints,
                clients: routeClients,
                totalClients: routeClients.length
            };
        });

        // Asegurar que todos los clientes estén asignados a una ruta
        if (missingClients.length > 0) {
            console.warn('¡ADVERTENCIA! Clientes faltantes:', missingClients.map(c => ({
                id: c.id,
                name: c.name,
                coordenadas: `${c.lat}, ${c.lng}`
            })));
        } else {
            console.log('¡ÉXITO! Todos los clientes han sido incluidos en las rutas.');
        }

        return {
            success: true,
            routes: routes,
            summary: {
                totalClients: exampleClients.length,
                totalRoutes: routes.length,
                clientsPerRoute: routes.map(r => ({
                    vehicle: r.vehicle_id,
                    clientCount: r.totalClients,
                    clients: r.clients.map(c => c.id)
                })),
                missingClients: missingClients.length > 0 ? missingClients.map(c => ({
                    id: c.id,
                    name: c.name,
                    coordinates: [c.lng, c.lat]
                })) : []
            }
        };
    } catch (error) {
        console.error('Error en optimización de rutas:', error);
        throw error;
    }
}

export async function GET() {
    try {
        const result = await getOptimizedRoutes();
        return NextResponse.json(result);
    } catch (error) {
        console.error('Error en el procesamiento:', error);
        return NextResponse.json({
            success: false,
            error: error.message
        }, { status: 500 });
    }
} 

Ruta 1:
Visita 1: Cliente 4 (Cliente 4)
Visita 2: Cliente 1 (Cliente 1)
Visita 3: No tiene shipmentIndex
Visita 4: Cliente 2 (Cliente 2)
Visita 5: Cliente 3 (Cliente 3)
¡ADVERTENCIA! Clientes faltantes: [ { id: 5, name: ‘Cliente 5’, coordenadas: ‘20.6934,
-103.4212’ } ]

How to Export Chart Data from React Plotly.js to Excel on Button Click?

I’m developing a React application with multiple charts using the Plotly.js library. I want to implement a feature where users can download the data used to generate the charts in an Excel file.

Currently, I have a button labeled “Export to Excel”, and when it’s clicked, I want the underlying data (that was used to render the chart) to be downloaded as an Excel file.

What I’ve tried:
I know that Plotly.js exposes the chart data via plotly.react or plotly.js’s data property.

I’ve explored libraries like xlsx to create Excel files, but I’m facing error after installing the dependencies since we are using vite in the application.

What I need help with:
How can I extract the data from Plotly.js (e.g., the traces) and format it into a downloadable Excel file when the user clicks the “Export to Excel” button?

If you have any specific code snippets or examples using xlsx or other libraries to achieve this, that would be helpful.

Additional Notes:

The charts are created dynamically, so I want to ensure that the data changes are captured at the moment the export button is clicked.

I am using react-plotly.js as the wrapper for Plotly in React.

If possible, I’d like to keep the export process as simple as possible.

The component is getting dragged when i try to select the text – React

<LabelCard
      identifier={identifier}
      type={LabelType.Default}
      defaultPosition={defaultPosition}
      $expandedOffset={expandedOffset}
      locked={locked}
      selectedToolTypeProp={selectedToolType}
      isExpanded={isExpanded}
      originalPosRef={originalPosRef}
      cardRef={cardRef}
    >
      <Content ref={cardRef}>
        <Title selected={isSelected}>{title}</Title>
        {!isMobile && <SubTitle selected={isSelected}>({subtitle})</SubTitle>}
        {isMobile && isExpandable && (
          <InfoButton onClick={onExpand}>
            <Icon name={Icons.Info} selected={isExpanded} />
          </InfoButton>
        )}
        {description.length > 0 && (
          <DescriptionContent
            ref={descriptionRef}
            expanded={isExpanded}
            expandedHeight={expandedHeight}
          >
            <Description>{description}</Description>
          </DescriptionContent>
        )}
      </Content>
</LabelCard>

This is my component where we render LabelCard inside which i have a hook responsible for dragging.
inside this hook i have mouseDown function:

function mouseDown(e: { clientX: number; clientY: number }) {
      if (!card) {
        return;
      }

      startX = e.clientX;
      startY = e.clientY;
      initialX = card.offsetLeft;
      initialY = card.offsetTop;

      document.addEventListener('mousemove', mouseMove);
      document.addEventListener('mouseup', mouseUp);
    }

I tried to check:

if (cardRef?.current && cardRef.current.contains(e.target as Node)) {
        return;
      }

This prevents dragging even when i click on some blank space. This blank space is typically part of the text itself like whitespace so maybe thats why i can not drag the label altogether even when i am not clicking on text.
Is there any solution to prevent dragging when i am selecting the text? while also being able to drag when i click on the blank space?
(I also tried to check if click was on TEXT NODE but it seems as it is not able to differentiate between text and space).

Two simultaneously events in Javascript [closed]

I have two simultaneously events

document.addEventListener("DOMContentLoaded", function() {
 Array.from(popUps).forEach((el, index) => {
  const listener = () => {
        let trParent = el.parentNode;
        popUpsChilds[index].classList.toggle("show");
        tableThMain.classList.toggle("toggle-goods-popup-for-head");
        el.classList.toggle("toggle-goods-popup-for-cell");
        trParent.classList.toggle("tr-height");
       
    }

    el.addEventListener("mouseover", listener, false);
    el.addEventListener("mouseout", listener, false);
 });
});

Sometimes, when page may be is not loaded completely, “mouseout” couldn’t happen. But i’ve putted DOMContentLoaded event.
What should I do with it?

Query Selector Ref in React returns empty NodeList when trying to access children element

I have some content that I dynamically inject onto the DOM using dangerously set inner HTML. When I reference it using a Ref, and query it, the NodeList is always empty, but when I look at the just sidebarContent.current, the NodeList is not empty.

Why does this happen?

import React, { useEffect, useState } from 'react';

const PostSideBar = ({ sidebarContent }) => {
    const [childNodes, setChildNodes] = useState([]);

    useEffect(() => {
        if (sidebarContent.current) {
            const h2Elements = sidebarContent.current.querySelectorAll('h2');
            setChildNodes(h2Elements);
            console.log(h2Elements); // Check the h2 elements
        }
    }, [sidebarContent]);

    return <div>PostSideBar</div>;
};

export default PostSideBar;

conerting text to worshiptools format using javascript

Im trying to use javascript to convert ultimate guitar.com formatting to worshiptools/chordpro as im going to use the javascript code in gdevelop5 to make a webapp for my church to utilise

I tried writing it many ways but its not exactly putting the text inline but my code outputs only

[G]           [D]          [Em]
Amazing grace, how sweet the sound
[G]          [D]           [C]
That saved a wretch like me

i Tried This

function convertUltimateGuitarToWorshipTools(ultimateGuitarText) {
    // Split input text into lines (songs may have multiple lines of chords/lyrics)
    const lines = ultimateGuitarText.split('n');

    const worshipToolsText = lines.map(line => {
        // This pattern finds the chords, which are typically words in uppercase or lowercase
        const chordPattern = /b([A-G][#b]?(m|maj|min|sus|dim|aug)?)b/g;
        
        // Replace each found chord with the WorshipTools format (i.e., [chord] )
        return line.replace(chordPattern, (match, chord) => {
            return `[${chord}]`;
        });
    }).join('n'); // Join the lines back into a single string

    return worshipToolsText;
}

// Example Ultimate Guitar input (with chords above the lyrics)
const ultimateGuitarText = `
G           D          Em
Amazing grace, how sweet the sound
G          D           C
That saved a wretch like me
`;

// Convert the Ultimate Guitar text to WorshipTools format
const worshipToolsText = convertUltimateGuitarToWorshipTools(ultimateGuitarText);

// Output the converted text
console.log(worshipToolsText);

but i need this to be the output

[G]Amazing grac[D]e, how swee[Em]t the sound
[G]That saved [D]a wretch lik[C]e me