React-Native Expo-Go app: ‘Not a valid React component’ error

I am trying to develop my first proper React-Native app and I’m having trouble straight out the gate. I am trying to use a few different imported Navigation libraries (BottomTabNavigator, NativeStackNavigator, Stack.Screen, etc.).

I am getting an error when I run the app on Expo-Go saying something like “Error: Got an invalid value for ‘component’ prop for the screen ‘ManageExpense’. It must be a valid React Component.”
So far a I have App.js, and 3 screens, AllExpenses.js, ManageExpense.js, and RecentExpenses.js.
I’ll post them in that order below.

import { StatusBar } from 'expo-status-bar';
import { StyleSheet, Text, View } from 'react-native';
import { NavigationContainer } from '@react-navigation/native';
import { createNativeStackNavigator } from '@react-navigation/native-stack';
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';

//importing custom components
import ManageExpense from './screens/ManageExpense';
import RecentExpenses from './screens/RecentExpenses';
import AllExpenses from './screens/AllExpenses';

const Stack = createNativeStackNavigator();// this stack will create an object that gives access to 2 components (nav, register screens): https://reactnavigation.org/docs/native-stack-navigator
const BottomTabs = createBottomTabNavigator(); // allows bottom tab navigation: npm install @react-navigation/bottom-tabs

//this function handles the bottom tab navigator
function ExpensesOverview() {
  return (
    <BottomTabs.Navigator>
      <BottomTabs.Screen name="RecentExpenses" component={RecentExpenses} />
      <BottomTabs.Screen name="AllExpenses" component={AllExpenses} />
    </BottomTabs.Navigator>
  );
}

export default function App() {
  return (
    <>
      <StatusBar style="auto" />
      {/* setting up navigation */}
      <NavigationContainer>
        {/* StackNavigator allows me to dynamically load the tabs options based on which screen is selected*/}
        <Stack.Navigator>
          {/* below uses the custom function above to display both options in one stack.screen */}
          <Stack.Screen name="ExpensesOverview" component={ExpensesOverview} />
          <Stack.Screen name="ManageExpense" component={ManageExpense} />
        </Stack.Navigator>
      </NavigationContainer>
    </>
  );
}


import React from 'react';
import { Text } from 'react-native';

export default function AllExpenses() {

    return <Text>AllExpenses Screen</Text>

}
import React from 'react';
import { Text } from 'react-native';

export default function ManageExpense() {

    return <Text>ManageExpense Screen</Text>

}


import React from 'react';
import { Text } from 'react-native';

export default function RecentExpenses() {

    return <Text>RecentExpenses Screen</Text>

}

I’m trying to get the imported navigation components to work properly. I really can’t spot where I’m going wrong I’ve been looking at it for a while and even ChatGPT can’t seem to spot it… Any help would be appreciated. Thanks.

Why doesn’t my mobile menu open anymore ever since I’ve added some new script?

Ever since I’ve added the color-choice script, my hamburger menu isn’t working anymore. I don’t know what is in conflict but the only thing that happens when I click on the hamburger menu is that I get a notification ‘Javascript:void(0)’. Can anyone help me figure this problem out? Of course I need the mobile menu to work before I can launch my website, but I also really want to keep my color choice script because I think that’s a cool feature. Hope someone can help me out.

$(window).on("load", function () {

    "use strict";

/* ===================================
        Loading Timeout
 ====================================== */
$('.side-menu').removeClass('hidden');

    setTimeout(function(){
        $('.preloader').fadeOut();
    }, 1000);
});

jQuery(function ($) {

    "use strict";

/* ===================================
    Side Menu
====================================== */

if ($("#sidemenu_toggle").length) {
    $("#sidemenu_toggle").on("click", function () {
        $(".side-menu").removeClass("side-menu-opacity");
        $(".pushwrap").toggleClass("active");
        $(".side-menu").addClass("side-menu-active"), $("#close_side_menu").fadeIn(700)
    }), $("#close_side_menu").on("click", function () {
        $(".side-menu").removeClass("side-menu-active"), $(this).fadeOut(200), $(".pushwrap").removeClass("active");
        setTimeout(function(){
            $(".side-menu").addClass("side-menu-opacity");
        }, 500);
    }), $(".side-menu .navbar-nav .nav-link").on("click", function () {
        $(".side-menu").removeClass("side-menu-active"), $("#close_side_menu").fadeOut(200), $(".pushwrap").removeClass("active");
        setTimeout(function(){
            $(".side-menu").addClass("side-menu-opacity");
        }, 500);
    }), $("#btn_sideNavClose").on("click", function () {
        $(".side-menu").removeClass("side-menu-active"), $("#close_side_menu").fadeOut(200), $(".pushwrap").removeClass("active");
        setTimeout(function(){
            $(".side-menu").addClass("side-menu-opacity");
        }, 500);
    });
}

/* ===================================
    Bottom Nav Appear
====================================== */

$(function () {
    var $win = $(window);
    jQuery(function($) {
        $(window).scroll(function() {
            if($(window).scrollTop() + $(window).height() > $(document).height() - 200) {
                // alert("near bottom!");
                $('.sidenav-bottom').css('opacity','1');
                $('.sidenav-bottom').addClass('sidenav-bottom-fixed');
            }
            if($(window).scrollTop() + $(window).height() < $(document).height() - 300 && $(window).scrollTop() + $(window).height() > $(document).height() - 400 )  {
                $('.sidenav-bottom').css('opacity','0');
                $('.sidenav-bottom').removeClass('sidenav-bottom-fixed');
            }
        });
    });
});

if ($(window).width() <= 991) {
    $(".scroll").on("click", function (event) {
        event.preventDefault();
        $('html,body').animate({
            scrollTop: $(this.hash).offset().top - 40
        }, 200);
    });
}

/* ===================================
    Header Appear
====================================== */

$(window).on('scroll', function () {
    if ($(this).scrollTop() > 260) { // Set position from top to add class
        $('.sidenav-bottom').css('opacity','0');
        $('header .inner-header').addClass('header-appear');
    }
    if($(this).scrollTop() < 260) {
        $('.sidenav-bottom').css('opacity','1');
        $('header .inner-header').removeClass('header-appear');
    }
});

/*===================================
    Go Top Scroll
====================================== */
$(function(){
    // Scroll Event
    $(window).on('scroll', function(){
        var scrolled = $(window).scrollTop();
        if (scrolled > 260) $('.go-top').addClass('active');
        if (scrolled < 260) $('.go-top').removeClass('active');
    });
    // Click Event
    $('.go-top').on('click', function() {
        $("html, body").animate({ scrollTop: "0" },  100);
    });
});

/* ===================================
    Portfolio Carousel
====================================== */

$('.portfolio-carousel').owlCarousel({
    loop:true,
    margin:10,
    slideSpeed: 5000,
    slideTransition:'linear',
    nav:false,
    dots:false,
    autoplay:false,
    autoplayTimeout:8000,
    autoplayHoverPause:false,
    responsive:{
        0:{
            items:1
        },
        600:{
            items:1
        },
        1000:{
            items:1
        },
    }
});

$('.portfolio-right-arr').click(function() {
    var owl = $('.portfolio-carousel');
    owl.owlCarousel();
    owl.trigger('next.owl.carousel');
});
$('.portfolio-left-arr').click(function() {
    var owl = $('.portfolio-carousel');
    owl.owlCarousel();
    owl.trigger('prev.owl.carousel');
});

/* ===================================
    Banner Carousel
====================================== */

$('.slider-carousel').owlCarousel({
    loop: true,
    margin: 10,
    slideSpeed: 9999,
    slideTransition: 'linear',
    nav: false,
    dots: false,
    autoplay: true,
    smartSpeed: 450,
    autoplayTimeout: 3000,
    autoplayHoverPause: false,
    responsive:{
        0:{
            items:1
        },
        600:{
            items:1
        },
        1000:{
            items:1
        },
    }
});

/* ===================================
    Testimonial Carousel
====================================== */

$('.review-carousel').owlCarousel({
    loop:true,
    margin:10,
    slideSpeed: 5000,
    slideTransition:'linear',
    nav:false,
    dots:false,
    autoplay:false,
    autoplayTimeout:8000,
    autoplayHoverPause:true,
    responsive:{
        0:{
            items:1
        },
        600:{
            items:1
        },
        1000:{
            items:1
        },
    }
});

/* ===================================
     Wow Effects
======================================*/

var wow = new WOW(
    {
        boxClass:'wow',      // default
        animateClass:'animated', // default
        offset:0,          // default
        mobile:false,       // default
        live:true        // default
    }
);
    wow.init();
});

