How do I get a NextUI ListBox to scroll to the last ListItem?

Some background, I’m attempting to create a message chat feed.

I have a NextUI ListBox component that has the property isVirtualized and the appropriate params. It is created using the following:

        <ListboxWrapper>
            <Listbox
                isVirtualized
                aria-label="Dynamic Actions"
                items={chats}
                selectedKeys={selectedKeys}
                selectionMode="single"
                onSelectionChange={setSelectedKeys}
                virtualization={{
                    maxListboxHeight: 600,
                    itemHeight: 40,
                }}
                ref={messagesEndRef}
            >
                {(item) => (
                    <ListboxItem key={item.id}>
                        {item.text}
                    </ListboxItem>
                )}
            </Listbox>
        </ListboxWrapper>

And the ListboxWrapper:

const ListboxWrapper = ({children}) => (
    <div className="grid row-span-6 w-full h-full border-small px-1 py-2 rounded-small border-default-200 dark:border-default-100">
        {children}
    </div>
);

The items of the list are loaded dynamically. I would like the last item in the list to always be at the bottom of the containing div.

I currently have:

const scrollToBottom = () => {
    messagesEndRef.current?.scrollIntoView({behavior: 'smooth' , block: 'end'})
}

Which scrolls to the top. It doesn’t seem to matter what block I set (end or start), the behaviour is the same. Am I doing something wrong or is there an easier way to do this?

I had the same results with document.getElementById(..).scrollIntoView(..). I also moved the ref to the last list item, but when I do that, the last list item appears at the top of the container and the other items are not visible and cannot be scrolled.

Thanks in advanced!

PayPal API eror – trying to retrieve Paypal Email Address and verification status | Error 400

I’m trying to have my application using React, trying to retrieve the users PayPal Email address, but everything I do returns an ‘Error 400 – Bad Request – Unable to fetch details to serve the request’.

Any idea why? I have double checked my return URI in PayPal, as well as my client / secret ID’s.

My backend:

export const handlePaypalOAuthCallback = async (req, res) => {
  try {
    const { code, state } = req.query;
    console.log('PayPal callback received:', { 
      code: code ? 'present' : 'missing',
      state: state ? 'present' : 'missing',
      fullQuery: req.query 
    });
    
    if (!code) {
      throw new Error('Authorization code not received');
    }

    if (!state) {
      throw new Error('User ID not received in state parameter');
    }

    const CLIENT_ID = "xxx";
    const CLIENT_SECRET = "xxx";
    
    if (!CLIENT_ID || !CLIENT_SECRET) {
      console.error('Missing PayPal credentials');
      throw new Error('Server configuration error');
    }

    const auth = Buffer.from(`${CLIENT_ID}:${CLIENT_SECRET}`).toString('base64');

    console.log('Preparing token request:', {
      url: 'https://api-m.sandbox.paypal.com/v1/oauth2/token',
      grantType: 'authorization_code',
      hasCode: !!code,
      hasAuth: !!auth,
      redirectUri: '<my return uri>/api/paypal/oauth/callback'
    });

    const params = new URLSearchParams();
    params.append('grant_type', 'authorization_code');
    params.append('code', code);
    params.append('redirect_uri', 'http://dev.gotasker.com.au:4000/api/paypal/oauth/callback');
    // Add these additional parameters
    params.append('scope', 'openid email');
    params.append('client_id', CLIENT_ID);
    params.append('client_secret', CLIENT_SECRET);

    try {
      // Get access token
      const tokenResponse = await axios.post(
        'https://api-m.sandbox.paypal.com/v1/oauth2/token', 
        params,
        {
          headers: {
            'Authorization': `Basic ${auth}`,
            'Content-Type': 'application/x-www-form-urlencoded',
            'PayPal-Request-Id': `${Date.now()}`,
            'Accept': 'application/json',
            'Accept-Language': 'en_US'
          }
        }
      );

      console.log('Token response received:', {
        hasAccessToken: !!tokenResponse.data.access_token,
        tokenType: tokenResponse.data.token_type,
        scope: tokenResponse.data.scope,
        status: tokenResponse.status,
        headers: tokenResponse.headers
      });

      const accessToken = tokenResponse.data.access_token;

      // Log token details for debugging (first few chars only)
      console.log('Access token details:', {
        prefix: accessToken.substring(0, 10),
        length: accessToken.length,
        tokenType: tokenResponse.data.token_type
      });

      if (!accessToken || typeof accessToken !== 'string') {
        throw new Error('Invalid access token received from PayPal');
      }

      // Make the userInfo request with proper authorization header
      const userInfoResponse = await axios.get(
        'https://api-m.sandbox.paypal.com/v1/identity/oauth2/userinfo',  // Changed URL
        {
          headers: {
            'Authorization': `Bearer ${accessToken}`,
            'Content-Type': 'application/json',
            'Accept': 'application/json',
            'PayPal-Request-Id': `${Date.now()}`,
          },
        }
      );

      // Log successful userInfo response
      console.log('User info response received:', {
        status: userInfoResponse.status,
        hasData: !!userInfoResponse.data,
        dataKeys: Object.keys(userInfoResponse.data)
      });

      const paypalEmail = userInfoResponse.data.email;
      
      if (!paypalEmail) {
        throw new Error('PayPal email not received in user info response');
      }

      // Update user with PayPal email
      const userId = state;
      const user = await UserModel.findById(userId);
      if (!user) {
        throw new Error('User not found');
      }

      user.paypalEmail = paypalEmail;
      user.paypalVerified = true;
      await user.save();

      console.log('User PayPal email updated successfully:', {
        userId: user._id,
        verified: true
      });

      // Redirect back to frontend with success
      res.redirect(`${process.env.FRONTEND_URL}/account?paypal=success`);
      
    } catch (error) {
      // Enhanced error logging
      console.error('API request failed:', {
        status: error.response?.status,
        statusText: error.response?.statusText,
        data: error.response?.data,
        message: error.message,
        headers: error.response?.headers,
        config: {
          url: error.config?.url,
          method: error.config?.method,
          headers: {
            ...error.config?.headers,
            Authorization: error.config?.headers?.Authorization 
              ? `${error.config.headers.Authorization.substring(0, 10)}...` 
              : 'missing'
          }
        },
        wwwAuthenticate: error.response?.headers?.['www-authenticate']
      });
      throw error;
    }

  } catch (error) {
    console.error('PayPal OAuth error:', {
      message: error.message,
      response: error.response?.data,
      status: error.response?.status,
      statusText: error.response?.statusText
    });
    res.redirect(`${process.env.FRONTEND_URL}/account?paypal=error&message=${encodeURIComponent(error.message)}`);
  }
};

