AI Bot with stopGenerating element

Hello im working on some project that includes AI. User send an message to AI API and AI response. This is not my problem it work very well. But we have some stop generating button. It’s like the chatGPT when user touch to the Stop Generating button the response should be left incomplete and should appear like that in the ui. Like the bots message is “Hello!” but if user touch stop scrolling button ben index is in e letter it should be shown as “He”. Actually it works too but i get the full message after. So both “He” and “hello!” are output in the ui. I just want “He” text. Can someone help me?

const connectSocket = async () => {
    try {
      const token = await AsyncStorage.getItem('userToken');
      if (!token) {
        console.log("JWT Token bulunamadı");
        return;
      }

      // Eğer önceki socket varsa temizle
      if (socketRef.current) {
        socketRef.current.removeAllListeners();
        socketRef.current.disconnect();
      }

      socket = io("/////", {
        extraHeaders: {
          Authorization: `Bearer ${token}`,
        },
      });

      socketRef.current = socket;

      socket.on('connect', () => {
        console.log("Socket bağlantısı başarılı");
        // Sadece mevcut bir chatId varsa odaya katıl
        if (currentChatId) {
          //console.log("Odaya katılınıyor:", currentChatId);
          socket.emit('join_chat', { chatId: currentChatId });
        }
      });

      socket.on('connect_error', (error) => {
        console.error('Socket bağlantı hatası:', error);
      });

      socket.on('ai_response', (data) => {
        if (data.message) {
          const { text, isUser, sendDate, chatId } = data.message;
          //console.log("AI yanıtı alındı:", {
          //  receivedChatId: chatId,
          //  currentChatId,
          //  isUser,
          //  messageLength: text.length
          //});
       
          // Sadece ilgili chat odasına ait mesajları işle
          if (chatId === currentChatId && !isUser) {
            //console.log("Mesaj işleniyor - Aynı oda ID'si");
            setIsTyping(true);
            setTypingText('');
            animateTyping(text);
          } else {
            console.log("Mesaj işlenmiyor - Farklı oda ID'si veya kullanıcı mesajı");
          }
        } else if (data.error) {
          console.log("AI yanıt hatası:", data.error);
          Toast.show({
            type: 'error',
            text1: 'Error',
            text2: data.error,
            position: 'bottom',
          });
        }
      });
    } catch (error) {
      console.error('Token yükleme hatası:', error);
    }
  };

  connectSocket();


  // Cleanup function - ekran kapandığında çalışır
  return () => {
    //console.log("Chat Detail Screen kapatılıyor");
    // Odadan çık
    if (socketRef.current && currentChatId) {
      //console.log("Odadan çıkış yapılıyor:", currentChatId);
      socketRef.current.emit('leave_chat', { chatId: currentChatId });
    }
    // Socket bağlantısını kapat
    if (socket) {
      //console.log("Socket bağlantısı kapatılıyor");
      socket.removeAllListeners();
      socket.disconnect();
    }
    if (socketRef.current) {
      socketRef.current.removeAllListeners();
      socketRef.current.disconnect();
    }
  };
}, [currentChatId]); // Sadece currentChatId değiştiğinde yeniden bağlan

const addMessage = (message, isUser, sendDate) => {
  const newMessage = {
    text: message,
    isUser: isUser,
    sendDate: sendDate || new Date().toISOString(),
  };

  setMessages((prevMessages) => [...prevMessages, newMessage]);
  setShowLogoAndBoxes(false);

  setTimeout(() => {
    scrollViewRef.current?.scrollToEnd({ animated: true });
  }, 100);
};

