“Fake ‘Please select a variation’ alert on Add to Cart button in WooCommerce product variation selection”

I’m working on a custom WooCommerce product page where the user can select product variations (like size, color, etc.) and then add the product to the cart. Everything is functioning correctly, including the variation selection and the dynamic price update based on the selected variation.

However, I’ve encountered a problem. When a user selects a variation and clicks the ‘Add to Cart’ button, a fake alert appears, saying “Please select a variation,” even though a valid variation has already been selected. After closing this fake alert, the product is successfully added to the cart, and a success message appears.

I want to prevent this fake alert from showing when the product is added to the cart successfully. How can I modify the event handling to ensure only the success alert is shown, and the fake alert doesn’t appear?

Any help or suggestions are appreciated!

global $product;



// Get the product's default price HTML

$default_price_html = $product->get_price_html();



// Get available variations

$available_variations = $product->get_available_variations();



$product_id = $product->get_id();



echo '<div class="custom-product-price" style="text-align:center;">';

echo '<p id="product-price-' . $product_id . '" style="font-size:18px;font-weight:bold;">Price: ' .  $default_price_html . ' </p>';

echo '</div>';



echo '<div class="custom-product-variations" style="text-align:center;">';

$attributes = $product->get_variation_attributes();



foreach ($attributes as $attribute_name => $options) {

    echo '<div class="variation-group">';

    foreach ($options as $index => $option) {

        $input_id = 'attribute_' . sanitize_title($attribute_name) . '_' . $product_id . '_' . $index;

        echo '<input type="radio" id="' . $input_id . '" class="variation-option" name="attribute_' . sanitize_title($attribute_name) . '_' . $product_id . '" value="' . esc_attr($option) . '" data-attribute_name="' . sanitize_title($attribute_name) . '" data-product_id="' . $product_id . '">';

        echo '<label for="' . $input_id . '">' . esc_html($option) . '</label>';

    }

    echo '</div>';

}

echo '</div>';



echo '<div class="custom-add-to-cart">';

echo '<button id="add-to-cart-button-' . $product_id . '" disabled>Add to Cart</button>';

echo '</div>';



echo '<script type="text/javascript">

document.addEventListener("DOMContentLoaded", function () {

    var productID = "' . $product_id . '";

    var variationOptions = document.querySelectorAll(".variation-option[data-product_id='" + productID + "']");

    var priceElement = document.getElementById("product-price-" + productID);

    var addToCartButton = document.getElementById("add-to-cart-button-" + productID);

    var selectedVariationId = null;



    var availableVariations = ' . json_encode($available_variations, JSON_HEX_TAG | JSON_HEX_AMP | JSON_HEX_APOS | JSON_HEX_QUOT) . ';

    var defaultPriceHtml = ' . json_encode($default_price_html) . ';



    // Function to update the price display

    function updatePrice(priceHtml) {

        priceElement.innerHTML = "Price: " + priceHtml;

    }



    // Function to find and set the matching variation

    function findMatchingVariation(selectedAttributes) {

        return availableVariations.find(function (variation) {

            return Object.keys(selectedAttributes).every(function (key) {

                return variation.attributes[key] === selectedAttributes[key];

            });

        });

    }



    // Function to gather selected attributes

    function getSelectedAttributes() {

        var selectedAttributes = {};

        variationOptions.forEach(function (opt) {

            if (opt.checked) {

                var attrName = "attribute_" + opt.getAttribute("data-attribute_name");

                selectedAttributes[attrName] = opt.value;

            }

        });

        return selectedAttributes;

    }



    // Event listener for option changes

    variationOptions.forEach(function (option) {

        option.addEventListener("change", function () {

            var selectedAttributes = getSelectedAttributes();



            // Find matching variation

            var matchingVariation = findMatchingVariation(selectedAttributes);



            // Update the price and enable the Add to Cart button if a matching variation is found

            if (matchingVariation) {

                var priceHtml = "<span class="woocommerce-Price-amount amount"><bdi><span class="woocommerce-Price-currencySymbol">&#36;</span>" + matchingVariation.display_price.toFixed(2) + "</bdi></span>";

                updatePrice(priceHtml);

                selectedVariationId = matchingVariation.variation_id;

                addToCartButton.disabled = false; // Enable the Add to Cart button

            } else {

                updatePrice(defaultPriceHtml);

                selectedVariationId = null;

                addToCartButton.disabled = true; // Disable the Add to Cart button

            }

        });

    });



    // Add to Cart button click event

    addToCartButton.addEventListener("click", function (event) {

        // Before proceeding, check if any variation is selected and valid

        if (!selectedVariationId) {

            // Stop the function from proceeding and show the appropriate alert

            event.preventDefault();

            alert("Please select a variation before adding to cart.");

            return;

        }



        // If variation is selected, proceed with the add-to-cart functionality

        var formData = new FormData();

        formData.append("action", "woocommerce_add_to_cart");

        formData.append("product_id", selectedVariationId); // Use the selected variation ID

        formData.append("variation_id", selectedVariationId);

        formData.append("quantity", 1);



        // Include selected attributes in the form data

        var selectedAttributes = getSelectedAttributes();

        for (var key in selectedAttributes) {

            if (selectedAttributes.hasOwnProperty(key)) {

                formData.append(key, selectedAttributes[key]);

            }

        }



        fetch("' . admin_url('admin-ajax.php') . '", {

            method: "POST",

            body: formData,

            credentials: "same-origin"

        })

        .then(function (response) {

            return response.json();

        })

        .then(function (data) {

            if (data.error) {

                alert("Error adding to cart: " + data.error);

            } else {

                alert("Product added to cart successfully!");



                // Optionally, update the cart count or show a success message

                var cartCountElement = document.querySelector(".cart-count");

                if (cartCountElement) {

                    cartCountElement.textContent = data.cart_count;

                }

            }

        })

        .catch(function (error) {

            alert("There was an error processing your request. Please try again.");

        });

    });

});

