Trouble making a transparent radial gradient (JavaScript/HTML)

CONTEXT:
I am trying to make a light source using ray casting, that the player can use in a randomly generated maze. The rays cast from the mouse pointer. The radial gradient that I’m using changes their colour from white (the light) to black (to simulate darkness).

The problem:
The problem that I’m having is that the ctx.createRadialGradient() isnt making the lines transparent, and is rather just a solid white colour, and I cant see the other stroke lines through the transparency of the white colour.

The goal:
I want the player to be unable to see other ctx.stroke() lines when the gradient of the line is black, but when the gradient of the line is still a transparent white, I want to be able to actually see the other ctx.stroke() lines.

WORTH NOTING: there are exactly 1,000 rays that are being cast to create a circle (using rays).

Code:

const x = this.rays[i].x
const y = this.rays[i].y
const color0 = this.rays[i].radialGradient.colorStop0 // this color is white;
const color1 = this.rays[i].radialGradient.colorStop1 // this color is black;
const radius = this.circularRayRadius // the radius is equal to 200;
gradient = this.ctx.createRadialGradient(x, y, 0, x, y, radius);
gradient.addColorStop(0, color0);
gradient.addColorStop(1, color1);

Detect route change inside inner/partial component (VueRoute 3 in Nuxt 2.14)

Environment

There’s a legacy nuxt (v2.14.6) project with vue-route (v3.4.3), module nuxt-i18n (v6.15.1), and vuetify (v2.7.2). Indeed… Some history here!

A page change there is being done via push:

<!-- File: ./pages/user/_slug/index.vue -->

<script lang="ts">
import mixins from 'vue-typed-mixins';
import SomeMixin from '~/mixins/SomeMixin';

export default mixins(SomeMixin).extend({
  name: 'UserPage',
  // ...
  methods: {
    async submit(): Promise<void> {
      const response = await this.$api(/* ... */) // ...
      // ...
  
      this.$router.push(
        this.localePath({
          name: 'user-slug-management',
          params: {
            slug: String(this.user.slug ?? this.user.id)
          }
        })
      );
    }
    // ...
  }
  // ...
});
</script>

Another page has the path name in head:

<!-- File: ./pages/user/_slug/management.vue -->

<template>
  <div>
    <SomeComponent />
  </div>
</template>

<script lang="ts">
import mixins from 'vue-typed-mixins';
import SomeMixin from '~/mixins/SomeMixin';
import config from '~/utils/config';
import SomeComponent from '~/components/SomeComponent.vue'

export default mixins(SomeMixin).extend({
  transition: 'scroll-x-reverse-transition',
  name: 'UserManagement',

  components: {
    SomeComponent
  },

  head(): any {
    const canonicalPathOptions = {
      name: 'user-slug-management',
      params: {
        slug: String(this.user.slug ?? this.user.id)
      }
    }

    return {
      title: this.$t('this.title'),
      meta: [{ hid: 'robots', name: 'robots', content: 'noindex' }],

      link: [
        {
          rel: 'canonical',
          href: config.BASE_URL + this.localePath(canonicalPathOptions),
          hid: 'canonical'
        },
        {
          rel: 'alternate',
          hreflang: 'en',
          content: config.BASE_URL + this.localePath(canonicalPathOptions, 'en')
        },
        {
          rel: 'alternate',
          hreflang: 'lt',
          content: config.BASE_URL + this.localePath(canonicalPathOptions, 'lt')
        },
        // ...
      ]
    }
  }
});

Issue

The Vue component PartialComponent has another InnerPartialComponent that, in turn, has a Google Recaptcha (i.e. VueRecaptcha) inside that actually is an old vue-recaptcha (v1.3.0). So, in general:

management.vue
> SomeComponent
>> PartialComponent
>>> InnerPartialComponent
>>>> VueRecaptcha

Due to Vue Route transition scroll-x-reverse-transition of management.vue that comes from Vuetify, the following happens on page change:

enter image description here

The captcha “jumps” on the page during the transition. Therefore, I guess, it would be appropriate to use v-show or v-if on the captcha VueRecaptcha component to hide the element during route change, but am still searching for an adequate approach.

Current Workaround

Currently, the somewhat odd workaround is to dispatch a CustomEvent in beforeRouteLeave in the “route component” and change a prop of that InnerPartialComponent that has VueRecaptcha inside to control its visibility like <InnerPartialComponent :is-captcha-visible="isCaptchaVisible" /> and then <VueRecaptcha v-show="isCaptchaVisible" /> inside.

<!-- File: ./mixins/SomeMixin.ts -->

import Vue from 'vue'

export default Vue.extend({
  layout: 'main',
  transition: 'scroll-x-transition',
  // ...

  beforeRouteLeave(to, from, next) {
    window.dispatchEvent(new CustomEvent('before-route-leave', {
      detail: { to, from }
    }));

    next();
  }
});
<!-- File: ./components/PartialComponent.vue -->

<template>
  <div>
    <InnerPartialComponent v-if="isCaptchaVisible" ref="recaptcha" :site-key="reCaptchaSiteKey" />
  </div>
</template>

<script lang="ts">
import Vue from 'vue'
import InnerPartialComponent from '~/components/InnerPartialComponent.vue';
import config from '~/utils/config';

export default Vue.extend({
  name: 'PartialComponent',

  components: {
    InnerPartialComponent
  },

  data() {
    return {
      reCaptchaSiteKey: '' as string
    }
  },

  computed: {
    isCaptchaVisible(): boolean {
      return (this.reCaptchaSiteKey as string).length > 0
    }
  },

  created() {
    if (process.client) {
      this.reCaptchaSiteKey = config.RECAPTCHA_SITE_KEY as string;

      window.addEventListener('before-route-leave', () => {
        if (process.client) {
          this.reCaptchaSiteKey = '';
        }
      }, { once: true });
    }
  },
});