const sendMessage = async () => {
  const text = inputText.trim();
  if (!text) return;

  //console.log("Mesaj gönderme işlemi başlatıldı");
  const sendDate = new Date().getTime();
 
  // Eğer mevcut bir chatId yoksa, yeni bir chat oluştur
  let chatIdToUse = currentChatId;
  if (!chatIdToUse) {
    //console.log("Yeni chat oluşturuluyor");
    try {
      const token = await AsyncStorage.getItem('userToken');
      if (!token) {
        console.error('Token bulunamadı');
        return;
      }

      const chatData = {
        categoryId: categoryId,
        content: text
      };

      const response = await DatabaseManager.createChat(chatData, token);
      if (response.success) {
        chatIdToUse = response.data.chatId;
        setCurrentChatId(chatIdToUse);
        //console.log("Yeni chat oluşturuldu:", chatIdToUse);


        // Odaya katılma
        if (socketRef.current) {
          //console.log("Yeni odaya katılınıyor:", chatIdToUse);
          socketRef.current.emit('join_chat', { chatId: chatIdToUse });
          // Kısa bir bekleme süresi ekleyelim socket'in odaya katılması için
          await new Promise(resolve => setTimeout(resolve, 500));
          //console.log("Odaya katılma tamamlandı");
        }
      } else {
        console.error("Chat oluşturulamadı:", response.error);
        return;
      }
    } catch (error) {
      console.error("Chat oluşturma hatası:", error);
      return;
    }
  } else {
    console.log("Mevcut chat kullanılıyor:", chatIdToUse);
  }

  // Mesajı ekle ve socket üzerinden gönder
  addMessage(text, true, sendDate);
 
  const messageData = {
    message: {
      text: text,
      categoryId: categoryId,
      chatId: chatIdToUse,
      sendDate: sendDate
    }
  };

  //console.log('Socket üzerinden mesaj gönderiliyor:', messageData);
  if (socketRef.current) {
    socketRef.current.emit('send_message', messageData);
    //console.log("Mesaj gönderildi");
  } else {
    console.error('Socket bağlantısı bulunamadı');
    Toast.show({
      type: 'error',
      text1: 'Error',
      text2: 'Connection error. Please try again.',
      position: 'bottom',
    });
  }
  setInputText('');
};

const animateTyping = (text) => {
  setIsTyping(true);
  setTypingText('');
  let index = 0;
  let currentInterval = null;

  currentInterval = setInterval(() => {
    if (index < text.length && !stopGenerating) {
      setTypingText(prevText => {
        const newText = prevText + text[index];
        // Her karakter eklendiğinde scroll yap
        setTimeout(() => {
          scrollToBottom(true);
        }, 50);
        return newText;
      });
      index++;
    } else {
      clearInterval(currentInterval);
      setIsTyping(false);

      if (!stopGenerating) {
        const sendDate = new Date().toISOString();
        addMessage(text, false, sendDate);
      }
      setTypingText('');
      setStopGenerating(false);
    }
  }, 50);

  return () => {
    if (currentInterval) {
      clearInterval(currentInterval);
    }
  };
};

const handleStopGenerating = () => {
  console.log("Stop generating başlatıldı");
  setStopGenerating(true);
  setIsTyping(false);
 
  if (typingText) {
    console.log("Yarım kalan mesaj kaydediliyor");
    const sendDate = new Date().toISOString();
    addMessage(typingText, false, sendDate);
  }
  setTypingText('');
};


{isTyping && (
              <View style={styles.botMessageContainer}>
                <View style={styles.botMessage}>
                  <Text style={styles.botMessageText}>{typingText}</Text>
                </View>
                <View style={styles.actionButtons}>
                  <TouchableOpacity
                    onPress={() => copyToClipboard(typingText)}>
                    <CopyIcon
                      width={17}
                      height={17}
                      style={styles.actionIcon}
                    />
                  </TouchableOpacity>
                  <TouchableOpacity onPress={() => shareMessage(typingText)}>
                    <ShareIcon
                      width={17}
                      height={17}
                      style={styles.actionIcon}
                    />
                  </TouchableOpacity>
                </View>
              </View>
            )}
            {isTyping && (
              <TouchableOpacity
                style={styles.stopGeneratingButton}
                onPress={handleStopGenerating}>
                <View style={styles.stopGeneratingContent}>
                  <View style={styles.stopDot} />
                  <Text style={styles.stopGeneratingText}>
                    {t('Stop generating...')}
                  </Text>
                </View>
              </TouchableOpacity>
            )}

My PWA is not installable. Ive clearly made some error, need help from a human [closed]

heres the site online…

heres all the source code on git

I copied it from this tutorial

On both iOS and Android I dont see any install option.
Also I added an explicit install button from this SO post, but it doesnt seem to do anything on mobile

Ive clearly made a critical error but I have no idea where. I have never made a PWA before. It’d probably be really obvious to someone with any experience.

`formData` not setting `defaultValue` in react select input

I am working with a React form component, and I have a select field inside it. When the form is submitted, I want to preserve the selected value (the default value) in the select field. However, after the form is submitted, the default value resets to the first option, which is not what I want.

This issue seems to be happening only with the <select> field, as similar behavior works with text inputs (they retain their values correctly).

How can I prevent the select field from resetting its value after the form is submitted whilst using useActionState?

export default function Form() {
  const [formData, formAction, isPending] = useActionState(async (previous, current) => current);

  return (
    <form action={formAction}>
      <select name="example" defaultValue={formData?.get('example')}>
        <option value='1'>1</option>
        <option value='2'>2</option>                       
      </select>
      <button type='submit'>Submit</button>
    </form>
  );
}

How to properly pass authentication to cloud functions when calling from chrome extension

this is cloud function im using to access the firestore