</script>'; ```

How can I get FontAwesome icons to display in Vuetify checkboxes?

I’m new to Vue. I’m migrating a Vue app from BootstrapVue to Vuetify. The app already uses FontAwesome5, although it imports specific icons by name. I’ve managed to get icons to display, including the faCheckSquare icon. However, when I replace <b-form-checkbox> with <v-checkbox>, the <i> element is empty, so no checkbox displays.

What step am I missing to get the checkbox to render?

Here’s my setup:

import { createApp } from 'vue'
import { createVuetify } from 'vuetify'
import * as components from 'vuetify/components'
import * as directives from 'vuetify/directives'
import 'vuetify/styles'
import { aliases, fa } from 'vuetify/iconsets/fa'
import { library } from '@fortawesome/fontawesome-svg-core'
import App from './App.vue'

import {
  faSquare
} from '@fortawesome/free-regular-svg-icons'
import {
  faCheck,
  faCheckSquare
} from '@fortawesome/free-solid-svg-icons'

library.add(
  faCheck,
  faCheckSquare,
  faSquare
)

const vuetify = createVuetify({
  components,
  directives,
  theme: {
    defaultTheme: 'light'
  },
  icons: {
    defaultSet: 'fa',
    aliases,
    sets: {
      fa
    }
  }
})

app.use(vuetify)

…and then this template is in a separate file—I’ve added a <font-awesome-icon> tag just to show that the relevant icon is, in fact, imported and loaded.

<template>
  <font-awesome-icon :icon="['fas', 'check-square']" />
  <v-checkbox value="foo" label="Foo"></v-checkbox>
</template>

What I see rendered in the web inspector is this. The icon’s <svg> loads fine, but the checkbox element should also have an <svg> element inside its <i> element (apologies for all the boilerplate):

<svg class="svg-inline--fa fa-square-check" aria-hidden="true" focusable="false" data-prefix="fas" data-icon="square-check" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512">
  <path [...]></path>
</svg>
<div class="v-input [...] v-checkbox v-checkbox">
  <div class="v-input__control">
    <div class="v-selection-control v-selection-control--density-default v-checkbox-btn v-checkbox-btn">
      <div class="v-selection-control__wrapper">
        <div class="v-selection-control__input">
          <i class="far fa-square v-icon notranslate v-theme--light v-icon--size-default" aria-hidden="true"></i>
          <input id="checkbox-5" aria-label="Foo" type="checkbox" aria-describedby="checkbox-5-messages" value="true">
        </div>
      </div>
      <label class="v-label v-label--clickable" for="checkbox-5">Foo</label>
    </div>
  </div>
  <div class="v-input__details">
    <div role="alert" aria-live="polite" id="checkbox-5-messages"></div>
  </div>
</div>

Although invisible, the checkbox “works”—i.e., it switches from <i class="far fa-square"> to <i class="fas fa-check-square"> when I click on the blank space where the icon should render.

JavaScript / Tailwind.css – issue creating bingo card layout with grid-rows-5

I’m trying to create a Bingo game using vanilla JavaScript, with tailwind.css for the styling. I’m able to create a Bingo card, but the layout of numbers is incorrect. Let me explain:

This is for 75-ball Bingo. The first column, B, contains numbers from 1-15. The second column, I, contains numbers 16-30. The third column, N, contains numbers 31-45. The fourth column, G, contains numbers 46-60. The fifth column, O, contains numbers 61-75.

