AWS Amplify GraphQL fetches nothing on first load, works properly on refresh in NextJS

I’m about ready to move off of AWS Amplify and tell everyone I ever meet to avoid it.

I have the below code to retrieve multiple choice questions from a GraphQL database. The code is called by a page. On my local machine, on first load, with no cached data, the code below returns nothing.

Simply refreshing the page in the browser causes the code to properly fetch the data.

AWS docs are useless and I can’t figure out why sometimes the same query returns nothing and sometimes it returns data.

import { Amplify } from "aws-amplify";
import amplifyconfig from "../amplifyconfiguration.json";
Amplify.configure(amplifyconfig);

import { generateClient } from "aws-amplify/api";

import { questionMultipleChoicesByIncidentID } from "../graphql/queries";

export default async function getQuestionsByIncident(incidentId: any) {

  const client = generateClient();

  let questionSet: any;
  let questionData: any[] = [];
  let attempts = 0;


  const fetchQuestions = async () => {
    try {
      questionSet = await client.graphql({
        query: questionMultipleChoicesByIncidentID,
        variables: {
          incidentID: incidentId,
        },
      });
      questionData = questionSet.data.questionMultipleChoicesByIncidentID.items;
    } catch (error) {
      console.log("getQuestionsByIncident - Error getting Questions:", error);
    }
  };

  while (questionData.length === 0 && attempts < 5) {
    await fetchQuestions();
    if (questionData.length === 0) {
      attempts += 1;
      // Wait for 300ms before retrying
      console.log("No data retrieved, retrying. Attempt number: ", attempts);
      await new Promise((resolve) => setTimeout(resolve, 300));
    }
  }

  return { questionData };
}

I expect data to be retrieved every time this code is run, regardless of if we are refreshing from the browser or landing on the page.

styling title/tooltip in jqxgrid cell

I am using jqxgrid to create a grid and added a title to some span texts inside cells.
But now I want to style these titles which is not possible as I know. So I tried to add tooltips, but tooltips are not shown properly.
This is the css code