const functions = require("firebase-functions");
const admin = require("firebase-admin");
admin.initializeApp();
exports.getUserCredits = functions.https.onCall(async (data, context) => {
    if (!context.auth) {
        throw new functions.https.HttpsError("unauthenticated", "User must be signed in.");
    }
    const uid = context.auth.uid;
    const userRef = admin.firestore().doc(`users/${uid}`);
    try {
        const docSnap = await userRef.get();
        if (!docSnap.exists) {
            throw new functions.https.HttpsError("not-found", "User document does not exist.");
        }
        const userData = docSnap.data();
        const credits = userData?.credits ?? 0; // Default to 0 if undefined
        return { credits };
    } catch (error) {
        console.error("Error getting user credits:", error);
        if (error.code && error.code.startsWith("permission-denied")) {
            throw new functions.https.HttpsError("permission-denied", "Access to Firestore denied.");
        }
        throw new functions.https.HttpsError("internal", "An unexpected error occurred.");
    }
});

I’m sending request from chrome extension and user is logged in but from cloud function I get the error:

“Error getting user credits from Cloud Function: FirebaseError: User must be signed in.”

export async function getUserCredits(): Promise<number | undefined> {
  const auth = Auth.getAuth(); // Initialize Firebase Auth
  const user = auth.currentUser;

  if (!user) {
    console.log("No user is logged in.");
    return undefined;
  }

  // Initialize Firebase Functions
  const functions = getFunctions();

  try {
    // Call the Firebase Cloud Function
    const getUserCreditsFunction = httpsCallable(functions, "getUserCredits");

    // Call the function, passing the necessary data if needed
    const result = await getUserCreditsFunction();

    // Get the 'credits' from the result returned by the Cloud Function
    const credits = (result.data as { credits: number })?.credits ?? undefined;

    return credits;
  } catch (error) {
    console.log("Error getting user credits from Cloud Function:", error);
    return undefined;
  }
}

User is logged in extension, I have user data in “if” thats why its calling the functions. I tried almost anything I could. I can access firestore directly from extension but not from cloud functions.

Frontend fails to fetch data from Backend

I am using React for my front end and Node.js for my backend. My main.py is under my backend folder and App.js under frontend. My backend works fine fine when I run uvicorn main:app –reload –host 127.0.0.1 –port 8000, however front end poses an error in fetch when I run any stock ticker to have the stock data displayed in the frontend. My main.py and App.js are as follows:

main.py

from fastapi import FastAPI
import yfinance as yf
import pandas as pd
from typing import Optional
from fastapi.middleware.cors import CORSMiddleware
from datetime import datetime, timedelta
import logging

# Create a cache for temporary in-memory storage
stock_data_cache = {}
CACHE_EXPIRY_TIME = 10  # Cache expiry time in minutes

app = FastAPI()

#Disable WebSocket logs to debug connectivity issues
logging.getLogger("uvicorn.error").setLevel(logging.ERROR)
logging.getLogger("uvicorn.access").setLevel(logging.ERROR)

# Allow requests from React frontend
app.add_middleware(
    CORSMiddleware,
    allow_origins=["http://localhost:3000"],  # Allow requests from frontend
    allow_credentials=True,
    allow_methods=["*"],  # Allow all HTTP methods
    allow_headers=["*"],  # Allow all headers
)

@app.get("/stocks/{symbol}")
def get_stock_data(symbol: str, start: str = "2023-01-01", end: str = "2024-01-01"):
    """Fetch historical stock data from Yahoo Finance with temporary in-memory cache"""

    # Check if the symbol is provided (non-empty)
    if not symbol:
        return {"error": "Symbol is required. Please provide a valid stock symbol."}

    # Check if the data is already cached and still valid
    if symbol in stock_data_cache:
        cached_data, last_fetched = stock_data_cache[symbol]
        # If cached data is older than the expiry time, invalidate it
        if datetime.now() - last_fetched < timedelta(minutes=CACHE_EXPIRY_TIME):
            print("Returning cached data.")
            return {"data": cached_data}

    try:
        print(f"Fetching data for {symbol} from {start} to {end}...")
        data = yf.download(symbol, start=start, end=end)
        
        if data.empty:
            return {"error": f"No data found for symbol '{symbol}'. Please check the symbol and try again."}

        # Convert DataFrame to JSON
        data_json = data.to_json(orient="split")
        
        # Cache the data with the current time
        stock_data_cache[symbol] = (data_json, datetime.now())

        return {"data": data_json}

    except Exception as e:
        # Catch any errors during data fetching or processing
        print(f"Error: {e}")
        return {"error": f"An error occurred while processing the request: {str(e)}"}