This works, but… it feels quite odd and unreliable. There were other ideas, including:

  1. Use event @leave of Vue built-in transition (e.g. https://jsfiddle.net/wy9mu0cf), yet it seems the event is not passed deep enough, where component InnerPartialComponent would not catch it.
    Related answer (Fire event when changing route before DOM changes and outside the route itself?…).

  2. Watch $route inside InnerPartialComponent, but it doesn’t work since the watcher gets removed before it actually handles the change the moment InnerPartialComponent gets “destroyed” on page change.
    Related answer (Vuejs: Event on route change…).

Question

There’s a hope this project will reach an upgrade point, but until that moment, what would be an adequate option to replace the workaround and catch the route change to hide the captcha during the transition?

Despite the route change technique, which is still very interesting, what would cause the captcha to “jump” in the first place? It seems there’s no custom CSS property that replaces the Vuetify’s styles that would modify the captcha position so much.

And… thank you very much for a suggestion in advance! ✨

Table fix using map.()

logged the typeinfoThis is the result of my try I am Need these map to go in each col but they keep Repeating and i have no idea how to fix

the data i am getting this from is this one
enter link description here

How do i get this to stop mappiong insides Other sections of the table

<div className="">
  <table className="table-auto bg-white border-black border-2 mt-5">
    <thead className="">
      <tr className="flex">
        <th className="px-4"> Weak to</th>
        <th className="px-4"> Strong Against</th>
        <th className="px-4">Half Damg to</th>
        <th className="px-4"> Half Damg From</th>
      </tr>
    </thead>
    <tbody>
      {typeinfo.damage_relations.double_damage_from.map((e, index) => (
        <tr key={index} className="flex flex-wrap px-2">
          <td className={`px-2 h-20 cursor-pointer content-${e.name}`}>
            {e.name}
          </td>

          {typeinfo.damage_relations.double_damage_to.map((f, idx) => (
            <td
              key={idx}
              className={`px-2 h-20 cursor-pointer content-${f.name}`}
            >
              {f.name}
            </td>
          ))}
        </tr>
      ))}
    </tbody>
  </table>
</div>

if i can get an reason why its and how to fix id appreciate it.

Label and input is moving with the wrong div

Each time i adjusted the position of the current-grade-name-input, the entirely of the grade-point-input goes with it for some reason

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link rel="stylesheet" href="styles.css">
    <title>Calculator</title>
</head>
<body>
    <main>
        <h1>Calculator</h1>
        <div id="question">
            <p>What Type Of Calculator</p>
        </div>
        <div class="options" id="options">
            <button id="gpa-btn">GPA Calculator</button>
            <button id="current-grade-btn">Current Grade Calculator</button>
            <button id="final-grade-btn">Final Grade Calculator</button>
        </div>
        <div class="gpa-calculator hidden">
            <div class="gpa-container hidden">
                <div>
                    <p class="credit-hour-text">Credit Hours:</p>
                    <p id="credit-hour-number">0</p>
                </div>
                <div>
                    <p class="gpa-text">GPA:</p>
                    <p id="gpa-number">0.00</p>
                </div>
                <div>
                    <p class="qp-text">Quantity Points:</p>
                    <p id="qp-number">0</p>
                </div>
            </div>
            <div id="add-class-btn" class="hidden">
                <button id="add-class-gpa" type="button">Add New Class</button>
            </div>
            <form id="gpa-form" class="hidden">
                <div class="gpa-tab">
                    <label for="name-input" class="label-name">Name (Optional)</label>
                    <input type="text" class="name-input" id="name-input" value=""/>
                    <label for="credit-hour-input" class="label-name">Credit Hour</label>
                    <input type="number" class="credit-hour-input" id="credit-hour-input" min="0" required/>
                    <label for="gpa-input" class="label-name">GPA</label>
                    <input type="number" class="gpa-input" id="gpa-input" min="0" required/>
                </div>
                <div class="adding-in-tab">
                    <button id="add-update-btn" type="submit">Add</button>
                </div>
                <div class="close-btn">
                    <button id="cancel-btn" type="button">Cancel</button>
                </div>
            </form>
        </div>
        <div class="current-grade-calculator hidden">
            <form id="current-grade-form">
                <div class="current-grade-tab">
                    <p id="current-grade-text" class="hidden">Which Grading System</p>
                    <div id="add-class-btn" class="hidden">
                        <button id="add-class-current-grade" type="button">Add New Class</button>
                    </div>
                    <div id="choose-grading-system" class="choose-grading-system hidden">
                        <button id="point-system-btn" type="button">Points System</button>
                        <button id="percentage-system-btn" type="button">Percentage System</button>
                    </div>
                    <div id="current-grade-name-input" class="hidden">
                        <label for="current-grade-name" class="label-name">Name (Optional)</label>
                        <input type="text" class="name-input" id="name-input" value=""/>
                    </div>
                    <div id="point-system-input" class="hidden">
                        <div class="grade-point-input hidden">
                            <div class="grade-row">
                                <label for="a-input">A:</label>
                                <input type="number" id="a-min-number" min="0" placeholder="Minimum Points" required/>
                                <input type="number" id="a-max-number" min="1" placeholder="Maximum Points" required>
                            </div>
                            <div class="grade-row">
                                <label for="b-input">B:</label>
                                <input type="number" id="b-min-number" min="0" placeholder="Minimum Points" required/>
                                <input type="number" id="b-max-number" min="1" placeholder="Maximum Points" required>
                            </div>
                            <div class="grade-row">
                                <label for="c-input">C:</label>
                                <input type="number" id="c-min-number" min="0" placeholder="Minimum Points" required/>
                                <input type="number" id="c-max-number" min="1" placeholder="Maximum Points" required>
                            </div>
                            <div class="grade-row">
                                <label for="d-input">D:</label>
                                <input type="number" id="d-min-number" min="0" placeholder="Minimum Points" required/>
                                <input type="number" id="d-max-number" min="1" placeholder="Maximum Points" required>
                            </div>
                            <div class="grade-row">
                                <label for="f-input">F:</label>
                                <input type="number" id="f-min-number" min="0" placeholder="Minimum Points" required/>
                                <input type="number" id="f-max-number" min="1" placeholder="Maximum Points" required>
                            </div>
                        </div>
                    </div>
                </div>
            </form>
        </div>
        <dialog id="closing-tab-confirm">
            <form method="dialog">
                <p class="closing-message">Unsaved Changes</p>
                <p class="closing-message">Delete?</p>
                <div class="yes-or-no-btn">
                    <button id="yes" type="button" class="btn">Yes</button>
                    <button id="no" type="button" class="btn">No</button>
                </div>
            </form>
        </dialog>
    </main>
    <script src="script.js"></script>
</body>
</html>

*, *::before, *::after {
    margin: 0;
    padding: 0;
    box-sizing: border-box;
}

body{
    background-color: beige;
}

main{
    /* this part allows the item to be move according */
    display: flex;
    /* this lets the html know that it will move up and down */
    flex-direction: column;
    /* this next 2 lets the html know that everything will be in the center */
    justify-content: center;
    align-items: center;
}

/* spaces everything out and center them */
.options{

    font-size: 25px;

    /* the space between element and box */
    padding: 5px;

    /* the space between element and outside element */
    margin: 5px;

    /* Set the element's position to relative, allowing it to be positioned relative to its normal position in the document flow */
    position: relative;

    /* Enable the flexbox layout model on the element, treating its direct children as flex items */
    display: flex;

    /* Arrange the flex items vertically from top to bottom */
    flex-direction: column;

    /* Add a 10px gap (space) between each flex item within the flex container */
    gap: 20px;
}

#gpa, #current-grade, #final-grade{
    border-width: 2px;
    padding: 2px;
    border-radius: 10px;
}

