Grid items sized incorrectly in GridStack.js

I am trying to display groups of tiles (or in GridStack.js terminology, a list of grid stacks), where tiles have one of few predetermined sizes.

My project should be displaying 3 tiles/”grid items” (one green (large) and one magenta/red
(wide) in the left group (one below the other), and one another blue (small) in the right group). More specifically, something like:

image 1

But in my project it displays that instead (resulting into almost not visible tiles):

image 2

In the example below, it displays nothing (but I’ve inspected it to see and the grid stack items are there).

Worth noting I use position: relative in the grid stacks (.TileGroup.grid-stack). If I remove that property, the tiles (or grid stack items) display very large. I am also doing width: 100%; height: 100%; inside the grid stack item contents.

Here is some code:

I am assuming cell height determines the width and height of the smallest tiles/”grid items” in the grids.

const gridstack = GridStack.init({
    alwaysShowResizeHandle: false,
    disableResize: false,
    margin: `${margin}rem`,
    maxRow: options.direction == "horizontal" ? 6 : undefined,
    rtl: localeDir == "rtl",
    cellHeight: `${small_size.height}rem`,
    acceptWidgets(el) {
        return div_ref.current!.contains(el);
    },
}, group_element);

// Add gridstack widget
const widget_element = gridstack.addWidget({
    x: tile.x,
    y: tile.y,
    w: get_tile_columns(tile.size),
    h: get_tile_rows(tile.size),
});

Here, get_tile_columns() returns a value from 1-4

/**
 * Gets width of tile size in small tiles unit.
 */
function get_tile_columns(size: TileSize): number
{
    return size == "large" ? 4 : size == "wide" ? 4 : size == "medium" ? 2 : 1;
}

/**
 * Gets height of tile size in small tiles unit.
 */
function get_tile_rows(size: TileSize): number
{
    return size == "large" ? 4 : size == "wide" ? 2 : size == "medium" ? 2 : 1;
}

Note: I apologize, but I could not provide a Stack Snippet because GridStack uses ES2015 module export in the CDN and I get an error indicating that GridStack is not defined therefore.

Here is a minimal reproducible example

Javascript mouseenter and mouseleave flickering effect

I have a course card section, on which i want to show he popup of details about that course card, so that i attached an mouseenter and mouseleave events on that element, but it is creating a flickering effect.

