Submitting form conditionally using enter press in react application

In a react application, I have a page where there are mainly 2 sections. 1) Input unit. 2) Others.

In the input unit there are multiple input controls. For example, 1) Multiline textfield, 2) Select dropdown, 3) Date picker etc.

There are multiple buttons and other elements that are focusble using tab key. Inside the input unit, on tapping the tab key I need to change focus of the input control. For example from input control-1 if I press tab, it focuses the second input control. When a input field is focused, then pressing enter opens that control, for example when select control is focused then enter press will open its menu with options.

But when no element in the page is focused, enter press will submit the form.

And more problem arises when a dialog appears with a similar type of form input fields over the page. I also need to submit the dialog form when enter is clicked if the dialog is open. Otherwise the main page form will be submitted on enter press.

How can I acheive this behavior.

Failed to load resource: the server responded with a status of 404 error in console when clicking to view product for Strapi-ecommerce application

Home page with the product listing for categories map functionality

import Product from "./Product";
import { Row, Col } from "reactstrap";
import { useProducts } from "./useProducts";
import { useNavigate } from "react-router-dom";

const Home = () => {
 const { categories, products } = useProducts();
 const navigate = useNavigate();

  

  const navigateToProductView = (url) => {
    navigate(url);
  };
  return (
    <div>
      <div className="home">
        <h2 style={{ textAlign: "center" }}>Enjoy our sales!</h2>
       
        {categories.length
          ? categories.map((category) => {
              const hasProducts = products.filter(
                (product) =>
                  product.category?.id === category.id
              );
              return hasProducts && hasProducts.length ? (
                <div key={category.id}>
                  <h2 className="category-title">{category.name}</h2>
                  <Row key={category.id} className="category">
                    {hasProducts.map((product) => (
                      <Col
                        sm="12"
                        md="3"
                        key={product.id}
                        onClick={() =>
                          navigateToProductView(
                            `/product-details/${product.id}`
                          )
                        }
                      >
                        <Product product={product} />
                      </Col>
                    ))}
                  </Row>
                </div>
              ) : null;
            })
          : null}
      </div>
    </div>
  );
};

export default Home;

ProductView.js file

import { useProductView } from "./useProductView";
import {
  Row,
  Col,
  Label,
  Input,
  Button,
  CardImg,
  CardText,
  CardBody,
  CardTitle,
  FormGroup,
  CardSubtitle,
} from "reactstrap";
import ProductReview from "../ProductReview";
import { Rating } from "react-simple-star-rating";