/* move everything away from the header text */
h1{
    margin: 20px 0 40px 0;
}

.gpa-calculator{
    background-color: azure;
    /* make the box around the things */
    width: 330px;
    height: 300px;
    border: 5px solid cadetblue;
    border-radius: 8px;


    /* spaces everything out and center them */

    /* move everything away from the box */
    padding: 15px;

    /* Set the element's position to relative, allowing it to be positioned relative to its normal position in the document flow */
    position: relative;

    /* Enable the flexbox layout model on the element, treating its direct children as flex items */
    display: flex;

    /* Arrange the flex items vertically from top to bottom */
    flex-direction: column;

    /* Add a 10px gap (space) between each flex item within the flex container */
    gap: 20px;
}

.current-grade-calculator{
    background-color: azure;
    /* make the box around the things */
    width: 400px;
    height: 300px;
    border: 5px solid cadetblue;
    border-radius: 8px;


    /* spaces everything out and center them */

    /* move everything away from the box */
    padding: 15px;

    /* Set the element's position to relative, allowing it to be positioned relative to its normal position in the document flow */
    position: relative;

    /* Enable the flexbox layout model on the element, treating its direct children as flex items */
    display: flex;

    /* Arrange the flex items vertically from top to bottom */
    flex-direction: column;

    /* Add a 10px gap (space) between each flex item within the flex container */
    gap: 20px;
}

/* fix and center everything correctly */
.gpa-tab{
    display: flex;
    flex-direction: column;
    justify-content: space-around;
    gap: 5px;
    margin-top: -220px;
}


#add-class-btn{
    display: flex;
    justify-content: center;
    margin-top: 200px;
}

/* these two adding in btn and tab are for centering the add button */
.adding-in-tab{
    display: flex;
    justify-content: center;
}

#add-update-btn, #cancel-btn{
    font-size: 15px;
    align-self: center;
    justify-self: center;
    /* move it down a little */
    margin-top: 20px;
}

#add-update-btn{
    width: 35px;
}

#cancel-btn{
    width: 60px;
}

.close-btn{
    display: flex;
    justify-content: center;
}

#closing-tab-confirm {
    padding: 10px;
    margin: 10px auto;
    border-radius: 15px;
    margin-top: 200px;
}

.yes-or-no-btn{
    display: flex;
    justify-content: center;
    margin-top: 10px;
    gap: 10px;
}

.btn{
    width: 50px;
}

.closing-message{
    text-align: center;
}

.hidden{
    display: none;
}

/* put all in the center */
.gpa-container {
    display: flex;
    justify-content: space-between;
    align-items: center;
    font-size: 13px;
}

/* 
make sure they are in the center and right position 
and the number next to the text
*/
.gpa-container>div {
    display: flex;
    gap: 2px;
}

.grade-point-input {
    display: flex;
    flex-direction: column;
    gap: 10px;
}

.grade-row {
    display: flex;
    align-items: center;
    gap: 10px;
}

.grade-row label {
    width: 30px; /* Adjust as needed */
}

.current-grade-tab {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    /* content is centered vertically */
    height: 100%;
}

#choose-grading-system {
    text-align: center;
    margin-top: -130px;
}

#choose-grading-system button {
    /* to display the button as block element */
    display: block;
    /* create space between the two buttons */
    /* top margin: 10px, left and right margin to auto, 20px for bottom */
    margin: 10px auto 30px;
}