$(document).ready(function() {
    // Toon de kleurkeuze pop-up bij het laden van de pagina
    setTimeout(function() {
        $("#color-choice-popup").fadeIn();
        $("#color-choice-overlay").fadeIn(); // Laat ook de overlay zien
        $("body").addClass("no-scroll"); // Voeg een klasse toe om scrollen te voorkomen
    }, 1500);

    // Functie om de themaklasse van de website aan te passen
    function updateThemeClass(themeClass) {
        document.documentElement.className = themeClass; // Stel de klasse van het root element in
    }

    // Event listener voor kleurkeuze
    $(".color-choice").on("click", function() {
        var themeClass = $(this).data("theme");
        updateThemeClass(themeClass); // Pas de themaklasse aan met de gekozen klasse
        $("#color-choice-popup").fadeOut(); // Verberg de pop-up
        $("#color-choice-overlay").fadeOut(); // Verberg ook de overlay
        $("body").removeClass("no-scroll"); // Verwijder de klasse om scrollen mogelijk te maken
    });

    // Controleer of de kleurindicator al bestaat om te voorkomen dat deze meerdere keren wordt toegevoegd
    if($("#color-indicator-menubar").length === 0) {
        // Zorg ervoor dat dit geplaatst wordt in het juiste header-element, naast de Get a Quote knop
        $("<div id='color-indicator-menubar'></div>")
            .insertBefore(".inner-header .row .col-lg-4.d-flex.justify-content-end .btn-main");
    }

    // Laat de kleurkeuzepopup opnieuw zien wanneer op de kleurindicator wordt geklikt
    $("#color-indicator-menubar").on("click", function() {
        $("#color-choice-popup").fadeIn();
        $("#color-choice-overlay").fadeIn(); // Laat ook de overlay zien
        $("body").addClass("no-scroll"); // Voeg een klasse toe om scrollen te voorkomen
    });
});

Drad&Drop in JS: detect a file

I’m implementing a drag&drop in JS, it works but the detection of my file is quite bad (when the file is drag over the dropzone it isn’t always detected).
Also i would like to click anywhere in the dropzone to activate my input it doesn’t work either.

Here is my code and a link of my codePen to test it: https://codepen.io/ChloeMarieDom/pen/QWPLqNz?editors=0010)

<div class="frame">
  <div class="container">
        <div class="title">Drop file to upload</div>
        <div class="line"></div>
        <div class="dropzone">
            <svg class="upload" viewBox="0 0 640 512" width="100" title="cloud-upload-alt">
        <path d="M537.6 226.6c4.1-10.7 6.4-22.4 6.4-34.6 0-53-43-96-96-96-19.7 0-38.1 6-53.3 16.2C367 64.2 315.3 32 256 32c-88.4 0-160 71.6-160 160 0 2.7.1 5.4.2 8.1C40.2 219.8 0 273.2 0 336c0 79.5 64.5 144 144 144h368c70.7 0 128-57.3 128-128 0-61.9-44-113.6-102.4-125.4zM393.4 288H328v112c0 8.8-7.2 16-16 16h-48c-8.8 0-16-7.2-16-16V288h-65.4c-14.3 0-21.4-17.2-11.3-27.3l105.4-105.4c6.2-6.2 16.4-6.2 22.6 0l105.4 105.4c10.1 10.1 2.9 27.3-11.3 27.3z" />
            </svg>
            <span class="filename"></span>
            <input type="file" class="input">
        </div>
        <div class="upload-btn">Upload file</div>
        <svg class="syncing" viewBox="0 0 512 512" width="100" title="circle-notch">
    <path d="M288 39.056v16.659c0 10.804 7.281 20.159 17.686 23.066C383.204 100.434 440 171.518 440 256c0 101.689-82.295 184-184 184-101.689 0-184-82.295-184-184 0-84.47 56.786-155.564 134.312-177.219C216.719 75.874 224 66.517 224 55.712V39.064c0-15.709-14.834-27.153-30.046-23.234C86.603 43.482 7.394 141.206 8.003 257.332c.72 137.052 111.477 246.956 248.531 246.667C393.255 503.711 504 392.788 504 256c0-115.633-79.14-212.779-186.211-240.236C302.678 11.889 288 23.456 288 39.056z" />
    </svg>
        <svg class="done" viewBox="0 0 512 512" width="100" title="check-circle">
    <path d="M504 256c0 136.967-111.033 248-248 248S8 392.967 8 256 119.033 8 256 8s248 111.033 248 248zM227.314 387.314l184-184c6.248-6.248 6.248-16.379 0-22.627l-22.627-22.627c-6.248-6.249-16.379-6.249-22.628 0L216 308.118l-70.059-70.059c-6.248-6.248-16.379-6.248-22.628 0l-22.627 22.627c-6.248 6.248-6.248 16.379 0 22.627l104 104c6.249 6.249 16.379 6.249 22.628.001z" />
    </svg>
        
        
  </div>