if __name__ == "__main__":
    import uvicorn
    uvicorn.run(app, host="127.0.0.1", port=8000)

App.js

import React, { useState } from "react";

const API_BASE_URL = "http://127.0.0.1:8000";  // Backend URL

function App() {
    const [symbol, setSymbol] = useState("");  // Stores user input for stock symbol
    const [data, setData] = useState(null);  // Stores fetched stock data
    const [error, setError] = useState("");  // Stores error messages

    const fetchStock = async () => {
        setError("");  // Clear previous errors
        setData(null);  // Reset data before new request

        if (!symbol) {
            setError("Please enter a stock symbol!");  // Prevent empty input
            return;
        }

        try {
            const requestUrl = `${API_BASE_URL}/stocks/${symbol}`;
            console.log(`Fetching data from: ${requestUrl}`);  // Debugging log

            const response = await fetch(requestUrl);

            console.log("Response Status:", response.status);

            if (!response.ok) {
                throw new Error(`HTTP error! Status: ${response.status}`);
            }

            const result = await response.json();
            console.log("API Response:", result);

            if (result.error) {
                setError(result.error);  // Handle API error response
            } else {
                setData(result.data);  // Store API response
            }
        } catch (error) {
            console.error("Fetch Error:", error);
            setError("Failed to fetch stock data");  // Display generic error
        }
    };

    return (
        <div className="p-4 max-w-lg mx-auto">
            <h1 className="text-xl font-bold mb-4">Stock Market Data</h1>
            <input
                type="text"
                placeholder="Enter Stock Symbol (e.g., AAPL)"
                value={symbol}
                onChange={(e) => setSymbol(e.target.value.toUpperCase())}
                className="border p-2 w-full"
            />

            <button onClick={fetchStock} className="bg-blue-500 text-white p-2 mt-2 w-full">
                Get Stock Data
            </button>

            {error && <p className="text-red-500 mt-2">{error}</p>}

            {data && (
                <pre className="bg-gray-200 p-2 mt-2 overflow-x-auto">
                    {JSON.stringify(data, null, 2)}
                </pre>
            )}
        </div>
    );
}

export default App;

  • I was using axios before but it didn’t work too
  • I added CORS middleware as well in CORSMIddleware but still don’t know what the issue is

I am having issues on adjusting layout on android when soft keyboard appears on screen in react-native

I am working on a react-native app and using “react-native”: “0.73.6”, and I am facing some UI issues when the keyboard appears on the screen in my MessageInboxScreen. Below is the code for the screen:

import React, { useEffect, useRef, useState } from 'react';
import { View, Text, StyleSheet, TouchableOpacity, Image, TextInput, ActivityIndicator, FlatList, Alert, SafeAreaView, } from 'react-native';
import { COLORS } from '../../themes/palette';
import MainCommonHeader from '../../components/headers/MainCommonHeader';
import { moderateScale, scale, verticalScale } from 'react-native-size-matters/extend';