const ProductView = ({ token, addToBasket }) => {
  const {
    rating,
    product,
    getImage,
    setRating,
    description,
    selectedColor,
    selectedSize,
    selectedQuantity,
    setSelectedColor,
    setSelectedSize,
    handleQuantityChange,
    setgetLatestProductUpdate,
  } = useProductView();
  
  console.log({product});

  if (!product || !product.attributes) {
    return null;
  }
  const { id, attributes } = product;
  const quantity = Array.from(Array(Number(attributes.quantity)).keys());

  return (
    <div className="product-details">
      <Row>
        <Col sm="12" md="6">
          <div className="image-wrapper">
            <CardImg
              left="true"
              width="100%"
              src={`http://localhost:1337${getImage(selectedColor)}`}
              alt=""
            />
          </div>
        </Col>
        <Col sm="12" md="6">
          <CardBody>
            <CardTitle>{attributes.name}</CardTitle>
            <CardText>{attributes.description}</CardText>
            <div className="rating">
              <Rating
                allowFraction
                readonly
                size={24}
                initialValue={rating.stars}
              />
              <span>{`${
                rating.count > 1
                  ? `${rating.count} ratings`
                  : `${rating.count} rating`
              }`}</span>
            </div>
            <CardSubtitle>
              <strong>Price: £{attributes.price}</strong>
            </CardSubtitle>
            <CardSubtitle>{attributes.quantity} items Left</CardSubtitle>
            <div>
              <CardSubtitle>Sizes:</CardSubtitle>
              <div className="sizes">
                {attributes.sizes.map((size) => (
                  <span
                    key={size.name}
                    className={`${selectedSize === size.name ? "active" : ""}`}
                    onClick={() => setSelectedSize(size.name)}
                  >
                    {size.name}
                  </span>
                ))}
              </div>
            </div>
            <div>
              <CardSubtitle>Selected colour: {selectedColor}</CardSubtitle>
              <div className="colours">
                {attributes.colours.map((colour) => (
                  <span
                    key={colour.name}
                    className={`${
                      selectedColor === colour.name ? "active" : ""
                    }`}
                    onClick={() => setSelectedColor(colour.name)}
                  >
                    <img
                      src={`http://localhost:1337${getImage(colour.name)}`}
                      alt={colour.name}
                    />
                  </span>
                ))}
              </div>
              <FormGroup className="quantity">
                <Label for="exampleSelect">Selected items</Label>
                <Input
                  value={selectedQuantity}
                  type="select"
                  name="quantity"
                  id="exampleSelect"
                  onChange={handleQuantityChange}
                >
                  {quantity.map((number) => (
                    <option key={number}>{number}</option>
                  ))}
                </Input>
              </FormGroup>
            </div>
            <Button
              color="primary"
              onClick={() =>
                addToBasket({
                  ...product,
                  description,
                  size: selectedSize,
                  color: selectedColor,
                  quantity: selectedQuantity,
                  imageUrl: getImage(selectedColor),
                })
              }
            >
              Add to basket
            </Button>
          </CardBody>
        </Col>
      </Row>

      <ProductReview
        token={token}
        productId={id}
        setRating={setRating}
        setgetLatestProductUpdate={setgetLatestProductUpdate}
      />
    </div>
  );
};

export default ProductView;

To retrieve data from the Strapi server I use a custom hook with getImage function to view a product from the list after the user click the product card.

useProductView.js

import React, { useEffect, useState } from "react";
import { useLocation, useParams } from "react-router-dom";

export const getQuery = (key, search) => {
  const querys = search?.replace("?", "")?.split("&");
  const query = querys.find((query) => query.includes(key));
  const queryValue = query?.replace(`${key}=`, "");
  return queryValue;
};

export const useProductView = () => {
  const { id: productId } = useParams();
  const [rating, setRating] = useState({ stars: null, count: 0 });
  const [getLatestProductUpdate, setgetLatestProductUpdate] = useState(false);
  const { search } = useLocation();

  const [product, setProduct] = useState({});
  const [selectedColor, setSelectedColor] = useState("");
  const [selectedSize, setSelectedSize] = useState("");
  const [selectedQuantity, setSelectedQuantity] = useState(1);

  const handleQuantityChange = ({ target: { value } }) => {
    setSelectedQuantity(value);
  };

  const getImage = (colour) => {
    const { attributes } = product;
    const image = attributes.images.data.find((image) =>
      image.attributes.name.includes(colour)
    );

    return image?.attributes?.url || "";
  };

  useEffect(() => {
    if (product && product.attributes) {
      const { attributes } = product;
      setSelectedColor(getQuery("color", search) || attributes.colours[0].name);
      setSelectedSize(getQuery("size", search) || attributes.sizes[0].name);
    }
  }, [product, search, setSelectedColor, setSelectedSize]);

  useEffect(() => {
    const fetchCategories = async () => {
      try {
        const {
          data: { data },
        } = await axios.get(
          `http://localhost:1337/api/products/${productId}?populate=*`
        );
        setProduct(data);
        setgetLatestProductUpdate(false);
      } catch (error) {
        console.log({ error });
      }
    };

    if (productId) {
      fetchCategories();
    }
  }, [productId, getLatestProductUpdate]);

  return {
    rating,
    product,
    getImage,
    setRating,
    selectedSize,
    selectedColor,
    selectedQuantity,
    setSelectedColor,
    setSelectedSize,
    handleQuantityChange,
    setgetLatestProductUpdate,
  };
};

Can someone show me how to retrieve the data from Strapi when the user click a product from the list they are able to view that product image desc and price from the images below as you can see i am getting the error product not found and the product is setup in the server