</div>
@import url(https://fonts.googleapis.com/css?family=Open+Sans:400);

.frame {
  position: absolute;
    display: flex;
    justify-content: center;
    align-items: center;
  top: 50%;
  left: 50%;
  width: 400px;
  height: 400px;
  margin-top: -200px;
  margin-left: -200px;
  border-radius: 2px;
    box-shadow: 4px 8px 16px 0 rgba(0,0,0,0.1);
  background:linear-gradient(to top right, #3A92AF 0%, #5CA05A 100%);
  color: #676767;
    font-family: 'Open Sans', Helvetica, sans-serif;
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
}

.container {
  position: absolute;
    width: 300px;
    height: 260px;
    background: #fff;
    border-radius: 3px;
    box-shadow: 8px 10px 15px 0 rgba(0,0,0,0.2);
}

.title {
    position: absolute;
    top: 0;
    width: 100%;
    font-size: 16px;
    text-align: center;
    border-bottom: 1px solid #676767;
    line-height: 50px;
}

.line {
    position: relative;
    width: 0px;
    height: 3px;
    top: 49px;
    left: 0;
    background: #6ECE3B;
    &.active {
        animation: progressFill 5s ease-out forwards;
    }
}
@keyframes progressFill {
  from {
    width: 0;
  }
  to {
    width: 100%;
  }
}

.dropzone {
    visibility: show;
    position: absolute;
    display: flex;
    justify-content: center;
    align-items: center;
  top: 50%;
  left: 50%;
  transform: translate(-50%,-50%);
    width: 100px;
    height: 80px;
    border: 1px dashed #676767;
    border-radius: 3px;
}
.dropzone.dragover {
  background-color: rgba(0, 0, 0, 0.1); 
}

.upload {
    position: absolute;
    width: 60px;
    opacity: 0.3;
}

.input {
    position: absolute;
    inset: 0;
    opacity: 0;
}

.filename {
    overflow: hidden;
}

.syncing {
    opacity: 0;
    position: absolute;
  top: calc(50% - 25px);
    left: calc(50% - 25px);
    width: 50px;
    height: 50px;
    animation: rotate 2s linear infinite;
}
@keyframes rotate {
    from {
        transform: rotate(0deg);
    }
    to {
        transform: rotate(360deg);
    }
}

.done {
    opacity: 0;
    position: absolute;
  top: 50%;
    left: 50%;
    transform: translate(-50%,-50%);
    width: 50px;
    height: 50px;
}

.upload-btn {
    position: relative;
    top: 180px;
    left: 80px;
    width: 140px;
    height: 40px;
    line-height: 40px;
    text-align: center;
    background: #6ECE3B;
    border-radius: 3px;
    cursor: pointer;
    color: #fff;
    font-size: 14px;
    box-shadow: 0 2px 0 0 #498C25;
    transition: all .2s ease-in-out;
    &:hover {
        box-shadow: 0 2px 0 0 #498C25, 0 2px 10px 0 #6ECE3B;
    }
    
    
}
// Variables
const dropzone = document.querySelector('.dropzone');
const filenameDisplay = document.querySelector('.filename');
const input = document.querySelector('.input');
const uploadBtn = document.querySelector('.upload-btn');
const syncing = document.querySelector('.syncing');
const done = document.querySelector('.done');
const upload = document.querySelector('.upload');
const line = document.querySelector('.line');


dropzone.addEventListener("dragover", (e) => {
  e.preventDefault();
    e.stopPropagation();
    dropzone.classList.add("dragover");
});

dropzone.addEventListener("dragleave", () => {
  dropzone.classList.remove("dragover");
});

dropzone.addEventListener("drop", (e) => {
    e.preventDefault();
  e.stopPropagation();
  dropzone.classList.remove("dragover");
  handleFiles(e.dataTransfer.files);
});

dropzone.addEventListener("dragenter", (e) => {
  e.preventDefault();
  e.stopPropagation();
  dropzone.classList.add("dragover");
});

dropzone.addEventListener("click", () => {
  input.click(); 
});

input.addEventListener('change', (event) => {
  const files = event.target.files;
  if (files.length > 0) {
    const fileName = files[0].name;
    document.querySelector('.filename').textContent = fileName;
    upload.style.display = 'none';
  }
});

dropzone.addEventListener('click', () => {
    input.click();
})

uploadBtn.addEventListener('click', () => {
  const files = document.querySelector('.input').files;
  if (files.length > 0) {  
    dropzone.style.transition = 'opacity 0.5s ease';
    syncing.style.transition = 'opacity 1s ease';
    dropzone.style.opacity = '0';
    syncing.style.opacity = '0.3';
    line.classList.add('active');
    uploadBtn.textContent = 'Uploading...';

    setTimeout(() => {
            done.style.transition = 'opacity 1s ease';
            syncing.style.transition = 'opacity 0.5s ease';
      syncing.style.opacity = '0';
        done.style.opacity = '0.3';
            uploadBtn.textContent = 'Done!';
            input.value = ''; 
    }, 5000); 
  }
});
  

this is what i tried to click everywhere in the dropzone :
dropzone.addEventListener("click", () => { input.click(); });

2d HTML5 Game: How to add collision shapes to loaded tiles that might be rotated and flipped?

I have map data like this, each element separated by space is a different tile with own properties:

static get TILEMAP() {
    return "0C0003 0W1003 0W0003 0W2003 0W3003 0W4003".split(" "); // example tiles, its much longer for real maps
  }

I load tile images like this:

let tiles = {};
const tilemap = Constants.TILEMAP;

function loadTiles() {
  for (const tileIndex in tilemap) {
    const rawTile = tilemap[tileIndex].substring(0, 3); // 0W1.png for example
    const tileImg = new Image();
    tileImg.src = `sprites/maps/tiles/${rawTile}.png`;
    tiles[rawTile] = tileImg;
  }
}

And I draw them to canvas like this:

static rotationKeys = {0: 0, 1: 90, 2: 180, 3: 270};
static tileSize = 50;

function drawMap() {
  const tileSize = Constants.tileSize;
  gameSettings.mapWidth = 35;
  gameSettings.mapHeight = 24;

  const startX = Math.max(0, Math.floor(camera.x / (tileSize * scaleFactor)));
  const startY = Math.max(0, Math.floor(camera.y / (tileSize * scaleFactor)));

  const endX = Math.min(gameSettings.mapWidth, startX + Math.ceil(canvas.width / (tileSize * scaleFactor)) + 1);
  const endY = Math.min(gameSettings.mapHeight, startY + Math.ceil(canvas.height / (tileSize * scaleFactor)) + 1);

  for (let y = startY; y < endY; y++) {
    for (let x = startX; x < endX; x++) {
      let index = y * gameSettings.mapWidth + x;
      const tile = tilemap[index];
      const rotation = parseInt(tile[3]); // Get rotation value for this tile
      const flip = parseInt(tile[4]);

      // Apply rotation transformation
      ctx.save(); // Save the current canvas state
      ctx.translate((x + 0.5) * tileSize * scaleFactor, (y + 0.5) * tileSize * scaleFactor); // Translate to the center of the tile
      ctx.rotate(Constants.rotationKeys[rotation] * Math.PI / 180); // Rotate by the specified angle (converted to radians)

      // Apply flip transformation
      var xScale = 1;
      var yScale = 1;
      if (flip == 1 || flip == 3) {
        xScale = -1;
      }
      if (flip == 2 || flip == 3) {
        yScale = -1;
      }
      ctx.scale(xScale, yScale);

      try {
          ctx.drawImage(tiles[tile.substring(0, 3)], -0.5 * tileSize * scaleFactor, -0.5 * tileSize * scaleFactor, tileSize * scaleFactor, tileSize * scaleFactor); // Draw the rotated image
      } catch (error) {
          console.error(`Failed to draw tile at (${x}, ${y}):`, error);
          console.log("Responsible tile:", tile);
      }
      ctx.restore();
    }
  }
}

As you can see, the tiles can go through quite a lot. Rotations or flips or combined.

I’ve tried defining all collisions like this:

 static colTransforms = {
    "5": {
      rotations: {
        "0": { x: -1, y: -1, width: 52, height: 38,
        flips: {
          "1": { x: -1, y: -1, width: 52, height: 38 },
          "2": { x: -1, y: 13, width: 52, height: 38 },
          "3": { x: -1, y: -1, width: 52, height: 38 }
        }},

        "1": { x: -1, y: -1, width: 38, height: 52,
        flips: {
          "1": { x: 13, y: -1, width: 38, height: 52 },
          "2": { x: -1, y: -1, width: 38, height: 52 },
          "3": { x: 13, y: -1, width: 38, height: 52 }
        }},

        "2": { x: -1, y: 13, width: 52, height: 38,
        flips: {
          "1": { x: -1, y: 13, width: 52, height: 38 },
          "2": { x: -1, y: -1, width: 52, height: 38 },
          "3": { x: -1, y: 13, width: 52, height: 38 }
        }},

        "3": { x: -1, y: -1, width: 38, height: 52,
        flips: {
          "1": { x: 13, y: -1, width: 38, height: 52 },
          "2": { x: -1, y: -1, width: 38, height: 52 },
          "3": { x: 13, y: -1, width: 38, height: 52 }
        }}
      },
    },

    "6": {
      rotations: {
        "0": { x: -1, y: -1, width: 52, height: 26,
        flips: {
          "1": { x: -1, y: -1, width: 52, height: 26 },
          "2": { x: -1, y: 25, width: 52, height: 26 },
          "3": { x: -1, y: -1, width: 52, height: 26 }
        }},

        "1": { x: -1, y: -1, width: 26, height: 52,
        flips: {
          "1": { x: 25, y: -1, width: 26, height: 52 },
          "2": { x: -1, y: -1, width: 26, height: 52 },
          "3": { x: 25, y: -1, width: 26, height: 52 }
        }},

        "2": { x: -1, y: 25, width: 52, height: 26,
        flips: {
          "1": { x: -1, y: 25, width: 52, height: 26 },
          "2": { x: -1, y: -1, width: 52, height: 26 },
          "3": { x: -1, y: 25, width: 52, height: 26 }
        }},

        "3": { x: -1, y: -1, width: 52, height: 26,
        flips: {
          "1": { x: -1, y: -1, width: 52, height: 26 },
          "2": { x: -1, y: 25, width: 52, height: 26 },
          "3": { x: -1, y: -1, width: 52, height: 26 }
        }}
      },
    },

    "7": {
      rotations: {
        "0": { x: -1, y: -1, width: 52, height: 13,
        flips: {
          "1": { x: -1, y: -1, width: 52, height: 13 },
          "2": { x: -1, y: 38, width: 52, height: 13 },
          "3": { x: -1, y: -1, width: 52, height: 13 }
        }},

        "1": { x: -1, y: -1, width: 13, height: 52,
        flips: {
          "1": { x: 38, y: -1, width: 13, height: 52 },
          "2": { x: -1, y: -1, width: 13, height: 52 },
          "3": { x: 38, y: -1, width: 13, height: 52 }
        }},

        "2": { x: -1, y: 38, width: 52, height: 13,
        flips: {
          "1": { x: -1, y: 38, width: 52, height: 13 },
          "2": { x: -1, y: -1, width: 52, height: 13 },
          "3": { x: -1, y: 38, width: 52, height: 13 }
        }},

        "3": { x: -1, y: -1, width: 52, height: 13, 
        flips: {
          "1": { x: -1, y: -1, width: 52, height: 13 },
          "2": { x: -1, y: 38, width: 52, height: 13 },
          "3": { x: -1, y: -1, width: 52, height: 13 }
        }}
      },
    },

    "8": {
      rotations: {
        "0": { x: -1, y: -1, width: 26, height: 26,
        flips: {
          "1": { x: 25, y: -1, width: 26, height: 26 },
          "2": { x: -1, y: 25, width: 26, height: 26 },
          "3": { x: 25, y: -1, width: 26, height: 26 }
        }},

        "1": { x: 25, y: -1, width: 26, height: 26,
        flips: {
          "1": { x: -1, y: -1, width: 26, height: 26 },
          "2": { x: 25, y: 25, width: 26, height: 26 },
          "3": { x: -1, y: -1, width: 26, height: 26 }
        }},

        "2": { x: 25, y: 25, width: 26, height: 26,
        flips: {
          "1": { x: -1, y: 25, width: 26, height: 26 },
          "2": { x: 25, y: -1, width: 26, height: 26 },
          "3": { x: -1, y: 25, width: 26, height: 26 }
        }},

        "3": { x: -1, y: 25, width: 26, height: 26,
        flips: {
          "1": { x: 25, y: 25, width: 26, height: 26 },
          "2": { x: -1, y: -1, width: 26, height: 26 },
          "3": { x: 25, y: 25, width: 26, height: 26 }
        }}
      },
    },
    "9": {
      Lfirst: {
        rotations: {
          "0": { x: -1, y: -1, width: 52, height: 26,
          flips: {
            "1": { x: -1, y: -1, width: 52, height: 26 },
            "2": { x: -1, y: 25, width: 52, height: 26 },
            "3": { x: -1, y: -1, width: 52, height: 26 }
          }},

          "1": { x: 25, y: 25, width: 26, height: 52,
          flips: {
            "1": { x: 25, y: -1, width: 26, height: 52 },
            "2": { x: -1, y: -1, width: 26, height: 52 },
            "3": { x: 25, y: -1, width: 26, height: 52 }
          }},

          "2": { x: -1, y: 25, width: 52, height: 26,
          flips: {
            "1": { x: -1, y: 25, width: 52, height: 26 },
            "2": { x: -1, y: -1, width: 52, height: 26 },
            "3": { x: -1, y: 25, width: 52, height: 26 }
          }},

          "3": { x: -1, y: 25, width: 52, height: 26,
          flips: {
            "1": { x: -1, y: -1, width: 52, height: 26 },
            "2": { x: -1, y: 25, width: 52, height: 26 },
            "3": { x: -1, y: -1, width: 52, height: 26 }
          }}
        },
      },
      Lsecond: {
        rotations: {
          "0": { x: -1, y: -1, width: 26, height: 52,
          flips: {
            "1": { x: 25, y: -1, width: 26, height: 52 },
            "2": { x: -1, y: -1, width: 26, height: 52 },
            "3": { x: 25, y: -1, width: 26, height: 52 }
          }},

          "1": { x: -1, y: -1, width: 52, height: 26,
          flips: {
            "1": { x: -1, y: -1, width: 52, height: 26 },
            "2": { x: -1, y: 25, width: 52, height: 26 },
            "3": { x: -1, y: -1, width: 52, height: 26 }
          }},

          "2": { x: 25, y: -1, width: 26, height: 52,
          flips: {
            "1": { x: -1, y: -1, width: 26, height: 26 },
            "2": { x: 25, y: 25, width: 26, height: 26 },
            "3": { x: -1, y: -1, width: 26, height: 26 }
          }},
          "3": { x: -1, y: -1, width: 26, height: 52,
          flips: {
            "1": { x: 25, y: -1, width: 26, height: 52 },
            "2": { x: -1, y: -1, width: 26, height: 52 },
            "3": { x: 25, y: -1, width: 26, height: 52 }
          }}
        },
      }
    }
  } // transformations for collisions

So that we could later check for collision like this when the player is walking into the tile:

let newTileX;
let newTileY;

let newTileX;
    let newTileY;

    this.x = this.body.x;
    this.y = this.body.y;

    if (speedX != null) {
      newTileX = Math.floor((this.x + speedX) / 50);
    } else {
      newTileX = Math.floor(this.x / 50);
    }

    if (speedY != null) {
      newTileY = Math.floor((this.y + speedY) / 50);
    } else {
      newTileY = Math.floor(this.y / 50);
    }

    const tileName = Constants.TILEMAP[newTileY * 35 + newTileX];

    const rotation = tileName[3]; // Get rotation value for this tile
    const flip = tileName[4]; // Get flip value
    const collision = tileName[5]; // Get collision type

    let collisionShape = null;

    switch (parseInt(collision)) {
      case 0:
      case 1:
      case 2:
        // The entire tile is walkable
        collisionShape = null; // No need to define a collision shape for walkable tiles
        break;
      case 3:
      case 4:
        // The entire tile is an obstacle
        collisionShape = { x: -1, y: -1, width: 52, height: 52 };
        break;
      case 5:
      case 6:
      case 7:
      case 8:
        if (parseInt(flip) > 0) {
          collisionShape = Constants.colTransforms[collision].rotations[rotation].flips[flip];
          
        } else {
          collisionShape = Constants.colTransforms[collision].rotations[rotation];
        }
        break;
      case 9:
        if (parseInt(flip) > 0) {
          collisionShape = [];
          console.log(collision)
          collisionShape.push(Constants.colTransforms[collision].Lfirst.rotations[rotation].flips[flip]);
          collisionShape.push(Constants.colTransforms[collision].Lsecond.rotations[rotation].flips[flip]);
        } else {
          console.log(collision)
          collisionShape = [];
          collisionShape.push(Constants.colTransforms[collision].Lfirst.rotations[rotation]);
          collisionShape.push(Constants.colTransforms[collision].Lsecond.rotations[rotation]);
        }
        break
    }

    // Check for collision only if collision shape is defined
    if (collisionShape != null && !Array.isArray(collisionShape)) {
      // Calculate the player's local position within the tile
      const localPlayerX = (this.x + (speedX || 0)) % 50;
      const localPlayerY = (this.y + (speedY || 0)) % 50;

      // Calculate the center of the circular area (head radius)
      const playerCenterX = localPlayerX + Constants.playerCircle;
      const playerCenterY = localPlayerY + Constants.playerCircle;

      // Calculate the closest point on the rectangle to the circle
      const closestX = this.clamp(playerCenterX, collisionShape.x, collisionShape.x + collisionShape.width);
      const closestY = this.clamp(playerCenterY, collisionShape.y, collisionShape.y + collisionShape.height);

      // Calculate the distance between the circle's center and the closest point
      const distanceX = playerCenterX - closestX;
      const distanceY = playerCenterY - closestY;

      // Check if the distance is less than or equal to the circle's radius
      if ((distanceX * distanceX + distanceY * distanceY) <= (Constants.playerCircle * Constants.playerCircle)) {
          // Collision detected, player cannot move
          speedX = 0;
          speedY = 0;
      }
    } else if (collisionShape != null && Array.isArray(collisionShape)) {
      for (let shape of collisionShape) {
        // Calculate the player's local position within the tile
        const localPlayerX = (this.x + (speedX || 0)) % 50;
        const localPlayerY = (this.y + (speedY || 0)) % 50;

        // Calculate the center of the circular area (head radius)
        const playerCenterX = localPlayerX + Constants.playerCircle;
        const playerCenterY = localPlayerY + Constants.playerCircle;

        // Calculate the closest point on the rectangle to the circle
        const closestX = this.clamp(playerCenterX, shape.x, shape.x + shape.width);
        const closestY = this.clamp(playerCenterY, shape.y, shape.y + shape.height);

        // Calculate the distance between the circle's center and the closest point
        const distanceX = playerCenterX - closestX;
        const distanceY = playerCenterY - closestY;

        // Check if the distance is less than or equal to the circle's radius
        if ((distanceX * distanceX + distanceY * distanceY) <= (Constants.STICK_FIGURE_HEAD_RADIUS * Constants.STICK_FIGURE_HEAD_RADIUS)) {
            // Collision detected, player cannot move
            speedX = 0;
            speedY = 0;
        }
      }
    }

Its not working as expected though, and honestly the whole approach seems messy to say the least. Some shapes arent flipped or rotated properly (could be my calculations, but it also could be that the code is just doing wrong math). How to actually properly add collision shapes to the individual tiles and make sure they go through the same rotations and flips when necessary?

Linear time increase per promise when resolving concurrently using Promise.all?

I have a method that steps through a JSON payload to run computation on some data within that payload. When I create 100 promises of that method and then pass them into Promise.all(), it seems that for every promise that is resolved concurrently, the next one takes a bit longer to resolve.

This is not specific to my method, I have tried a similar thing with a public API that returns simple JSON data. In calling that API concurrently using Promise.all I observed the same thing… every consecutive promise would take longer and longer to resolve.

Here is a simple code snippet to illustrate what I’m doing:

const axios = require('axios');

const getSomeData = async () => {
  try {
    await axios.get('https://some.api.com');
  } catch (error) {
    console.log('Failed to get data...');
  }
};

const promiseList = [];

for (let i = 0; i < 100; i += 1) {
  promiseList.push(new Promise(async (res) => {
    const startTime = performance.now();
    await getSomeData();
    const stopTime = performance.now();
    console.log(`time taken by promise: ${stopTime - startTime}`);
    res();
  }));
}

const main = async () => {
  const startTime = performance.now();
  await Promise.all(promiseList);
  const stopTime = performance.now();
  console.log(`total time taken: ${stopTime - startTime}`);
};

main();

This of course is a pretty pointless method but I created it strictly to observe how promises behave when running concurrently and how much performance benefit there is versus running sequentially (it’s obviously a significant improvement).

My question is, what would cause every consecutive promise to take longer and longer until all the promises are resolved? In which case if I were to run this again, it would reset the time taken back to around 200ms for the first promise, before it started increasing again until the last promise would take around 600ms to resolve.

Is this just the nature of single threaded Javascript execution and concurrency? I am really interested in hearing a more in depth explanation of this phenomenon.

Recurring events in Fullcalendar version 6 using rrule

I’m trying to figure out recurring events in fullcalendar version 6 using rrule but it is not working. I need to do recurring events every week on specific days, every month, and yearly. I can’t figure out what is wrong neither is shows me any error in console.

  calendar = new Calendar(calendarEl, {
        // Event handlers
        eventClick: function(info) {
            var eventObj = info.event;
            populateAndShowModal(eventObj, eventObj.extendedProps.procedure);
        },
        eventReceive: function(info) {
            var eventObj = info.event;
            populateAndShowModal(eventObj, eventObj.title);
        },

        schedulerLicenseKey: 'CC-Attribution-NonCommercial-NoDerivatives',
        droppable: true,
        themeSystem: 'bootstrap5',
        displayEventTime: false,
        slotLabelInterval: {
            minutes: 30
        },
        slotMinTime: '08:00:00',
        slotMaxTime: '19:00:00',
        eventTimeFormat: {
            hour: '2-digit',
            minute: '2-digit',
            hour12: false,
        },
        height: "auto",
        initialView: 'resourceTimelineDay',
        aspectRatio: 1.5,
        headerToolbar: {
            left: 'prev,next,custom2',
            center: 'title',
            right: 'custom1,resourceTimelineDay,resourceTimelineWeek,resourceTimelineMonth'
        },
        editable: true,
        resourceAreaHeaderContent: 'Staff',
        resources: [{
            id: 6,
            title: "New",
        }, {
            id: 211,
            title: "Test",
        }],
        events: [{
            title: "SiH|97155|Processed|208|97155",
            duration: '39:00',
            resourceId: 211,
            assignedToName: "Matt Randall",
            procedure: "97155",
            color: "#00ffca",
            rrule: {
                freq: rrule.RRule.WEEKLY,
                interval: 2,
                byweekday: [rrule.RRule.WED],
                dtstart: '2024-03-13T08:00:00'
            }
        }]
    });
    calendar.render();

picture of calendar

CSP works with Next.js prod build but not on dev server

I’ve been trying to implement CSP on my Next.js application, and I’ve managed to get it working when running next build and next start, but for some reason when running next dev it doesn’t render at all, and the following error is logged on the console:

Uncaught EvalError: Refused to evaluate a string as JavaScript because 'unsafe-eval' is not an allowed source of script in the following Content Security Policy directive: "script-src 'self'".
    at ./node_modules/next/dist/compiled/@next/react-refresh-utils/dist/runtime.js (react-refresh.js?ts=1710261451116:30:26)

I tried following the suggestions in the Next.js docs as well as in this GitHub discussion of using a nonce, but I was only able to get it working by adding the header to next.config.js. I’m also using the page router, if that info is helpful. This is what the relevant parts of my next.config.js file looks like:

const cspHeader = `
  default-src 'self';
  script-src 'self';
  style-src 'self' 'unsafe-inline' fonts.googleapis.com;
  font-src 'self' https:;
  img-src 'self' blob: data:;
  object-src 'none';
  connect-src 'self' https:;
  upgrade-insecure-requests;
`

module.exports = {
  ...
  async headers() {
    return [
      {
        source: '/(.*)',
        headers: [
          {
            key: 'Content-Security-Policy',
            value: cspHeader.replace(/n/g, ''),
          },
        ],
      },
    ]
  },
}

Any idea on how to resolve this issue (preferably without modifying the CSP header just for local development)?

zTree to explore files

Is there an easy way to convert a list of files, with full path, into ztree nodes?

For example

Folder_1/Folder_1_1/File_1_1_a.txt
Folder_1/Folder_1_1/File_1_1_b.txt
Folder_1/Folder_1_1/Folder_1_1_1/File_1_1_1_a.txt
Folder_2/Folder_2_1/File_2_1_a.txt
Folder_2/Folder_2_1/File_2_1_b.txt

I want to convert into this

-Folder_1
    |-Folder_1_1
        |-File_1_1_a.txt
        |-File_1_1_b.txt
        |-Folder_1_1_1
            |-File_1_1_1_a.txt
-Folder_2
    |-Folder_2_1
        |-File_2_1_a.txt
        |-File_2_1_b.txt

Why do I receive a console error saying I need to define props even though they are defined in the parent and the child?

I am building a website using Vue JS 3 and Laravel and when I try and implement my Index.vue component I receive these errors:

[Vue warn]: Missing required prop: “label”
[Vue warn]: Missing required prop: “isDisabled”

I am pretty sure they are defined correctly in both the parent:

Vue.component('biometricos', {
  props: {
    label: {
      required: true,
      type: String,
      default: '',
    },
    className: {
      type: String
    },
    isDisabled: {
      required: true,
      type: Boolean,
      default: false
    },
    hours: Boolean,
    minutes: Boolean,
  }
});

and child:

props: {
  label: {
    required: true,
    type: String,
    default: '',
  },
  className: {
    type: String
  },
  isDisabled: {
    required: true,
    type: Boolean,
    default: false
  },
  hours: Boolean,
  minutes: Boolean,
},

It might make sense to declare a label like this

<Component label="YourLabelHere" isDisabled="false"></Component>

But I don’t ever call the component in this way. Plus I don’t think this should be necessary with all of my declarations anyways.

Any ideas on why this might be happening are much

How return false from with regex when string contains an empty space

I have been trying to get the following regex to return false if the string has an empty space for the past 3 days. I have read about 24 Stack Overflow postings among other web resources. I’ve take 3 tutorials.

I have been able to return true when there’s at least a number and a letter, and a string between 8 and 24 characters. I have not been able to return false when there is an empty space.

I know that [^S] is supposed to solve the issue, but I haven’t been able to get it to work.

Here’s my function.

      function validatePassword(password) {
         const pattern = /^(?=.*d)(?=.*[a-zA-Z])^(?=.*s+$).{8,24}$/;
         return pattern.test(password);
      }

      console.log(validatePassword("AlmostBald1 2"));

I have read about 24 Stack Overflow postings among other web resources. I’ve take 3 tutorials.

I have been able to return true when there’s at least a number and a letter, and a string between 8 and 24 characters. I have not been able to return false when there is an empty space.

I have tried adding this piece to my current regex pattern. Examples below:

const pattern = /^(?=.*d)(?=.*[a-zA-Z])^(?=.*s+$).{8,24}$/;
const pattern = /^(?=.*d)(?=.*[a-zA-Z])[^S].{8,24}$/;

I have read (to name a few):
https://regexone.com/lesson/excluding_characters
Detect if string contains any spaces
Regular expression for not allowing spaces in the input field
https://regex101.com/r/zG6Gbz/1
https://www.tutorialspoint.com/validating-a-password-using-javascript#:~:text=To%20validate%20a%20password%20using,the%20password%20matches%20the%20pattern.

Cascading dropdown in React

I’m developing a web app feature where the City dropdown values should filter based on the selected Province. The problem is that when a user selects a Province, the City dropdown jumps to the first city of that province, but still displays all cities, including those from other provinces. I want the City dropdown to only show cities belonging to the selected province. Check out the live codesandbox here. Filtering logic is in /src/components/shared/header > Header.tsx.

Header component (attempted filtering logic lives here):

export const Header = ({ data, isLoading, error }: HeaderProps) => {
  ...

  // Bring in global state
  const {
    provinceDropdownFilter,
    cityDropdownFilter,
  } = useFilterStore();

  const filteredData = data.map((group) => group.equipments).flat();

  ...

  const handleDropdownFilterProvince = (
    e: React.ChangeEvent<HTMLSelectElement>
  ) => {
    useFilterStore.setState({ provinceDropdownFilter: e.target.value });

    // Filter the data based on the selected province
    const filteredCities = filteredData
      .filter((item) => item.state === e.target.value)
      .map((item) => item.city);

    // Set the filtered city dropdown options
    useFilterStore.setState({ cityDropdownFilter: filteredCities[0] || "" });
  };

  const handleDropdownFilterCity = (
    e: React.ChangeEvent<HTMLSelectElement>
  ) => {
    useFilterStore.setState({ cityDropdownFilter: e.target.value });

    // Filter the data based on the selected city
    const filteredProvinces = filteredData
      .filter((item) => item.city === e.target.value)
      .map((item) => item.state);

    // Set the filtered province dropdown options
    useFilterStore.setState({
      provinceDropdownFilter: filteredProvinces[0] || "",
    });
  };

  ...

  return (
    <>
      ...
          <Dropdown
            data={data}
            value={provinceDropdownFilter}
            onChange={handleDropdownFilterProvince}
            filterType="state"
          />
          <Dropdown
            data={data}
            value={cityDropdownFilter}
            onChange={handleDropdownFilterCity}
            filterType="city"
          />
      ...
    </>
  );
};

Dropdown component:

export const Dropdown: React.FC<DropdownProps> = ({
  data,
  onChange,
  value,
  filterType,
}) => {
  ...

  // Map over the parent array as it has nested children arrays with all data containing.
  // Combine all chidren into one combined array
  const filteredData = data.map((group) => group.equipments).flat();

  // Filter the data based on the filterType
  const filteredOptions = filteredData.filter((i) => {
    if (filterType === "manufacturer") {
      return i.manufacturer;
    }
    if (filterType === "state") {
      return i.state;
    }
    if (filterType === "city") {
      return i.city;
    }

    return false;
  });

  ...

  return (
    <>
      <Select
        aria-label="Select"
        placeholder={getCustomPlaceholder(filterType) as string}
        value={value}
        onChange={handleFilters}
      >
        {Array.from(uniqueValues)
          .sort()
          .map((value) => (
            <option key={value} value={value}>
              {value}
            </option>
          ))}
      </Select>
    </>
  );
};

Creating and saving new tr elements with JS

I’m fairly new to coding, especially JS. I’m building a program meant to calculate input and put the result (along with the date) into a table. There should be a new entry in the table every time there is new input. Whenever the page is reloaded, the table’s data should be saved and retrieved.

The problem I’m having now is that only the first entry is saved. All the data in the table must be saved. Does anybody have a suggestion? Thanks.

Here’s my code:

// variables

const input = document.getElementById('input');

//buttons

const enter = document.getElementById('enter-value');
const log = document.getElementById("log-value");
const save = document.getElementById("save-value");
const done = document.getElementById("done-button");

//log areas

const itemHolder = document.getElementById('item-holder');
const totalMarker = document.getElementById("grand-total");

// messagges

const negativeValueMessage = document.getElementById('value-message-negative');
const positiveValueMessage = document.getElementById('value-message-positive');
const doneMessage = document.getElementById('done');

//other

const tool = document.getElementById('tool');
const date = new Date();

//input testing code

function checkInput (){
    input.addEventListener('input', function(){
        if(input.value < 0 ){
           negativeValueMessage.style.display = "block";
           positiveValueMessage.style.display = "none";
           enter.style.display = "block";
           enter.disabled = false;
           enter.style.opacity = "100%";
        }
        else if (input.value > 0) {
            negativeValueMessage.style.display = "none";
            positiveValueMessage.style.display = "block";
            enter.style.display = "block";
            enter.disabled = false;
            enter.style.opacity = "100%";
        }
        else {
            negativeValueMessage.style.display = "none";
            positiveValueMessage.style.display = "none";
            enter.disabled = true;
            if(enter.disabled){
                enter.style.opacity = '60%';
            }
        }
    });
}
checkInput();

// input reception

function useInput (){
    enter.addEventListener('click', function(){
        enter.style.display = 'none';
        log.style.display = 'block';
        inputDisalowed();
        log.addEventListener('click', function(){
            const addValues = Number(input.value) + Number(totalMarker.value);
            const total = addValues;
            totalMarker.value = total;
            function newInfo(){
                itemHolder.innerHTML += '<tr><td id="date">' + dateHolder + '</td><td id="amount">$' + totalMarker.value + '</td></tr>';
            }
            newInfo();
            log.style.display = 'none';
            save.style.display = 'block';
            save.addEventListener('click', function(){
                doneMessage.style.display = "grid";
                tool.style.display = 'none';
                const dateData = document.getElementById('date').innerText;
                const amountData = document.getElementById('amount').innerText;
                const dataArray = [dateData, amountData];
                localStorage.setItem('savedDate', (dataArray[0]));
                localStorage.setItem('savedAmount', dataArray[1]);
                localStorage.setItem('savedTotal', Number(totalMarker.value));
                done.addEventListener('click', function(){
                    reloadPage();
                });
            });
        });
    });
}
useInput();
retrieveOnReload();
const dateHolder = monthFixedValue() + '/' + date.getDate() + '/' + date.getFullYear();

function monthFixedValue (){
    return date.getMonth() + 1;
}
function inputDisalowed (){
    input.addEventListener('input', function(){
        alert("You have already input your value. Inputing again will always restart the proccess.");
        location.reload();
    });
}
function retrieveOnReload(){
    window.addEventListener('DOMContentLoaded', function(){
    const retrievedDate = localStorage.getItem('savedDate');
    const retrieveAmount = localStorage.getItem('savedAmount');
    itemHolder.innerHTML += '<tr><td id="date">' + retrievedDate + '</td><td id="amount">' + retrieveAmount + '</td></tr>';});
    totalMarker.value = Number(localStorage.getItem('savedTotal'));
};
function reloadPage() {
    window.location.href = window.location.href;
}
*{
    box-sizing: border-box;
    font-family: 'Lucida Sans', 'Lucida Sans Regular', 'Lucida Grande', 'Lucida Sans Unicode', Geneva, Verdana, sans-serif;
}
::-webkit-scrollbar{
    width:13px;
}
::-webkit-scrollbar-track{
    background: rgb(160,180,190);
    border-radius: 5px;
}
::-webkit-scrollbar-thumb{
    background: rgb(120,140,150);
    border-radius: 10px;
}
body {
    background-image: url(/Background.svg);
    display: grid;
    width: 100vw;
    justify-content: center;
    margin: 0;
    background-position: center;
    align-content: center;
    justify-items: center;
}
h1{
    border: 1px solid black;
    display: flex;
    justify-content: center;
    align-items: center;
    background-image: linear-gradient(
        rgb(150,170,180),
        rgb(120,140,150)
    );
    border-radius: .5vw;
    margin-bottom: 10px;
    width: 80vw;
    height: 70px;
    min-width: 400px;
    font-family:'Lucida Sans', 'Lucida Sans Regular', 'Lucida Grande', 'Lucida Sans Unicode', Geneva, Verdana, sans-serif;
    color: rgb(20,20,90);
    font-size: 40px;
    border: none;
    margin-top: -150px;
    margin-left: -20px;
}
main{
    display: grid;
    align-items: center;
    justify-items: center;
    background: linear-gradient(
        rgb(150,170,180) 20%,
        rgb(120,140,150) 
    );
    border-radius: .5vw;
    margin-top: 10px;
    padding: 20px;
    width: 80vw;
    min-width: 400px;;
}
.inputs {
    margin: 20px;
    width: 90%;
    display: flex;
    justify-content: center;
}
input {
    border: none;
    background-color: rgb(30,90,130);
    color: rgb(10,10,50);
    height: 35px;
    width: 220px;
    font-family:'Lucida Sans', 'Lucida Sans Regular', 'Lucida Grande', 'Lucida Sans Unicode', Geneva, Verdana, sans-serif;
    font-size: 15px;
    border-bottom: 2px solid rgb(20,80,100);
    border-radius: .2vw;
    margin-right: 3px;
    &::placeholder{
        color: rgb(100,140,180);
        font-family:'Lucida Sans', 'Lucida Sans Regular', 'Lucida Grande', 'Lucida Sans Unicode', Geneva, Verdana, sans-serif;
        font-size: 15px;
        font-weight: 900;
    }
}
#enter-value, #save-value, #log-value{
    border: none;
    border-radius: .2vw;
    background: rgb(20,80,180);
    font-size: 20px;
    font-weight: bolder;
    color: rgb(10,10,50);
    margin-left: 3px;
    &:hover{
        background: rgb(10,70,170);
    }
    &:active{
        background: rgb(20,80,180);
    }
}
#enter-value{
    display: none;
}
#save-value{
    display: none;
}
#log-value{
    display: none;
}
.value-message{
    color: rgb(30,40,100);
    display: none;
    margin-bottom: -20px;
}
label{
    text-align: center;
    font-weight: bolder;
    display: flex;
    align-items: baseline;
    font-size: 35px;
    
}
#grand-total{
    height: 40px;
    width: 150px;
    margin-bottom: 30px;
    margin-top: 0px;
    background: rgb(10,10,100);
    color: rgb(150,170,180);
    display: grid;
    align-content: center;
    text-align: center;
    font-family: 'Lucida Sans', 'Lucida Sans Regular', 'Lucida Grande', 'Lucida Sans Unicode', Geneva, Verdana, sans-serif;
    border-radius: 2px;
    font-weight: bolder;
    font-size: 35px;
}
.table-window{
    height: 100px;
    width: 100%;
    display: grid;
    justify-items: center;
    align-items: center;
    overflow-y: scroll;
}
table{
    background-color: rgb(60,120,160);
    border-style: none;
    border-collapse: collapse;
}
.heading-row{
    background: rgb(100,160,200);
    height: 40px;
    width: 750px;
}
th{
    border: 0;
    width: 170px;
}
td{
    text-align: center;
    padding: 4px;
    width: 170px;
}
.th1,
.th2,
.th3{
    border-right: 2px solid rgb(170,170,255);
}
.td1,
.td2,
.td3{
    border-right: 2px solid rgb(170,170,255);
}
#done{
    position: absolute;
    display: grid;
    justify-items: center;
    display: none;
}
#done-img-holder{
    display: flex;
    justify-content: center;
    align-content: center;
    width: 100%;
    height: 100%;
}
#done-img-holder > img{
    width: 490px;
    display: grid;
    margin-top: -30px;
}
#done-info-holder{
    display: grid;
    justify-items: center;
    width: 400px;
    height: 170px;
    background: linear-gradient(
        rgb(180,180,190),
        rgb(140,140,150)
    );
    align-content: center;
    border-radius: .5vw;
}
#done-info-holder > p{
    font-size: 20px;
    color: rgb(10,70,160);
    font-weight: 900;
}
#done-info-holder > button{
    height: 50px;
    width: 130px;
    font-size: 30px;
    font-weight: 900;
    background: rgb(10,10,100);
    border: none;
    border-radius: 30px;
    color: rgb(120,140,150);
    &:hover{
        background: rgb(120,140,150);
        color: rgb(10,10,100);
    }
    &:active{
        background: rgb(10,10,100);
        color: rgb(120,140,150);
    }
}
<html lang="en">
<head>
    <meta charset="utf-8">
    <meta name="veiwport" content="width=device-width, initial-scale=1.0">
    <link rel="stylesheet" href="FinanceTool.css">
    <title>Finance_Tool</title>