const NewInboxScreen = ({ route, navigation }) => {
    const { data } = route.params || {};
    const [filteredMessages, setFilteredMessages] = useState([]);
    const [loading, setLoading] = useState(true);
    const [messageBody, setMessageBody] = useState('');
    const [sending, setSending] = useState(false); // Track sending state
    const conversationNumber = data;

    const sendSMS = async () => {
        if (!messageBody.trim()) {
            Alert.alert('Error', 'Message body cannot be empty!');
            return;
        }
        setSending(true);
        console.log(`Message sent to +${conversationNumber}:`, messageBody);

        try {
                setFilteredMessages((prevMessages) => [...prevMessages, newMessage]);
                setMessageBody(''); // Clear the TextInput
                setSending(false);
        } catch (error) {
            console.error('Error sending SMS:', error);
            Alert.alert('Error', 'Failed to send SMS');
        } finally {
            setSending(false);
        }
    };

    const renderItem = ({ item }) => {
        const isOutGoing = item.sb === 'out';
        return (
            <TouchableOpacity disabled style={{
                paddingVertical: verticalScale(12),
                paddingHorizontal: scale(12),
                borderWidth: 1,
                width: '100%',
                borderColor: COLORS.SOFT_GREY,
                backgroundColor: isOutGoing ? '#CCDBFD26' : COLORS.WHITE,
                borderRadius: scale(8),
                marginBottom: verticalScale(10),
                alignSelf: item.direction === 'inbound' ? 'flex-start' : 'flex-end',
            }}>
                <View style={{ flex: 1, flexDirection: 'row', alignItems: 'flex-start' }}>
                    {!isOutGoing && <View style={{ width: scale(40), height: scale(40), borderRadius: scale(20), backgroundColor: COLORS.DARK_FADE_40, marginRight: scale(20) }} />}

                    <Text style={{ fontFamily: 'BlinkerRegular', color: COLORS.DARK, fontSize: moderateScale(16, 0.5), textAlign: 'left', flexShrink: 1 }}>{item.mb}</Text>
                </View>
                <Text style={{ fontFamily: 'BlinkerLight', fontSize: moderateScale(15, 0.5), color: COLORS.DARK_GRAY, textAlign: 'right' }}>{new Date(item.sdt).toLocaleString()}</Text>
            </TouchableOpacity>
        );
    };

    return (
        <SafeAreaView style={styles.container}>
            <MainCommonHeader
                leftText="SMS"
                leftSubText={`+${conversationNumber}`}
                goBackIcon="left"
                leftAction={() => navigation.goBack()}
            />
            <View style={styles.subContainer}>
                {loading ? (
                    <ActivityIndicator size="large" color="#0000ff" />
                ) : (
                    <FlatList
                        data={filteredMessages}
                        renderItem={renderItem}
                        keyExtractor={(item, index) => index.toString()}  // Unique key for each item
                        onContentSizeChange={() => flatListRef.current?.scrollToEnd({ animated: true })}
                        onLayout={() => flatListRef.current?.scrollToEnd({ animated: true })} // Ensure scrolling on layout
                    />
                )}

            </View>
            <View style={{ width: '100%', height: verticalScale(185), paddingHorizontal: scale(16), paddingVertical: verticalScale(12), alignSelf: 'center' }}>
                <View style={{ flex: 1, flexDirection: 'row', alignItems: 'center', backgroundColor: COLORS.WHITE, borderRadius: scale(8), borderColor: COLORS.SOFT_GREY, borderWidth: 1, paddingHorizontal: scale(12) }}>
                    <TextInput
                        style={{ flex: 1, height: '100%', paddingHorizontal: scale(16), color: COLORS.DARK, verticalAlign: 'top' }}
                        placeholder="Write new message"
                        placeholderTextColor={COLORS.DARK_FADE_40}
                        multiline
                        value={messageBody}
                        onChangeText={setMessageBody}
                        editable={!sending}  // Disable input when sending
                    />
                    <TouchableOpacity onPress={() => sendSMS()}>
                        <Image source={require('../../assets/images/send.png')} style={{ width: scale(27), height: scale(27) }} />
                    </TouchableOpacity>
                </View>
            </View>
        </SafeAreaView>
    );
};

const styles = StyleSheet.create({
    container: {
        flex: 1,
        backgroundColor: COLORS.OFFWHITE,
    },
    subContainer: {
        flex: 1,
        paddingHorizontal: scale(16),
        paddingVertical: verticalScale(16),
    },
    itemContainer: {
        padding: 16,
        borderBottomWidth: 1,
        borderColor: '#ccc',
    },
    text: {
        fontSize: 16,
        marginVertical: 2,
        color: COLORS.DARK,
    },
});

export default NewInboxScreen;

Now in this screen when the keyboard appears here then the header or say screen layout automatically gets resized. You can see the below screenshots.

  1. This is the actual layout of the screen before opening keyboard.
    This is the actual layout of the screen before opening keyboard.

  2. This is the layout of the screen after opening keyboard.
    enter image description here

you can see the header height gets reduced on opening the keyboard.
Also in my in AndroidManifest.xml I have android:windowSoftInputMode="adjustResize"
and when I change it to android:windowSoftInputMode="adjustPan" then when the keyboard appears my UI looks like:
enter image description here

Here you can see that when keyboard appears it everything is pushed up the header also and the input-box is under the keyboard.
I also tried using KeyboardAvoidingView but it is not working as expected. So please help here how can I solve this issue. Thank you.

Using tone.js to play a wav file at specific intervals

When I attempt to use tone.js’s Player to repeatedly play a wav file at specific intervals (i.e., at the start, the first measure, and the fourth measure), the first few tones are at the correct intervals but subsequent tones are played at the beginning of every interval.

My html file has a button to start the playing:

<button id="playIt">Play</button>

Here is my javascript/jquery:

$(document).ready(function () {
    $("#playIt").click(function () {
        if (Tone.context.state != "running") {
            Tone.start();
        }

        playNotes();
    });
});

const player = new Tone.Player({
    url: "/tick.mp3",
    loop: true,
    autostart: false
}).toDestination();

Tone.Transport.bpm.value = 140;

// Schedule the player to start at specific times
Tone.Transport.schedule(time => {
    player.start(time);
}, "0:0:0"); // Play at the start

Tone.Transport.schedule(time => {
    player.start(time);
}, "0:1:0"); // Play at 1st measure

Tone.Transport.schedule(time => {
    player.start(time);
}, "0:4:0"); // Play at 4th measure