Failed to load resource: the server responded with a status of 404

Data Structure from strapi

Remove white-space inside inline style with JS?

A CMS generates inline styles with many whitespaces in them, which makes it difficult to traverse and select element via dev tools. An example of that would be:

style="
      
      
        --headerBorderColor: hsla(var(--black-hsl), 1);
      
      
        --solidHeaderBackgroundColor: hsla(var(--white-hsl), 1);
      
      
        --solidHeaderNavigationColor: hsla(var(--black-hsl), 1);
      
      
        --gradientHeaderBackgroundColor: hsla(var(--white-hsl), 1);
      
      
        --gradientHeaderNavigationColor: hsla(var(--black-hsl), 1);
      
    "

I’m currently removing whitespace like this, but doesn’t look like best / most optimal approach:

      var newStyle = [];
        styleEl.getAttribute('style').split(';').forEach(styleLine => {
            var newLine = styleLine.trim().replace(/^s+|s+$/gm, '');
            if(/^[A-Za-z0-9]*$/.test(newLine) === false) {
                newStyle.push(newLine);
            }
        });
        newStyle = newStyle.join('; n') + ';';

        styleEl.setAttribute('style', newStyle)

Is there a better way to remove whitespace from inline styles?

TypeScript type of all JavaScript `typeof` return values

I’m working on a function to validate function parameters in embedded untyped JavaScript in an input stream for a TypeScript system something like a templating engine.

const javaScriptType = (untyped: unknown) => typeof untyped;
type JavaScriptType = ReturnType<typeof javaScriptType>;

So JavaScriptType ends up being:

type JavaScriptType = "string" | "number"
    | "bigint" | "boolean" | "symbol"
    | "undefined" | "object" | "function";

But, using my method, I end up with the “useless” function javaScriptType which only exists to enable me to use ReturnType to get the results I want.

Is there an easier way I can do this without “wasting” a function?

The simple answer would just to hard code the expected values… it’s not like JavaScript’s typeof operator is going to change anytime soon… but hard coded values feel, somehow, “dirty”.

Just to clarify, this type will be used something like this:

const failedTypes = (
    parameters: Array<unknown>, allowedTypes: Array<JavaScriptType> 
): => {
    const failed: Array<string> = [];
    for (const [index, parameter] of parameters.entries()) {
        const typeOf = typeof parameter;
        if (!allowedTypes.includes(typeOf)) {
            failed.push(`${index}: ${typeOf}`);
        }
    }
    return failed;
};

How to intiate Ping/Pong in CCXT websockets under Node

I’m working on a CCXT based app server on Node. I want to measure websocket connection latency between Node and remote exchanges. For this purpose I’d like to initiate a ping right after websocket stream subscription and then repeat it periodically according to ‘keepAlive’ settings. Upon receipt of a reply pong I could calculate the roundtrip time.

I can override the handler of the pongs:

ex = new Exchange();
if(ex.handlePong)
{
   const original_handler = ex.handlePong.bind(ex);
   ex.handlePong = (ws, data) => { original_handler(ws, data); console.log("Pong at ", Date.now(), "after", ex.myPing); ... actual stuff here ...}
}

But I can’t figure out how to send pings. The following attempts do not produce any effect:

if(!ex.myPing || Date.now() - ex.lastPong > 30000)
{
   ex.myPing = Date.now();
   for(const key in ex.clients)
   {
      if(key.startsWith("ws"))
      {
         ex.clients[key].connection.ping(); // ?data, mask, cb?
         // ex.clients[key].ping(); // doesn't seem to do anything
      }
   }
}

I intercept the pongs, but they look as arriving by server’s own schedule, after the predefined interval. In other words, my pings either are not sent at all, or ignored for some reason, silently – there are no exceptions.

Probably my approach with “poking” the client object is incorrect, but it’s just a result of digging into the source code and debugging, because I did not find any official info on how to do this.

Any suggestions on how to send “effective” pings (force the remote server to answer with pongs) or measure websocket latency in another way?

Use Flask-SocketIO to send messages continuously

I would like to build an application to monitor files on my local computer through the browser. I have written a minimalistic example to illustrate this.