I am using CSS Grid via Tailwind to try and create the Bingo card. I am able to successfully create each square for each number as an element and insert it into the HTML. I am able to get unique random numbers for the card and insert them into the squares. I have the numbers as sub-arrays of an array, one array for each letter’s group of numbers.

The problem comes in when I try to lay out the card as a 5×5 grid.

I tried using the Tailwind class grid-rows-5. What I wanted to happen was for the first sub-array to populate rows 1 through 5 in one column, then the second array to populate rows 1 through 5 in another column, and so on. What happened instead was that the numbers/squares all printed in one column from the top down.

If I use grid-cols-5 instead of grid-rows-5, then I do get a 5×5 grid. The problem with that though is that the numbers 1 to 15 print all in the first row instead of the first column, and so on with each other group of numbers.

Here is the code:

HTML

<body>
    <button onclick="bingoCard()">Click to create card</button>
    <script src="./script.js"></script>
</body>

JavaScript

const bingoCard = () => {
    const card = document.createElement("div");
    card.setAttribute("id", "card");
    card.classList.add('inline-grid', 'grid-rows-5', 'gap-2', 'bg-zinc-900', 'border-2', 'border-zinc-900');
    document.body.appendChild(card);

    let cardNumbers = [];
    cardNumbers = createCardArrays();
    for (let i = 0; i < 5; i++) {
        for (let j = 0; j < 5; j++) {
            const cardCell = document.createElement("div");
            let cardCellNumber = cardNumbers[i][j];
            cardCell.textContent = cardCellNumber;
            cardCell.classList.add('w-28', 'h-28', 'text-5xl', 'flex', 'justify-center', 'items-center', 'bg-pink-100');
            card.appendChild(cardCell);
        }
    }
}
function createCardArrays() {
    const cardNumbers = new Array(5);
    let max, min;
    for (let i = 0; i < 5; i++) {
        cardNumbers[i] = [];
        max = 15 * (i + 1);
        min = max - 14;
        cardNumbers[i] = generateRandomNumbers(5, min, max);
    }
    return cardNumbers;
}

function generateRandomNumbers(count, min, max) {
    let uniqueNumbers = new Set();
    while (uniqueNumbers.size < count) {
        uniqueNumbers.add(Math.floor(Math.random() * (max - min + 1)) + min);
    }
    const uniqueNumbersArray = [...uniqueNumbers];
    return uniqueNumbersArray;
}

Any help is appreciated.

React application lazy imports – TypeError: undefined is not an object (evaluating ‘a._result.default’)

I have a react application which I monitor with Sentry. Inside the Sentry I see quite often the following error:

React ErrorBoundary TypeError: undefined is not an object (evaluating 'a._result.default')

As far as I understand the Error seems to be related to some lazy imports. But I am unsure since none of the listed files contain a lazy import and the whole application is Wrapped in a Supsense boundary. The Sentry trace is pointing me to some snippet from react (placed at the very end of the post). If I look at the stack trace it seems that the Error is originating from TanStackQuery, but I am unsure if this is really the case or if I do something wrong here.

This is the last file of the stack trace.

import type { FC, PropsWithChildren } from 'react';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { useState } from 'react';

const client = () =>
  new QueryClient({
    defaultOptions: {
      queries: {
        networkMode: 'always',
        staleTime: 1000 * 60 * 60 * 24 * 0.5, // 12h
        retry: 2,
        refetchOnWindowFocus: false
      }
    }
  });

const TanStackQueryProvider: FC<PropsWithChildren> = ({ children }) => {
  const [queryClient] = useState(client); // Sentry points at this line

  return <QueryClientProvider client={queryClient}>{children}</QueryClientProvider>;
};

export default TanStackQueryProvider;

};

Maybe anyone has some insights?

Appendix

Code Snippet from Sentry
Screenshot from Sentry

StackTrace
enter image description here

How to detect errors in the WooCommerce checkout form added with the checkout block?

I have a WooCommerce store that uses a checkout block. I want to track with Google Analytics what WooCommerce checkout fields are empty or are incorrectly filled in. The check should happen after a user clicks the “Pay now” button. How do I do this?

In the old shortcode checkout this was very easy with just a simple jQuery event listener, but the old solution doesn’t work with the block checkout.

How do I apply Tailwind CSS to a specific div block and Bootstrap for the rest?