#current-grade-name-input{
    margin-top: -100px;
}
/*
final grade calculator:

    (wanted-grade - (current-grade * (1 - final%))) / final%

    Ex: 
        have a 80 and wants 85, final is 20%

        (85 - (80 * (1 - 0.2))) / 0.2 = 105

*/



// intro text and buttons
const questionText = document.getElementById("question");
const options = document.getElementById("options");

// gpa variables
const gpaBtn = document.getElementById("gpa-btn");
const gpaCalculator = document.querySelector(".gpa-calculator");
const gpaContainer = document.querySelector(".gpa-container");
const gpaForm = document.getElementById("gpa-form");
const gpaTab = document.querySelector(".gpa-tab");

// add class button
const addGpaClassBtn = document.getElementById("add-class-gpa");
const addCurrentGradeClassBtn = document.getElementById("add-class-current-grade");

// current grade variables
const currentGradeBtn = document.getElementById("current-grade-btn");
const currentGradeCalculator = document.querySelector(".current-grade-calculator");
const pointSystemBtn = document.getElementById("point-system-btn");
const currentGradeNameInput = document.getElementById("current-grade-name-input");
const chooseGradingSystem = document.getElementById("choose-grading-system");
const currentGradeText = document.getElementById("current-grade-text");
const pointSystemInput = document.getElementById("point-system-input");

// exit button variables
const cancelBtn = document.getElementById("cancel-btn");
const confirmClose = document.getElementById("closing-tab-confirm");
const noBtn = document.getElementById("no");



gpaBtn.addEventListener("click", () => {
    questionText.classList.toggle("hidden");
    options.classList.toggle("hidden");
    gpaCalculator.classList.toggle("hidden");
    gpaContainer.classList.toggle("hidden");
    addGpaClassBtn.addEventListener("click", () => {
        gpaForm.classList.toggle("hidden");
        addGpaClassBtn.classList.toggle("hidden");
    });
});

cancelBtn.addEventListener("click", () => {
    confirmClose.showModal();
});

noBtn.addEventListener("click", () => {
    confirmClose.close();
});

currentGradeBtn.addEventListener("click", () => {
    questionText.classList.toggle("hidden");
    options.classList.toggle("hidden");
    currentGradeCalculator.classList.toggle("hidden");
    addCurrentGradeClassBtn.addEventListener("click", () => {
        chooseGradingSystem.classList.toggle("hidden");
        addCurrentGradeClassBtn.classList.toggle("hidden");
        currentGradeText.classList.toggle("hidden");
    });
});

pointSystemBtn.addEventListener("click", () => {
    pointSystemInput.classList.toggle("hidden");
    chooseGradingSystem.classList.toggle("hidden");
    currentGradeText.classList.toggle("hidden");
    currentGradeNameInput.classList.toggle("hidden");
});


At first I put it with the grade-point-input div and when i try to move it by itself, everything move with it so i took it out and made a div with it by itself, and it still does the same thing for some reason. i also try to move them individuely but that didnt work either

JQuery Texting Animation Lagging At the End

I’ve created a little Personal Communication Device (PCD) to run a fake scrolling series of text messages. However, I’ve recently run into two problems:

It lags a lot towards the bottom message or two and sometimes doesn’t want to even manually scroll upwards if it gets stuck.

When I use it on the forums site I made it for, it doesn’t want to run the scroll animation at all (but runs fine on Codepen). I have it hosted on the same page as another PCD that runs the exact same animation just has a different aesthetic build and the other one works just fine.

<div class="middle">
      <div class="message" id="one">hey</div>
      <br>
      <div class="message" id="two">how's it going?</div>
      <br>
      <div class="message" id="three">just wanted to check in</div>
      <br>
      <div class="message" id="four">I know Tuesdays have been rough for you</div>
      <br>
      <div class="message" id="five">You wanna call?</div>
  </div>

<style>
.screen {  
  position: relative;
  width: 250px;
  margin: auto;
  filter: drop-shadow(10px 10px 4px gray);
  display: grid;
  grid-template-columns: 250px;
  grid-template-rows: 50px 200px 67px;
  grid-auto-flow: row;
  grid-template-areas:
    "top"
    "middle"
    "bottom";
}

.middle { 
  grid-area: middle;
  background: #36454f;
  text-align: right;
  overflow: scroll;
  overflow-x: hidden;
  scrollbar-width: thin;
  scrollbar-color: #36454f #36454f;
}

.message {
  background-color: #ff91af;
  filter: drop-shadow(0 0 0.25rem white);
  color: white;
  padding: 15px;
  margin-top: 10px;
  border-radius: 10px 10px 3px 10px;
  text-align: right;
  margin: 10px;
  display: none;
}
</style>

<script>
$(document).ready(function () {
  $(".grabTexts").on("click", function () {
    $(".message").each(function (index) {
      $(this)
        .delay(1500 * index)
        .fadeIn("fast");
      $(".middle").animate(
        {
          scrollTop: $(".middle").get(0).scrollHeight
        },
        2000
      );
      $(".wipeTexts").on("click", function () {
        $(".message").removeAttr("style");
      });
    });
  });
});
</script>