</head>
<body>
    <main id="tool">
            <h1 class="heading">Simple Finance Tool</h1>
        <p id="value-message-negative" class="value-message">Your number is negative. This will be calculated as a financial loss.</p>
        <p id="value-message-positive" class="value-message">Your number is positive. This will be calculated as a financial gain.</p>
        <div class="inputs">
            <input type='number' id="input" class="input" placeholder="Input financial loss or gain." min="0"/>
            <button type="button" id="enter-value">Enter</button>
            <button type="button" id="log-value">Log Change</button>
            <button type="button" id="save-value">Save Change</button>
        </div>
        <label for="grand-total">$<input id="grand-total" disabled/></label>
        <div class="table-window">
            <table id="item-holder">
                <tr class="heading-row">
                    <th class="th1">Date</th>
                    <th class="th4">Total After Change</th>
                </tr>
            </table>
            
            
        </div>
        
    </main>
    <div id="done">
        <div id="done-img-holder">
            <img src="/Finance Tool/check-circle-svgrepo-com.svg"/>
        </div>
        <div id="done-info-holder">
            <p>All done! You're entry is complete.</p>
            <button id="done-button">Done</button>
        </div>
    </div>
    <script src="FinanceTool.js"></script>
</body>
</html>

Also here’s a link to the code in codePen(note: due to a peculiarity of codePen, the code will not work properly in it, but you can copy it from codePen to your IDE).