Currently, I only want to apply Tailwind CSS and React to a the “First Impressions” section. This is a div block I added recently (through the help of ChatGPT) and when I loaded the page, I noticed that the Bootstrap CSS styling was overridden by Tailwind. Removing the Tailwind CDN link allows the rest of the page to be styled as intended, albeit at the cost of the newly-added div block rendering improperly.

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>MapPalette - Login</title>
  
  <script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.2.0/umd/react.development.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.2.0/umd/react-dom.development.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/babel-standalone/7.23.5/babel.min.js"></script>

    <!-- Tailwind CSS -->
    <link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet">
    <link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/tailwind.min.css" rel="stylesheet">
    
    

  <style>
    .navbar {
        position: sticky;
        top: 0;
        z-index: 3;
    }

    .navbar-brand {
        /*controls brand name size in navbar*/
        font-size: 1.5rem;
    }

    .nav-link {
        /*controls font size and margin of nav links*/
        font-size: 1.2rem;
        margin-left: 20px;
    }

    .navbar-brand img {
        /*brand logo sizing*/
        width: 50px;
        height: 50px;
        margin-right: 8px;
    }

    .app-name {
      font-size: 2.5rem;
      color: #007bff;
    }

    /* Full-width hero section */
    .hero {
      background: url('../resources/index/run-background.jpeg') no-repeat center center/cover;
      height: 80vh;
      position: relative;
    }

    .hero-content {
      position: absolute;
      top: 50%;
      left: 50%;
      transform: translate(-50%, -50%);
      text-align: center;
      color: white;
    }

    .hero h1 {
      font-size: 4rem;
      margin-bottom: 1rem;
    }

    .btn-primary {
      margin-right: 10px;
    }

    /* Key Features section */
    .key-features {
      display: flex;
      justify-content: space-between;
      margin: 2rem 0;
      text-align: center;
    }

    .features-image {
      width: 50px;
      height: 50px;
      margin-bottom: 1rem;
    }

    /* Video container */
    .video-container {
        text-align: center;
    }

    /* About us */
    .about-us {
      padding: 3rem 0;
    }

    .about-us-description {
        font-style: italic;
        font-weight: lighter;
    }

    /* First Impressions section */
    .first-impressions .card {
      border: none;
      background-color: #f8f9fa;
    }

    /* Fade-in scroll effect */
    .fade-in {
      opacity: 0;
      transform: translateY(50px);
      transition: opacity 0.8s ease-out, transform 1s ease-out;
    }

    .fade-in.show {
      opacity: 1;
      transform: translateY(0);
    }

    /* Sequential rendering for Key Features */
    .col-sm-4 {
      opacity: 0;
      transform: translateY(50px);
      transition: opacity 0.8s ease-out, transform 2s ease-out;
    } 

    /* Additional hover feature */
    .col-sm-4:hover {
      background-color: #f1f1f1;
      transform: scale(1.05);
    }

    /* Carousel modifications */
    .carousel-container {
        position: relative;
        max-width: 35%;
        margin: auto;
        overflow: hidden;
    }

    .carousel-slide {
        display: flex;
        transition: transform 0.5s ease-in-out;
    }

    .carousel-item {
        min-width: 100%;
        text-align: center;
        opacity: 1;
        visibility: visible;
    }

    .person-image {
        width: 100%;
        height: auto;
        object-fit: contain;
    }

    .person-name {
        font-size: 1.5em;
        margin: 10px 0;
    }

    .person-description {
        font-size: 1em;
        color: #666;
        font-style: italic;
    }

    .carousel-control-prev, .carousel-control-next {
        top: 40%;
        transform: translateY(-50%);
        z-index: 2;
    }

    .prev, .next {
      cursor: pointer;
      position: absolute;
      font-size: 2em;
      color: #333;
      background-color: transparent;
      border: none;
      padding: 0 10px;
    }

    .prev {
      left: 10px;
    }

    .next {
      right: 10px;
    }

    .scrollbar-hide::-webkit-scrollbar {
        display: none;
    }

    /* Hide scrollbar for IE, Edge and Firefox */
    .scrollbar-hide {
        -ms-overflow-style: none;  /* IE and Edge */
        scrollbar-width: none;  /* Firefox */
    }
  </style>
</head>
<body>
  <nav class="navbar navbar-expand-lg navbar-light bg-light px-3">
    <div class="container-fluid">
        <a class="navbar-brand" href="#"><img src="../resources/index/mappalettelogo.png"><span style="color: #007bff;">MapPalette</span></a>
        <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav"
            aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
            <span class="navbar-toggler-icon"></span>
        </button>
        <div class="collapse navbar-collapse justify-content-end" id="navbarNav">
            <ul class="navbar-nav">
              <li class="nav-item">
                <a href="login.html" class="nav-link btn btn-outline-primary">Login</a>
              </li>
              <li class="nav-item">
                <a href="signup.html" class="nav-link btn btn-primary">Sign Up</a>
              </li>
            </ul>
        </div>
    </div>