I haven’t really been able to figure this one out — I’m still brand new to coding anything and this is just a fun little hobby project to get me dabbling. I’d really appreciate whatever information can be shared and if I can learn something new. A good portion of the snippets in my script were filched from perusing this site. ( : Thanks!

how to implement a main table and subform-like tables with react

I am new to JS react framework. My application will list the projects when the web page is loaded, then user could select one or many projects, then make API calls to get the product orders related with that project.
I have Projects components, which create a html table, each row will be a project. When a project row is clicked, I could use the project ID to make API call. once the API response for the product orders is received, how will these product order data be passed to ProductOrders components?
also will the web page have an empty div (place holder) for ProductOrders, then when the ProductOrders data is in, it gets refreshed?

In jQuery, I could use the response data to construct productorders html and append or replace existing web elements. In React, I have no idea how to achieve that.

Issue about repetitives fetches in useEffect – React right now [closed]

I’m developing a web game with React on the front end and Symfony on the back end. I’m having an issue with a useEffect where I use Promise.all (I’ve also tried separate useEffects for each fetch), and the problem is that it keeps fetching, which saturates and slows down everything. This is due to some dependencies that I have but are necessary:

const GamePage = () => {
  const { gameId } = useParams();

  const [abilities, setAbilities] = useState([]);
  const [enemies, setEnemies] = useState([]);
  const [weapons, setWeapons] = useState([]);
  const [amulet, setAmulet] = useState([]);
  const [saves, setSaves] = useState([]);
  const [heroe, setHeroe] = useState([]);
  const [loading, setLoading] = useState(true);

  const [selectedSkill, setSelectedSkill] = useState(null);
  const [selectedEnemy, setSelectedEnemy] = useState(null);
  const [isAttacking, setIsAttacking] = useState(false)

  useEffect(() => {
    Promise.all([getSaveSlot(gameId), getWeaponsEquiped(), getAmuletEquiped()])
      .then(([saveData, weaponsData, amuletData]) => {
        setSaves(saveData);
        setAbilities(saveData.stage[0].heroes[0].abilities);
        setHeroe(saveData.stage[0].heroes[0]);
        setEnemies(saveData.stage[0].enemies);
        setWeapons(weaponsData);
        setAmulet(amuletData);
      })
      .catch((error) => {
        console.error("Error:", error);
        setLoading(false);
      })
      .finally(() => {
        setLoading(false);
      });
  }, [ saves, weapons, amulet ]);

  useEffect(() => {
    const attackHeroe = async () => {
      if (selectedSkill && selectedEnemy) {
        try {
          setIsAttacking(true);
          console.log(isAttacking);
          await getWithAuth(`/heroe/attack/${heroe.id}/${selectedEnemy}/${selectedSkill}`);
        } catch (error) {
          console.error("Error:", error);
        } finally {
          setSelectedSkill(null);
          setSelectedEnemy(null);
          setIsAttacking(false);
          console.log(isAttacking);
        }
      }
    };

    attackHeroe();
  }, [selectedSkill, selectedEnemy]);

  return (
    <>
      {loading ? (
        <>
          <div className="bg-auto font-pixel size-screen bg-gradient">
            <div className=" bg-[url('/src/assets/images/background.png')] bg-[length:150px] bg-animation h-screen w-screen flex flex-col justify-center items-center">
              <div className="h-screen w-screen font-pixelify flex justify-center items-center">
                <Loading />
              </div>
            </div>
          </div>
        </>
      ) : (
        <>
          <Header saves={saves} />
          <div className="bg-[url(/src/assets/images/game-background.png)] bg-cover h-[57.5vh]">
            <Heroe heroe={heroe} weapons={weapons} isAttacking={isAttacking}/>
            <Enemies enemies={enemies} setSelectedEnemy={setSelectedEnemy}/>
          </div>
          <Footer abilities={abilities} heroe={heroe} weapons={weapons} amulet={amulet} setSelectedSkill={setSelectedSkill} selectedSkill={selectedSkill}/>
        </>
      )}
    </>
  );
};

export default GamePage;

The dependencies within the useEffect are necessary to fetch data, such as enemy life when attacking or if I equip any new weapon or amulet. Therefore, they are necessary.

The fetch functions are like this but with different URLs:

export async function getSaveSlot(saveSlotId) {
try {

    return await getWithAuth(`/save/slot/${saveSlotId}`)

} catch (error) {
console.error("Error:", error);
throw error;
}
}

I’ve tried removing the dependencies, but it only updates once as it should, and therefore doesn’t keep fetching repeatedly, which isn’t what I’m looking for.

I’ve also tried separating the Promise.all into several useEffects to separate the dependencies in case there was any kind of conflict, but it still behaves the same way.

Any help is appreciated. Thanks.

Trying to insert a variable from my C++ code to MySQL via Javascript

I’m currently working on a project involving Arduino and Node-RED, where I’m attempting to insert a variable declared in Arduino, visible in my serial monitor, into a MySQL database using a JavaScript function. The function I’m using is as follows:

var value = JSON.parse(JSON.stringify(msg.payload));
value = msg;
var sensor = msg.payload;
msg.payload = [sensor];
msg.topic = "INSERT INTO tbl_sensor(ID_sensor) VALUES (null, ?);";
return msg;

However, the issue I’m facing is that the function attempts to JSON encode everything displayed in my serial monitor. This isn’t feasible because my Arduino code includes additional serial prints besides the variable I’m interested in, which is named “tmp”.

I’ve attempted various adjustments like changing msg.payload to msg.payload.tmp and experimenting with additional variables. However, since this is my first time working with JavaScript, I’m uncertain about the correct approach. Can anyone provide guidance on how to accomplish this? Any assistance would be greatly appreciated! Thank you!

Prevent iOS browser to enable full screen camera mode when streaming camera video

I have worked through this tutorial https://www.digitalocean.com/community/tutorials/front-and-rear-camera-access-with-javascripts-getusermedia to capture video streams from a Front or Rear camera on an iPhone.

When testing the website on my desktop browser, everything works as expected but when testing it on my iPhone with Safari or Edge it shows the camera feed in full screen mode and not in the grey video box.

Website can be tested here: https://codepen.io/chrisbeast/pen/ebYwpX

feather.replace();

const controls = document.querySelector('.controls');
const cameraOptions = document.querySelector('.video-options>select');
const video = document.querySelector('video');
const canvas = document.querySelector('canvas');
const screenshotImage = document.querySelector('img');
const buttons = [...controls.querySelectorAll('button')];
let streamStarted = false;

const [play, pause, screenshot] = buttons;

const constraints = {
  video: {
    width: {
      min: 1280,
      ideal: 1920,
      max: 2560,
    },
    height: {
      min: 720,
      ideal: 1080,
      max: 1440
    },
  }
};

cameraOptions.onchange = () => {
  const updatedConstraints = {
    ...constraints,
    deviceId: {
      exact: cameraOptions.value
    }
  };

  startStream(updatedConstraints);
};

play.onclick = () => {
  if (streamStarted) {
    video.play();
    play.classList.add('d-none');
    pause.classList.remove('d-none');
    return;
  }
  if ('mediaDevices' in navigator && navigator.mediaDevices.getUserMedia) {
    const updatedConstraints = {
      ...constraints,
      deviceId: {
        exact: cameraOptions.value
      }
    };
    startStream(updatedConstraints);
  }
};

const pauseStream = () => {
  video.pause();
  play.classList.remove('d-none');
  pause.classList.add('d-none');
};

const doScreenshot = () => {
  canvas.width = video.videoWidth;
  canvas.height = video.videoHeight;
  canvas.getContext('2d').drawImage(video, 0, 0);
  screenshotImage.src = canvas.toDataURL('image/webp');
  screenshotImage.classList.remove('d-none');
};

pause.onclick = pauseStream;
screenshot.onclick = doScreenshot;

const startStream = async (constraints) => {
  const stream = await navigator.mediaDevices.getUserMedia(constraints);
  handleStream(stream);
};


const handleStream = (stream) => {
  video.srcObject = stream;
  play.classList.add('d-none');
  pause.classList.remove('d-none');
  screenshot.classList.remove('d-none');

};


const getCameraSelection = async () => {
  const devices = await navigator.mediaDevices.enumerateDevices();
  const videoDevices = devices.filter(device => device.kind === 'videoinput');
  const options = videoDevices.map(videoDevice => {
    return `<option value="${videoDevice.deviceId}">${videoDevice.label}</option>`;
  });
  cameraOptions.innerHTML = options.join('');
};

getCameraSelection();

React native “rendered more hooks than during the previous render” when not first load

In my React Native (expo) app, I have a firstLoad variable in AsyncStorage to determine whether the welcome screen or home screen is rendered. The app loads the welcome screen followed by the home screen perfectly well when firstLoad isn’t set (meaning it is the first load). However, I get a “Rendered more hooks than during the previous render” error when firstLoad is false and the home screen needs to be rendered directly.

Here’s my App class in App.js:

export default class App extends React.Component {

  constructor(props) {
    super(props);
    this.state = {
      isLoading: true,
      showHome: false,
    }
  }

  componentDidMount() {
    AsyncStorage.getItem('firstLoad').then((value) => {
      if (value == null || value == 'true') {
        this.setState({ showHome: false, isLoading: false });
      } else {
        this.setState({ showHome: true, isLoading: false });
      }
    });
  }

  _onContinue = () => {
    AsyncStorage.setItem('firstLoad', 'false').then(() => {
      this.setState({ showHome: true, isLoading: false});
    });
  }

  render() {

    Appearance.addChangeListener(({ colorScheme }) => {
      this.forceUpdate();  
    });

    if (this.state.isLoading) {
      return (
        <View style={{flex: 1, justifyContent: 'center', alignItems: 'center'}}>
          <ActivityIndicator size="large" color="#037bfc" />
        </View>
      );
    } else if (!this.state.showHome) {
      return (
        <Welcome onContinue={() => this._onContinue()} />
      );
    } else {
      return (
        <RootSiblingParent>
          <ActionSheetProvider>
            <NavigationContainer theme={
              Appearance.getColorScheme() === 'dark' ? DarkTheme : LightTheme
            }>
              <BottomNav />
            </NavigationContainer>
          </ActionSheetProvider>
        </RootSiblingParent>
      );
    }

  }
}

And this is what my code for the Home Screen looks like:

export default function Home({route, navigation}) {

    const [imagesLoaded, setImagesLoaded] = useState(true);
    const [topStory, setTopStory] = useState({}); 
    const [topPost, setTopPost] = useState({});
    const [loading, setLoading] = useState(true);
    const [articles, setArticles] = useState([
        // article stuff here
    ]);

    const [fontsLoaded, fontError] = useFonts({
        'Open-Sans': require('../assets/fonts/Open_Sans/static/OpenSans-Regular.ttf'),
        'Madimi-One': require('../assets/fonts/Madimi_One/MadimiOne-Regular.ttf'),
    });

    const cardTheme = useColorScheme() === 'dark' ? ColorTheme.cardDark : ColorTheme.cardLight;
    const textTheme = useColorScheme() === 'dark' ? ColorTheme.textDark : ColorTheme.textLight;
    const blurhash = '|rF?hV%2WCj[ayj[a|j[az_NaeWBj@ayfRayfQfQM{M|azj[azf6fQfQfQIpWXofj[ayj[j[fQayWCoeoeaya}j[ayfQa{oLj?j[WVj[ayayj[fQoff7azayj[ayj[j[ayofayayayj[fQj[ayayj[ayfjj[j[ayjuayj[';

    if (!fontsLoaded || !imagesLoaded || fontError) {
        return (
            <SafeAreaView style={styles.container}>
                <ActivityIndicator size="large" color="#0000ff" />
            </SafeAreaView>
        );
    }

    const fetchTopStory = async () => {
        try {
            const postRef = ref(db, 'reports');
            const postSnapshot = await get(postRef).then((snapshot) => {
                if (snapshot.exists()) {
                    const posts = snapshot.val();
                    const postKeys = Object.keys(posts);
                    const postsWithImages = postKeys.filter(key => posts[key].images !== undefined);
                    const postsWithoutImages = postKeys.filter(key => posts[key].images === undefined);

                    const topStoryKey = postsWithImages[Math.floor(Math.random() * postsWithImages.length)];
                    const topStory = posts[topStoryKey];

                    const topPostKey = postsWithoutImages[Math.floor(Math.random() * postsWithoutImages.length)];
                    const topPost = posts[topPostKey];

                    setTopStory(topStory);
                    setTopPost(topPost);
                    setLoading(false);
                } else {
                    console.log("No data available");
                }
            });
        } catch (error) {
            console.error(error);
        }
    }


    useEffect(() => {
        fetchTopStory();
    }, []);

    const refresh = () => {
        setLoading(true);
        fetchTopStory();
    }

    return (
        <SafeAreaView style={styles.container}>
            {loading ? (
                <ActivityIndicator size="large" color="#0000ff" />
            ) : (
                <ScrollView 
                    contentContainerStyle={styles.content}
                    refreshControl={
                        <RefreshControl refreshing={loading} onRefresh={() => refresh()} />
                    }
                >
                    // content is shown here
                </ScrollView>
            )}
        </SafeAreaView>
    );
}

Any help is appreciated. Thank you!

How to resolve Schema validation failed in AWS Graphql Schema Transformer v1 to v2

I had an old project which had the following schema:

type User @model {
  id: ID!
  username: String!
  email: String!
  imageUri: String
  posts: [Post] @connection(keyName: "byUser", fields: ["id"])
}

type Post @model @key(name: "byUser", fields: ["userID"]) {
  id: ID!
  videoUri: String!
  description: String!

  userID: ID!
  user: User @connection(fields: ["userID"])

  songID: ID!
  song: Song @connection(fields: ["songID"])
}

type Song @model {
  id: ID!
  name: String!
  imageUri: String
}

But when I tried changing the code or transform the code v2, I started having the error below, when I try using amplify update api:

Schema validation failed.

Unknown argument “fields” on directive “@index”.

GraphQL request:13:41
12 | description: String!
13 | byUser: [Post] @index(name: “byUser”, fields: [“userID”])
| ^
14 | userID: ID!

Please, what’s the right code to resolve the issue?

Scrolling through cards horizontally only works for 18 cards :(

I have a problem, that our scroll card functionality only works for 18 cards but no more.
The first card is empty as well as the last so we always have the current card displayed in the center. Unfortunately, the scroll function via button is a bit buggy (80% success rate) and after 18 cards it receives free will and scrolls back to the 18th card.

Btw, smooth scrolling only works on firefox :/

Thanks for helping out! 🙂

import React, { useState, useEffect, useRef } from 'react';
import QuestionCard from './QuestionCard';
import questionsData from '../data/questions.json';
import { throttle } from 'lodash';

const Questionnaire = () => {
  const [currentQuestionIndex, setCurrentQuestionIndex] = useState(1);
  const [answers, setAnswers] = useState([]);
  const [questions, setQuestions] = useState([]);
  const containerRef = useRef(null);
  const isButtonScroll = useRef(false);  // Track button clicks

  useEffect(() => {
    setQuestions(questionsData);
  }, []);

  useEffect(() => {
    if (containerRef.current && containerRef.current.firstChild) {
      const cardWidth = containerRef.current.firstChild.offsetWidth;
      const scrollPosition = cardWidth * currentQuestionIndex - (containerRef.current.offsetWidth / 2 - cardWidth / 2);
      containerRef.current.scrollTo({
        left: scrollPosition,
        behavior: 'smooth'
      });
    }
  }, [currentQuestionIndex]);

  const handleAnswer = (answer) => {
    setAnswers([...answers, { question: questions[currentQuestionIndex], answer }]);
    scrollToIndex(Math.min(currentQuestionIndex + 1, questions.length - 1));
  };

  const scrollToIndex = (index) => {
    if (containerRef.current && containerRef.current.firstChild) {
      isButtonScroll.current = true;  // Indicate button click
      const cardWidth = containerRef.current.firstChild.offsetWidth;
      let scrollPosition;
  
      if (index === 0) { // Skip the first card
        scrollPosition = 0;
      } else if (index === questions.length - 2) { // Second last card
        scrollPosition = cardWidth * (index + 1) - (containerRef.current.offsetWidth / 2 - cardWidth / 2);
      } else if (index === questions.length - 1) { // Last card
        scrollPosition = containerRef.current.scrollWidth - containerRef.current.offsetWidth;
      } else {
        scrollPosition = cardWidth * index - (containerRef.current.offsetWidth / 2 - cardWidth / 2);
      }
  
      containerRef.current.scrollTo({
        left: scrollPosition,
        behavior: 'smooth'
      });
      setCurrentQuestionIndex(index);
    }
  };
  
  
  const handleLeft = () => {
    scrollToIndex(Math.max(currentQuestionIndex - 1, 1)); // Skip the first card
  };
  
  const handleRight = () => {
    scrollToIndex(Math.min(currentQuestionIndex + 1, questions.length - 2)); // Skip the last card
  };
  

  useEffect(() => {
    const handleScroll = throttle(() => {
      if (isButtonScroll.current) {
        isButtonScroll.current = false;  // Reset button scroll flag
        return;
      }
      if (containerRef.current) {
        const container = containerRef.current;
        const containerCenter = container.offsetWidth / 2;
        const cards = Array.from(container.children);
        let closestIndex = 0;
        let closestDistance = Infinity;

        cards.forEach((card, index) => {
          const cardCenter = card.offsetLeft + card.offsetWidth / 2;
          const distance = Math.abs(cardCenter - container.scrollLeft - containerCenter);
          if (distance < closestDistance) {
            closestDistance = distance;
            closestIndex = index;
          }
        });

        setCurrentQuestionIndex(closestIndex);
      }
    }, 100);

    const container = containerRef.current;
    if (container) {
      container.addEventListener('scroll', handleScroll);
    }
    return () => {
      if (container) {
        container.removeEventListener('scroll', handleScroll);
      }
    };
  }, [questions]);

  const scrollBarHideStyle = {
    scrollbarWidth: 'none', // Firefox
    msOverflowStyle: 'none', // IE and Edge
  };

  return (
    <div className="flex-grow bg-red my-20 h-auto py-20 flex items-center justify-center relative w-full">
      <div className="absolute top-0 left-0 w-full bg-gradient-to-r from-slate-950 to-purple-950 transform skew-y-3" style={{ height: '110%' }} />
      
      <div className="relative w-full overflow-x-hidden">
        <div className="absolute left-0 top-0 h-full w-40 bg-gradient-to-r from-slate-950 to-transparent z-20 pointer-events-none" />
        <div className="absolute right-0 top-0 h-full w-40 bg-gradient-to-l from-purple-950 to-transparent z-20 pointer-events-none" />

        {currentQuestionIndex !== 1 && (
          <button 
            onClick={handleLeft} 
            className="absolute left-20 top-1/2 transform -translate-y-1/2 bg-white text-black p-6 rounded-full z-30">
              <svg className="w-8 h-8" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
                <path strokeLinecap="round" strokeLinejoin="round" strokeWidth="3" d="M15 19l-7-7 7-7"></path>
              </svg>
          </button>
        )}

        {currentQuestionIndex < questions.length - 2 && (
          <button 
            onClick={handleRight} 
            className="absolute right-20 top-1/2 transform -translate-y-1/2 bg-white text-black p-6 rounded-full z-30">
              <svg className="w-8 h-8" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
                <path strokeLinecap="round" strokeLinejoin="round" strokeWidth="3" d="M9 5l7 7-7 7"></path>
          </svg>
          </button>
        )}


        <div ref={containerRef} className="w-full px-4 py-20 flex space-x-4 overflow-x-scroll relative snap-x snap-mandatory"
             style={{ ...scrollBarHideStyle, WebkitOverflowScrolling: 'touch' }}>
          {questions.map((question, index) => (
            <div key={index} className={`shrink-0 w-120 h-80 transition-opacity duration-800 snap-center ${index === currentQuestionIndex ? 'transform scale-110 opacity-100' : 'transform scale-100 opacity-50'}`}>
              <QuestionCard
                question={question}
                onAnswer={handleAnswer}
              />
            </div>
          ))}
        </div>
      </div>
    </div>
  );
};

export default Questionnaire;

we tried everything :/
hoping that the answers from chatgpt converge to a usable code.

Difference Between Subscribe and Promise In Javascript

I want to understand the exact differences between these functions. Since both are used for asynchronous programming, where should we use promises, and where should we use subscriptions?

In asynchronous programming, promises and subscriptions (often via Observables) are two common approaches to handle asynchronous operations, each with its own use cases and advantages.

Promises
A promise represents the eventual completion (or failure) of an asynchronous operation and its resulting value. A promise can only handle a single event. Here’s when to use promises:

Single Asynchronous Operations: Use promises when you only need to handle a single async operation that will either succeed or fail, like fetching data from an API.
Simpler Syntax: Promises provide a simpler syntax with then(), catch(), and finally() methods, which can make your code easier to read and manage when dealing with a single asynchronous response or error.
Chaining Asynchronous Operations: Promises are well-suited for scenarios where you need to perform several asynchronous tasks in a sequence, where each subsequent task starts only after the previous one has completed.
Subscriptions (Observables)
Subscriptions often involve Observables, which can handle multiple values over time, from zero to an infinite number of values. Use subscriptions in the following scenarios:

Multiple Asynchronous Events: Subscriptions are ideal for dealing with streams of events or data, such as user input, progress indicators, or other recurring events.
More Control Over the Asynchronous Streams: Observables provide operators like map, filter, debounceTime, etc., which allow for more control and flexibility in processing streams of data.
Non-blocking Operations: In cases where your application needs to continue reacting to incoming events without waiting for previous operations to complete, subscriptions allow more granular control over these streams.
Key Differences
Completion: Promises are either resolved or rejected a single time, whereas Observables can emit multiple values over time and must be manually unsubscribed to avoid memory leaks and unwanted behavior.
Use of Operators: Observables can be transformed, combined, and manipulated using a variety of operators provided by libraries like RxJS, which can be extremely powerful for handling complex asynchronous logic.
Error Handling: Promises handle errors in a linear path with catch(), while Observables handle errors in the stream flow, which can be caught and managed using operators like catchError.

How to handle Jest/Axios error without using try/catch?

is there existing another way how to handle error message while using JS/TS with Axios and Jest libs in order to get more information why request get failed ?

For example:

const req = await callApi(payload) 
expect(req.status).toEqual(200)

Let’s assume that check above get failed on status 400
With code above you received only

Request failed with status code 400 and has no info which validation failed.

I know about try/catch – but something telling me that using try/catch on automation test is not good idea. Maybe i am wrong. Moreover, if you are using try/catch you have to expect status 200 too in catch block, because if you do not use expect there, the test will be facing like success, despite of fact that error occurred.

Another way is using promise – then – construction. Actually its worse that try/catch 🙂 you know, a lot of unnecessary and complex code.

So, is it possible somehow extend error handler / function in Axios or Jest in order to receive info?