The frontend should be able to request messages from the backend on events. In my example below, I am calling these “standard messages”. They are triggered in the frontend by a button click and a fetch call, and handled in the backend by a route.

The backend should also send messages every 5 seconds. I am calling these “continuous messages” and I am trying to send them using Flask-SocketIO. They are sent by the backend with socketio start_background_task and emit, and are received by the frontend with socket.on().

The “standard messages” part works fine if I comment the socketio part (and replace socketio.run with app.run). But when I uncomment the socketio part to have “continuous messages”, the communication fails. The backend doesn’t receive the “standard messages” calls, and the frontend doesn’t receive the “continuous messages”.

It looks like I am not writing the socketio part correctly. What do I need to add so that both messages type work correctly?

Backend

import time

from flask import Flask
from flask_cors import CORS
from flask_socketio import SocketIO

app = Flask(__name__)
CORS(app)

# Continuous messages ##########################################
socketio = SocketIO(app, cors_allowed_origins="*")

@socketio.on('connect')
def handle_connect():
    print('Client connected')
    socketio.start_background_task(send_continuous_messages)

def send_continuous_messages():
    while True:
        print("Backend sends a continuous message")
        socketio.emit("continuous_message", {"data": "New continuous message"})
        time.sleep(5)
################################################################

@app.route("/standard-message", methods=["GET"])
def generate_standard_message():
    print("Backend sends a standard message")
    return {"data": "New standard message"}

if __name__ == "__main__":
    print("Starting app")
    socketio.run(app, debug=True)

Frontend

const myButton = document.getElementById('my-button');
const BASE_URL = "http://localhost:5000";

// Continuous messages #########################################
const socket = io(BASE_URL);

socket.on('connect', () => {
    console.log('WebSocket connected');
});

socket.on('disconnect', () => {
    console.log('WebSocket disconnected');
});

socket.on('continuous_message', (data) => {
    console.log('Frontend received a continuous message:', data);
});
// #############################################################

async function receiveStandardMessage() {
    console.log('Frontend is requesting a standard message');
    const response = await fetch(`${BASE_URL}/standard-message`);
    const data = await response.json();
    console.log('Frontend received a standard message:', data);
}

myButton.addEventListener('click', receiveStandardMessage);

index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>My app</title>
    <script src="https://cdn.socket.io/4.0.0/socket.io.min.js"></script>
</head>
<body>
    <div id="app">
        <button id="my-button">Send standard message</button>
    </div>
    <script src="app.js"></script>
</body>
</html>

How would I fix the code to this cash register web app project? [closed]

I am currently completing the JavaScript project course of freeCodeCamp.org. Now I have these two steps I can’t really pass through:

Failed: 18. When price is 19.5, the value in the #cash element is 20, cid is [[“PENNY”, 0.5], [“NICKEL”, 0], [“DIME”, 0], [“QUARTER”, 0], [“ONE”, 0], [“FIVE”, 0], [“TEN”, 0], [“TWENTY”, 0], [“ONE HUNDRED”, 0]], and the #purchase-btn element is clicked, the value in the #change-due element should be “Status: CLOSED PENNY: $0.5”.

Failed: 19. When price is less than the value in the #cash element, total cash in drawer cid is equal to change due, and the #purchase-btn element is clicked, the value in the #change-due element should be “Status: CLOSED” with change due in coins and bills sorted in highest to lowest order.

I believe the issue on step 18 is on the calculateChange function, but I can’t determine what specifically it is.

here is my whole code: codepen – source code

If you want to check the specific project link in freeCodeCamp and try to reproduce my code in there, here is the link: freecodecamp.org – build a cash register project

Why am I getting this OAuthCallback error

I am trying to build a linked clone with next.js and despite everything being correct I am getting this OAuthCallback error after signing in with my credentials and I am getting redirected to home page instead of index page. Below are the codes for reference –

home.js –