</nav>

  <!-- Hero Section -->
  <section class="hero">
    <div class="hero-content">
      <h1>Explore the World with MapPalette</h1>
      <p>Creative routes for every adventure</p>
      <a href="signup.html" class="btn btn-primary">Get Started</a>
      <a href="login.html" class="btn btn-outline-light">Login</a>
    </div>
  </section>

  <!-- First Impressions Section -->
  <section class="first-impressions fade-in">

  <div id="root">
    <!-- Your React component -->
    <script type="text/babel">
        

        // Copy the entire GalleryComponent code here
        const GalleryComponent = () => {
            const [activeIndex, setActiveIndex] = React.useState(null);
            const [scrollPosition, setScrollPosition] = React.useState(0);
            const scrollContainerRef = React.useRef(null);
            
            const images = [
                "../resources/index/about_us/placeholder.jpg",
                "../resources/index/about_us/placeholder.jpg",
                "../resources/index/about_us/placeholder.jpg",
                "../resources/index/about_us/placeholder.jpg",
                "../resources/index/about_us/placeholder.jpg",
                "../resources/index/about_us/placeholder.jpg",
                "../resources/index/about_us/placeholder.jpg",
                "../resources/index/about_us/placeholder.jpg",
            ];

            const handleScroll = (e) => {
                if (scrollContainerRef.current) {
                    const container = scrollContainerRef.current;
                    const scrollPos = container.scrollLeft;
                    setScrollPosition(scrollPos);
                    
                    const itemWidth = container.offsetWidth / 3;
                    const newActiveIndex = Math.round(scrollPos / itemWidth);
                    setActiveIndex(newActiveIndex);
                }
            };

            const getItemScale = (index) => {
                if (activeIndex === null) return 0.6;
                
                const distance = Math.abs(index - activeIndex);
                
                switch (distance) {
                    case 0:
                        return 1;
                    case 1:
                        return 0.85;
                    case 2:
                        return 0.75;
                    case 3:
                        return 0.65;
                    default:
                        return 0.6;
                }
            };

            const getVerticalOffset = (index) => {
                const scale = getItemScale(index);
                return (1 - scale) * 20;
            };

            return (
                <div className="w-full h-screen bg-white relative overflow-hidden">
                    <div 
                        ref={scrollContainerRef}
                        className="flex overflow-x-auto h-full items-center snap-x snap-mandatory scrollbar-hide px-12"
                        onScroll={handleScroll}
                        style={{
                            scrollBehavior: 'smooth',
                            WebkitOverflowScrolling: 'touch'
                        }}
                    >
                        <div className="flex-shrink-0 w-[20vw]" />
                        {images.map((src, index) => (
                            <div
                                key={index}
                                className="snap-start flex-shrink-0 h-full flex items-center justify-center transition-all duration-500 ease-in-out px-2"
                                style={{
                                    width: 'auto',
                                    opacity: getItemScale(index) * 0.8 + 0.2,
                                }}
                            >
                                <div 
                                    className="relative overflow-hidden group transition-all duration-500"
                                    onMouseEnter={() => setActiveIndex(index)}
                                    style={{
                                        height: `${getItemScale(index) * 70}vh`,
                                        transform: `translateY(${getVerticalOffset(index)}%)`,
                                        transformOrigin: 'center center'
                                    }}
                                >
                                    <img
                                        src={src}
                                        alt={`Gallery image ${index + 1}`}
                                        className="h-full w-auto object-cover transition-transform duration-500 group-hover:scale-105"
                                        style={{
                                            maxWidth: 'none'
                                        }}
                                    />
                                </div>
                            </div>
                        ))}
                        <div className="flex-shrink-0 w-[20vw]" />
                    </div>

                    <div className="absolute bottom-8 left-1/2 transform -translate-x-1/2">
                        <div className="flex space-x-0.5">
                            {images.map((_, index) => (
                                <div
                                    key={index}
                                    className={`h-px transition-all duration-300 ${
                                        activeIndex === index ? 'bg-black w-8' : 'bg-gray-300 w-4'
                                    }`}
                                />
                            ))}
                        </div>
                    </div>
                </div>
            );
        };

        // Render the component
        const root = ReactDOM.createRoot(document.getElementById('root'));
        root.render(<GalleryComponent />);
    </script>