async function playNotes() {
    Tone.Transport.start();
}

If I turn off looping, it plays once, correctly. When it loops, it plays correctly once and then plays the tone on every measure.

Thanks for your help!

Canceling a react-query mutation

I have a mutation that comprises of a sequence of long-running actions:

useMutation({
  mutationFn: async () => {
    await firstTask()
    await secondTask()
    await thirdTask()
  },
  ...
})

I know I can’t cancel the individual tasks once they are in-flight, but I’d like to prevent the execution of any of the tasks that haven’t been executed yet once a ‘Cancel’ button elsewhere in the UI has been clicked.

One option is to pass a ref to mutate and check it in between tasks. If it’s false continue. If it’s true exit. Then set the ref to false from the cancel button.

How do I make my virtual scrolling less choppy or make it more smooth?

I’m using a map named “buffer” to load the data as I scroll down, so once we have all the data in the buffer the scrolling is smooth but the initial fetching and rendering rows is not smooth.

_updateVisibleRows() {
    const tableBody = document.querySelector(".table-wrapper tbody");
    if (!tableBody) return;

    const startIndex = Math.floor(this.scrollTop / this.averageRowHeight);
    const endIndex = Math.min(startIndex + this.limit, this.totalRowsInTable);

    const topSpacerHeight = startIndex * this.averageRowHeight;
    const bottomSpacerHeight =
      (this.totalRowsInTable - endIndex) * this.averageRowHeight;

    let topSpacer = document.querySelector("#top-spacer");
    let bottomSpacer = document.querySelector("#bottom-spacer");

    if (!topSpacer) {
      topSpacer = document.createElement("tr");
      topSpacer.id = "top-spacer";
    }
    if (!bottomSpacer) {
      bottomSpacer = document.createElement("tr");
      bottomSpacer.id = "bottom-spacer";
    }

    topSpacer.style.height = `${topSpacerHeight}px`;
    bottomSpacer.style.height = `${bottomSpacerHeight}px`;

    //tableBody.innerHTML = "";
    tableBody.appendChild(topSpacer);

    const fragment = document.createDocumentFragment();
    for (let i = startIndex; i < endIndex; i++) {
      const rowData = this.buffer.get(i); // Get row from buffer
      if (rowData) {
        const row = this.page.contentBuilder.buildRow(rowData, false);
        fragment.appendChild(row);
      }
    }

    tableBody.appendChild(fragment);

    tableBody.appendChild(bottomSpacer);
  }

I use spacers or ghost rows as some may call to make a realistic scroll height. And the scroll event is based on scrollTop so whenever the scrollTop value changes by a small or even a change in decimal place the scroll event will fire and rows will be rendered. I’m not sure why the initial scroll is so choppy. Can someone suggest me a better algorithm or a way to do it. Besides I’m only using built-in function and no cdn.

How can I optimize my full-screen rain animation to balance GPU/CPU load and maintain control?

I’m developing a full-screen rain animation using HTML, CSS, and JavaScript. I use a single <canvas> element with a requestAnimationFrame loop to animate 500 raindrops. Despite this, my GPU memory usage remains high and load times increase at high FPS. Below is a minimal code snippet that reproduces the issue:

const canvas = document.getElementById('rainCanvas');
const ctx = canvas.getContext('2d');
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;

const numDrops = 500;
const drops = [];
for (let i = 0; i < numDrops; i++) {
  drops.push({
    x: Math.random() * canvas.width,
    y: Math.random() * canvas.height,
    speed: 2 + Math.random() * 4,
    length: 10 + Math.random() * 10
  });
}

function drawRain() {
  ctx.clearRect(0, 0, canvas.width, canvas.height);
  ctx.strokeStyle = "rgba(255, 255, 255, 0.5)";
  ctx.lineWidth = 2;
  
  drops.forEach(drop => {
    ctx.beginPath();
    ctx.moveTo(drop.x, drop.y);
    ctx.lineTo(drop.x, drop.y + drop.length);
    ctx.stroke();
    drop.y += drop.speed;
    if (drop.y > canvas.height) {
      drop.y = -drop.length;
    }
  });
  
  requestAnimationFrame(drawRain);
}

drawRain();
body, 
html { 
  margin: 0; 
  padding: 0; 
  overflow: hidden; 
  background-color: black;
}

canvas { 
  display: block; 
}
<canvas id="rainCanvas"></canvas>

How can I optimize this canvas-based rain animation to reduce GPU load while maintaining smooth performance?

React msal sessionStorage to localStorage login system

I’m currently working on a React application where I initially used sessionStorage to store user session data. However, I need to switch to localStorage because I have some links that open in a new tab (same website), and using sessionStorage requires the user to log in again in the new tab.