`

// Generating course card -
const generateCourseCard = (course, parent) => {
    const newCourse = document.createElement("div");
    newCourse.classList.add("courses");
    newCourse.id = course.id;

    newCourse.innerHTML = `
            <img src=${course.img} class="courseImages" alt=${course.title}>
            <div class="course-Content">
                <h4 class="course-title">${course.title}</h4>
                <p class="course-Instructor">${course.instructor}</p>
                <p>${course.Rating}</p>
                <p>${course.price}</p>
                <p>${course.tag}</p>
            </div>   
    `

    // Adding Hover eventListener to show preview -
    newCourse.addEventListener("mouseenter", (event) => {
        courseCardPopup.style.display = "block";
    });

    newCourse.addEventListener("mouseleave", (event) => {
        courseCardPopup.style.display = "none";
    });

    // Adding to Parent -
    parent.appendChild(newCourse);
}

Suffering from flickering effect

Infinite Marquee with gradient text

I need to make an endless running line with gradient text that changes as it moves, as in the example, it works, but there are problems in Safari, everything twitches there and the letters seem to run into each other, maybe something can be done so that it also works in Safari without freezes. Maybe there are other solutions for such an implementation.

Example marquee

document.querySelectorAll('.running-lines__wrapper').forEach(
  (line) => {
    const content = line.innerHTML;
    const duplicateCount = line.getAttribute('data-duplicate-count') || 1;
    const duration =
      parseInt(line.getAttribute('data-duration'), 10) || 10000;
    const direction = line.getAttribute('data-direction') || 'normal';
    let duplicatedContent = '';

    for (let i = 0; i < duplicateCount; i++) {
      duplicatedContent += content;
    }

    line.innerHTML = duplicatedContent;

    const lineText = line.querySelectorAll('.running-lines__items');

    lineText.forEach((text) => {
      const fromFrame = {
        textIndent: 0
      };
      const toFrame = {
        textIndent: '-100%'
      };
      const options = {
        duration,
        iterations: Infinity,
        direction
      };
      text.animate([fromFrame, toFrame], options);
    });
  });
.running-lines {
  font-family: "Poppins";
  display: -webkit-box;
  display: -ms-flexbox;
  display: flex;
  -webkit-box-orient: vertical;
  -webkit-box-direction: normal;
  -ms-flex-direction: column;
  flex-direction: column;
  row-gap: 0.5rem;
  overflow: hidden;
  background-image: linear-gradient(92.55deg,
      #852fff 0%,
      #dd26ed 48.5%,
      #ed2662 100%);
  -webkit-background-clip: text;
  background-clip: text;
  padding-top: 4rem;
  padding-bottom: 4rem;
  mix-blend-mode: lighten;
}

@media (min-width: 956px) {
  .running-lines {
    row-gap: 1rem;
    padding-top: 3.5rem;
    padding-bottom: 3.5rem;
  }
}

@media (min-width: 1184px) {
  .running-lines {
    row-gap: 1.25rem;
  }
}

.running-lines__wrapper {
  display: -webkit-box;
  display: -ms-flexbox;
  display: flex;
  padding-top: 0.625rem;
  padding-bottom: 0.625rem;
}

.running-lines__items {
  margin-bottom: 0;
  text-wrap: nowrap;
  will-change: text-indent;
  /*   animation: marquee 15s linear infinite; */
}

.running-lines__item {
  margin-right: 2rem;
  font-size: 1.25rem;
  line-height: 1.5rem;
  font-style: italic;
  color: transparent;
}

@media (min-width: 956px) {
  .running-lines__item {
    margin-right: 3rem;
    font-size: 1.5rem;
    line-height: 2rem;
  }
}

@media (min-width: 1184px) {
  .running-lines__item {
    margin-right: 4rem;
  }
}

@keyframes marquee {
  from {
    text-indent: 0;
  }

  to {
    text-indent: -100%;
  }
}
<div class="running-lines">
  <div class="running-lines__wrapper" data-duration="28000" data-duplicate-count="7">
    <p class="running-lines__items">
      <span class="running-lines__item">Security Kit</span>
      <span class="running-lines__item">Honeypot</span>
      <span class="running-lines__item">Antibot</span>
      <span class="running-lines__item">Flood Control</span>
      <span class="running-lines__item">Move 403 to 404</span>
      <span class="running-lines__item">Rabbit Hole</span>
      <span class="running-lines__item">Username Enumeration Prevention</span>
    </p>
  </div>
  <div class="running-lines__wrapper" data-duration="50000" data-direction="reverse" data-duplicate-count="7">
    <p class="running-lines__items">
      <span class="running-lines__item">Content Moderation</span>
      <span class="running-lines__item">Workflows</span>
      <span class="running-lines__item">Simple Menu Permissions</span>
      <span class="running-lines__item">Group Node</span>
      <span class="running-lines__item">Scheduler</span>
      <span class="running-lines__item">Media</span>
    </p>
  </div>
  <div class="running-lines__wrapper" data-duration="40000" data-duplicate-count="7">
    <p class="running-lines__items">
      <span class="running-lines__item">Paragraphs & Paragraphs Browser</span>
      <span class="running-lines__item">Group</span>
      <span class="running-lines__item">Gin & Gin Toolbar</span>
      <span class="running-lines__item">Crop & Image Widget Crop</span>
      <span class="running-lines__item">Migrate & Migrate Plus</span>
    </p>
  </div>
</div>

Authenticating with OAuth 2.0 Application-Only error when curl/php posting

I have gathered the following code in an attempt to post to X:

$api_key='xx';
$api_secret='yy';

$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, 'https://api.twitter.com/oauth2/token');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');
curl_setopt($ch, CURLOPT_HTTPHEADER, [
    'Content-Type: application/x-www-form-urlencoded',
]);
curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
curl_setopt($ch, CURLOPT_USERPWD, $api_key.':'.$api_secret);
curl_setopt($ch, CURLOPT_POSTFIELDS, 'grant_type=client_credentials');

$response = curl_exec($ch);

curl_close($ch);

$response=json_decode($response);
$access_token=$response->access_token;

$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, 'https://api.twitter.com/2/tweets');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');
curl_setopt($ch, CURLOPT_HTTPHEADER, [
    'Authorization: Bearer '.$access_token,
    'Content-Type: application/json',
]);
curl_setopt($ch, CURLOPT_POSTFIELDS, '{"text":"Hello, world!"}');

$response = curl_exec($ch);

curl_close($ch);

print_r($response);

I’m getting the access_token but in the end I’m presented the following error: “Authenticating with OAuth 2.0 Application-Only is forbidden for this endpoint. Supported authentication types are [OAuth 1.0a User Context, OAuth 2.0 User Context].”

Any idea to what I’m doing wrong?

Assistance Required for Migrating to FCM HTTP V1 in Symfony 2.8 Project

Currently I am working on a project which was created with Symfony 2.8 and have some problems when trying to migrate to the FCM HTTP V1 API. I have no idea what is the procedure and would be very grateful for your help in solving this problem. Here are the relevant code snippets for the current FCM implementation:

class HomeController extends Controller
{
function send_notificationToken ($tokens, $message,$key)
{
    $url = 'https://fcm.googleapis.com/fcm/send';
    $fields = array(
        'registration_ids'  => $tokens,
        'data'   => $message

        );
    $headers = array(
        'Authorization:key = '.$key,
        'Content-Type: application/json'
        );
   $ch = curl_init();
   curl_setopt($ch, CURLOPT_URL, $url);
   curl_setopt($ch, CURLOPT_POST, true);
   curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
   curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
   curl_setopt ($ch, CURLOPT_SSL_VERIFYHOST, 0);  
   curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
   curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($fields));
   $result = curl_exec($ch);           
   if ($result === FALSE) {
       die('Curl failed: ' . curl_error($ch));
   }
   curl_close($ch);
   return $result;
}
function send_notification ($tokens, $message,$key)
{
    $url = 'https://fcm.googleapis.com/fcm/send';
    $fields = array(
        'to'  => '/topics/Flixo',
        'data'   => $message
        );
    $headers = array(
        'Authorization:key = '.$key,
        'Content-Type: application/json'
        );
   $ch = curl_init();
   curl_setopt($ch, CURLOPT_URL, $url);
   curl_setopt($ch, CURLOPT_POST, true);
   curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
   curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
   curl_setopt ($ch, CURLOPT_SSL_VERIFYHOST, 0);  
   curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
   curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($fields));
   $result = curl_exec($ch);           
   if ($result === FALSE) {
       die('Curl failed: ' . curl_error($ch));
   }
   curl_close($ch);
   return $result;
}
  public function privacypolicyAction() {
    $em = $this->getDoctrine()->getManager();
    $setting = $em->getRepository("AppBundle:Settings")->findOneBy(array(), array());
    return $this->render("AppBundle:Home:privacypolicy.html.twig", array("setting" => $setting));
}
public function apprefundpolicyAction() {
    $em = $this->getDoctrine()->getManager();
    $setting = $em->getRepository("AppBundle:Settings")->findOneBy(array(), array());
    return $this->render("AppBundle:Home:apprefundpolicy.html.twig", array("setting" => $setting));
}
public function notifChannelAction(Request $request)
{
    $imagineCacheManager = $this->get('liip_imagine.cache.manager');
    $em=$this->getDoctrine()->getManager();
    $defaultData = array();
    $form = $this->createFormBuilder($defaultData)
        ->setMethod('GET')
        ->add('title', TextType::class)
        ->add('message', TextareaType::class)
        ->add('object', 'entity', array('class' => 'AppBundle:Channel'))           
        ->add('icon', UrlType::class,array("label"=>"Large Icon","required"=>false))
        ->add('image', UrlType::class,array("label"=>"Big Picture","required"=>false))
        ->add('send', SubmitType::class,array("label"=>"Send notification"))
        ->getForm();
    $form->handleRequest($request);
    if ($form->isSubmitted() && $form->isValid()) {
        $data = $form->getData();
        $selected_channel = $em->getRepository("AppBundle:Channel")->find($data["object"]);
        $message = array(
              "type"=> "channel",
              "id"=> $selected_channel->getId(),
              "title"=> $data["title"],
              "message"=>$data["message"],
              "image"=> $data["image"],
              "icon"=>$data["icon"]
            );

        $setting = $em->getRepository('AppBundle:Settings')->findOneBy(array());            
        $key=$setting->getFirebasekey();
        $message_image = $this->send_notification(null, $message,$key); 
        $this->addFlash('success', 'Operation has been done successfully ');
    }
    return $this->render('AppBundle:Home:notif_channel.html.twig',array(
      "form"=>$form->createView()
      ));
}

Thanks in advance.

Can I get fillable PDF form value using Angular?

I got a particular scenario ๐Ÿ™

I need to show a fillable PDF file to the user in an angular app, once that the user fills all the fields, I need to get the base64 string or byte array of that file (with all fields filled by the user), to upload it in a server using node api.

Did I explain correctly my problem?
Anyone could give me a hand?
๐Ÿ™

I tried to use different libraries like pdf-js, but I couldn’t get what I need.

I also tried to get the data of the filled fields as json object to then fill a blank file and after that upload it, yes I know, a very strange scenario but I’m desperate XD

How to css links grouped in on file to a single html file?

I am developing a project and it requieres lots of css link tags. after using so many link my html files looks to clustered and hard to read.

Is there any way to store all the link tags in a single seperate file and import that file in index html file using only single line?

i tried using imports it was not working

React Native PDF – Single Page Styling Issues (alignment)

Problem

I’m using react-native-pdf in my React Native application to display PDF documents. I’ve encountered two issues that only happen when displaying a PDF with a single page:

  1. The single page appears centered instead of starting at the top of the container
  2. The borderRadius styles I’ve applied to the PDF component aren’t working for single-page PDFs

When the PDF has 2 or more pages, everything works as expected – the first page starts at the top of the container and the borderRadius is properly applied.

Code
Here’s my implementation:

import React, { useEffect, useState } from 'react';
import { SafeAreaView, ScrollView, View } from 'react-native';
import Pdf from 'react-native-pdf';

export function DocumentViewerScreen() {
  const [pdfUrl, setPdfUrl] = useState<string | null>(null);
  const [isLoading, setIsLoading] = useState(true);

  useEffect(() => {
    // Simulated data loading
    const loadDocument = async () => {
      try {
        // In real app, we'd fetch the PDF from an API
        // This is just for demo purposes
        setPdfUrl('https://example.com/sample.pdf'); // Or your base64 data URI
        setIsLoading(false);
      } catch (error) {
        setIsLoading(false);
      }
    };
    loadDocument();
  }, []);

  if (isLoading) {
    return <View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }} />;
  }

  return (
    <SafeAreaView style={{ flex: 1 }}>
      <ScrollView
        style={{ flex: 1 }}
        showsVerticalScrollIndicator={false}
        contentContainerStyle={styles.scrollViewContent}>
        <View style={{ height: 60 }}>
          {/* Header placeholder */}
        </View>
        <View style={styles.pdfContainer}>
          {pdfUrl && (
            <Pdf
              trustAllCerts={false}
              source={{
                uri: pdfUrl,
              }}
              style={styles.pdf}
            />
          )}
        </View>
      </ScrollView>
      <View style={styles.buttonContainer}>
        {/* Share button placeholder */}
      </View>
    </SafeAreaView>
  );
}

And here are my styles:

import { BorderRadius } from '@foundation/config';
import { ColorPalette } from '@foundation/config/colorPalette';
import { getScreenHeight, getScreenWidth } from '@foundation/helpers';
import { StyleSheet } from 'react-native';

export const styles = StyleSheet.create({
  scrollViewContent: {
    gap: getScreenHeight(2.5),
    paddingBottom: getScreenHeight(6.4),
    alignItems: 'center',
    flexGrow: 1,
  },
  pdfContainer: {
    flex: 1,
    height: '100%',
    flexDirection: 'column',
    display: 'flex',
    borderWidth: 1,
  },
  pdf: {
    flex: 1,
    width: getScreenWidth(94),
    height: '100%',
    maxHeight: getScreenHeight(100),
    flexDirection: 'column',
    display: 'flex',
    overflow: 'scroll',
    backgroundColor: ColorPalette.BackgroundPrimary,
    borderRadius: BorderRadius.Large,
    borderWidth: 1,
  },
  buttonContainer: {
    position: 'absolute',
    bottom: getScreenHeight(4.1),
  },
});

Expected Behavior:

  1. For single page pdf, the document should start from the top of the container, not centered vertically
  2. The borderRadius style should be applied to single page PDF.

Current Behavior

  • Multi-page PDFs: Everything works as expected – pages start from the top and borderRadius is applied
  • Single-page PDFs: The page appears centered vertically in the container and the borderRadius style is not applied

What I’ve Tried

I’ve experimented with:

  1. Different fitPolicy values (0, 1, 2)
  2. Setting singlePage to true/false
  3. Adjusting scale, minScale and various other properties
  4. Various container styling combinations

Question
How can I make single-page PDFs behave the same as multi-page PDFs where they start from the top of the container and properly apply the borderRadius styling?

Image:
enter image description here

Rejection System for Consultancy System

I have an accept/reject system for a consultation request. When a consultation request is sent from a user, on the consultant’s interface, they have the ability to either accept or reject. The accept system is working, however, when rejecting, a popup to enter the rejection reason will open and the database column status will change from pending to rejected, after the reason is typed and entered.

Here is the structure of my table:
enter image description here

However, it’s supposed to get the rejection reason from the popup and insert it into the rejection_reason column, and change the status to rejected. Also, I have a notifictions sytem for the consultant which is supposed to update accordingly (when accepted/rejected, it will change: self-explanatory with code). It’s not working how it’s intended to.

consultant_consult.php:

HTML & Javascript:

  function toggleNotifications() {
        const dropdown = document.getElementById('notificationsDropdown');
        const overlay = document.getElementById('overlay');

        // Toggle Dropdown Visibility
        const isVisible = dropdown.style.display === 'block';
        dropdown.style.display = isVisible ? 'none' : 'block';
        overlay.style.display = isVisible ? 'none' : 'block';

        // If opening, fetch notifications & reset unread count
        if (!isVisible) {
            fetch('consultant_consult.php?fetchConsultations=true')
            .then(response => response.json())
            .then(data => {
                const notificationList = document.getElementById("notification-list");
                notificationList.innerHTML = "";

                if (data.error) {
                    notificationList.innerHTML = `<p style="color: red;">${data.error}</p>`;
                    return;
                }

                if (data.length === 0) {
                    notificationList.innerHTML = `<p style="margin-left: 15px;">Nothing Here!</p>`;
                    return;
                }

                // Display consultations in the dropdown
                data.forEach(consultation => {
                    const consultationHTML = `
                        <div class="notification-item">
                            <p><strong>From:</strong> ${consultation.user_name}</p>
                            <p><strong>Symptoms:</strong> ${consultation.symptoms}</p>
                            <p><strong>Date:</strong> ${consultation.date} | <strong>Time:</strong> ${consultation.time}</p>
                            ${consultation.medical_docs ? `<p><a href="${consultation.medical_docs}" target="_blank">View Medical Documents</a></p>` : ""}
                            <div class="button-group">
                                <button class="accept-btn" onclick="processConsultation(${consultation.id}, 'accept')">Accept</button>
                                <button type='button' class="reject-btn" onclick="openRejectionPopup(${consultation.id})">Reject</button>
                            </div>
                        </div>
                    `;
                    notificationList.innerHTML += consultationHTML;
                });

                // Reset unread count to zero (since the user has now read them)
                unreadNotificationCount = 0;
                document.getElementById("notification-count").innerText = unreadNotificationCount;
            })
            .catch(error => console.error("Error fetching consultations:", error));
        }
    }

    // Fetch notification count on page load
    document.addEventListener("DOMContentLoaded", fetchNotificationCount);

    // Allow clicking on overlay to close the dropdown
    document.getElementById('overlay').addEventListener('click', function() {
        document.getElementById('notificationsDropdown').style.display = 'none';
        this.style.display = 'none';
    });

    function processConsultation(consultationId, action) {
        fetch('process_consult.php', {
            method: "POST",
            headers: { "Content-Type": "application/x-www-form-urlencoded" },
            body: `consultation_id=${consultationId}&action=${action}`
        })
        .then(response => response.text())
        .then(data => {
            alert(data);
            toggleNotifications(); // Refresh Notifications List
        })
        .catch(error => console.error("Error:", error));
    }

  // Rejection Reason and Reject System

  let rejectConsultationId = null;

  function openRejectionPopup(consultationId) {
      rejectConsultationId = consultationId; // Store the consultation ID
      document.getElementById("rejectionPopup").style.display = "flex";
  }

  function closeRejectionPopup() {
      document.getElementById("rejectionPopup").style.display = "none";
  }

  function submitRejection() {
      let reason = document.getElementById("rejectionReason").value.trim();

      if (reason === "") {
          alert("Please provide a reason for rejection.");
          return;
      }

      fetch("process_consult.php", {
          method: "POST",
          headers: { "Content-Type": "application/x-www-form-urlencoded" },
          body: `reject=true&consultation_id=${rejectConsultationId}&rejection_reason=${encodeURIComponent(reason)}`
      })
      .then(response => response.text())
      .then(data => {
          alert(data);
          closeRejectionPopup();
          location.reload(); // Refresh page to update consultations
      })
      .catch(error => console.error("Error:", error));
  }
<!-- Rejection Popup -->
<div id="rejectionPopup" class="popup-overlay">
    <div class="popup-box">
        <h2>Why are you rejecting this patient?</h2>
        <textarea id="rejectionReason" placeholder="Enter reason here..." rows="4"></textarea>
        <button class="reject-confirm-btn" onclick="submitRejection()">Reject</button>
        <button class="close-btn" onclick="closeRejectionPopup()">Cancel</button>
    </div>
</div>

process_consult.php

<?php
session_start();
$dbHost = "localhost";
$dbUser = "root";
$dbPass = "root";
$database = "medconnect";
$connection = mysqli_connect($dbHost, $dbUser, $dbPass, $database) or die ("Connection Failed");

if (!isset($_SESSION['signUpBtn'])) {
    echo "Unauthorized action!";
    exit;
}

if ($_SERVER["REQUEST_METHOD"] == "POST" && isset($_POST['consultation_id'], $_POST['action'])) {
    $consultation_id = intval($_POST['consultation_id']);
    $action = $_POST['action'];

    if ($action === "accept") {
        $query = "UPDATE consultations SET status='accepted' WHERE id=$consultation_id";
    } elseif ($action === "reject" && isset($_POST['rejection_reason'])) {
        $rejection_reason = mysqli_real_escape_string($connection, $_POST['rejection_reason']);
        $query = "UPDATE consultations SET status='rejected', rejection_reason='$rejection_reason' WHERE id=$consultation_id";
    } else {
        echo "Invalid action!";
        exit;
    }

    if (mysqli_query($connection, $query)) {
        echo "Consultation $action successfully!";
    } else {
        echo "Error: " . mysqli_error($connection);
    }
}

mysqli_close($connection);
?>

P.S. I’m using alert(data) as debugging to see if any data is recieved, and localhost always alerts blank (nothing), which indicates no data is being recieved itself, which is probably why there is no database update or notifications change taking place like how it’s supposed to.

How do I redirect to an edit page with the ID as a query parameter after form submission in Next.js?

I’m building a book management application using Next.js. I have a form that collects book details and submits them using an asynchronous function (onSubmit). The form data is sent to an action.ts file where it is validated and inserted into a Supabase database. After a successful submission, I want to redirect the user to an edit page while passing the ISBN of the newly submitted book in the URL.

  //submitting the forms
  async function onSubmit(data: BookInferSchema) {
    try {
      const formData = new FormData();
      Object.entries(data).forEach(([key, value]) => {
        formData.append(
          key,
          value instanceof Date ? value.toISOString() : value.toString()
        );
      });

      //sending the formData to the action.ts for submitting the forms
      const response = action(formData) as {
        error?: string;
        message?: string;
      } | void;

      //Error or success messages for any submissions and any errors/success from the server
      if (response?.error) {
        toast({
          title: "Error",
          description: `An error occurred: ${response.error}`,
        });
      } else {
        //after submitting the form, reset the form
        // form.reset();
      }
    } catch {
      toast({
        title: "Error",
        description: "An unexpected error occured.",
      });
    }
  }

And hereโ€™s a snippet of my action.ts where I validate and insert the book into the database:

const validatedFields = BookSchema.safeParse({
  ISBN: formData.get("ISBN"),
  //...other fields
});

if (!validatedFields.success) {
  console.error("Validation Errors:", validatedFields.error.format());
  return {
    errors: validatedFields.error.flatten().fieldErrors,
  };
}

const { ISBN } = validatedFields.data;

const supabase = createClient();
const { data, error } = await (await supabase)
  .from('books')
  .insert({
    isbn: ISBN,
    // ... other fields
  });

if (error) {
  return {
    error: true,
    message: error.message,
  };
}

return {
  error: false,
  message: 'Book updated successfully',
};

What I tried:

I tried returning the ISBN:

const successMessage = {
    error: false,
    message: "Book updated successfully",
    ISBN,
  };

return successMessage;

and use it here inside a !response?.error and it would just show as undefined when checking for the value of the response.

2nd try:
I put this code in the action.ts after submissions:

// Perform the redirect after returning the success message
  redirect(`/admin/books/${ISBN}/edit`);

But it would show this an application error, and this is what the console would redirect me with: https://nextjs.org/docs/messages/sync-dynamic-apis

This is the edit book page link: /admin/books/${id}/edit:

I am sure that I can access this page as I am also handling a redirect page for viewing each book.

const BookEdit = async (props: { params: Promise<{ id: string }> }) => {
  const supabase = await createClient();

  const {
    data: { user },
  } = await supabase.auth.getUser();

  if (!user) {
    return redirect("/login");
  }

  const params = await props.params;
  const id = params.id;

  const books = await fetchAllBooks(id);
  const bookData = books ? books[0] : null;

  return <h1>Edit Book {JSON.stringify(bookData, null, 2)}</h1>;
};

export default BookEdit;

Problem importing GLTF model in Three.js: Lights not working properly

I have been trying to import a GLTF model into Three.js, but I’m encountering several issues. When I import my scene with all the elements, the lights do not work as expected. The directional lights I configured in Blender (using the Eevee engine) do not appear correctly in Three.js.

Context:

  • I exported my model from Blender in GLTF/GLB format with all materials and textures.
  • I am using Three.js to render the scene.
  • The lights are imported as Object3D instead of DirectionalLight.

Code:

Here is the code I am using to load the model and set up the lights:

import * as THREE from "three";
import { GLTFLoader } from "three/addons/loaders/GLTFLoader.js";
import { OrbitControls } from "three/addons/controls/OrbitControls.js";
import { ModelViewerProps } from "./types";

export class ModelViewer {
  private _container: HTMLDivElement | null;
  private _scene: THREE.Scene = new THREE.Scene();
  private _camera: THREE.PerspectiveCamera;
  private _renderer: THREE.WebGLRenderer;
  private _controls?: OrbitControls;

  constructor(props: ModelViewerProps) {
    this._container = props.container;

    this._renderer = new THREE.WebGLRenderer({ antialias: true });
    this._renderer.setPixelRatio(window.devicePixelRatio);
    this._renderer.setSize(window.innerWidth, window.innerHeight);
    this._renderer.shadowMap.enabled = true;
    this._renderer.toneMapping = THREE.ACESFilmicToneMapping;
    this._renderer.toneMappingExposure = 1.25;
    this._renderer.setClearColor(0x000000, 1);

    this._camera = new THREE.PerspectiveCamera(
      75,
      window.innerWidth / window.innerHeight,
      0.1,
      1000
    );
    this._camera.position.set(0, 2, 5);

    if (props.useOrbitControls) {
      this._controls = new OrbitControls(
        this._camera,
        this._renderer.domElement
      );
    }

    this.loadModel(props.modelPath);

    if (this._container) {
      this._container.appendChild(this._renderer.domElement);
    }

    window.addEventListener("resize", this.onWindowResize.bind(this));
    this.animate();
  }

  private loadModel(url: string) {
    const loader = new GLTFLoader();
    loader.load(
      url,
      (gltf) => {
        this._scene.add(gltf.scene);
        if (gltf.cameras.length > 0) {
          if (gltf.cameras[0] instanceof THREE.PerspectiveCamera) {
            this._camera = gltf.cameras[0];
          }
        }
      },
      (xhr) => {
        console.log((xhr.loaded / xhr.total) * 100 + "% loaded");
      },
      (error) => {
        console.error(error);
      }
    );
  }

  private onWindowResize() {
    const width = window.innerWidth;
    const height = window.innerHeight;

    this._camera.aspect = width / height;
    this._camera.updateProjectionMatrix();

    this._renderer.setSize(width, height);
  }

  private animate() {
    requestAnimationFrame(() => this.animate());
    if (this._controls) {
      this._controls.update();
    }
    this._renderer.render(this._scene, this._camera);
  }
}

This is how the scene looks in Blender:
enter image description here

JSON.parse fails with quotation in template literal

I’m using Editor.js (which saves the HTML blocks as JSON) to create content on my website and it works great unless there is a " in the JSON value.

Data insertion works correctly, but when editing entries containing escaped double quotes (") within JSON values, JavaScript’s JSON.parse fails. For example:

j = JSON.parse(`{"data": "<a href="https://www.google.com/">Google</a>"}`);

The above would not parse and will say:

SyntaxError: JSON Parse error: Expected '}'

I’ve tried with just single quotes and that doesn’t work either. I’ve checked if the JSON is valid and jsonlint.com says both the JSON I generated with Editor.js is valid and the JSON above is valid.

What am I doing wrong? Again, everything works if as long as I don’t have an escaped quote (") in the JSON.

JavaScript json.parse fails on “

I’m using Editor.js (which saves the HTML blocks as JSON) to create content on my website and it works great unless there is a ” in the JSON value. So if I enter a quote or add a link, which puts the URL in quotes, it inserts the resulting JSON into PostgreSQL just fine, but when I go to “edit” the entry the data will not load if there is a ” in the JSON values. If I don’t enter a link or any quotes, then it works fine. Again, this data inserts into PostgreSQL just fine in a JSON column, so the JSON is valid, but JavaScript isn’t parsing the data correctly when I do JSON.parse to edit the data. Something isn’t right. I have tried with Safari and Chrome. Chrome actually says which character the error occurs on and I’ve confirmed that the first ” is where the error occurs. Here is an example of the JavaScript:

j = JSON.parse(`{"data": "<a href="https://www.google.com/">Google</a>"}`);

The above would not parse and will say: SyntaxError: JSON Parse error: Expected ‘}’

I’ve tried with just single quotes and that doesn’t work either. I’ve checked if the JSON is valid and jsonlint.com says both the JSON I generated with Editor.js is valid and the JSON above is valid.

What am I doing wrong? Again, everything works if as long as I don’t have an escaped quote (“) in the JSON.

“Why doesn’t `scrollIntoView()` work when clicking a search result to scroll to the corresponding product in the main list?”

React SearchBar: Scroll to Clicked Product Not Working

I’m trying to create a search bar that filters products and scrolls to the selected product when clicked. However, the scrolling does not work. The element does not scroll into view when I click a search result.

What I Tried

  • Used useRef(new Map()) to store product references dynamically.
  • Called scrollIntoView({ behavior: "smooth", block: "center" }) inside handleProductClick.
  • Added useEffect to reset the refs when products change.

Expected Behavior

  • When I click a search result, the corresponding product should smoothly scroll into view.

Actual Behavior

  • Clicking a search result does not scroll to the product.

My Code

import { useState, useRef, useEffect } from "react";
import searchIcon from "../assets/icons/search-icon.png";

const SearchBar = ({ products }) => {
    const [query, setQuery] = useState("");
    const filteredProducts = products.filter((product) =>
        product.name.toLowerCase().includes(query.toLowerCase())
    );

    const productRefs = useRef(new Map()); // Store refs using Map()

    useEffect(() => {
        productRefs.current = new Map(); // Reset refs when list updates
    }, [products]);

    const handleProductClick = (id) => {
        const element = productRefs.current.get(id); // Get element from Map
        if (element) {
            element.scrollIntoView({
                behavior: "smooth",
                block: "center",
            });
        }
        setQuery(""); // Clear search
    };

    return (
        <div className="flex w-full pl-3 max-w-xs sm:max-w-md md:max-w-lg relative">
            <input
                type="text"
                className="bg-amber-50 w-3/4 h-9 md:h-10 pl-3 rounded-bl-md rounded-tl-md text-sm focus:outline-0 md:font-semibold"
                placeholder="Search"
                value={query}
                onChange={(event) => setQuery(event.target.value)}
            />
            <button className="bg-[#FEBD69] flex items-center rounded-br-md rounded-tr-md cursor-pointer focus:outline-0 h-9 md:h-10 p-2">
                <img className="w-4 md:w-8" src={searchIcon} alt="Search" />
            </button>
            {query && filteredProducts.length > 0 && (
                <ul className="flex flex-col gap-5 absolute bg-amber-50 top-10 md:top-13 rounded-md shadow-lg p-2 max-h-60 overflow-y-auto border-1 border-gray-300">
                    {filteredProducts.map((product) => (
                        <li
                            key={product.id}
                            ref={(el) => productRefs.current.set(product.id, el)} // Store ref in Map
                            className="p-2 w-70 md:w-full flex items-center gap-2 md:gap-5 max-h-8 md:max-h-10 text-sm md:font-semibold cursor-pointer mt-4 duration-200 hover:opacity-80"
                            onClick={() => handleProductClick(product.id)}
                        >
                            {product.name} - <img className="max-w-7" src={product.image} alt="" />
                        </li>
                    ))}
                </ul>
            )}
        </div>
    );
};

export default SearchBar;