</div>
</section>

  <!-- Key Features Section -->
  <section class="container py-5 text-center">
    <div class="mb-5 fade-in">
        <h2>Why Choose MapPalette?</h2>
    </div>
    <div class="row mt-4 fade-in">
      <div class="col-sm-4">
        <img class="features-image" src="../resources/index/features/maps.png" alt="">
        <h4>Creative Route Drawing</h4>
        <p>Design and follow fun, custom running routes on the map.</p>
      </div>
      <div class="col-sm-4">
        <img class="features-image" src="../resources/index/features/share.png" alt="">
        <h4>Share Your Routes</h4>
        <p>Easily share your routes with friends or on social media.</p>
      </div>
      <div class="col-sm-4">
        <img class="features-image" src="../resources/index/features/integration.png" alt="">
        <h4>Seamless Integration</h4>
        <p>Connect with fitness apps like Strava to track your runs.</p>
      </div>
    </div>
  </section>
</body>
</html>

Image Preview with Bootstrap, HTML + JS

I am attempting to make a system that allows the user to upload an image and then it will replace the already placeholder image with the uploaded image by the user, I have attempted the JavaScript code below, but it simply just does not display the image when I upload it, the website shows the uploaded image.

I have used Bootstrap to style my columns and make my image fluid.

Below is the block of code relating to my issue

 </div>
    <div class="col-md-6">
      <div class="input-group mb-3" style="width: 40%;">
        <label class="input-group-text" for="inputGroupFile01" id="uploader">Upload</label>
        <input type="file" class="form-control" id="inputGroupFile01" id="inputimg">
        <img src="profile.jpg" class="img-fluid" alt="">
      </div>      
  </div>

HTML CODE ABOVE

JS CODE BELOW

document.getElementById('uploader').addEventListener('change', function(event) {
    const file = event.target.files[0];
    if (file) {
        const reader = new FileReader();
        reader.onload = function(e) {
            document.getElementById('inputimg').src = e.target.result;
        };
        reader.readAsDataURL(file);
    }
});

Tried the JS code embedded above, I expected the placeholder image to be replaced by the image I uploaded, that did not happen and nothing actually happened

Set.Has() does not work with arrays because they are mutable. What’s the alternative?

I have a list of (lots of) coordinates.

coordinateList = [[1,2], [2,1], [3,5]];

This coordinates are unique and since I have a lot of them I want to be able to quickly check if a new coordinate is already in the list without having to search in the list. So a Set if the perfect Data Type to store my coordinates and hash them.

let coordinateSet = new Set();
for (let coordinate of coordinateList) {
    coordinateSet.add(coordinate);
}

Now coordinateSet is a Set that contains coordinates.

However, those coordinates are saved as an array of two elements, which is mutable. Because of this I cannot check if the set has already a coordinate

coordinateSet.has([1,2])  --> false

I have seen solutions that convert the array to a string to get immutability, but it looks like a hack that although it might work it feels not the correct way of solving that.

How could I store my coordinates (2 numbers) such that they are immutable and can then be used in a set? Is there something like a tuple which is immutable and can be used for this purpose?

Request remains pending and it never times out

Is there a browser-imposed default setting where a request is closed if the server doesn’t respond after a certain amount of time?

I have this simple NodeJS example:

const app = require("express")();
const cors = require("cors");

app.use(cors());

app.get("/", (req, res) => {

});

app.listen(3000, () => {
  console.log("App is up");
});

As you can notice inside app.get() the response is never sent back by the server.

On the front-end I send a request like this:

console.time('Req')
fetch('http://localhost:3000').catch((e) => {
  console.timeEnd('Req')
})

I would expect that the browser will close the request after a given time, but this never happens and the request remains in the PENDING state.
I’ve tried this in Chrome, Edge and Firefox.
Is this the default behavior?

static/css/3d055d199bf4c760.css:29:22: Unknown word in next js