Here’s the change I made:

cacheLocation: “localStorage”,

While sessionStorage was working fine, after switching to localStorage, I encounter an issue where, after a successful login (confirmed via console logs), I am immediately signed out.

Has anyone faced a similar issue or can provide guidance on what might be causing this problem? Any help would be greatly appreciated!

Additional information about my setup:

authConfig.ts file:
used for configuring my settings

import { LogLevel } from "@azure/msal-browser";

/**
 * Configuration object for MSAL (Microsoft Authentication Library).
 * This object is used to initialize the MSAL instance with the necessary settings.
 */
export const msalConfig = {
  /**
   * Authentication parameters.
   */
  auth: {
    /**
     * The client ID of your application. This is a mandatory field.
     * @example "xxxxxxx"
     */
    clientId: "xxxxxxx",

    /**
     * The authority URL for your tenant. Replace the placeholder with your tenant subdomain.
     * @example "https://xxxxx.ciamlogin.com/"
     */
    authority: "https://xxxxx.ciamlogin.com/",

    /**
     * The redirect URI after a successful login. This should be registered in the Microsoft Entra admin center/App Registration.
     * @example "https://xxxxx.xxxxx.com/"
     */
    redirectUri: "http://xxxxx:xxxxx/",

    /**
     * The URI to navigate to after logout.
     * @example "/"
     */
    postLogoutRedirectUri: "/",

    /**
     * If true, will navigate back to the original request location before processing the auth code response.
     * @default false
     */
    navigateToLoginRequestUrl: true,
  },

  /**
   * Cache configuration parameters.
   */
  cache: {
    /**
     * Specifies where the cache should be stored. Options are "localStorage" or "sessionStorage".
     * @default "sessionStorage"
     */
    cacheLocation: "localStorage",

    /**
     * If true, the authentication state will be stored in cookies.
     * @default false
     */
    storeAuthStateInCookie: false,
  },

  /**
   * System configuration parameters.
   */
  system: {
    /**
     * Logger options for MSAL.
     */
    loggerOptions: {
      /**
       * Callback function for logging messages.
       * @param level - The log level (Error, Info, Verbose, Warning).
       * @param message - The log message.
       * @param containsPii - Indicates if the message contains Personally Identifiable Information (PII).
       */
      loggerCallback: (level: LogLevel, message: string, containsPii: boolean) => {
        if (containsPii) {
          return;
        }
        switch (level) {
          case LogLevel.Error:
            console.error(message);
            return;
          case LogLevel.Info:
            console.info(message);
            return;
          case LogLevel.Verbose:
            console.debug(message);
            return;
          case LogLevel.Warning:
            console.warn(message);
            return;
        }
      },
    },
  },
};

export const accessTokenRequest = {
  scopes: ["api://xxxx-xxxxx/xxxx"],
};

export const loginRequest = {
  scopes: ["User.Read"],
};

authProvider.tsx
Used to validate the login and set the active account.

import { AuthenticationResult, EventType, PublicClientApplication } from "@azure/msal-browser";
import { msalConfig } from "./authConfig";
import { ReactNode } from "react";
import { MsalProvider } from "@azure/msal-react";

interface AuthProviderProps {
  children: ReactNode;
}

export const AuthProvider = ({ children }: AuthProviderProps) => {
  const msalInstance = new PublicClientApplication(msalConfig);

  msalInstance.addEventCallback((event) => {
    const authenticationResult = event.payload as AuthenticationResult;
    const account = authenticationResult?.account;
    if (event.eventType === EventType.LOGIN_SUCCESS && account) {
      msalInstance.setActiveAccount(account);      
    }
  });

  return <MsalProvider instance={msalInstance}>{children}</MsalProvider>;
};

main.tsx

import ReactDOM from "react-dom/client";
import App from "./App";
import { AuthProvider } from "./services/authProvider";

ReactDOM.createRoot(document.getElementById("root")!).render(
  <>
    <AuthProvider>
      <App />
    </AuthProvider>
  </>
);

App.tsx

import { lazy, Suspense, useEffect } from "react";
import { BrowserRouter as Router, Route, Routes } from "react-router-dom";
import "./tailwind.css";
import { themeChange } from "./scripts/ThemeMode.tsx";
import { AuthenticatedTemplate, UnauthenticatedTemplate } from "@azure/msal-react";

const About = lazy(() => import("./pages/About.tsx"));
const Login = lazy(() => import("./pages/Login.tsx"));