.title-styled[title]:hover:after {
    content: attr(title);
    color: #333;
    position: absolute;
    left: 0;
    top: 100%;
    white-space: nowrap;
    z-index: 2147483647 !important;
    -moz-border-radius: 5px;
    -webkit-border-radius: 5px;
    border-radius: 5px;
    -moz-box-shadow: 0px 0px 4px #222;
    -webkit-box-shadow: 0px 0px 4px #222;
    box-shadow: 0px 0px 4px #222;
    background-image: -moz-linear-gradient(top, #eeeeee, #cccccc);
    background-image: -webkit-gradient(linear,left top,left bottom,color-stop(0, #eeeeee),color-stop(1, #cccccc));
    background-image: -webkit-linear-gradient(top, #eeeeee, #cccccc);
    background-image: -moz-linear-gradient(top, #eeeeee, #cccccc);
    background-image: -ms-linear-gradient(top, #eeeeee, #cccccc);
    background-image: -o-linear-gradient(top, #eeeeee, #cccccc);
}

span:

...
    else {
         return '<br>&nbsp<span class="title-styled" title="Road:' + record.Quantity + '">' + value;
         }
...

enter image description here

Automatic refresh on API request

I’m currently working on a small school project. However, I have a problem that I can’t solve.

In short, every time I add or delete a photo, my page refreshes completely, whereas I want it to update dynamically, without having the effect of a complete page refresh, like a simple data reload…

Here’s my code for those who have time to help me…

https://pastebin.mozilla.org/hhUfEC4s

I tried with event.preventDefault() but no success…

document.addEventListener('DOMContentLoaded', () => {
  const galleryContainer = document.querySelector('.gallery')
  const allWorks = [] // Keep a list of all works for easy filtering

  // Function to create a figure element
  function createFigure(work) {
    const figure = document.createElement('figure')
    const image = document.createElement('img')
    image.src = work.imageUrl
    image.alt = work.title
    figure.appendChild(image)

    const figcaption = document.createElement('figcaption')
    figcaption.textContent = work.title
    figure.appendChild(figcaption)

    return figure
  }

  // Fetching works from the API
  fetch('http://localhost:5678/api/works')
    .then((response) => {
      if (!response.ok) {
        throw new Error(`HTTP error! status: ${response.status}`)
      }
      return response.json()
    })
    .then((works) => {
      allWorks.push(...works) // Add all works to the list
      displayWorks(allWorks) // Display all works in the gallery
      displayWorksInDialog(allWorks) // Display works in the dialog window
      updateCategoryDropdown(allWorks) // Update the category dropdown
    })
    .catch((error) => console.error('Error fetching works:', error))

  // Function to display works in the gallery
  function displayWorks(works) {
    galleryContainer.innerHTML = ''
    works.forEach((work) => {
      const figure = createFigure(work)
      galleryContainer.appendChild(figure)
    })
  }

  // Display works/images in your modal
  function displayWorksInDialog(works) {
    const dialogGalleryContent = document.getElementById('dialog__gallery').querySelector('.dialog__content')
    dialogGalleryContent.innerHTML = ''

    works.forEach((work, index) => {
      // Create a <figure> element
      const figure = document.createElement('figure')
      figure.setAttribute('data-id', work.id)

      // Create a <div> element to contain the image and icons
      const container = document.createElement('div')
      container.style.position = 'relative'

      // Create an <i> element for the trash can icon
      const trashIcon = document.createElement('i')
      trashIcon.classList.add('fas', 'fa-trash-can')
      container.appendChild(trashIcon)

      // Add an event listener for the trash can icon
      trashIcon.addEventListener('click', function () {
        // Call a function to delete the photo
        deletePhoto(work.id).then(() => {
          // Remove the project from the modal
          figure.remove()
        })
      })

      // Create an <img> element to display the image
      const image = document.createElement('img')
      image.src = work.imageUrl
      image.alt = 'Image'
      container.appendChild(image)

      // If it's the first iteration (index = 0), add the Move icon
      if (index === 0) {
        const iconMove = document.createElement('i')
        iconMove.classList.add('fas', 'fa-arrows-up-down-left-right', 'custom-icon')
        iconMove.style.color = '#ffffff'
        container.appendChild(iconMove)
      }

      // Create an <a> element with the text "Edit"
      const editLink = document.createElement('a')
      editLink.textContent = 'edit'
      editLink.href = '#'
      editLink.classList.add('edit__link')

      // Add the container to the figure
      figure.appendChild(container)

      // Add the "edit" link to the figure
      figure.appendChild(editLink)

      dialogGalleryContent.appendChild(figure)
    })
  }

  function deletePhoto(photoId) {
    // Get the authentication token from local storage
    const authToken = localStorage.getItem('userToken')

    if (!authToken) {
      console.error('Missing authentication token')
      alert('You must be logged in to perform this action.')
      return Promise.reject(new Error('Missing authentication token'))
    }

    const headers = new Headers({
      Authorization: `Bearer ${authToken}`,
      'Content-Type': 'application/json',
    })

    return fetch(`http://localhost:5678/api/works/${photoId}`, {
      method: 'DELETE',
      headers: headers,
    })
      .then((response) => {
        if (response.ok) {
          // If deletion is successful, return a resolved promise
          console.log(`Photo with ID ${photoId} deleted successfully.`)
          return Promise.resolve()
        } else if (response.status === 401) {
          console.error('Unauthorized to delete the photo')
          alert('You are not authorized to perform this action.')
          return Promise.reject(new Error('Unauthorized to delete the photo'))
        } else {
          return response.json().then((data) => {
            throw new Error(data.message)
          })
        }
      })
      .catch((error) => {
        console.error('Error deleting the photo:', error)
        alert('Error deleting the photo: ' + error.message)
        return Promise.reject(error)
      })
  }

  // Function to submit the form
  async function submitForm(event) {
    event.preventDefault()

    const title = document.getElementById('form__title').value
    const category = parseInt(document.getElementById('form__category').value)
    const imageInput = document.getElementById('form__image')
    const authToken = localStorage.getItem('userToken')
    const dialog = document.getElementById('dialog')

    const formData = new FormData()
    formData.append('title', title)
    formData.append('category', category)

    if (imageInput.files.length > 0) {
      formData.append('image', imageInput.files[0])
    } else {
      alert('Please select an image file.')
      return
    }

    try {
      const response = await fetch('http://localhost:5678/api/works', {
        method: 'POST',
        headers: new Headers({
          Authorization: `Bearer ${authToken}`,
        }),
        body: formData,
      })

      if (!response.ok) {
        throw new Error('Error updating the work: ' + response.statusText)
      }

      const result = await response.json()
      console.log(result)
      alert('Work updated successfully')

      allWorks.push(result)
      displayWorks(allWorks)
      updateCategoryDropdown(allWorks)
    } catch (error) {
      console.error('Error updating the work:', error)
      alert('Error updating the work: ' + error.message)
    }

    dialog.style.display = 'none'
    document.getElementById('dialog__edit__work__form').reset()
  }

  // Event listener for image preview
  document.getElementById('form__image').addEventListener('change', function () {
    const file = this.files[0]
    const photoAddIcon = document.getElementById('photo__add__icon')
    const photoSizeText = document.getElementById('photo__size')
    const newImageLabel = document.getElementById('new__image')
    const newPhotoElements = document.querySelectorAll('.dialog__content__new__photo')

    const maxFileSize = 4 * 1024 * 1024 // 4 MB (in bytes)

    if (file) {
      if (file.type.match('image.*')) {
        if (file.size > maxFileSize) {
          alert('The image should not exceed 4 MB!')
          return
        }

        const reader = new FileReader()
        reader.onload = function (e) {
          const newImage = document.createElement('img')
          newImage.src = e.target.result
          newImage.style.height = '169px'
          newImage.style.width = 'auto'

          photoAddIcon.replaceWith(newImage)
          photoSizeText.style.display = 'none'
          newImageLabel.style.display = 'none'

          newPhotoElements.forEach(function (element) {
            element.style.padding = '0px'
          })
        }
        reader.readAsDataURL(file)
      } else {
        alert('The selected file is not an image.')
      }
    }

    // Event listener to submit the form
    document.getElementById('dialog__edit__work__form').addEventListener('submit', submitForm)

    document.getElementById('form__image').addEventListener('change', updateSubmitButton)
    document.getElementById('form__title').addEventListener('input', updateSubmitButton)

    function updateSubmitButton() {
      const file = document.getElementById('form__image').files[0]
      const title = document.getElementById('form__title').value
      const submitButton = document.getElementById('submit__new__work')

      // Check if the file is an image and the title is filled
      if (file && title.trim() !== '') {
        submitButton.style.backgroundColor = '#1d6154'
      } else {
        submitButton.style.backgroundColor = '' // Revert to default style
      }
    }
  })
})
<section id="portfolio">
        <div class="projects__modifier">
          <h2>My Projects</h2>
          <a id="update-works" class="connexion projet__btn__modifier" href="#dialog"><i class="fa-sharp fa-regular fa-pen-to-square"></i> Edit </a>
        </div>
        <div class="filters">
          <button class="btn__filters">All</button>
          <button class="btn__filters">Objects</button>
          <button class="btn__filters">Apartments</button>
          <button class="btn__filters">Hotels & Restaurants</button>
        </div>
        <div class="gallery">
          <!-- Gallery items (photos, titles, etc.) will be added here by JavaScript in the script.js file in assets -->
        </div>
      </section>

<!-- Dialog/Modal -->
    <dialog id="dialog" class="dialog__overlay" aria-hidden="true" role="dialog" aria-labelledby="title-dialog-overlay">
      <div id="dialog__gallery" class="dialog__gallery">
        <a id="button__to__close__first__window" href="#" class="dialog__close"><i class="fa-solid fa-xmark"></i></a>
        <h3 id="title__dialog__overlay" class="dialog__title">Photo Gallery</h3>
        <div class="dialog__content"></div>
        <hr />
        <div class="container__dialog__add__and__dialog__delete">
          <button id="dialog__edit__add" class="dialog__add">Add a Photo</button>
          <a href="#" class="dialog__delete__all">Delete the Gallery</a>
        </div>
      </div>
      <div id="dialog__edit" class="dialog__edit__work">
        <div class="container__for__icon__in__second__window__of__dialog">
          <a id="arrow__return" href="#"><i class="fa-solid fa-arrow-left"></i></a>
          <a id="button__to__close__second__window" href="#"><i class="fa-solid fa-xmark"></i></a>
        </div>
        <h3 class="dialog__title">Add a Photo</h3>
        <form id="dialog__edit__work__form" method="post" action="#">
          <div id="dialog__edit__new__photo image-preview" class="dialog__content__new__photo">
            <i id="photo__add__icon" class="fa-regular fa-image"></i>
            <label id="new__image">+ Add a Photo</label>
            <input id="form__image" type="file" name="image" accept="image/*, .jpg, .jpeg, .png" required />
            <p id="photo__size">jpg, png: max 4MB</p>
          </div>
          <div class="dialog__content__new__category__title">
            <label for="form__title">Title</label>
            <input type="text" name="title" id="form__title" value="" required />
            <label for="form__category">Category</label>
            <select class="choice__category" id="form__category" required></select>
            <hr class="border__in__second__window__of__dialog" />
            <input type="submit" id="submit__new__work" value="Submit" />
          </div>
        </form>
      </div>
    </dialog>

Ant UI collapse ul tag

When i put in antd collapse children tags like this

<Collapse items=[{
  key: '1',
  label: '123',
  children: <ul><li>1</li><li>2</li><li>3</li></ul>
}]/>

Than collapse render every li element without bullets
collapse when i put 'ul li' tags

How to make antd render ul items with bullets?

I new in antd library and dont know how to fix it if it is possible

Vue router prop not working after migrating project from vuejs2 to vuejs3

Why it is not possible to pass router params as prop anymore in vuejs 3? The following code use to work perfectly fine in vuejs 2 but now it doesn’t work. I’ve check the documentation and I am doing exactly as per it and it is still not working. Please bear in mind that I am using vue version 3.3.13 and vue-router version 4.2.5. Here is the link to the demo:

(https://codesandbox.io/p/sandbox/vue-router-forked-5xd2tn?file=%2Fsrc%2Fmain.js%3A18%2C20)

I have 2 pages Home.vue and Detail.vue;

In Home.vue I have a simple router-link

<router-link :to="{ name: 'detail', params: { id: '123' }}">Go on the page detail</router-link>

And on the detail page, I am trying to display the id param but it’s not working.

<template>
  <div class="hello">Hello on the Detail page: {{ id }}</div>
</template>

<script>
export default {
  props: ["id"],
  mounted() {
    console.log(this.id); // id is undefined in console
  },
};
</script>

This is the router config:

const routes = [
  { path: "/", component: Home },
  {
    path: "/detail/",
    name: "detail",
    component: Detail,
    props: true,
  },
];

I also tried the following router config but still didn’t work:

const routes = [
  { path: "/", component: Home },
  {
    path: "/detail/",
    name: "detail",
    component: Detail,
    props: (route) => { id: route.params.id },
  },
];

Can someone please help me with this issue?

Problem with uploading image files to postgres and show in the frontend

I really hope someone can help as I have been stuck in this problem for a few days, watched videos etc. I have a simple html file and in it I want to show images (jpg) that are stored in postgres. The problem is that it seems that my images are not stored as they are not shown on pgadmin4 when I choose view all rows. So here are my questions:

  • In my bytea column in postgtes on pgadmin4 it says [binary data] – does this mean my image is uploaded?
  • My server, built on node.js, is running successfully but on the endpoint /api/images the json shows foto_id, username but not foto_data which is my bytea – why?
  • How do I manage to show the image in the frontend? I use html, css and javascript for the frontend and its running on a node.js server

My file for displaying the images is:

function loadImages() {
  fetch('http://localhost:3000/api/images')
      .then(response => response.json())
      .then(images => {
          const imageContainer = document.getElementById('image_container');
          images.forEach(image => {
              const div = document.createElement('div');
              div.className = 'w3-third';
              div.innerHTML = `
                  <div class="w3-card">
                      <img src="${image.url}" style="width:100%" class="w3-image">
                      <div class="w3-container">
                          <h5 class="h5icon">${image.username}</h5>
                          <img src="../Backend/Bilder/download.png" style="width:24px" class="downloadicon">
                      </div>
                  </div>
              `;
              imageContainer.appendChild(div);
          });
      })
      .catch(error => console.error(error));
}

loadImages();

The corresponding html is:

 <div>
    <div id="image_container"></div>
  </div>

Can someone help me with that? As a sidenote: the username (${image.username}) is shown, so the conncetion to the server is working.

And yes, in html the script.js is connected.

Thanks in advance, Andrea

  • I tried different javascript and expected the images to be displayed, but it doesn’t work.
  • I tried different postgresql versions of my table and how to insert the image files from my filesystem, but no progress
  • I watched servaral youtube videos, tried their recommendations, but still not working

Plot netCDF files from ERDDAP server with leaflet

I have deployed a ERDDAP server on a AWS machine, which has multiple datasets, each of which contains multiple NetCDF files. I’m trying to develop a JavaScript interface, using Leaflet, so that I can plot the data on the .nc files in a map. However, I’m not being able to do it.

I have a selector in HTML to select a parameter and date, and the following JavaScript code. However, when I acces the web app, the map is not being shown properly, and no data is plotted.
[![The map is cutted and no data is shown][1]][1]

    // Inicializar el mapa
          var map = L.map('map', {
          center: [-5, 35],
          zoom: 4
        });

    // Agregar capa base
    var layer = L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
      attribution: '&copy; OpenStreetMap contributors'
    });

    map.addLayer(layer);

    // Obtain data
    function obtenerDatos(parametro, ano, mes) {
      // URL
      var url = `https://http://13.53.65.240:8080/erddap/files/${parametro}gridtemp/${parametro}_${ano}${mes}.nc`;

      // GET request
      var xhr = new XMLHttpRequest();
      xhr.open('GET', url, true);
      xhr.onload = function() {
        // Decodificar la respuesta
        var response = JSON.parse(xhr.responseText);

        // Return data
        return response;
      };
      xhr.send();
    }

    // Parameter selector
    var selectorParametros = document.getElementById('parameter');

        // Listener for Parameter selector
    selectorParametros.addEventListener('change', function() {
      var parametro = selectorParametros.value;
      var data = data.value;

      var datos = obtenerDatos(parametro, data.split('-')[0], data.split('-')[2]);

      actualizarCapa(datos);
    });
    
    
    // Date selector
    var selectorData = document.getElementById('data');
    
    // Listener for date selector
    selectorData.addEventListener('change', function() {
      var parametro = parametro.value;
      var data = selectorData.value;

      var datos = obtenerDatos(parametro, data.split('-')[0], data.split('-')[2]);

      actualizarCapa(datos);
    });

    // Update layer
    function actualizarCapa(datos) {
      // Create data layer
      var gridLayer = L.gridLayer(datos, {
        columns: ['latitude', 'longitude', 'CO_column_data_density'],
        style: function(feature) {
          return {
            color: feature.properties.CO_column_data_density
          };
        }
      });

      // Add layer to map
      map.addLayer(gridLayer);
    }``


  [1]: https://i.stack.imgur.com/845lC.png

my react front end validation is not working properly

I am defining the validation in the checkbox where if it is does not checked then it should not go to the next step but i implemented the validation but it successfully go to the next step but showing the error on the checkbox icon

export function isValidEmployement(data) {

  const isValidOccupation = data.occupation === null || data.occupation.value === null ? false : regex.isNotEmpty.test(data.occupation);
  const isValidSourceOfIncome = data.sourcesOfIncome === null ? false : data.sourcesOfIncome
  const isValidFreelancerConsent = data.freelancerConsent;

  return {
    isValidOccupation: isValidOccupation,
    isValidSourceOfIncome: isValidSourceOfIncome,
    isValidFreelancerConsent,

    allValid:
      isValidOccupation && isValidSourceOfIncome && isValidFreelancerConsent,
  };
}

this is the function that will handle the validation

const applicantList = [...state.applicantList];
const validationResultEmployment = isValidEmployement(
   applicantList[index]
);

applicantList: [
      {
        //BASIC INFO
        fullName: "",
        purposeAccount: "",
        mobileOtp: "",
        dateOfBirth: "",
        isTaxResidentOtherThanPakistan: "",
        presentAddressConsent: false,
        permanentAddressConsent: false,
        officeCity: "",
        officeHouseNumber: "",
        officeLandmark: "",
        officeTown: "",
        officeCountry: "",
        mobileOperator: "",
        docType: "",
        docNumber: "",
        isRecapcha: false,
        selectedCardReason: "",
        factaStatus: "",
        docIssueDate: "",
        docExpiryDate: "2099-12-31",
        nationality: [],
        email: "",
        cellNo: "",
        confirmationDialogIsOpen: false,
        selectedBasicInfoPhoneNumber: {
          name: "+92",
          value: "+92",
        },
        iUnderstand: false,
        iConsent: false,
        validationResultBasicInfo: {
          isValidFullName: true,
          isValidEmail: true,
          isValidRecapcha: true,
          isValidDateOfBirth: true,
          isValidDocType: true,
          isValidDocNumber: true,
          isValidDocIssueDate: true,
          isValidDocExpiryDate: true,
          isValidCellNo: true,
          isValidIUnderstand: true,
          isValidIConsent: true,
          allValid: true,
        },

        nationalityInformation: [
          {
            nationality: "",
            passportNumber: "",
            passportExpiryDate: "",
            validationResult: {
              isValidNationality: true,
              isValidPassportNumber: true,
              isValidPassportExpiryDate: true,
              allValid: true,
            },
          },
        ],
        birthCountry: "",
        gender: "",
        motherMaidenName: "",
        fatherName: "",
        educationalLevel: "",
        isPdf: false,
        maritalStatus: "",
        residentCountry: {
          value: "Pakistan",
        },
        nationality: [],
        passportNumber: "",
        passportExpiryDate: "",
        presentHouseNumber: "",
        presentLandmark: "",
        addressType: "",
        presentTown: "",
        presentCountry: {
          value: "Pakistan",
        },
        officeCountry: {
          value: "Pakistan",
        },
        confirmationDialogIsOpen: false,
        presentCity: "",
        presentPostalCode: "",
        presentHomePhoneNo: "",
        nextOfKinpermanentAddress: "",
        permanentAddress: "",
        permanentHouseNumber: "",
        permanentLandmark: "",
        presentResidenceHomePhoneCountryCode: "",
        incomeTaxConsent: false,

        //Consent info
        adaAndAdraConsent: false,
        freelancerConsent: false,

        permanentTown: "",
        permanentCountry: {
          value: "Pakistan",
        },
        permanentCity: "",
        permanentPostalCode: "",
        permanentHomePhoneNo: "",
        permanentPhoneCode: {
          value: "+92",
        },
        presentPhoneCode: {
          value: "+92",
        },
        showAddNewAddressTextBox: true,
        validationNationalityResult: {
          isValidNationality: true,
          isValidPassportNumber: true,
          isValidPassportExpiryDate: true,
        },
        validationResultCustomerinfo: {
          isValidBirthCountry: true,
          isValidGender: true,
          isValidNationality: true,
          isValidMotherMaidenName: true,
          isValidFatherName: true,
          isValidEducationalLevel: true,
          isValidMaritalStatus: true,
          isValidResidentCountry: true,
          isValidPresentHouseNumber: true,
          isValidPresentLandmark: true,
          isValidPresentTown: true,
          isValidPresentCountry: true,
          isValidPresentCity: true,
          isValidPresentPostalCode: true,
          isValidPresentHomePhoneNo: true,
          isValidPermanentAddress: true,
          isValidPermanentHouseNumber: true,
          isValidPermanentLandmark: true,
          isValidPermanentTown: true,
          isValidPermanentCountry: true,
          isValidPermanentCity: true,
          isValidPermanentPostalCode: true,
          isValidDateOfBirth: true,
          isValidDocIssueDate: true,
          isValidDocExpiryDate: true,
          isValidPermanentHomePhoneNo: true,
          isValidCorrespondenceAddress: true,
          isValidOfficeHouseNumber: true,
          isValidOfficeLandMarkError: true,
          isValidOfficeTown: true,
          isValidOfficeCountry: true,
          isValidOfficeError: true,
        },
        rowAdded: true,

        //NEXT OF KIN INFO

        kinName: "",
        kinRelation: "",
        kinContactNo: "",
        kinId: "",
        nextKinAddress: "",
        selectedKinPhoneNumber: "",
        kinHouseNumber: "",
        kinLandmark: "",
        kinTown: "",
        kinCountry: "",
        kinCity: "",
        kinPermanentAddress: "",
        kinPostalCode: "",
        kinHomePhoneNo: "",
        kinConfirmationDialogIsOpen: false,
        kinSelectedLandLinePhoneNumber: "",
        validationResultNextOfKin: {
          isValidKinName: true,
          isValidKinRelation: true,
          isValidKinContactNo: true,
          isValidKinId: true,
          isValidNextKinAddress: true,
          isValidHouseNumber: true,
          isValidLandmark: true,
          isValidTown: true,
          isValidCountry: true,
          isValidCity: true,
          isValidPostalCode: true,
          isValidHomePhoneNo: true,
        },

        //EMPLOYMENT INFO

        occupation: "",
        validationResultEmployment: {
          isValidOccupation: true,
          isValidSourceOfIncome: true,
          isValidFreelancerConsent: true
        },
        sourcesOfIncome: [],
        validationResultFund: {
          isValidAddress: true,
          isValidCity: true,
          isValidCountry: true,
          isValidEmployerOrBusinessName: true,
          isValidEmploymentType: true,
          isValidHomePhone: true,
          isValidHomePhoneCountryCode: true,
          isValidLegalIdNo: true,
          isValidNearestLandmark: true,
          isValidContactNumber: true,
          isValidOfficePhone: true,
          isValidOfficePhoneCountryCode: true,
          isValidPostalCode: true,
          isValidRelationship: true,
          isValidTownTehsil: true,
          isValidFundProviderConsent: true,
        },
        isValidEmploymentBusinessAddress: {
          isValidAddress: true,
          isValidNearestLandmark: true,
          isValidTownTehsil: true,
        },

        //FACTA INFO
        usPerson: "",
        usConnections: "",
        countryOfTaxResidency: "",
        taxIdentificationNumber: "",
        confirmationDialogIsOpen: false,
        tinReason: "",
        tinReasonIfBSelect: "",
        countryTaxInfoList: [
          {
            countryOfTaxResidency: "",
            taxIdentificationNumber: "",
            tinReason: "",
            tinReasonIfBSelect: "",
            validationResult: {
              isValidCountryOfTaxResidency: true,
              isValidTaxIdentificationNumber: true,
              isValidTinReason: true,
              isValidTinReasonIfB: true,
              allValid: true,
            },
          },
        ],
        validationResultFactaInfo: {
          isValidCountryInfoList: true,
          isValidUsConnections: true,
          isValidUsPerson: true,
        },
        isValidCountryInfoList: {
          isValidcountryOfTaxResidency: true,
          isValidTaxIdentificationNumber: true,
          isValidTinReason: true,
          isValidTinReasonIfB: true,
        },
        validationResultIncomeAndTax: {
          isValidOccupation: true,
          isValidSourceOfIncome: true,
          isValidFactaStatus: true,
          isValidZakatExemption: true,
          isValidFiqqah: true,
          isValidZakatExemptionsConsent: true,
          isValidIncometaxConsent: true,
          isValidTaxResidentOtherThanPakistan: true,
        },

        // Employer Business Detail Info
        employerBusinessName: "",
        employerBusinessAddress: "",

        //ACCOUNT INFORMATION SUBMIT
        eftConsent: false,
        submitButtoClicked: false,
        addAnotherAccountDialog: false,
        debitCardList: [
          {
            debitCardType: {
              value: "CARD_TYPE_SONERI_PAYPAK",
            },
            debitCardName: "",
            validationResult: {
              isValidDebitCardType: true,
              isValidDebitCardName: true,
              allValid: true,
            },
          },
          {
            debitCardType: {
              value: "CARD_TYPE_SONERI_PAYPAK",
            },
            debitCardName: "",
            validationResult: {
              isValidDebitCardType: true,
              isValidDebitCardName: true,
              allValid: true,
            },
          },
          {
            debitCardType: {
              value: "CARD_TYPE_SONERI_PAYPAK",
            },
            debitCardName: "",
            validationResult: {
              isValidDebitCardType: true,
              isValidDebitCardName: true,
              allValid: true,
            },
          },
          {
            debitCardType: {
              value: "CARD_TYPE_SONERI_PAYPAK",
            },
            debitCardName: "",
            validationResult: {
              isValidDebitCardType: true,
              isValidDebitCardName: true,
              allValid: true,
            },
          },
        ],
        bankAccountDetails: [
          {
            foreignBankName: "",
            accountNumber: "",
          },
        ],
        natureOfCashWithDraw: [],
        raastRegistration: "",
        smsAlertActivation: "",
        smsAlertActivationConsent: false,
        electronicFundTransfer: "",

        accountTypeState: account && account.get("productType"),
        accountProductId: account && account.get("productId"),
        foreignRemittances: false,
        fundsTransfer: false,
        outwardClearing: false,
        annualIncome: "",
        monthlyCreditTRansactions: "",
        monthlyDebitTransactions: "",
        monthlyCredit: "",
        monthlyDebit: "",
        foreignBankName: "",
        accountNumber: "",
        // correspondenceAddress: "",
        correspondenceAddress: "",
        correspondenceNearestLandmark: "",
        correspondenceTownTehsil: "",
        correspondenceCountry: "",
        correspondenceCity: "",
        correspondencePostalCode: "",
        correspondenceHomePhone: "",
        correspondenceHomePhoneCountryCode: "",
        eStatementSubscriptionConsent: false,
        chequebook: "",
        chequebookLeaves: "",
        chequebookLabel: "",
        chequebookLabel2: false,
        successDialogIsOpen: false,
        debitCard: "",
        debitCardType: "",
        debitCardLabel: "",
        electronicFundTransfer: "",
        electronicFundTransferLabel: "",
        eStatementSubscription: [],
        zakatExemptions: "",
        fiqqah: "",
        desiredBranch: "",
        zakatExemptionsConsent: false,
        selectedProvince: "",
        selectedCity: "",
        isEStatementSubscription: "",
        staffReferal: "",
        annualIncomeAmountEstimateRanges: "",
        monthlyAccountCreditAmountEstimateRanges: "",
        monthlyAccountCreditCountEstimateRanges: "",
        monthlyAccountDebitAmountEstimateRanges: "",
        monthlyAccountDebitCountEstimateRanges: "",
        validationBankAccountsResult: {
          isValidForeignBankName: true,
          isValidAccountNumber: true,
        },
        validationResultAccount: {
          isValidCashWithdrawl: true,
          isValidZakatExemptionDropdown: true,
          isValidBankAccountDetails: true,
          isValidForeignRemittances: true,
          isValidChequeBookConsent2: true,
          isValidFundsTransfer: true,
          isValidOutwardClearing: true,
          isValidEStatementSubscriptionConsent: true,
          isValidMonthlyAccountDebitCountEstimateRanges: true,
          isValidRaastRegistration: true,
          isValidSmsAlertActivationConsent: true,
          isValidSmsAlertActivation: true,
          isValidCorrespondenceAddress: true,
          isValidHouseNumber: true,
          isValidLandmark: true,
          isValidTown: true,
          isValidCountry: true,
          isValidCity: true,
          isValidPostalCode: true,
          isValidHomePhoneNo: true,
          isValidChequebook: true,
          isValidChequebookLeaves: true,
          isValidDebitCard: true,
          isValidDebitCardType: true,
          isValidElectronicFundTransfer: true,
          isValidEStatementSubscription: true,
          isValidZakatExemptions: true,
          isValidFiqqah: true,
          isValidDesiredBranch: true,
          isValidStaffReferal: true,
          isValidZakatExemption: true,
          isValidAnnualIncome: true,

          monthlyAccountCreditAmountEstimateRanges: true,
          isValidMonthlyDebit: true,
          isValidMonthlyAccountCreditCountEstimateRanges: true,
          isValidMonthlyCredit: true,
          isValidForeignBankAccountDetails: true,
          isValidDebitCardConsent: true,
          isValidChequeBookConsent: true,
          isValidElectronicTransferConsent: true,
          isValidZakatExemptionConsent: true,
          isValidPurposeAccount: true,
          isValidDebitCardReason: true,
          isValidIsEStatementSubscription: true,
          isValidEftConsent: true,
        },

        validationResultSingleAccount: {
          isValidAnnualIncome: true,
          isValidBankAccountDetails: true,
          isValidZakatExemption: true,
          isValidZakatExemptionConsent: true,
        },
        rowAddedAccount: true,

        //DOCUMENTS

        occupation: "",
        selectedValue: "",
        imagePreviewDialogIsOpen: false,
        termsAndConditionDialogIsClicked: false,
        disclaimersClicked: false,
        showDisclaimersError: false,
        livePictureDialogIsOpen: false,
        confirmationDialogIsOpen: false,
        submitButtonIsClicked: false,
        showTermsAndConditionError: false,
        showKFSError: false,
        errorDialogIsOpen: false,
        employerBusinessName: "",
        successDialogIsOpen: false,
        houseNumber: "",
        landmark: "",
        town: "",
        country: "",
        city: "",
        postalCode: "",
        homePhoneNo: "",
        signature: false,
        validationResultConsentAndDeclaration: {
          isValidDisclaimers: true,
          isValidTermsAndConditions: true,
          isValidUndertakingOfPersonalFunds: true,
        },
        validationResultDocuments: {
          isValidSignature: true,
        },
        termsAndConditions: false,
        disclaimers: false,
        undertakingOfPersonalFunds: false,
        KfsClicked: false,
        invalidType: [],
      },
    ],

In validationResultEmployment i called the function isValidEmployement
this is my applicantList array inside the state

 <Employement
redirectTo={redirectTo}
execStatusGetConfigurations={execStatusGetConfigurations}
validationCheck={validationCheck}
handleTaxesOfInformation={handleTaxesOfInformation}
handleChange={handleChange}
productId={account && account.get("productId")}
execStatusAddFactaCrsInfo={execStatusSaveApplication}
handleFactaRow={handleFactaRow}
handleAccountChange={handleAccountChange}
handleSourceOfIncomeValueChange={handleSourceOfIncomeValueChange}
initialSourceOfIncome={initialSourceOfIncome}
handleTaxesOfInformationSelect={handleTaxesOfInformationSelect}
onConsentChange={onConsentChange}
goBack={goBack}
{...props}
{...state.applicantList[currentActiveStep]}
validationResultFund={{
...state.applicantList[currentActiveStep].validationResultFund,
 }}
validationResultEmployment={{
   ...state.applicantList[currentActiveStep]
  .validationResultEmployment,
 }}
  validationResult={{
...state.applicantList[currentActiveStep]
.validationResultIncomeAndTax,
              }}
            />

I am passing the validationResultEmployment to the employment comp as a prop

isValid={
 props.validationResultEmployment.isValidFreelancerConsent ===
 false
? false
: true
 }

and this is i am checking if it is valid but it does not work

I am trying to get the similar implementation but it did not work

LangChain ConversationalRetrievalQAChain: Full Response Instead of Tokens in Streaming

I’m working on a LangChain project using ConversationalRetrievalQAChain and OpenAI to achieve token-based incremental processing. My goal is to process each generated token as it’s written for custom formatting and sentiment analysis. Unfortunately, I’m encountering an issue where I only receive the entire response at the end, instead of individual tokens as expected

const model = new OpenAI({
  ... // relevant options like temperature, modelName, etc.
  streaming: true,
  callbacks: [
    {
      handleLLMNewToken(token) {
        console.log("Expected to receive individual tokens here, but only getting full response object.");
      },
    },
  ],
});

    const chain = ConversationalRetrievalQAChain.fromLLM(
  model,
  vectorstore.asRetriever({ k: 6 }),
  ... // relevant chain options like qaTemplate and questionGeneratorTemplate
);

    const response = await chain.stream({ question: "Sample question", chat_history: 
    "Previous conversation..." });

for await (const data of responseStream) {
  console.log("Expected to iterate over individual tokens, but only receiving full 
 response object.");
}

Expected Behavior:

 I expect the handleLLMNewToken callback to log each generated token individually, and the for await loop to iterate over these individual tokens. This would allow me to process each token as it's written.

Observed Behavior:

However, the handleLLMNewToken callback only logs the complete response object, and the for await loop iterates over a single full response object, not individual tokens.enter code here

White screen in electron when using react-chartjs-2

I have this typical chart implementation of react-chartjs-2. Why is this not working in electron generated using Vite and with react with TypeScript (.tsx) as the front-end? The problem: I can’t see the chart, my other components/UI elements disappears when this component is used with other components, the terminal and the app doesn’t give me errors; I just see a blank screen (image attached below).

import { Doughnut } from "react-chartjs-2";

const Analytics = () => {
    const data = {
        labels: ["Rent", "Groceries", "Utilities", "Others"],
        datasets: [
            {
                data: [8000, 15000, 5000, 12000],
                backgroundColor: ["#FF6384", "#36A2EB", "#FFCE56", "#4CAF50"],
                hoverBackgroundColor: [
                    "#FF6384",
                    "#36A2EB",
                    "#FFCE56",
                    "#4CAF50",
                ],
            },
        ],
    };

    return (
        <div>
            {/* Add the Doughnut chart */}
            <Doughnut data={data} />
        </div>
    );
};

export default Analytics;

This is what my component looks like before using the component.
NOTE: I want to display the chart below the “Hello, World!” text:
enter image description here
This is what I see after using the component:
enter image description here

magento 2.4 – blocked due to MIME type (“text/html”)

I have a third party module (HK2_Addbootstrap5) that require a on line js file.

Vendor/hk2/addboostrap5/view/frontend/requirejs-config.js

    var config = {
    "paths": {
        "bootstrap523": "https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min",
        "bootstrap513": "https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min",
        "bootstrap462": "https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min",
    },

    map: {
        "*": {
            "customjs523": "HK2_AddBootstrap5/js/init523",
            "customjs513": "HK2_AddBootstrap5/js/init513",
            "customjs462": "HK2_AddBootstrap5/js/init462",
        }
    },

    shim: {
        'bootstrap462': {
            deps: ['jquery']
        },
        'bootstrap513': {
            deps: ['jquery']
        },
        'bootstrap523': {
            deps: ['jquery']
        }
    }
};

when loading the page, I got the following error

http://www.example.com/static/frontend/Ortho/tizzyWatch/fr_FR/customjs523.js » was blocked due to MIME type (« text/html ») (X-Content-Type-Options: nosniff).

I have the .htaccess file in ./pub/static, The allow Symlink is set to know.

Thank you for your help,

Google maps API: map doesn’t load every time (Uncaught (in promise) InvalidValueError)

I built a contact form in which a user can find his house via Google Maps and afterwards adjust the exact position via marker so that this information will be sent to my WPForms as static image together with pre-filled address details.

Everything works like expected, but there is this strange problem that the google map won’t always load. It happens in every browser, beside Safari, sometimes it loads, sometimes it doesn’t. I can refresh the page a few times and I’d say that it works 4 out of 5 times. When the map is not able to load, this is what the console is showing:

Uncaught (in promise) InvalidValueError: Map: Expected mapDiv of type HTMLElement but was passed null.

This is my script (I’ve randomized the api key)

<script src="https://maps.googleapis.com/maps/api/js?key=AIzaS1234567890hIP123456789051hbRgLF0UM&libraries=places&callback=initMap" 
        async defer></script>
<script>
var map;
var autocomplete;
var marker;
var hintDiv;

function initMap() {
    // Initialisiere die Karte
    map = new google.maps.Map(document.getElementById('map'), {
        center: {lat: 51.1657, lng: 10.4515},
        zoom: 6,
        mapTypeId: 'roadmap',
        mapTypeControl: false,
        streetViewControl: false,
        tilt: 0
    });

    // Autocomplete-Feld
    var input = document.getElementById('addressInput');
    autocomplete = new google.maps.places.Autocomplete(input);

    // Kein Browser-Autocomplete
    input.setAttribute('autocomplete', 'off');

    // Marker
    marker = new google.maps.Marker({
        position: {lat: 0, lng: 0},
        map: map,
        draggable: true
    });

    // Listener für Autocomplete-Auswahl
    autocomplete.addListener('place_changed', function() {
        var place = autocomplete.getPlace();
        if (!place.geometry) {
            console.error("Returned place contains no geometry");
            return;
        }

        // Zentriere die Karte und setze den Marker an die ausgewählte Position
        map.setCenter(place.geometry.location);
        marker.setPosition(place.geometry.location);

        // Ändere die Kartenansicht auf Sattelitenbild
        map.setMapTypeId('satellite');
        map.setZoom(19);

        // WPForms Autofill
        updateFormFields(place);

        // Hinweis für Stecknadel
        showHint();

        // Image Export für Formular
        showImageMap();
    });

    // Listener für Marker-Bewegung
    marker.addListener('dragend', function(event) {
        // Debug 
        console.log('Marker position:', event.latLng.lat(), event.latLng.lng());
        // Geocode für Adresse des Markers
        geocodeLatLng(event.latLng, function() {
            // Update Image Export
            showImageMap();
        });
    });
}

function updateFormFields(place) {
    // WPForms Autofill
    document.getElementById('wpforms-1307-field_10').value = getPostalCode(place);
    document.getElementById('wpforms-1307-field_11').value = getCity(place);
    document.getElementById('wpforms-1307-field_12').value = getStreet(place);
    document.getElementById('wpforms-1307-field_13').value = getStreetNumber(place);
}

function getPostalCode(place) {
    // Extrahiere PLZ
    for (var i = 0; i < place.address_components.length; i++) {
        for (var j = 0; j < place.address_components[i].types.length; j++) {
            if (place.address_components[i].types[j] === 'postal_code') {
                return place.address_components[i].long_name;
            }
        }
    }
    return '';
}

function getCity(place) {
    // Extrahiere Stadt
    for (var i = 0; i < place.address_components.length; i++) {
        for (var j = 0; j < place.address_components[i].types.length; j++) {
            if (place.address_components[i].types[j] === 'locality') {
                return place.address_components[i].long_name;
            }
        }
    }
    return '';
}

function getStreet(place) {
    // Extrahiere Straße
    for (var i = 0; i < place.address_components.length; i++) {
        for (var j = 0; j < place.address_components[i].types.length; j++) {
            if (place.address_components[i].types[j] === 'route') {
                return place.address_components[i].long_name;
            }
        }
    }
    return '';
}

function getStreetNumber(place) {
    // Extrahiere Hausnummer
    for (var i = 0; i < place.address_components.length; i++) {
        for (var j = 0; j < place.address_components[i].types.length; j++) {
            if (place.address_components[i].types[j] === 'street_number') {
                return place.address_components[i].long_name;
            }
        }
    }
    return '';
}

function geocodeLatLng(latlng, callback) {
    var geocoder = new google.maps.Geocoder();
    geocoder.geocode({'location': latlng}, function(results, status) {
        if (status === 'OK') {
            if (results[0]) {
                // ADresse formatiert
                var address = results[0].formatted_address;
                console.log('Address:', address);
                // An WPForms via static Image senden

                // Callback Bewegung Marker
                if (callback && typeof callback === 'function') {
                    callback();
                }
            } else {
                console.error('No results found');
            }
        } else {
            console.error('Geocoder failed due to: ' + status);
        }
    });
}

// Hinweis für Stecknadel
function showHint() {
    if (!hintDiv) {
        hintDiv = document.createElement('div');
        hintDiv.innerHTML = '<p>Bitte überprüfen Sie die Lage Ihres Hauses.<br>Sie können die rote Stecknadel verschieben, um Ihr Haus auszuwählen.</p>';
        hintDiv.style.backgroundColor = 'white';
        hintDiv.style.padding = '10px';
        hintDiv.style.border = '1px solid #ccc';
        hintDiv.style.borderRadius = '5px';
        hintDiv.style.marginTop = '10px';

        document.getElementById('hintContainer').appendChild(hintDiv);
    }
}
// Image Export an WPForms
function showImageMap() {
    // Erstelle ein neues Bild-Element
    var imageMap = new Image();

    // Aktualisierte Position des Markers
    var markerPosition = marker.getPosition();

    // URL für die statische Karte mit dem aktualisierten Marker
    var imageUrl = "https://maps.googleapis.com/maps/api/staticmap?" +
        "center=" + markerPosition.lat() + "," + markerPosition.lng() +
        "&zoom=19" +
        "&size=600x300" +
        "&maptype=satellite" +
        "&markers=color:yellow%7Clabel:Ihr%20Haus%7C" + markerPosition.lat() + "," + markerPosition.lng() +
        "&key=AIz1234567890QmhIP123456789051hbRgLF0UM";

    // URL für Bild
    imageMap.src = imageUrl;
document.getElementById('wpforms-1307-field_15').value = imageUrl;

    // HTML Export
    document.getElementById('imageMapContainer').innerHTML = '';
    document.getElementById('imageMapContainer').appendChild(imageMap);
}
</script>

These are my div containers:

<div>
    <input type="text" id="addressInput" placeholder="Bitte geben Sie hier Ihre Adresse ein" autocomplete="off">
</div>
<div id="map"></div>
<div id="hintContainer"></div>

thanks in advance!

tried to run it on a different server (not wordpress), expected that is has something to do with the way my theme loads the function. Did not work.

tried to remove the callback function for the eventlistener when the marker has been moved, no difference.

Can we store images or documents in firebase?

Can we store images or documents in firebase in the firestore database which is submitted by user in the form ?

I tried it in the following way but I didn’t get the output.

  function submitForm() {
    var name = document.getElementById("name").value;
    var email = document.getElementById("email").value;
    var countrycode = document.getElementById("country-code").value;
    var mobilenumber = document.getElementById("mobile-number").value;
    var certificate = document.getElementById("certificate").value;
    var graduationyear = document.getElementById("graduation-year").value;
    var joiningreason = document.getElementById("joining-reason").value;

    // Access the Firestore database
    var db = firebase.firestore();

    // Add the form data to a 'users' collection
    db.collection("users").add({
      name: name,
      email: email,
      country_code: countrycode,
      mobile_number: mobilenumber,
      certificate: certificate,
      graduation_year: graduationyear,
      joining_reason: joiningreason
    })
    .then(function(docRef) {
      console.log("Document written with ID: ", docRef.id);
      // You can do something after the data is successfully added
    })
    .catch(function(error) {
      console.error("Error adding document: ", error);
    });
  }

Add click event to highcharts Sunburst level that adds style to any class

I have this issue where i would like to toggle the style display: none; to a class in my dataLabelFormatter .chart-amount-visibility. It should only happen whenever a level has been expanded.I just cant seem to wrap my head around how to do it.

Here’s how my SunBurst chart looks like

SunBurst chart

And here when it’s expanded

SunBurst chart expanded

You see the amount, that should not be visible in the inner pie whenever it’s not expanded. That should only be visible whenever any section is expanded.

Here’s my current code:

async generateSunburstData(strContainerID: string, strCurrencyCode: string, oSunburstData: SunburstData) {
        const arrOrderTypeColors: { [key: string]: string } = {
            Pre: '#8BBC21',
            Stock: '#528F8F'
        };

        oSunburstData.arrData.forEach(dataItem => {
            if (dataItem.name === 'Pre' || dataItem.name === 'Stock') {
                dataItem.color = arrOrderTypeColors[dataItem.name];
            }
        });

        const fTotalSum = oSunburstData.arrData.reduce((fTotalSum, DataPoint) => fTotalSum + DataPoint.value, 0);
        if (fTotalSum <= 0) {

            const strTurnoverContainer = document.getElementById('turnoverPieChart');
            const strMarginContainer = document.getElementById('marginPieChart');

            if (strTurnoverContainer) {
                strTurnoverContainer.innerHTML = '<div class="no-data-available-text"><p class="no-data-available-header">Turnover share on sales channels</p><p class="no-data-available-unset">No data available to display the chart.</p></div>';
            }

            if (strMarginContainer) {
                strMarginContainer.innerHTML = '<div class="no-data-available-text"><p class="no-data-available-header">Margin share on sales channels</p><p class="no-data-available-unset">No data available to display the chart.</p></div>';
            }
            
            return;
        }

        interface DataPoint {
            parent?: string;
            value: number;
            level: number;
            name: string;
            id: string;
        }

        const dataLabelFormatter = function () {
            const oPoint: DataPoint = this.point;
            const oSeries = this.series;

            const iLevel = oPoint.parent ? 1 : 2;

            if (iLevel === 2) {
                const parentTotal = oSeries.data.reduce((fTotalSum: number, dataPoint: DataPoint) => {
                    return dataPoint.parent === oPoint.parent ? fTotalSum + dataPoint.value : fTotalSum;
                }, 0);

                const strPercentage = (oPoint.value / parentTotal) * 100;
                const strFormattedPercentage = strPercentage.toFixed(2) + '%';

                return `<div class="inner-pie-chart"><b style="font-size: 14px;">${oPoint.name}</b><br><span dy="15" style="font-size: 12px;">${strFormattedPercentage}</span><br><span class="chart-amount-visibility" dy="28" style="font-size: 12px;">${number_format(oPoint.value, 0)} ${strCurrencyCode}</span></div>`;
            } else {
                return oPoint.name;
            }
        };


        const fnFormatter = function () {
            const oPoint = this.point,
                oSeries = this.series;
            let chartTotal;

            if (oPoint.level === 1) {
                chartTotal = oSeries.__myTotal || (oSeries.__myTotal = oSeries.data.reduce((a: number, b: DataPoint) => a + b.value, 0));
            } else {
                const siblings = oSeries.data.filter((p: DataPoint) => p.parent === oPoint.parent);
                chartTotal = siblings.reduce((a: number, b: DataPoint) => a + b.value, 0);
            }

            const fPercentage = oPoint.value / chartTotal;
            let strPercentage = fPercentage === undefined ? 'N/A' : number_format(fPercentage * 100, 2);

            return `<b>${this.point.name}</b><br>Percentage: ${strPercentage} % <br> Amount: ${number_format(this.point.value, 0)} ${strCurrencyCode}`;
        }

        return Sunburst.Highcharts.chart(document.getElementById(strContainerID)!, <Highcharts.Options>{
            chart: {
                backgroundColor: '#FCFCFC',
                height: 436,
            },
            navigation: {
                buttonOptions: {
                    enabled: false
                }
            },
            title: {
                text: oSunburstData.strTitle,
                style: {
                    color: '#3F3F3F'
                }
            },
            subtitle: {
                text: 'Percentage reflects the size of the pie cutout',
                style: {
                    color: '#3F3F3F'
                },
            },
            plotOptions: {
                sunburst: {
                    allowPointSelect: true,
                    cursor: 'pointer',
                    animation: false,
                    dataLabels: {
                        color: '#FFFFFF',
                        enabled: true,
                        formatter: dataLabelFormatter,
                    }
                },
            },
            series: [<Highcharts.SeriesSunburstOptions>{
                custom: {
                    percentage: 'parent'
                },
                breadcrumbs: {
                    buttonTheme: {
                        padding: 8,
                        stroke: '#CCCCCC',
                        'stroke-width': 1,
                        style: {
                            color: '#333333',
                            fill: '#333333',
                        }
                    },
                    floating: true,
                    position: {
                        align: 'left'
                    },
                    showFullPath: false,
                    formatter: function () {
                        const customText = '< Go back';

                        return `${customText} `;
                    },
                },
                type: 'sunburst',
                data: oSunburstData.arrData,
                allowTraversingTree: true,
                borderRadius: 8,
                cursor: 'pointer',
                levels: [{
                    level: 1,
                    levelIsConstant: false,
                    levelSize: {
                        unit: 'weight',
                        value: 3,
                    },
                    dataLabels: {
                        filter: {
                            property: 'outerArcLength',
                            operator: '>',
                            value: 64
                        }
                    }
                }, {
                    level: 2,
                    colorByPoint: true,
                }]
            }],
            tooltip: {
                useHTML: true,
                formatter: fnFormatter
            }
        });
    } 

Toast message color Django

In A django App I want to return a message from views and show it using toast.
and my main page is:

<div class="toast-container p-3">
  <div id="toast" class="toast align-items-center text-white bg-success border-0" role="alert" aria-live="assertive" aria-atomic="true">
    <div class="d-flex">
      <div id="toast-body" class="toast-body"></div>
      <button type="button" class="btn-close btn-close-white me-2 m-auto" data-bs-dismiss="toast" aria-label="Close"></button>
    </div>
  </div>
</div>


    <div class="col-md-3">
      <div id="Chamber_list">
        {% if messages %}
        {% for message in messages %}
          {% if message.tags == 'error' %}
              <div class="alert alert-danger" style="...">{{ message }}</div>
          {% else %}
          <div class="alert alert-success" style="...">{{ message }}</div>
          {% endif %}
        {% endfor %}
      {% endif %}

        {% include 'Home/MOG_Division/rooms/Detaile/Chamber_list.html' %}
      </div>
    </div>

And this is my views.py code

> def edit_actl(request, pk):
    theroom = get_object_or_404(room_actual, pk=pk)
    form_erAO = False
    if request.method == "POST":
        form = room_actualForm(request.POST, instance=theroom)
        try:
            if form.is_valid():
                form.save()
                response_data = {'success': True,'message': 'Room updated successfully'}
                response = HttpResponse(json.dumps(response_data), content_type='application/json',status=204)
                response['HX-Trigger'] = json.dumps({"roomListChanged": None, "showMessage": f"{theroom.room} {theroom.first_name} updated."  })
                return response
        except ValueError:
            form_erAO = 'Check your input dates'
            response_data = {'error': True, 'message': 'Room Already Occupied, Try another range'}
            response = HttpResponse(json.dumps(response_data), content_type='application/json',status=204)
            response['HX-Trigger'] = json.dumps({"roomListChanged": None, "showMessage":'Try another range'})
            return response
    else:
        form = room_actualForm(instance=theroom)
    return render(request, 'Home/MOG_Division/rooms/Detaile/Actul_form.html', {
        'form': form,
        'theroom': theroom,
        'form_erAO' : form_erAO
    })

and this is my form html page:

<form method="post" id="yourFormId"  hx-post="{{ request.path }}" hx-headers='{"X-CSRFToken":"{{ csrf_token }}"}' class="modal-content">
    <div class="col-sm-12">
        <div class="form-group row">
          <div class="col-sm-4">{{ form.as_p }}</div>
    <div class="modal-footer">
      <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Annuler</button>
      <button type="submit" class="btn btn-primary">Enregistrer</button>
  </div>
</form>


<script>
document.getElementById('yourFormId').addEventListener
  ('submit', function(event)
  {
      event.preventDefault();
      var form = event.target;
      var formData = new FormData(form);

        fetch(form.action, {
            method: form.method,
            body: formData,
            headers: {
                'X-CSRFToken': '{{ csrf_token }}',
            },
        })
        .then(response => {
            console.log('Raw Response:', response.text());
            return response.json();
        })
        .then(data => {
            handleResponse(data);
        })

        if (data.error) {
            document.getElementById('toast').classList.remove('bg-danger');
            document.getElementById('toast').classList.add('bg-danger');
        } 
        else {
            document.getElementById('toast').classList.remove('bg-success');
            document.getElementById('toast').classList.add('bg-success');
        }
        
      var toast = new bootstrap.Toast(document.getElementById('toast'));
      toast.show()
  })
</script>

the problem is that I need to change the color of the message when it is error.
the Javascript didn’t work when I use ;

    if (data.error) {
    document.getElementById('toast').classList.remove('bg-danger');
    document.getElementById('toast').classList.add('bg-danger');
} 
else {
    document.getElementById('toast').classList.remove('bg-success');
    document.getElementById('toast').classList.add('bg-success');
}

but when

I set it without if (data.error) it gives me a toast message in red

    document.getElementById('toast').classList.remove('bg-danger');
    document.getElementById('toast').classList.add('bg-danger');

have you any solution?