`npm run build

[email protected] build
next build

▲ Next.js 14.2.15

  • Environments: .env

Creating an optimized production build …
(node:10710) [DEP0040] DeprecationWarning: The punycode module is deprecated. Please use a userland alternative instead.
(Use node --trace-deprecation ... to show where the warning was created)
(node:10732) [DEP0040] DeprecationWarning: The punycode module is deprecated. Please use a userland alternative instead.
(Use node --trace-deprecation ... to show where the warning was created)
Failed to compile.

HookWebpackError: /Users/pratikmishra/Desktop/current/static/css/3d055d199bf4c760.css:29:22: Unknown word
at makeWebpackError (/Users/pratikmishra/Desktop/current/node_modules/next/dist/compiled/webpack/bundle5.js:28:312635)
at /Users/pratikmishra/Desktop/current/node_modules/next/dist/compiled/webpack/bundle5.js:28:106060
at eval (eval at create (/Users/pratikmishra/Desktop/current/node_modules/next/dist/compiled/webpack/bundle5.js:13:28858), :44:1)
— inner error —
CssSyntaxError: /Users/pratikmishra/Desktop/current/static/css/3d055d199bf4c760.css:29:22: Unknown word
at Input.error (/Users/pratikmishra/Desktop/current/node_modules/next/node_modules/postcss/lib/input.js:106:16)
at ScssParser.unknownWord (/Users/pratikmishra/Desktop/current/node_modules/next/node_modules/postcss/lib/parser.js:594:22)
at ScssParser.other (/Users/pratikmishra/Desktop/current/node_modules/next/node_modules/postcss/lib/parser.js:436:12)
at ScssParser.parse (/Users/pratikmishra/Desktop/current/node_modules/next/node_modules/postcss/lib/parser.js:471:16)
at scssParse (/Users/pratikmishra/Desktop/current/node_modules/next/dist/compiled/postcss-scss/scss-syntax.js:1:322)
at new LazyResult (/Users/pratikmishra/Desktop/current/node_modules/next/node_modules/postcss/lib/lazy-result.js:133:16)
at Processor.process (/Users/pratikmishra/Desktop/current/node_modules/next/node_modules/postcss/lib/processor.js:53:14)
at CssMinimizerPlugin.optimizeAsset (/Users/pratikmishra/Desktop/current/node_modules/next/dist/build/webpack/plugins/css-minimizer-plugin.js:48:12)
at /Users/pratikmishra/Desktop/current/node_modules/next/dist/build/webpack/plugins/css-minimizer-plugin.js:79:55
at async Span.traceAsyncFn (/Users/pratikmishra/Desktop/current/node_modules/next/dist/trace/trace.js:154:20)
caused by plugins in Compilation.hooks.processAssets
CssSyntaxError: /Users/pratikmishra/Desktop/current/static/css/3d055d199bf4c760.css:29:22: Unknown word
at Input.error (/Users/pratikmishra/Desktop/current/node_modules/next/node_modules/postcss/lib/input.js:106:16)
at ScssParser.unknownWord (/Users/pratikmishra/Desktop/current/node_modules/next/node_modules/postcss/lib/parser.js:594:22)
at ScssParser.other (/Users/pratikmishra/Desktop/current/node_modules/next/node_modules/postcss/lib/parser.js:436:12)
at ScssParser.parse (/Users/pratikmishra/Desktop/current/node_modules/next/node_modules/postcss/lib/parser.js:471:16)
at scssParse (/Users/pratikmishra/Desktop/current/node_modules/next/dist/compiled/postcss-scss/scss-syntax.js:1:322)
at new LazyResult (/Users/pratikmishra/Desktop/current/node_modules/next/node_modules/postcss/lib/lazy-result.js:133:16)
at Processor.process (/Users/pratikmishra/Desktop/current/node_modules/next/node_modules/postcss/lib/processor.js:53:14)
at CssMinimizerPlugin.optimizeAsset (/Users/pratikmishra/Desktop/current/node_modules/next/dist/build/webpack/plugins/css-minimizer-plugin.js:48:12)
at /Users/pratikmishra/Desktop/current/node_modules/next/dist/build/webpack/plugins/css-minimizer-plugin.js:79:55
at async Span.traceAsyncFn (/Users/pratikmishra/Desktop/current/node_modules/next/dist/trace/trace.js:154:20)

Build failed because of webpack errors`

I executed command npm run build but resulted an unexpected error