import Image from "next/image";
import Head from "next/head";
import { useSession, signIn } from "next-auth/react";
import { useRouter } from "next/router";
import { useEffect } from "react";
import { getProviders } from "next-auth/react";
import linkdin_full from "../public/logos/linkdin_full.svg";
import linkdin_home from "../public/linkdin_home.svg";
import HeaderLink from "../components/HeaderLink.js";
import NewspaperIcon from "@mui/icons-material/Newspaper";
import PeopleIcon from "@mui/icons-material/People";
import OndemandVideoIcon from "@mui/icons-material/OndemandVideo";
import BusinessCenterIcon from "@mui/icons-material/BusinessCenter";
import ExtensionIcon from "@mui/icons-material/Extension";
import { SessionProvider } from "next-auth/react"; // ✅ Added SessionProvider

function HomePage({ providers }) {
  return (
    <SessionProvider>
      <ActualHome providers={providers} />
    </SessionProvider>
  );
}

function ActualHome({ providers }) {
  const { data: session, status } = useSession();
  const router = useRouter();
  const { error } = router.query;

  useEffect(() => {
    if (status === "authenticated") {
      router.push("/");
    }
  }, [status, router]);

  if (status === "loading") {
    return <div>Loading...</div>;
  }

  return (
    <div className="space-y-10 relative">
      <Head>
        <title>LinkdIn: Log In or Sign Up</title>
        <link rel="icon" href="/logos/LinkdIn_Icon.png" />
      </Head>

      {error && (
        <div className="bg-red-100 border border-red-400 text-red-700 px-4 py-3 rounded mx-auto max-w-md mt-4">
          <p>Authentication error: {error}</p>
          <button
            className="underline mt-2"
            onClick={() => signIn("linkedin", { callbackUrl: "/" })}
          >
            Try again
          </button>
        </div>
      )}

      <header className="flex justify-around items-center py-4">
        <div className="relative w-36 h-10">
          <Image
            src={linkdin_full}
            alt="LinkedIn Full Logo"
            fill
            style={{ objectFit: "contain" }}
          />
        </div>
        <div className="flex items-center sm:divide-x divide-gray-300">
          <div className="hidden sm:flex space-x-8 pr-4">
            <HeaderLink Icon={NewspaperIcon} text="Articles" />
            <HeaderLink Icon={PeopleIcon} text="People" />
            <HeaderLink Icon={OndemandVideoIcon} text="Learning" />
            <HeaderLink Icon={BusinessCenterIcon} text="Jobs" />
            <HeaderLink Icon={ExtensionIcon} text="Games" />
          </div>
          <div className="space-x-4 px-2">
            <button className="font-semibold text-gray-700 hover:bg-gray-100 px-6 py-3 rounded-full hover:text-gray-800">
              Join now
            </button>
            {providers &&
              Object.values(providers).map((provider) => (
                <button
                  key={provider.id}
                  className="text-blue-600 font-semibold rounded-full border border-blue-600 px-6 py-3 transition-all hover:text-blue-900 hover:bg-blue-50"
                  onClick={() => signIn(provider.id, { callbackUrl: "/" })}
                >
                  Sign in
                </button>
              ))}
          </div>
        </div>
      </header>

      <main className="flex flex-col xl:flex-row items-center max-w-screen-lg mx-auto">
        <div className="space-y-6 xl:space-y-10">
          <h1 className="text-gray-700 text-3xl md:text-5xl max-w-xl !leading-snug pl-4 xl:pl-0">
            Welcome to your professional community
          </h1>
        </div>
        <div className="relative xl:absolute w-80 h-80 xl:w-[650px] xl:h-[650px] top-14 right-5">
          <Image
            src={linkdin_home}
            alt="LinkedIn Home Image"
            fill
            style={{ objectFit: "cover" }}
            priority
          />
        </div>
      </main>
    </div>
  );
}

export default HomePage;

export async function getServerSideProps() {
  const providers = await getProviders();

  return {
    props: {
      providers: providers || {}, // ✅ Ensure it doesn't crash if providers is undefined
    },
  };
}

index.js –

import { useSession } from "next-auth/react";
import { useRouter } from "next/router";
import { useEffect } from "react";
import { Geist, Geist_Mono } from "next/font/google";

const geistSans = Geist({
  variable: "--font-geist-sans",
  subsets: ["latin"],
});