codePenProjectLink

I want to use javascript to get my site users webcam and take some pictures with it

I want to use javascript to access my site users camera and take pictures with it which will be uploaded with php to my server please who can give me a full html css javascript and php example please full code

I want it to ask for permission from the user and the when accepted take some pictures or even short videos which will then be uploaded with php to my server with no encryption

discord bot is showing online but doesnt show up need commands

so i keep getting a: The application did not respond.

yet it shows up as online on discord
and now of the new commands i made are showing up yet the old ones i deleted are still there


import { Client, Collection, GatewayIntentBits } from 'discord.js';
import fs from 'fs';
import dotenv from 'dotenv';
dotenv.config();

const client = new Client({
  intents: [GatewayIntentBits.Guilds]
});

client.commands = new Collection();

const commandsPath = './src/commands';
const commandFiles = fs.readdirSync(commandsPath).filter(file => file.endsWith('.js'));

for (const file of commandFiles) {
  import(`./src/commands/${file}`).then(commandModule => {
    client.commands.set(commandModule.default.data.name, commandModule.default);
  });
}

client.once('ready', () => {
  console.log(`Logged in as ${client.user.tag}!`);
});

client.on('interactionCreate', async interaction => {
  if (!interaction.isCommand()) return;

  const command = client.commands.get(interaction.commandName);
  if (!command) return;

  try {
    await command.execute(interaction);
  } catch (error) {
    console.error(error);
    await interaction.reply({ content: 'There was an error executing that command.', ephemeral: true });
  }
});