Mirth Regex – Replace (

I am trying to write a transformer to replace various different characters but am having difficulties with ( and ). I understand that these are regex characters, but how do I work around wanting to replace instances of them in a string?

for(i=0; i<msg['IN1'].length(); i++){
    msg['IN1'][i]['IN1.4']['IN1.4.1'] = msg['IN1'][i]['IN1.4']['IN1.4.1'].toString().replace(//|(|)|%|.|,|'/g, '')
}

Prevent having to pass in headers for each use in custom axios instance to fix ts error after bump to 1.7.7

I recently bumped my axios from 0.28.0 to 1.7.7 and now I am starting to get ts errors.
Here is my current code:

import axios, {
  AxiosInstance,
  AxiosInterceptorManager,
  AxiosPromise,
  InternalAxiosRequestConfig,
  AxiosResponse,
} from 'axios';
import CryptoJS from 'crypto-js';
import { appConfig } from '../config/env';

interface RequestConfig extends InternalAxiosRequestConfig {}

interface CustomHttpInstance extends AxiosInstance {
  (config: RequestConfig): AxiosPromise;
  (url: string, config?: RequestConfig): AxiosPromise;
  interceptors: {
    request: AxiosInterceptorManager<RequestConfig>;
    response: AxiosInterceptorManager<AxiosResponse>;
  };
  getUri(config?: RequestConfig): string;
  request<T = any, R = T>(config: RequestConfig): Promise<R>;
  get<T = any, R = T>(url: string, config?: RequestConfig): Promise<R>;
  delete<T = any, R = T>(url: string, config?: RequestConfig): Promise<R>;
  head<T = any, R = T>(url: string, config?: RequestConfig): Promise<R>;
  options<T = any, R = T>(url: string, config?: RequestConfig): Promise<R>;
  post<T = any, R = T>(
    url: string,
    data?: any,
    config?: RequestConfig,
  ): Promise<R>;
  put<T = any, R = T>(
    url: string,
    data?: any,
    config?: RequestConfig,
  ): Promise<R>;
  patch<T = any, R = T>(
    url: string,
    data?: any,
    config?: RequestConfig,
  ): Promise<R>;
}

const customHttpProvider: CustomHttpInstance = axios.create({
  baseURL: appConfig.api.baseUrl,
  headers: {
    'X-SIGN-TYPE': 2,
    'X-API-KEY': appConfig.api.apiKey,
    'Content-Type': 'application/json',
  },
});

customHttpProvider.interceptors.request.use(async (config: RequestConfig) => {
  const timestamp = Date.now().toString();
  const apiKey = appConfig.api.apiKey;
  const secretKey = appConfig.api.apiSecret;
  const recvWindow = 5000; // in milliseconds
  let payload = '';
  if (config.params && Object.keys(config.params).length) {
    const params = config.params;
    payload = Object.keys(params)
      .map((key) => {
        return `${key}=${encodeURIComponent(params[key])}`;
      })
      .join('&');
  }

  if (config.data) {
    payload = JSON.stringify(config.data);
  }

  const body = timestamp + apiKey + recvWindow + payload;
  const apiSignature = CryptoJS.algo.HMAC.create(
    CryptoJS.algo.SHA256,
    secretKey,
  )
    .update(body)
    .finalize()
    .toString(CryptoJS.enc.Hex);

  config.headers['X-SIGN'] = apiSignature;
  config.headers['X-TIMESTAMP'] = timestamp;
  config.headers['X-RECV-WINDOW'] = recvWindow;

  return config;
});

customHttpProvider.interceptors.response.use(
  (response) =>
    new Promise(async (resolve, reject) => {
      resolve(response.data);
    }),

  (error) =>
    new Promise(async (resolve, reject) => {
      reject(error.response?.data ? error.response.data : error);
    }),
);

export default customHttpProvider;

And here is where I use it:

const getBalance = (accountType: string = 'UNIFIED') => {
  return customHttpProvider.get<{
    retCode: number;
    retMsg: string;
    result: {
      memberId: string;
      accountType: string;
      balance: {
        coin: string;
        transferBalance: string;
        walletBalance: string;
        bonus: '';
      }[];
    };
    retExtInfo: Record<string, any>;
    time: number;
  }>('/v5/asset/transfer/query-account-coins-balance', {
    params: {
      accountType,
    },
    // I don't want to pass this header each time to fix ts error
    headers: {
      'Content-Type': 'application/json',
    },
  });
};

The issue is that now RequestConfig extends InternalAxiosRequestConfig (instead of earlier AxiosRequestConfig. This means each time I use this customHttpProvider, I am having to pass in the same headers each time. Otherwise I get ts error:

TS2345: Argument of type '{ params: { accountType: string; }; }' is not assignable to parameter of type 'RequestConfig'.   Property 'headers' is missing in type '{ params: { accountType: string; }; }' but required in type 'InternalAxiosRequestConfig<any>'.

This is really quite tedious and I don’t want having to pass in headers each time to fix the ts error. Whats a proper solution to it?

Integrating Verifone V400c Plus terminal with browser-based POS system using ZVT protocol

The company I am working for has been tasked by a client to integrate a Verifone V400c Plus terminal with our existing browser-based point-of-sale system. This is our first time working with a payment terminal, and we need to implement communication using the ZVT protocol. Here are the details:

  1. Our POS system is custom-developed and runs in a web browser. Every customer can use our website and open the POS (cash register); it’s basically just frontend (JavaScript) with backend (PHP).

  2. Each location (the customer has multiple ones) has different instances of the cash register.

  3. We need to establish a connection to the terminal using PHP and/or JavaScript.

  4. Communication must use the ZVT protocol because the customer is accustomed to it from their previous service provider.

As this is new territory for us, we’re looking for guidance on:

How to establish a connection or communicate from a browser-based application to the terminal using ZVT in PHP/JavaScript?

We’ve researched ZVT documentation, but we’re struggling to find clear examples or guides for browser-based implementations. Any advice, code samples, or resources would be immensely helpful.

Thank you in advance