const geistMono = Geist_Mono({
  variable: "--font-geist-mono",
  subsets: ["latin"],
});

export default function Index() {
  const { data: session, status } = useSession();
  const router = useRouter();

  useEffect(() => {
    // If user is not authenticated, redirect to home page
    if (status === "unauthenticated") {
      router.push("/home");
    }
  }, [status, router]);

  // Show loading state while checking authentication
  if (status === "loading") {
    return <div>Loading...</div>;
  }

  // Show main content if authenticated
  return (
    <div className={`${geistSans.variable} ${geistMono.variable}`}>
      <h1>Welcome to LinkedIn</h1>
      {session && (
        <div>
          <p>You are logged in as: {session.user.name}</p>
          {/* Your authenticated content here */}
        </div>
      )}
    </div>
  );
}

[…nextauth].js –

import NextAuth from "next-auth";
import LinkedInProvider from "next-auth/providers/linkedin";
import { MongoDBAdapter } from "@next-auth/mongodb-adapter";
import clientPromise from "@/lib/mongodb";

export default NextAuth({
  providers: [
    LinkedInProvider({
      clientId: process.env.LINKEDIN_CLIENT_ID,
      clientSecret: process.env.LINKEDIN_CLIENT_SECRET,
      authorization: {
        params: {
          scope: "profile email openid", // Updated to newer LinkedIn OAuth 2.0 scopes
        },
      },
      profile(profile) {
        return {
          id: profile.sub,
          name: profile.name,
          email: profile.email,
          image: profile.picture,
        };
      },
    }),
  ],
  secret: process.env.NEXTAUTH_SECRET,
  adapter: MongoDBAdapter(clientPromise),
  pages: {
    signIn: "/home",
  },
  debug: process.env.NODE_ENV === "development", // Add debug mode for development
  callbacks: {
    async redirect({ url, baseUrl }) {
      // Handle callbackUrl properly to ensure redirection to index after login
      if (url.startsWith(baseUrl)) return url;
      // Make sure we redirect to index.js after successful login
      return baseUrl;
    },
    async session({ session, token, user }) {
      if (session.user) {
        session.user.id = token.sub || user?.id;
      }
      return session;
    },
    async jwt({ token, user }) {
      if (user) {
        token.id = user.id;
      }
      return token;
    },
  },
  session: {
    strategy: "jwt",
  },
});

also i have configured the .env.local file with all the necessary stuff so there’s not problem in that

How to clean url from disposable parameters like tracking?

Brave browser has a nice function to copy a clean link

copy clean link

How is it implemented? There are well known tracking parameters like fbclid or utm_source which are nicely dumped by this function. I would like to have an algorithm that guess the likelyhood that the parameter is “not clean” (disposable from the visitor’s perspective) or at least some general rules to decide it (hashed or overly long parameters tend to be “not clean”).

It doesn’t have to be perfect, I just don’t want to reinvent the wheel. The answer can be language agnostic, but if code is involved, I’d prefer javascript implementation.

How to prevent scrollLeft() from skipping values when scrolling too fast

I’ve been working on this draggable/scrollable infinite carousel for a few hours but I ran into an issue. When scrolling ‘too fast’, carousel.scrollLeft() seems to not be able to keep up and leaves gaps in between the values as seen below in the screenshot.

carousel.scrollLeft() values when scrolling too fast

For my infinite caroussel to work I need carousel.scrollLeft() to be equal to my trigger value, so it can ‘teleport’ back to the start/end.

I can’t use if (carousel.scrollleft() <= scrollTriggerStart) since that raises a whole bunch of other issues.

const carousel = $('.carousel');
const carouselCards = carousel.children('.card');

let cardAmount = 3; // The amount of cards visible within the carousel

carouselCards.slice(-cardAmount).get().reverse().forEach((e) => {
  let card = $(e);
  carousel.prepend(card.prop('outerHTML')); // Puts the last three cards in front of the first card in reverse order
})

carouselCards.slice(0, cardAmount).get().forEach((e) => {
  let card = $(e);
  carousel.append(card.prop('outerHTML')); // Puts the first three cards after the last card
})