function App() {
  useEffect(() => {
    themeChange();
  }, []);

  return (
    <>
      <div className="min-h-screen h-full min-w-fit bg-l_bg dark:bg-d_bg">
        <div className="flex flex-grow dark:text-d_text text-l_text">
          <Suspense fallback={<div>Loading...</div>}>
            <Router>
              <div className="w-full h-screen overflow-y-auto">
                <AuthenticatedTemplate>
                  <Routes>
                    <Route element={<About />} path="/about" />
                  </Routes>
                </AuthenticatedTemplate>
                <UnauthenticatedTemplate>
                  <Routes>
                    <Route path="*" element={<Login />} />
                  </Routes>
                </UnauthenticatedTemplate>
              </div>
            </Router>
          </Suspense>
        </div>
      </div>
    </>
  );
}

export default App;

Post-processing of autotest run results to create a report with existing test cases in testRail

I integrated my autotests with TestRail CLI, and as a result, new test cases are created in my run that correspond to the autotests. But I already have test cases in TestRail, and I would like to get existing tests from TestRail itself as a result of the run. Also, everything is complicated by the fact that for each test case in TestRail there can be several autotests created by the parameterized method. I think that a good solution would be to create a js postprocessor that would compose the results of each parameterized test, so that if at least one of them was failed, then in the report for TestRail the corresponding test would also be marked as failed. But I don’t know where to start, maybe someone has already done something like this?

How to trigger multiple views in Django with one button using HTMX?

I’m working on a Django project where I need to call two different views when clicking a single button using HTMX.

Scenario:
First, I need to send a POST request to edit a task (edit_positions_tasks view).
After the first request completes, I need to send a GET request to create a task (create_position_tasks view).
The second request should only execute after the first request is successfully processed.
Current Code:

<button 
    hx-post="{% url 'hrm_tenant:edit_positions_tasks' task.id %}" 
    hx-target="#task_{{ task.uuid }}" 
    hx-swap="outerHTML"
    hx-on::after-request="htmx.ajax('GET', '{% url 'hrm_tenant:create_position_tasks' empty_position.id %}', {target: '#task_table', swap: 'beforeend'})"
>
    Update
</button>

Problem:
The first POST request works correctly and updates the task.
However, the GET request to create_position_tasks doesn’t seem to fire or execute properly after the first request finishes.
What I Need Help With:
Is my approach correct for chaining two requests in HTMX?
If not, what is the recommended way to ensure the second request only fires after the first one completes successfully?
Are there better ways to handle this in HTMX or JavaScript?
Any insights would be greatly appreciated!

Allowed to pass undefined into Promise.all

Is it defined behaviour in JavaScript to pass undefined into Promise.all like so:

await Promise.all([fetchSomeData(), undefined])

What I want to achieve: execute a certain fetch only for authenticated users, like so:

const isAuthenticated = ...

const [resultA, resultB] = await Promise.all([
  fetchSomeData(),
  isAuthenticated ? fetchDataRequiringAuthentication() : undefined
])

It seems to work in Chrome and Firefox but I failed to understand the official spec.

TanStack router with react – deferred loading

I’m using tanstack with a react app and am testing the Await component with a promise. I’m following the guide here: https://tanstack.com/router/v1/docs/framework/react/guide/deferred-data-loading

const getLists: () => Promise<FLMList[]> = async () => {
    return new Promise<FLMList[]>(s => {
        setTimeout(
            () => s(flm_lists),
            8000
        )
    })
}

export const Route = createFileRoute('/flm')({
    component: RouteComponent,
    loader: async () => getLists()
})

function RouteComponent() {
    const flmLists = Route.useLoaderData()
    return (
        <Await promise={flmLists} fallback={<div>Loading...</div>}>
            {(data) => {
                return <FLMListTable flmLists={data} isSortable={true} title={'FLM list definitions'} />
            }}
        </Await>
    )
}

It does not render the Loading... div and then after 8 seconds when my promise resolves I get an error that is empty on the screen. The console gives me 2 warnings:

Warning: The following error wasn’t caught by any route! At the very least, consider setting an ‘errorComponent’ in your RootRoute! tiny-warning.esm.js:11:14

Warning: [object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object]

The error on the screen just says “Something went wrong!” with a “Hide Error” button and an empty red outline.

error in browser

This is a contrived example, but works if I remove the Await component and if I await the promise in the loader method like this:

export const Route = createFileRoute('/flm')({
    component: RouteComponent,
    loader: async () => await getLists()
})

function RouteComponent() {
    const flmLists = Route.useLoaderData()
    return (
        // <Await promise={flmLists} fallback={<div>Loading...</div>}>
        //     {(data) => {
                 <FLMListTable flmLists={flmLists} isSortable={true} title={'FLM list definitions'} />
        //     }}
        // </Await>
    )
}

What am I doing wrong with the first one?