client.login(process.env.DISCORD_TOKEN);

Make a discord bot for my discord

recognize_google do not work with sr.AudioData() in python

I want to get an audio file in js and then send this file to python and then recognise the text being spoken. I know that tools exist in js, but I need server-side recognition in order to secure the interface in an online mini-game.
main.js

async function try_case(click) {
    var el = click.target;
    el.innerHTML = microphoneHtml;
    for (var i = 0; i < items.length; i++) {
        items[i].removeEventListener('click', try_case);
    }
    navigator.mediaDevices.getUserMedia({ audio: true })
        .then(function(stream) {
            var mediaRecorder = new MediaRecorder(stream);
            mediaRecorder.start();
            var audioChunks = [];
            mediaRecorder.addEventListener("dataavailable", function(event) {
                audioChunks.push(event.data);
            });
            mediaRecorder.addEventListener("stop", function() {
                document.getElementsByClassName('micro-listener')[0].classList.add('exit');
                setTimeout(function() {
                    el.innerHTML = "";
                }, 500);
                var audioBlob = new Blob(audioChunks, { type: 'audio/wav' });
                var formData = new FormData();
                formData.append('audio', audioBlob);

                fetch(`/dashboard/games/memowordrize/${sessionID}/record`, {
                        method: 'POST',
                        headers: {
                            'X-CSRFToken': csrf_token
                        },
                        body: formData
                    })
                    .then(response => response.text())
                    .then(data => {
                        console.log(data);
                    });

            });
            setTimeout(function() {
                mediaRecorder.stop();
            }, 3000);
        });

    return;
}

memowordrize.py

@memowordrize_bp.route('/dashboard/games/memowordrize/<string:session_id>/record', methods=['POST'])
@check_game
def record(session_id):
    try:
        if 'audio' not in request.files:
            return jsonify({
                "code": 403,
                "message": "Aucun fichier audio n'a été trouvé!",
                "result": []
            })
        audio_file = request.files['audio']
        audio_data = audio_file.read()
        
        recognizer = sr.Recognizer()
        audio = sr.AudioData(audio_data, 16000, 2)
        text = recognizer.recognize_google(audio, language="fr-FR")
        print(text)
        return jsonify({
            "code": 200,
            "message": "Le texte a été reconnu!"
        })
        

    except Exception as e:
        logging.error("An error has occured: " + str(e))
        return jsonify({
            "code": 500,
            "message": "Une erreur s'est produite!",
            "result": []
        }), 500

Everything works (I didn’t put in all my code), it’s from the line text = recognizer.recognize_google(audio, language="fr-FR") that an error is detected.

The error is captured but nothing is displayed to indicate: ERROR:root:An error has occured:. But nothing is indicated. No indication on the net or by chatGpt.