let scrollTriggerStart = Math.round(carouselCards.outerWidth() + carouselCards.outerWidth() / 2 - carousel.outerWidth() / 2); // The exact scrollLeft value where the second card is in the center of the carousel
let scrollTriggerEnd = Math.round(carousel[0].scrollWidth - carouselCards.outerWidth() - carouselCards.outerWidth() / 2 - carousel.outerWidth() / 2); // The exact scrollLeft value where the second to last card is in the center of the carousel
let seamlessPosStart = carouselCards.length * carouselCards.outerWidth() - carouselCards.outerWidth() / 2 - carousel.outerWidth() / 2; // The exact scrollLeft value of the corresponding card of the second to last card
let seamlessPosEnd = carousel[0].scrollWidth - carouselCards.length * carouselCards.outerWidth() + carouselCards.outerWidth() / 2 - carousel.outerWidth() / 2; // The exact scrollLeft value of the corresponding card of the second card

infiniteScroll = () => {
  if (carousel.scrollLeft() === scrollTriggerStart) {
    carousel.addClass('no-transition');
    carousel.scrollLeft(seamlessPosEnd);
    carousel.removeClass('no-transition');
  } else if (carousel.scrollLeft() === scrollTriggerEnd) {
    carousel.addClass('no-transition');
    carousel.scrollLeft(seamlessPosStart);
    carousel.removeClass('no-transition');
  }
}