My frontend:

const PayPalLoginCard = () => {
  const { user, updateUserProfile } = useContext(AuthContext);
  const [isLoading, setIsLoading] = useState(false);
  const [error, setError] = useState('');
  const [successMessage, setSuccessMessage] = useState('');
  const location = useLocation();
  const navigate = useNavigate();

  useEffect(() => {
    // Handle OAuth response
    const searchParams = new URLSearchParams(location.search);
    const paypalStatus = searchParams.get('paypal');
    
    if (paypalStatus === 'success') {
      setSuccessMessage('PayPal account connected successfully');
      // Remove query params
      navigate('/account', { replace: true });
    } else if (paypalStatus === 'error') {
      setError(searchParams.get('message') || 'Failed to connect PayPal account');
      navigate('/account', { replace: true });
    }
  }, [location, navigate]);
 
  const handlePayPalLogin = () => {
    try {
      const PAYPAL_CLIENT_ID = "AYwuAs7zBcLHOCaCA0fmLsFKjZGY26T0hvN3KUgwu-uNIp44cpP1M5C_wB4lucVhlJ_BDuQwKUcEcAm-";
      const REDIRECT_URI = 'http://dev.gotasker.com.au:4000/api/paypal/oauth/callback';
      
      const userId = user?.id;
      if (!userId) {
        throw new Error('User ID not available');
      }
  
      // Updated scopes and parameters
      const scopes = 'openid email';
      const authUrl = `https://www.sandbox.paypal.com/signin/authorize?client_id=${PAYPAL_CLIENT_ID}&response_type=code&scope=${scopes}&redirect_uri=${encodeURIComponent(REDIRECT_URI)}&state=${userId}&nonce=${Date.now()}`;
      
      window.location.href = authUrl;
    } catch (error) {
      console.error('Error initiating PayPal login:', error);
      setError(error.message || 'Failed to initiate PayPal login');
    }
  };

  const handleDisconnect = async () => {
    setIsLoading(true);
    setError('');
    setSuccessMessage('');
    
    try {
      const response = await axios.post(
        'http://dev.gotasker.com.au:4000/api/paypal/disconnect',
        {},
        {
          headers: {
            Authorization: `Bearer ${localStorage.getItem('token')}`,
          },
        }
      );
      
      if (response.data.success) {
        await updateUserProfile({ paypalEmail: null });
        setSuccessMessage('PayPal account disconnected successfully');
      }
    } catch (error) {
      setError('Failed to disconnect PayPal account');
    } finally {
      setIsLoading(false);
    }
  };

I have verified my Client/Secret ID, I have triple checked my return URI.

How to Resolve Vulnerabilities in a Newly Created React App Using create-react-app?

I used the npx create-react-app my-app command to create a new React app, and while the app was successfully created, the terminal output mentioned 8 vulnerabilities (2 moderate, 6 high). Here’s a snippet of the output:

8 vulnerabilities (2 moderate, 6 high)

To address all issues (including breaking changes), run:
  npm audit fix --force

Run `npm audit` for details.

I am not sure how to proceed. Should I run npm audit fix –force as suggested, or is there a better way to address these vulnerabilities without potentially introducing breaking changes?

I’m new to React and want to ensure my environment is secure but also stable. Any advice or guidance would be greatly appreciated.

Additional Details:

Node.js version: [your Node.js version]
npm version: [your npm version]
OS: [your operating system and version]

I haven’t tried running npm audit fix –force yet because I’m worried it might introduce breaking changes. I was expecting the newly created app to be free of vulnerabilities, but instead, it shows 8 vulnerabilities (2 moderate, 6 high). I want to know the best way to resolve these issues without breaking the app.

How to retain previous data while fetching new data with useInfiniteQuery when using search queries?

I’m using @tanstack/react-query with the useInfiniteQuery hook to fetch paginated data for a list of items. The infinite query works fine for normal pagination and scrolling. However, when I change the searchQuery, the data is cleared and a loading spinner is shown until the new data arrives.

Goal: I want to keep showing the previous data on the screen while the new data is being fetched in the background after changing the searchQuery. I know useQuery supports keepPreviousData, but useInfiniteQuery does not have this option.

const fetchPaginatedIngredients = async ({
  pageParam = 1,
  queryKey,
}: QueryFunctionContext<QueryKey>) => {
  const [, searchQuery] = queryKey;
  const response = await axiosInstance.get("/api/ingredients", {
    params: { query: searchQuery, page: pageParam, limit: 20 },
  });
  return response.data;
};

const SupplierIngredients = () => {
  const [searchQuery, setSearchQuery] = useState("");

  const {
    data,
    fetchNextPage,
    hasNextPage,
    isFetchingNextPage,
    isLoading,
  } = useInfiniteQuery({
    queryKey: ["ingredients", searchQuery],
    queryFn: fetchPaginatedIngredients,
    getNextPageParam: (lastPage) => {
      if (lastPage.currentPage < lastPage.totalPages) {
        return lastPage.currentPage + 1;
      }
      return undefined;
    },
    staleTime: 1000 * 60 * 5,
    retry: 3,
  });

  const ingredients = useMemo(() => {
    return data?.pages.flatMap((page) => page.data) || [];
  }, [data]);

  return (
    <div>
      <input
        value={searchQuery}
        onChange={(e) => setSearchQuery(e.target.value)}
        placeholder="Search ingredients"
      />
      {isLoading && ingredients.length === 0 && <div>Loading...</div>}
      <ul>
        {ingredients.map((ingredient) => (
          <li key={ingredient.id}>{ingredient.name}</li>
        ))}
      </ul>
      {hasNextPage && (
        <button onClick={() => fetchNextPage()}>Load More</button>
      )}
    </div>
  );
};

Preventing click events on map panning using Panzoom library

I created a world map for learning in a .svg file and wanted to use the panzoom library to enable zooming. However, I encountered a problem that I can’t seem to resolve.

I created a simple game where you need to click on the correct country or island. Some of them are very small, so zooming or panning the map is necessary. The issue arises because when panning the map by clicking and holding the mouse button, releasing the button triggers a click event on the country, which is recognized as an attempt by the player.

Do you have any suggestions on how to prevent this click after releasing while panning the map?

    // Tooltip
const tooltip = document.getElementById('tooltip');
const svgContainer = document.getElementById('panzoom-container');

// Add hover and tooltip only to selected elements
idsToHighlight.forEach(id => {
    const element = document.getElementById(id);
    if (element) {
        // Add hover
        element.addEventListener('click', (event) => {
            element.classList.add('region-hover');
            const title = element.getAttribute('title') || 'No title';
            tooltip.textContent = title;
            tooltip.style.opacity = '1';
        });

        // Remove hover
        element.addEventListener('mouseleave', () => {
            element.classList.remove('region-hover');
            tooltip.style.opacity = '0';
        });

        // Update tooltip position
        element.addEventListener('mousemove', (event) => {
            const bounds = svgContainer.getBoundingClientRect();
            tooltip.style.left = `${event.clientX - bounds.left + 10}px`;
            tooltip.style.top = `${event.clientY - bounds.top + 10}px`;
        });
    }
});

// Panzoom Initialization with zoom limits
const svgMap = document.getElementById('svg1');
const panzoom = Panzoom(svgMap, { 
    contain: 'outside', 
    minScale: 0.5, // Minimum zoom level
    maxScale: 300    // Maximum zoom level
});
svgContainer.addEventListener('wheel', panzoom.zoomWithWheel);

// Button controls
document.getElementById('zoom-in').addEventListener('click', () => panzoom.zoomIn());
document.getElementById('zoom-out').addEventListener('click', () => panzoom.zoomOut());
document.getElementById('reset').addEventListener('click', () => panzoom.reset());


// Global attempts
const correctAnswers = [];
const incorrectAnswers = [];
const attempts = {};
let numberOfSelectedCountries = 0;

// Function to initialize map interactions
function initMapInteraction() {
    // Initialize number of selected countries
    numberOfSelectedCountries = 1;
    document.getElementById('liczba_wylosowanych_krajow').innerText = `${numberOfSelectedCountries}`;

    // Select random country
    currentTarget = idsToHighlight[Math.floor(Math.random() * idsToHighlight.length)];
    document.getElementById('losowy_kraj').innerText = "Choose country: " + document.getElementById(currentTarget).getAttribute('title'); // Display the selected country

    console.log(`Current target: ${currentTarget}`);

    // Add click listeners for each country
    idsToHighlight.forEach((id) => {
        const element = document.getElementById(id);
        if (element) {
            attempts[id] = 0; // Initialize attempt count

            element.addEventListener("click", () => {
                console.log(`Clicked on country: ${id}`);
                
                if (id === currentTarget) {
                    // Mark correct answer
                    if (attempts[currentTarget] >= 2) {
                        // If there were more than 2 attempts, remove flashing and mark in red
                        element.classList.remove('migajacy');
                        element.style.fill = "red";
                        incorrectAnswers.push(currentTarget);
                        console.log(`Added to incorrect answers: ${currentTarget}`);
                        let incorrectCount = incorrectAnswers.length;
                        document.getElementById('bledne_kraje').innerText = "incorrect: " + incorrectCount;
                    } else if (attempts[currentTarget] === 1) {
                        // On the second attempt
                        element.style.fill = "orange"; // Orange mark
                        incorrectAnswers.push(currentTarget);
                        console.log(`Added to incorrect answers: ${currentTarget}`);
                        let incorrectCount = incorrectAnswers.length;
                        document.getElementById('bledne_kraje').innerText = "incorrect: " + incorrectCount;
                    } else {
                        // On the first attempt
                        element.style.fill = "white"; // White mark
                        correctAnswers.push(currentTarget);
                        console.log(`Added to correct answers: ${currentTarget}`);
                        let correctCount = correctAnswers.length;
                        document.getElementById('Poprawne_kraje').innerText = "Correct: " + correctCount;
                    }
                    element.style.pointerEvents = "none"; // Disable clicks
                    correctAnswers.push(currentTarget);
                    console.log(`Country ${id} marked as correct.`);

                    numberOfSelectedCountries++; // Increase selected countries count
                    document.getElementById('liczba_wylosowanych_krajow').innerText = `${numberOfSelectedCountries}`;

                    // Check if there are still countries to choose
                    const remaining = idsToHighlight.filter(
                        (country) => !correctAnswers.includes(country) && !incorrectAnswers.includes(country)
                    );
                    if (remaining.length > 0) {
                        currentTarget = remaining[Math.floor(Math.random() * remaining.length)];
                        document.getElementById('losowy_kraj').innerText = document.getElementById(currentTarget).getAttribute('title'); // Update the selected country
                        attempts[currentTarget] = 0; // Reset attempts for new country
                    } else {
                        console.log("Game finished. All countries marked correctly.");
                        alert("All countries have been marked correctly!");
                    }
                } else {
                    // Handle incorrect selection
                    attempts[currentTarget]++; // Increase attempts globally
                    console.log(`Attempts for ${currentTarget}: ${attempts[currentTarget]}`);

                    if (attempts[currentTarget] === 2) {
                        // After 2 attempts, add flashing
                        document.getElementById(currentTarget).classList.add('migajacy');
                    }
                }
            });
        } else {
            console.error(`Element with id ${id} does not exist.`);
        }
    });
}

// CSS for flashing effect
const style = document.createElement('style');
style.textContent = `
@keyframes blink-red {
    0%, 100% { fill: red; }
    50% { fill: white; }
}

.migajacy {
    animation: blink-red 1s infinite;
}
`;
document.head.appendChild(style);

// Initialize interactions after DOM is loaded
window.addEventListener("DOMContentLoaded", initMapInteraction);

const occurrences = [];
function checkIdOccurrences() {
    const allElements = document.querySelectorAll('[id]');
    const idCounts = {};
    
    allElements.forEach((element) => {
        const id = element.id.toUpperCase(); // Use uppercase for consistency
        if (idsToHighlight.includes(id)) {
            if (idCounts[id]) {
                idCounts[id]++;
            } else {
                idCounts[id] = 1;
            }
        }
    });

    // Find the div with id `wszystkie_kraje`
    const allCountriesDiv = document.getElementById('wszystkie_kraje');
    
    if (allCountriesDiv) {
        allCountriesDiv.innerHTML = `${Object.keys(idCounts).length} `;
    } 
}

// Call the function after DOM is loaded
document.addEventListener('DOMContentLoaded', () => {
    checkIdOccurrences();
});

Transfer data with GOOGLE SHEETS

This code can transfer data of last row from sheet1 to the last row of sheet2 increaseing rows in the Sheet2.

How I make for overwrite the data of sheet 2?

That is to say, do not increase rows in the sheet 2 with the transfers, keep 1 row in the Sheet2, deleting the previous data in each transfer.

Any Idea, i apreciate so much your indications.


function transferData() {
  var ssDb = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Sheet1');
  var ssAs = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Sheet2');
  var lr = ssDb.getLastRow();
  var lc = ssDb.getLastColumn();
  var data = ssDb.getRange(3,1,lr-3,lc).getDisplayValues();
  var fData = data.map(data => {
    return [data[1], data[3], data[36], data[5], data[33], data[7], data[31], data[34], data[35], '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '','', '', '', '', '', '', '', '', '', '', '', ''];
  })
  ssAs.getRange(2,1,lr-3,37).setValues(fData);
  
}


I dont have VueRouter or Router from ‘vue-router’

I dont know how to make a web router in vue because im a beginner, so in every tutorial, i see that they import router or vuerouter from ‘vue-router’

What i’ve already tried? i ran npm install vue-router@, so i have some ‘vue-router’ dependencies, but i dont have Router or VueRouter, i see tutorials from 2020 to 2022
enter image description here

Any ideas, its my first time on vue, thanks!!

React: Why does the value of my input not update, but outputting the same same state to the page or console does?

Here is my code:

import { useState } from "react";

const Testing = () => {
    const [testa, setTesta] = useState({ Nickname: "Testing" });
    
    return (
        <>
            <button type="button" onClick={(e) => setTesta({})}>Add</button>
            <input type="text" value={testa?.Nickname} onChange={e => setTesta({ Nickname: e.target.value })} />
            <p>Output: {testa?.Nickname}</p>
        </>
    );
};
export default Testing;

When the page initially loads the textbox value and the text below it both reflect the correct Nickname value.

screenshot of initial load

When I type into the textbox the Nickname is correctly updated in both places.

updated text

When I click the Add button to reassign the state to an empty object, the output correctly disappears, but the textbox value remains unchanged.

unchanged textbox value

What causes the difference between the input value and the plain text in this case?

Encountered two children with the same key. Keys should be unique so that components maintain their identity across updates

I am making a drag and drop system with react dnd. In the drag section the unique id is generated while dragging item:{id:uuid(),type:type} the item the element and on drop the item is received in drop section

const [,drop] = useDrop(()=>({
    accept:Object.values(dragAbleTypes),
    drop:(item:{id:UUIDTypes,type:string}, monitor)=>{
      console.log(item.id);

On first drag and drop it generate the id. when i do it for second time it’s giving me this error. Also while i log the id console.log(item.id); the same id is loging every time which is generated at the first drag & drop

<div className='h-screen flex flex-col border w-full 'ref={drop}>
      {elements.map(e=>{
        console.log("key:",e.id);
        return(<EditorRenderingHelper key={e.id.toString()} element = {e}/>)
      })}

the logs:

key: 98f499f3-f214-401d-90ce-a069c7396a34

key: 98f499f3-f214-401d-90ce-a069c7396a34

key: 98f499f3-f214-401d-90ce-a069c7396a34

key: 98f499f3-f214-401d-90ce-a069c7396a34

The browser console is showing this,

Encountered two children with the same key, `f1ff56c1-0b2e-4f4c-9ba5-6c1568714635`. Keys should be unique so that components maintain their identity across updates. Non-unique keys may cause children to be duplicated and/or omitted — the behavior is unsupported and could change in a future version.

The component codes,

drag component

function DragElements({type}:{
  type:typeof dragAbleTypes[keyof typeof dragAbleTypes]}) {
    const [{isdragging},drag] = useDrag(()=>({
        type:type,
        item:{id:uuid(),type:type},
        collect:(e)=>{
        return {isdragging:!!e.isDragging()}
        }
    }))
  return (
    // @ts-ignore
    <div ref={drag}>
        {type}
    </div>
  )
}

export default DragElements

drop component

function Canvas() {
  const [elements, setElements] = useAtom(editorState)
  const [,drop] = useDrop(()=>({
    accept:Object.values(dragAbleTypes),
    drop:(item:{id:UUIDTypes,type:string}, monitor)=>{
      console.log(item.id);
      
      const newElement = {
        id:item.id,
        type:item.type
      }
      setElements(e=>e = [...e,newElement])
    }
  }))
  return (
    // @ts-ignore
    <div className='h-screen flex flex-col border w-full 'ref={drop}>
      {elements.map(e=>{
        return(<EditorRenderingHelper key={e.id.toString()} element = {e}/>)
      })}
    </div>

  )
}

export default Canvas

Service firestore is not available or No Firebase App with getFirestore

I have tried a few ways to get Firestore working in my javascript Module file.

When I do this….

import {initializeApp} from "https://www.gstatic.com/firebasejs/10.11.1/firebase-app.js";
import {getStorage, ref, uploadBytes, getDownloadURL} from "https://www.gstatic.com/firebasejs/10.11.1/firebase-storage.js";
import { getFirestore } from 'https://www.gstatic.com/firebasejs/11.1.0/firebase-firestore.js'


var firebaseConfig = {
    apiKey: "",
    authDomain: "",
    projectId: "",
    storageBucket: "",
    messagingSenderId: "",
    appId: ""
};


const app = initializeApp(firebaseConfig);
const storage = getStorage(app);
const db = getFirestore();

I get the following error on the getFirestore() method.

Uncaught FirebaseError: Firebase: No Firebase App ‘[DEFAULT]’ has been
created – call initializeApp() first (app/no-app).

When I try this const db = getFirestore(app); instead, I get the following error.

Service firestore is not available

How do I get Firestore implemented on my web app?
Im not using Firebase Functions

Document.createRange around multiple text matches gives IndexSizeError

I am writing a search engine and ran into a problem. I use document.createRange to select the matches and I used the AND operator.

I have the following text, it is Hungarian colors where half of it is already hightlighted:

<div id="x"><span class="highlight-occurrence">fehér</span>, fekete, vörös, kék, zöld, sárga, narancs, rózsaszín, barna, lila, türkízkék, szürke </div>

and I have to highlighting code for “sárga” something like this which gives out of range sort of error:

const x = document.getElementById("x");
const startOffset = 33;
const endOffset = 38;
const range = document.createRange();
range.setStart(x, startOffset);
range.setEnd(x, endOffset);

My search pattern is something like the following:

{"and": [
    {"contains": "fehér"},
    {"contains": "sárga"}
]}

The main problem here that the previous surroundContents added some HTML to the text, so the setStart(x, 33) will be somewhere in the HTML attribute "highlight-occurrence" which gives an out of range obviously. This happens because when I highlight with the AND operator I highlight the results separately. So first I highlight the occurrences of “fehér”, next I highlight the occurrences of “sárga”. It would be nice to keep it this way instead of completely overriding my code to mix the results for both words and always highlight from the end to the beginning of the text.

My real code looks like this, it is funny to have this many loops nested:

function highlightMatches(pattern, evidence){
    for (var match of evidence)
        for (var perMatcherTypeResults of match.evidence)
            for (var locations of perMatcherTypeResults)
                if (locations instanceof Array)
                    for (var location of locations){
                        var sectionIndexes = location.slice(0, location.length-1);
                        var positionRanges = location[location.length-1];
                        for (var i=positionRanges.length-1; i>=0; --i)
                            highlight(match.term.checksum, sectionIndexes, positionRanges[i]);
                    }
}

function highlight(id, sectionIndexes, positionRange){
    var selector = `#results-${id}-${sectionIndexes.join("-")}`;
    var element = selectOne(selector);
    element.classList.add("highlight-sentence");
    var range = new Range();
    range.setStart(element.firstChild, positionRange[0]);
    range.setEnd(element.firstChild, positionRange[1]);
    var highlightOccurrence = document.createElement("span");
    highlightOccurrence.className = "highlight-occurrence";
    range.surroundContents(highlightOccurrence);
}

I was wondering is there a solution where the order of text highlighting does not matter so I would need to override only the highlight function instead of the highlightMatches or the match generator?

In Firefox and Safari no way to add device change event listener?

Trying to listen for device change using devicechange event listener. In Edge & Chrome the following code works:

navigator.mediaDevices.ondevicechange = () => {
  console.log('device changed');
};

However in Safari & Firefox that doesn’t work, but if I look into caniuse, it says that it’s supported: https://caniuse.com/mdn-api_mediadevices_devicechange_event

Anybody have an idea what am I doing wrong ? Tried executing code in console and still device change event not detected in Safari & Firefox.

Thank you!

How to dynamically generate and execute unit tests for multiple programming languages as strings?

I am working on a system where solutions to problems are validated using predefined unit test cases. The system supports multiple programming languages, and the generated test cases need to be converted into strings for execution by an API.

The Problem:
To test submitted solutions, I need to dynamically generate unit test cases for each programming language. The generated tests should:

Include predefined base test cases for each problem (e.g., validating a palindrome function).

Allow dynamic addition of custom test cases (e.g., user-defined edge cases).
The generated tests must then be converted to a string and sent to Judge0 for execution.

Current Approach:
For Python:

I use unittest to define base test cases in a file (e.g., test_palindrome.py).
Custom test cases are dynamically added as new test methods.
Both base and custom test cases are combined into a single string.

The following code will already be existing with the is_palindrome.py file but new custom test cases will need to be added on.

import unittest   

class TestPalindrome(unittest.TestCase):  
    def test_base_cases(self):  
        self.assertTrue(is_palindrome("radar"))  
        self.assertFalse(is_palindrome("hello"))  

for example, for the given the user input:

[
  { "input": "'level'", "expected_output": "True" },
  { "input": "'world'", "expected_output": "False" }
]

I would need to generate a string of these test cases and add them on to the existing tests once the is_palindrome.py file is read.

    def test_custom_0(self):  
        self.assertEqual(is_palindrome('level'), True)  
    def test_custom_1(self):  
        self.assertEqual(is_palindrome('world'), False) 

For other languages like Java or JavaScript, I use their respective testing frameworks (e.g., JUnit, Jest) and follow a similar approach to dynamically generate test cases as strings. I know the string generation will be a pain to do, the languages I need to cover would be the following –

  • C
  • C++
  • Python 3
  • Java
  • JavaScript
  • TypeScript
  • C#
  • Ruby
  • PHP
  • Go
  • Rust

My Questions:

Is this approach of generating test cases dynamically and converting them to strings efficient for multiple languages?

Would creating a system to genenrate test cases as string for different languages be better approach?

Would maintaining predefined test files for each problem/language and appending custom test cases dynamically before converting to a string be a better approach?

How can I handle user-defined test cases securely and efficiently while ensuring the string generation process is not a bottleneck?

Is there an easy way to generate the test cases for different languages using python?

Any advice, best practices, or examples for implementing such a system would be greatly appreciated. Thank you!

JavaScript Fetch Request to Flask Server Fails with “TypeError: Failed to Fetch”

I’m developing a website using vanilla HTML, CSS, and JavaScript, and I have a Python script that runs an AI model. To facilitate interaction between JavaScript and Python, I set up a Flask server.

When I send a request from JavaScript, the Flask server receives it correctly, the AI model executes successfully, and I receive a 200 status code in the command line. However, the JavaScript code returns the following error: “TypeError: Failed to Fetch”.

I’m starting the Flask server first and then using Visual Studio Code’s live server for the HTML page.

Below are the relevant files for my flask server and javascript code:

Flask Server (app.py):

import json
import traceback
from flask import Flask, request, jsonify, render_template, send_from_directory
from diagnose import diagnose
from werkzeug.utils import secure_filename
import os
from flask_cors import CORS
import sys

# Get the absolute path to the project root
PROJECT_ROOT = os.path.abspath(os.path.join(os.path.dirname(__file__), '..', '..'))
UPLOADS_FOLDER = os.path.join(PROJECT_ROOT, 'uploads')

app = Flask(__name__, static_folder='../')
CORS(app, resources={
    r"/diagnose": {
        "origins": ["http://127.0.0.1:5000", "http://localhost:5000", "http://127.0.0.1:5500"], 
        "methods": ["POST"],
        "allow_headers": ["Content-Type", "Accept"],
        "expose_headers": ["Content-Type"]
    }
})

# Add detailed logging
import logging
logging.basicConfig(level=logging.DEBUG)
logger = logging.getLogger(__name__)

@app.route('/diagnose', methods=['POST'])
def diagnose_plant():    
    try:
        # Extensive logging of request details
        logger.debug("Diagnosis request received")
        logger.debug(f"Form data: {request.form}")
        logger.debug(f"Files data: {request.files}")
        
        print("Diagnosis request received")
        print(f"Form data: {request.form}")
        print(f"Files data: {request.files}")

        # Check if image is present in the request
        if 'image' not in request.files:
            logger.error("No image file in request")
            print("No image file in request")
            return jsonify({'error': 'No image file'}), 400
        
        # Get the uploaded image file
        image_file = request.files['image']
        
        # Check if filename is empty
        if image_file.filename == '':
            logger.error("No selected file")
            print("No selected file")
            return jsonify({'error': 'No selected file'}), 400

        # Save the image file to the uploads directory
        filename = secure_filename(image_file.filename)
        filepath = os.path.join(UPLOADS_FOLDER, filename)
        
        # Ensure uploads directory exists
        os.makedirs(UPLOADS_FOLDER, exist_ok=True)
        image_file.save(filepath)

        # Get the plant type from the request form data
        plant_type = request.form['plant_type']

        logger.debug(f"Diagnosing {plant_type} with image: {filepath}")
        print(f"Diagnosing {plant_type} with image: {filepath}")

        # Diagnose the plant disease using the uploaded image
        try:
            diagnosis = diagnose(plant_type, filepath)
            logger.debug(f"Diagnosis result: {diagnosis}")
            print(f"Diagnosis result: {diagnosis}")
        except Exception as diagnose_error:
            logger.error("Error in diagnosis process")
            logger.error(traceback.format_exc())
            print("Error in diagnosis process")
            print(traceback.format_exc())
            return jsonify({
                'error': 'Diagnosis failed', 
                'details': str(diagnose_error),
                'traceback': traceback.format_exc()
            }), 500

        response = jsonify({'diagnosis': diagnosis})
        response.headers.add('Access-Control-Allow-Origin', '*')
        return response
    
    except Exception as e:
        # Log the full error traceback
        logger.error("Unexpected error during diagnosis")
        logger.error(traceback.format_exc())
        print("Unexpected error during diagnosis")
        print(traceback.format_exc())
        
        # Return a more detailed error response
        return jsonify({
            'error': 'Diagnosis failed', 
            'details': str(e),
            'traceback': traceback.format_exc()
        }), 500
    finally:
        # Optional: Remove the uploaded file after processing
        if 'filepath' in locals() and os.path.exists(filepath):
            os.remove(filepath)

if __name__ == '__main__':
    app.run(debug=True)

JavaScript (app.js):

// Get the image file input element
const imageInput = document.getElementById('file-input');

// Get the dropdown element
const plantDropdown = document.getElementById('plant-dropdown');

const plantConversions = {
    'Select Plant Type': null,
    'Apple': 'Apple',
    'Cherry': 'Cherry_(including_sour)',
    'Corn': 'Corn_(maize)',
    'Grape': 'Grape',
    'Peach': 'Peach',
    'Bell Pepper': 'Pepper,_bell',
    'Potato': 'Potato',
    'Strawberry': 'Strawberry',
    'Tomato': 'Tomato'
}


const diagnoseButton = document.getElementById('diagnose-button');
console.log(diagnoseButton)
// Add an event listener to the diagnose button
diagnoseButton.addEventListener('click', async (event) => {  
  console.log('Button clicked'); // Debug point 1
  
  const plantType = plantDropdown.options[plantDropdown.selectedIndex].text;
  console.log('Plant type:', plantType); // Debug point 2
  
  if (!plantConversions[plantType]) {
    alert('Please select a valid plant type');
    return;
  }
  
  const imageFile = imageInput.files[0];
  console.log('Image file:', imageFile); // Debug point 3
  
  if (!imageFile) {
    alert('Please select an image');
    return;
  }
  
  const formData = new FormData();
  formData.append('image', imageFile);
  formData.append('plant_type', plantConversions[plantType]);
  
  console.log('FormData created with:'); // Debug point 4
  for (let [key, value] of formData.entries()) {
    console.log(key, ':', value);
  }
  
  try {
    console.log('Starting fetch...');
    const response = await fetch('http://127.0.0.1:5000/diagnose', {
      method: 'POST',
      body: formData,
      headers: {
        'Accept': 'application/json'
      },
      mode: 'cors',  // Explicitly state we're making a CORS request
      credentials: 'omit'  // Don't send credentials for cross-origin requests
    });
    console.log('Fetch completed, response:', response);
    
    const data = await response.json();
    console.log('Response data:', data);
    
    if (data && data.diagnosis) {
      alert(data.diagnosis);
    } else {
      alert('Invalid response format from server');
    }
    
} catch (error) {
    console.error('Detailed error:', {
      name: error.name,
      message: error.message,
      stack: error.stack
    });
    alert(`Error: ${error.message}`);
}
});

I am unsure which specific console and terminal outputs would be most helpful to provide, but I have a significant amount of output data available.

Key Points:

Flask server receives request and processes AI model successfully.

AI model provides correct output, and 200 status code is returned.

JavaScript fetch request fails with “TypeError: Failed to Fetch”.

Flask server is started first, followed by VS Code live server for the HTML page.

Question: What could be causing the “TypeError: Failed to Fetch” error in my JavaScript code, and how can I resolve this issue?

What I Tried:

Verified that the Flask server is running and accessible.

Confirmed that the AI model executes and returns the expected results on the server side.

Ensured that the JavaScript code is correctly sending the fetch request.

Checked for any errors in the console and terminal outputs to identify the issue.

What I Expected: I expected the JavaScript fetch request to successfully communicate with the Flask server, retrieve the AI model’s output, and handle the response without encountering the “TypeError: Failed to Fetch” error.