carousel.on('scroll', infiniteScroll);
*,
::before,
::after {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

* {
  font: inherit;
}

html,
body {
  min-height: 100vh;
}

ul:has([class]) {
  list-style: none;
}

body {
  font-family: sans-serif;
  display: flex;
  align-items: center;
  justify-content: center;
}

.wrapper {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 5em;
  width: 100%;
  padding-inline: 10em;
}

.carousel {
  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: calc(100% / 2);
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  border-radius: .5em;
  scroll-behavior: smooth;
  scrollbar-width: none;
  width: 100%;
}

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

.carousel .card {
  aspect-ratio: 1;
  scroll-snap-align: center;
  background: rgba(255, 0, 0, 0.25);
  border-radius: .5rem;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 2rem;
  scale: 0.95;
  border: 2px solid transparent;
  transition: 250ms ease;
}

.card.selected {
  border: 2px solid red;
  scale: 1;
}

.no-transition {
  scroll-behavior: auto;
}

.no-transition .card {
  scroll-snap-align: unset;
}

/* .slider-interactive {
    display: flex;
    gap: 4em;
}

.slider-interactive > * {
    background: rgba(255,0,0,0.25);
    aspect-ratio: 1;
    border-radius: 50%;
    cursor: pointer;
    transition: 250ms ease;
    width: 1.5rem;
}

.slider-interactive > *.selected {
    background: red;
} */
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <link rel="stylesheet" href="style.css">
  <title>Infinite carousel</title>
</head>

<body>
  <div class="wrapper">
    <ul class="carousel">
      <li class="card">
        <h2>Card 1</h2>
      </li>
      <li class="card">
        <h2>Card 2</h2>
      </li>
      <li class="card">
        <h2>Card 3</h2>
      </li>
      <li class="card">
        <h2>Card 4</h2>
      </li>
      <li class="card">
        <h2>Card 5</h2>
      </li>
    </ul>
  </div>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.7.1/jquery.min.js" integrity="sha512-v2CJ7UaYy4JwqLDIrZUI/4hqeoQieOmAZNXBeQyjo21dadnwR+8ZaIJVT8EE2iyI61OV8e6M8PP2/4hpQINQ/g==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
  <script src="main.js"></script>
</body>

</html>

ESLint rule to force explicit null checks

I’m looking for an eslint rule/plugin to disallow this kind of expression:

if (!something) {
    return // can be anything here, but it's often a return
}

// Or the other way equivalent
if (something) {
    // Use the variable here because we checked it is not null nor undefined 
}

if (someBoolean) {
    // This one is okay since it's a boolean
}

The problem is, in some cases, if the value is evaluated to false but not undefined/null, it’s not what we wanted:

const something: number | undefined = 0
if (!something) {
    return // Will return as 0 is falsy, but we actually wanted to check if it was undefined but forgot about this case!
}

So I want to force explicit checks (except if type is a pure boolean). It would become:

if (something === undefined || something === null) { // Or for short `== null`
    return // can be anything here, but it's often a return
}

if (something !== undefined && something !== null) { // Or for short `!= null`
    // Use the variable here because we checked it is not null nor undefined 
}

if (someBoolean) { // This is typed boolean so it stays the same
    
}

The rule would also be applied to ternary expression and other times this kind of check is written as if it was a boolean (but it is not, and can lead to issues).

Is there any existing rule for this?

I started to write my own, but it is not working as expected and I cannot figure out why. So if one is already made, I’ll take it!

I’m also open to recommendations or alternatives to improve syntax and avoid errors about this.

import * as tsutils from "tsutils"
import * as ts from "typescript"

export default {
    meta: {
        type: "problem",
        docs: {
            description: "Disallow implicit falsy checks; require explicit null/undefined checks.",
            recommended: true
        },
        schema: [],
        messages: {
            implicitFalsy: "Use explicit null/undefined checks instead of '!{{name}}'."
        }
    },
    create(context) {
        if (!context.parserServices?.program?.getTypeChecker) return {} // Exit if type information is unavailable
        const checker = context.parserServices.program.getTypeChecker()

        return {
            UnaryExpression(node) {
                if (node.operator === "!" && node.argument.type === "Identifier") {
                    const tsNode = context.parserServices.esTreeNodeToTSNodeMap.get(node.argument)
                    const type = checker.getTypeAtLocation(tsNode)
                    const isNullable = tsutils.isTypeFlagSet(type, ts.TypeFlags.Null) ||
                        tsutils.isTypeFlagSet(type, ts.TypeFlags.Undefined)

                    if (isNullable) context.report({
                        node,
                        messageId: "implicitFalsy",
                        data: {name: node.argument.name}
                    })
                }
            }
        }
    }
}

react image wont load

      <img
        src={siswa.url}
        alt={`Profile of ${siswa.nama1}`}
        className={styles.image}
        onError={(e) => {
          console.error("Image failed to load:", e.target.src);
          e.target.style.display = "none"; // Hide the broken image
        }}
      />

on the console chrome it say failed to load and also when I browse the link it say Cannot GET /images/e45c416f7e189371d42a196f2bacf989.jpg

Error “net::ERR_H2_OR_QUIC_REQUIRED” with Fetch API

I want to modify the url of the Request object, but I have some problems.

const r = () =>
  new Request("post", {
    method: "post",
    body: JSON.stringify({ name: "none" }),
  });

fetch(r()); // ok

fetch(new Request("post", r())); // net::ERR_H2_OR_QUIC_REQUIRED

On a server that does not support http2, the second request will fail.

On a server that supports http2, both requests succeed and the server receives the request body. However, in the Chrome network panel, the payload of the second request cannot be viewed.

The first request has the Payload panel:

img1

But the second does not:

img2

So what’s the difference between these two request? How can I make second request work on the serve that does not support http2? How can I have payload panel on chrome devtools?

How to make a simple annotation tool in Next.js?

I’ve been given a task to develop an annotation tool in Next.js. Here is the desired application:

enter image description here

It would work on PDF files, but will divide the PDF pages into images and separately do annotations on them.

For now only text and box annotations are required. Should be able to delete, resize and move the text and boxes.

What would be the best course of action to create this project? Is there a library that makes easier to develop this kind of application?

how to distinguish between an actual line break and a n character

I am trying to write a parser for JSON string, but stuck in one test case.

["line   // <--- unexpected end of string
break"] 

my json file should give this error, similar to vs code, but when my script is trying to parse this, I get a valid JSON object

[ 'linenbreak' ]

I am reading the file using fs.readFileSync(path).toString('utf-8')
which represents line breaks as n. Is there any other way to know if the string contains a n character or an actual line break?
How can I distinguish between them and throw an error here?