Low conversion rate after launch — need step-by-step digital marketing fix for new e-commerce clothing store [closed]

I launched a new e-commerce clothing store 3 months ago targeting urban 18–34 customers. Traffic sources are a mix of Google Ads (Search + Shopping), Facebook/Instagram paid campaigns, organic search, and a few influencer posts. Current monthly averages: ~10,000 sessions, 0.7% conversion rate (~70 orders), bounce rate ~65%, average order value ₹1,200, ad spend ₹60,000/month with CPA ≈ ₹857 and ROAS ~1.2. Users add to cart but drop off at checkout or during payment selection. Organic visibility is low for primary product keywords.your text

Launched Search + Shopping campaigns and several FB/IG creatives (carousel + short video).

Set up basic remarketing (FB pixel + Google remarketing tag).

Added 10% first-order discount, free shipping on orders over ₹1,000.

Reduced checkout steps from 5 to 3 and added trust badges.

Created blog posts and social content but with low posting cadence.

Ran one A/B test on CTA text and swapped product thumbnails.

Enabled dynamic product ads for cart abandoners.
Results: traffic increased slightly, CTR on ads is OK, but conversion rate and CPA barely moved.

Conversion rate to rise to 2–3% within 6–8 weeks.

CPA to fall to ₹200–₹350 and ROAS to reach 2.5–3x.

Reduced checkout abandonment and higher repeat purchase rate from remarketing flows.

What is the standard protocol for logging out a user in a React app? How to properly reset Redux and other state?

I’m building a React single-page application with authentication and Redux for state management. I need to ensure that when a user logs out, all app state—including Redux state, React Context, and local component state—is fully reset.

One approach I’ve seen (and tested) is:

window.location.reload();

This effectively resets the entire app, but it feels heavy-handed, causes a full page reload, and doesn’t allow for fine-grained control over cleanup.

My questions are:

  1. Is calling window.location.reload() considered standard or acceptable for logging out in modern React apps, especially when using Redux?

  2. What are the recommended alternatives to fully reset app state, including Redux state, React Context, and any internal component state, without reloading the page?

  3. Are there common patterns or pitfalls for implementing a “soft logout” that ensures a clean slate for the next user session?

I’m looking for guidance on best practices in the React ecosystem for handling logout properly while ensuring all app state is cleared.

I want to update a single item in a list, but it is not updating [duplicate]

I created a component which consist of a list of employees. I want to be able to edit and delete each item separately. The delete is working as desired, but the update is not working. My database is Mysql.

This is my code

import axios from "axios";
import { useState, useEffect } from "react";
import { Link, useNavigate, useParams } from "react-router-dom";
import Student from "./Student";
import { FaGetPocket } from "react-icons/fa";
import { FaHome } from "react-icons/fa";
import { FaAmazonPay } from "react-icons/fa";
import { FaPlus } from "react-icons/fa";
import { FaRegEdit } from "react-icons/fa";
import { FaTimes } from "react-icons/fa";
import "./DashboardList.css"; // Custom CSS file
//import { Pagination } from "./Pagination";


function Updatestudent () {

  const [users, setUsers] = useState([]);
  const [error, setError] = useState("");

  const navigate = useNavigate(); // ✅ Fix: Call useNavigate()

  const [email, setEmail] = useState("");
  const [name, setName] = useState("");
  const [age, setAge] = useState("");
  const [id, setId] = useState("");
  const [items, setItems] = useState([]);
  const [selectedItem, setSelectedItem] = useState(null);
  const [err, setErr] = useState("");
  const [currentPage, setCurrentPage] = useState(1);
  const [postsPerPage] = useState(5);

  const [data, setData] = useState({
    name: "",
    email: "",
    age: "",
  });
   
 
  useEffect(() => {
    axios
      .get("http://localhost:8081/users")
      .then((res) => {
        console.log("✅ Unique Data fetched:", res.data);
        setItems(res.data);
        //setData(res.data);
      })
      .catch((err) => {
        console.error("❌ Error fetching data:", err);
        setError("Failed to load data. Please check server.");
      });
  }, []);
  

  //const indexOfLastPost = currentPage * postsPerPage;
  //const indexOfFirstPost = indexOfLastPost - postsPerPage;
  //const currentPosts = posts.slice(indexOfFirstPost, indexOfLastPost);

  const handleSelectItem = (itemId) => {
    const item = items.find(i => i.id === itemId);
    setSelectedItem(item);
    setData(items);
  };

  //const handleChange = (e) => {
  //  setData({ ...items, [e.target.name]: e.target.value });
  //};

  const handleAdd= (event) => {
    event.preventDefault();
    axios
      .post("http://localhost:8081/users", { name, email, age })
      .then((res) => {
        console.log("✅ Employee added successfully:", res);
        navigate("/"); // ✅ Fix: Properly navigate after success
      })
      .catch((err) => console.error("❌ Error adding student:", err));
  };

  const handleChange = (e) => {
    const { name, value } = e.target;
    setData((prevData) => ({
      ...prevData,
      [name]: value,
    }));
  };

  const handleDelete = async (id) => {
    try {
      await axios.delete(`http://localhost:8081/student/${id}`);
      navigate("/"); // Fix: Properly navigate after success
      setUsers(users.filter((user) => user.id !== id)); // ✅ Optimized UI update without reloading
      console.log("✅ Employee deleted successfully:", res);
          } catch (err) {
      console.error("❌ Error deleting student:", err);
    }
  };

  const handleUpdate = async (id) => {
    try {
      await axios.put('http://localhost:8081/update/:id'+ id, items)
      .then( (event) => {
        console.log("Employee Updated successfully:", items);
      navigate("/")}); // Fix: Properly navigate after success
       } catch (err) {
        console.log("Employee Updated successfully:", items);
    }
  };


  const handleSubmit = (event) => {
    event.preventDefault();

    handleUpdate(id)
    axios
    .put('http://localhost:8081/update/:id'+ id,  data )
     .then((event) => {
       console.log("Employee Updated successfully:", data);
       navigate("/"); // Fix: Properly navigate after success
     })
    .catch((err) => console.error("Error Updating Employee:", err));
  };


  return (
    <div className="dashboard-list w-100 vh-100 justify-content-between align-items-center p-4" >
      <div className="container p-4 bg-white rounded shadow">
      <h2 className="list-title">Employees List</h2>
      <div className="mb-2 form-control">
      <button className=" ms-2 btn btn-outline-primary">Add
      <Link to="/create" >
        <FaPlus className="ms-2 icon" color="" size="1.5rem"
          ></FaPlus>
        </Link> 
        </button>
        </div>
      <ul id="list" className="list-container">
        {items.map(item => (
          <tr key={item.id} className="list-item" align-items-center="true">
            <button className=" ms-3 btn btn-outline-success">Edit
             <FaRegEdit className="ms-3 icon" color="green"  onClick={() =>  {handleSelectItem(item.id)}}
             size="1.5rem" ></FaRegEdit>
             </button>
             <button className=" ms-3 btn btn-outline-danger">Del.
             <FaTimes className="ms-3 icon" color="red" onClick={() => {if (confirm("Do you want to delete this item?")) {handleDelete(item.id)};}}
              size="1.5rem" ></FaTimes>
             </button>
             <td className=" ms-3 ">
            {item.name}  
            </td> 
            <td className=" ms-3 ">
            {item.email}  
            </td> 
            <td className=" ms-3 ">
            {item.age}  
             </td>
            </tr>
        ))}
      </ul>
      {selectedItem && (
        <div className="d-flex justify-content-right align-items-center">
          <div className="w-100 bg-white rounded p-3">
          <h3>Details</h3>
          <form >
          <div>
          <input className="mb-2 form-control"  
           type="text" 
            defaultValue={selectedItem.name} 
            onChange={handleChange}
               />
          </div>
          <div>
          <input className="mb-2 form-control"  
              type="email" 
               defaultValue={selectedItem.email} 
               onChange={handleChange}
           />
           </div>
            <div>
            <input  className="mb-2 form-control"  
            type="number" 
            defaultValue={selectedItem.age} 
             onChange={handleChange}
           />
           </div>
          {/* Display other item properties */}
          <p></p>
          <button
            className="btn btn-success"
              onClick={(e) => handleUpdate(e,selectedItem.id)}>
                Update
           </button>
           </form>
           
           </div>
          </div>
        
      )}
       <Link to="/" className="mb-2 form-control" >
            <FaHome className="ms-2 icon" color="green" size="3rem"
             ></FaHome>
          </Link>
        </div>
       </div>
       
      )
  }
     
export default Updatestudent;

When I click the Edit button, it display selected item with inputs to edit.
When I click the update, the record in the mysql database is suppose to be updated. below is the backend (server) code

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

const app = express();
app.use(cors());
app.use(express.json()); // Enable JSON parsing

// MySQL Connection
const db = mysql.createConnection({
  host: "localhost",
  user: "root",
  password: "",
  database: "crud",
});


db.connect((err) => {
  if (err) {
    console.error("Database connection failed:", err);
    return;
  }
  console.log("Connected to MySQL database");
});

// ✅ Fetch all users
app.get("/users", (req, res) => {
  const sql = "SELECT * FROM users";
  db.query(sql, (err, data) => {
    if (err) {
      console.error("SQL Query Error:", err);
      return res.status(500).json({ error: "Database query failed" });
    }
    return res.json(data);
  });
});

//Fetch a single user
app.get("/user/:id", (req, res) => {
  const { id } = req.params.id; // ✅ Extract id from URL
  const sql = "SELECT * FROM users WHERE id = ?";
  db.query(sql, id, (err, data) => {
    if (err) {
      console.error("SQL Query Error:", err);
      return res.status(500).json({ error: "Database query failed" });
    }
    return res.json(data);
  });
});


// ✅ Add a new user
app.post("/users", (req, res) => {
  const sql = "INSERT INTO users (`Name`, `Email`, `Age`) VALUES (?, ?, ?)";
  const values = [req.body.name, req.body.email, req.body.age];

  db.query(sql, values, (err, data) => {
    if (err) {
      console.error("SQL Insert Error:", err);
      return res.status(500).json({ error: "Database insertion failed" });
    }
    return res.json({ message: "User added successfully", id: data.insertId });
  });
});

// ✅ Update an existing user
app.put("/update/:id", (req, res) => {
  const { id } = req.params; // Extract id from URL
  db.query("UPDATE 'users' SET 'name' = ?, 'email' = ?, 'age' = ? WHERE 'id' = ?", [name, email, age], (err) => {
    const values = [req.body.name, req.body.email, req.body.age];
    if (err) return res.status(500).send(err);
    res.send('Record updated successfully');
  });
});


// ✅ Delete an existing user
app.delete("/student/:id", (req, res) => {
  const sql = "DELETE FROM users WHERE ID = ?";
  const id = req.params.id;

  db.query(sql, id, (err, data) => {
    if (err) {
      console.error("SQL Delete Error:", err);
      return res.status(500).json({ error: "Database deletion failed" });
    }
    return res.json({ message: "User deleted successfully" });
  });
});

// Fetch single record
app.get('/record/user/:id', (req, res) => {
  const {id} = req.params;
  db.query('SELECT * FROM users WHERE id = ?', [id], (err, result) => {
    if (err) return res.status(500).send(err);
    res.json(result[0]);
  });
});

// Update record
app.put('/record/:id', (req, res) => {
  const id = req.params.id;
  const { name1, email, age } = req.body; // Example fields
  db.query('UPDATE users SET name = ?, email = ?, age = ? WHERE id = ?', [name1, email, age], (err) => {
    const values = [req.body.name, req.body.email, req.body.age];
    if (err) return res.status(500).send(err);
    res.send('Record updated successfully');
  });
});


// ✅ Start the server
app.listen(8081, () => {
  console.log("Server is running on port 8081");
});

Prisma user.create() and user.delete() throwing errors with Clerk Inngest events

I’m using Prisma with PostgreSQL and Inngest to sync Clerk user events (user.created, user.updated, user.deleted) to my database.

I have the following Prisma schema for User:

model User {
  id     String @id
  name   String
  email  String?
  image  String
  cart   Json @default("{}")
}

And my Inngest functions:

import prisma from '/lib/prisma';
import { inngest } from './client';

export const syncUserCreation = inngest.createFunction(
  { id: 'sync-user-create' },
  { event: 'clerk/user.created' },
  async ({ event }) => {
    const { data } = event;
    await prisma.user.create({
      data: {
        id: data.id,
        email: data.email_addresses[0].email_addresses, // <- seems wrong
        name: `${data.first_name} ${data.last_name}`,
        image: data.image_url,
      }
    });
  }
);

export const syncUserDeletion = inngest.createFunction(
  { id: 'sync-user-delete' },
  { event: 'clerk/user.deleted' },
  async ({ event }) => {
    const { data } = event;
    await prisma.user.delete({
      where: { id: data.id }
    });
  }
);

When creating a user:

PrismaClientValidationError:
Invalid prisma.user.create() invocation:
Argument email is missing.

When deleting a user:

PrismaClientKnownRequestError:
Invalid prisma.user.delete() invocation:
No record was found for a delete.

What I’ve tried

Changed

email_addresses[0].email_addresses to email_addresses[0]?.email_address

Tried using prisma.user.deleteMany() instead of delete() to avoid errors if user doesn’t exist

Need help creating a filter interface in JSUI / V8UI for Max/MSP using the Mgraphics API

Since I am a complete novice in programming, I decided to ask you for help.

Here is a reference to the filter I would like to get.

enter image description here

Reference
My thoughts: most likely, this is not a Band Pass filter, but two cutoff filters with adaptive Slope (from 12 to 48 dB/Octave). Moving up sets the distance between the bands and the filter slope, while moving horizontally sets the frequency. The amplitude range on the graph is from (unknown) to ~+6 dB.

I tried to create this using GPT’s, but without success.

If anyone can help me with this, I would be very grateful! Thank you!

Countdown react hook

I’m trying to build a react hook that does a simple stateful second count down.

Example use case:

Rate limit (client-side) a user when requesting a new SMS code.

Usage:

const { cooldown, startCooldown } = useCooldown();

<button disabled={cooldown > 0}>Resend Code {`(${cooldown ? cooldown : ''})`}</button>

Hook code:

import { useState, useRef, useEffect } from 'react';

export default function useCooldown(cooldownTime = 10) {
  const [cooldown, setCooldown] = useState(0);
  const intervalRef = useRef(null);

  function updateTimer() {
    console.log('cooldown remaining: ', cooldown);
    setCooldown(cooldown - 1);
    if (cooldown === 0) {
      clearInterval(intervalRef.current);
      intervalRef.current = null;
    }
  }

  function startCooldown() {
    console.log('starting cooldown from: ', cooldownTime);
    setCooldown(cooldownTime);
    intervalRef.current = setInterval(updateTimer, 1000);
  }

  useEffect(() => {
    return () => {
      clearInterval(intervalRef.current);
      intervalRef.current = null;
    };
  }, []);

  return { cooldown, startCooldown };
}

The browser console stops at

starting cooldown from:  10

I’m thinking since cooldown is stateful, the parent component gets reloaded along with a new useCooldown() instance. How can this be solved?

Flashing text in function called every frame JS

I’m developing an addon for this project: https://jcm.joban.org/latest/dev/scripting/pids/ (It uses a version of javascript to create screens in-game. In the scripts, most code is run in a function that is called every frame. Within this function, I want to make a text object that flashes. Ideally, I want a solution that doesn’t change the flash interval based on the framerate, but setInterval() and setTimeout() aren’t available in the mod’s implementation of JS. What other ways should I try to make text flash within this function?

API call returns HTML (ERR_NGROK_6024) instead of JSON response

I’m building a small React,TypeScript,Axios app for encrypted notes.

  • Frontend: React (with Axios)

  • Backend: Node/Express on http://localhost:3000

  • Tunnel: ngrok (ngrok http 3000)

Everything works fine locally, but when I use ngrok, some requests return an HTML page from ngrok instead of the JSON response from my backend.

src/api/notes.ts

import axios from "axios";

const api = axios.create({
    baseURL: "https://efaed12151ea.ngrok-free.app",
    headers: {
        "Content-Type": "application/json",
    },
});

export type NotePayload = {
    encryptedContent: string;
    encryptedIv: string;
};

export type CreateNoteResponse = {
    data: {
        id: string;
    };
};

export type GetNoteResponse = {
    data: {
        id: string;
        encryptedContent: string;
        encryptedIv: string;
    };
};

export async function createNote(payload: NotePayload): Promise<string> {
    const response = await api.post<CreateNoteResponse>("/notes", payload);
    return response.data.data.id;
}

export async function getNote(id: string): Promise<GetNoteResponse["data"]> {
    const response = await api.get<GetNoteResponse>(`/notes/${id}`);
    console.log(response);
    return response.data.data;
}

src/pages/CreateNote.tsx

import React, { useState } from "react";
import { encrypt, generateShortKey } from "../utils/crypto";
import { createNote } from "../api/notes";
import NoteForm from "../components/NoteForm";
import NoteResult from "../components/NoteResult";


export default function CreateNote() {
    const [content, setContent] = useState("");
    const [shortKey, setShortKey] = useState<string | null>(null);
    const [link, setLink] = useState<string | null>(null);
    const [loading, setLoading] = useState(false);
    const [error, setError] = useState<string | null>(null);

    const handleSubmit = async (e: React.FormEvent) => {
        e.preventDefault();

        if (!content.trim()) {
            setError("Note content cannot be empty.");
            return;
        }

        setError(null);
        setLoading(true);

        try {
            const key = generateShortKey();
            const { ciphertext, iv } = await encrypt(content, key);

            const id = await createNote({
                encryptedContent: ciphertext,
                encryptedIv: iv,
            });

            setShortKey(key);
            setLink(`${window.location.origin}/${id}#${key}`);
        } catch (err: any) {
            console.error("Failed to create note:", err);
            setError("Failed to create note. Please try again.");
        } finally {
            setLoading(false);
        }
    }

    const handleReset = () => {
        setContent("");
        setShortKey(null);
        setLink(null);
        setError(null);
    };

    const copyLink = async () => {
        if (link) {
            try {
                await navigator.clipboard.writeText(link);
                alert("Link copy!");
            } catch (err) {
                console.error("Failed to copy link:", err);
            }
        }
    };

    return (
      <div className="p-6 mx-auto my-8 max-w-lg border rounded-lg shadow-lg bg-white">

            <NoteForm
              content={content}
              onChange={setContent}
              onSubmit={handleSubmit}
              loading={loading}
              error={error}
            />

          {link && (
            <NoteResult link={link} onCopy={copyLink} onReset={handleReset} />
          )}
      </div>
    );
}

src/pages/ViewNote.tsx (simplified)

useEffect(() => {
  const shortKey = window.location.hash.slice(1);

  if (!id || !shortKey) {
    navigate("/404");
    return;
  }

  const load = async () => {
    try {
      const { encryptedContent, encryptedIv } = await getNote(id);
      const decrypted = await decrypt(encryptedContent, encryptedIv, shortKey);
      setNote(decrypted);
    } catch (err) {
      console.error("Error fetching note:", err);
      navigate("/404");
    } finally {
      setLoading(false);
    }
  };

  load();
}, [id]);

Console.log(response) write FAIL:

{data: '<!DOCTYPE html>n<html class="h-full" lang="en-US" …EiLCJ0aXRsZSI6Ik9LIn0="></div>n </body>n</html>n', status: 200, statusText: '', headers: AxiosHeaders, config: {…}, …} config : {transitional: {…}, adapter: Array(3), transformRequest: Array(1), transformResponse: Array(1), timeout: 0, …} data : "<!DOCTYPE html>n<html class="h-full" lang="en-US" dir="ltr">n <head>n <link rel="preload" href="https://cdn.ngrok.com/static/fonts/euclid-square/EuclidSquare-Regular-WebS.woff" as="font" type="font/woff" crossorigin="anonymous" />n <link rel="preload" href="https://cdn.ngrok.com/static/fonts/euclid-square/EuclidSquare-RegularItalic-WebS.woff" as="font" type="font/woff" crossorigin="anonymous" />n <link rel="preload" href="https://cdn.ngrok.com/static/fonts/euclid-square/EuclidSquare-Medium-WebS.woff" as="font" type="font/woff" crossorigin="anonymous" />n <link rel="preload" href="https://cdn.ngrok.com/static/fonts/euclid-square/EuclidSquare-Semibold-WebS.woff" as="font" type="font/woff" crossorigin="anonymous" />n <link rel="preload" href="https://cdn.ngrok.com/static/fonts/euclid-square/EuclidSquare-MediumItalic-WebS.woff" as="font" type="font/woff" crossorigin="anonymous" />n <link rel="preload" href="https://cdn.ngrok.com/static/fonts/ibm-plex-mono/IBMPlexMono-Text.woff" as="font" type="font/woff" crossorigin="anonymous" />n <link rel="preload" href="https://cdn.ngrok.com/static/fonts/ibm-plex-mono/IBMPlexMono-TextItalic.woff" as="font" type="font/woff" crossorigin="anonymous" />n <link rel="preload" href="https://cdn.ngrok.com/static/fonts/ibm-plex-mono/IBMPlexMono-SemiBold.woff" as="font" type="font/woff" crossorigin="anonymous" />n <link rel="preload" href="https://cdn.ngrok.com/static/fonts/ibm-plex-mono/IBMPlexMono-SemiBoldItalic.woff" as="font" type="font/woff" crossorigin="anonymous" />n <meta charset="utf-8">n <meta name="author" content="ngrok">n <meta name="description" content="ngrok is the fastest way to put anything on the internet with a single command.">n <meta name="robots" content="noindex, nofollow">n <meta name="viewport" content="width=device-width, initial-scale=1">n <link id="style" rel="stylesheet" href="https://cdn.ngrok.com/static/css/error.css">n <noscript>You are about to visit efaed12151ea.ngrok-free.app, served by xx.xxx.xx.xxx. This website is served for free through ngrok.com. You should only visit this website if you trust whoever sent the link to you. (ERR_NGROK_6024)</noscript>n <script id="script" src="https://cdn.ngrok.com/static/js/error.js" type="text/javascript"></script>n </head>n <body class="h-full" id="ngrok">n <div id="root" data-payload="eyJjZG5CYXNlIjoiaHR0cHM6Ly9jZG4ubmdyb2suY29tLyIsImNvZGUiOiI2MDI0IiwiaG9zdHBvcnQiOiJlZmFlZDEyMTUxZWEubmdyb2stZnJlZS5hcHAiLCJtZXNzYWdlIjoiWW91IGFyZSBhYm91dCB0byB2aXNpdCBlZmFlZDEyMTUxZWEubmdyb2stZnJlZS5hcHAsIHNlcnZlZCBieSA5My4xNTkuNDYuMTMxLiBUaGlzIHdlYnNpdGUgaXMgc2VydmVkIGZvciBmcmVlIHRocm91Z2ggbmdyb2suY29tLiBZb3Ugc2hvdWxkIG9ubHkgdmlzaXQgdGhpcyB3ZWJzaXRlIGlmIHlvdSB0cnVzdCB3aG9ldmVyIHNlbnQgdGhlIGxpbmsgdG8geW91LiIsInNlcnZpbmdJUCI6IjkzLjE1OS40Ni4xMzEiLCJ0aXRsZSI6Ik9LIn0="></div>n </body>n</html>n" headers : AxiosHeaders {content-length: '2878', content-type: 'text/html'} request : XMLHttpRequest {onreadystatechange: null, readyState: 4, timeout: 0, withCredentials: false, upload: XMLHttpRequestUpload, …} status : 200 statusText : "" [[Prototype]] : Object

What works

  • POST /notes (creating a note) works both locally and via ngrok.

  • GET http://localhost:3000/notes/:id → returns the expected JSON:

{
  "id": "h7KH5MjnxY7",
  "encryptedContent": "...",
  "encryptedIv": "..."
}

What doesn’t work

  • GET https://efaed12151ea.ngrok-free.app/notes/:id → sometimes returns JSON, but returns an HTML page from ngrok instead.

Example log from console.log(response) in Axios:

{
  "status": 200,
  "headers": { "content-type": "text/html" },
  "data": "<!DOCTYPE html><html ... (ERR_NGROK_6024) ... </html>"
}

So Axios sees a 200 OK, but the response is an HTML warning page from ngrok, not JSON.


What I tried

Manually checked in browser:

  • https://efaed12151ea.ngrok-free.app/notes/:id → often HTML (ngrok error page)

    Curl tests:

    curl -i https://efaed12151ea.ngrok-free.app/notes/h7KH5MjnxY7   # returns HTML with ERR_NGROK_6024
    
  • Tried with /api/notes/:id as well — same behavior.


Why does ngrok return its own HTML page (ERR_NGROK_6024) instead of forwarding my backend’s JSON response?

  • Is this a limitation of ngrok free tunnels (idle timeout, etc.)?

  • Do I need to change how Axios calls the API (baseURL, headers, etc.)?

  • Is there a reliable way to ensure my frontend always gets JSON from ngrok?

But when I open "/ID#shortKey", instead of JSON I get an ngrok HTML page.
In console.log(response) I see status: 200, but response.data contains an HTML string (<!DOCTYPE html> ...), not JSON.

I changed some variables, also rewrote the code itself more than once. Output in the console.log id, shortkey, etc.
The backend is fine. Now I can’t get NGROK to work. Sorry if it’s unclear, this is the first time I’ve asked for help on this site.

How can I use the input search in a different component using Algolia/Vue

I am using the infinite scroll with Vue 3 and InstantSearch(Algolia) but the

<ais-search-box placeholder="Search here…" class="searchbox" />

it should be in a different component, because due to the organization of my Vue components and blade components(I am using Laravel), the input search must be in a different place. the input and the results must be in different components. What can I do?

Posts.vue

<template>
  <div class="container">
      <ais-instant-search
        :search-client="searchClient"
        index-name="posts"
        :insights="true"
        :future="{ preserveSharedStateOnUnmount: true }"
      >
        <div class="search-panel">
          <div class="search-panel__results">
            <ais-search-box placeholder="Search here…" class="searchbox" />
            <app-infinite-hits>
              <template #item="{ item }">
                <h1><ais-highlight :hit="item" attribute="title" /></h1>
                <p><ais-highlight :hit="item" attribute="slug" /></p>
              </template>
            </app-infinite-hits>
          </div>
        </div>
      </ais-instant-search>
    </div>
</template>

<script>
import algoliasearch from 'algoliasearch/lite';
import AppInfiniteHits from '../../Components/InfiniteHits.vue';

export default {
  components: { AppInfiniteHits },
  data() {
    return {
      searchClient: algoliasearch(
        'XXXXXXX',
        'XXXXXXXXXXXXXXXXXX'
      ),
    };
  },
};
</script>

and this is the InfiniteHits.vue component:

<template>
  <ol v-if="state">
    <li v-for="hit in state.items" :key="hit.objectID">
      <slot name="item" :item="hit"></slot>
    </li>
    <li class="sentinel" v-observe-visibility="visibilityChanged"></li>
  </ol>
</template>

<script>
import { createWidgetMixin } from 'vue-instantsearch/vue3/es';
import { connectInfiniteHits } from 'instantsearch.js/es/connectors';

export default {
  mixins: [createWidgetMixin({ connector: connectInfiniteHits })],
  methods: {
    visibilityChanged(isVisible) {
      if (isVisible && !this.state.isLastPage) {
        this.state.showMore();
      }
    },
  },
};
</script>

<style scoped>
.sentinel {
  list-style-type: none;
}
</style>

these are the packages I am using:

"algoliasearch": "^4.25.2"
"vue-instantsearch": "^4.21.3",
"vue-observe-visibility": "^1.0.0"
"vite": "^5.2.6",
"vue": "^3.5.18"

CSS animation flickering

I’m, creating the marquee of banners for my Shopify store, here is the code:

      <div class="site-header__banners-wrapper">
        <div class="site-header__banners">
          {% for header_banner in shop.metafields.custom.header_banners.value %}
            <div class="site-header__banner">
              {% assign banner_url = shop.metafields.custom.header_banner_urls.value[forloop.index0] %}
              {% if banner_url %}
                <a href="{{ banner_url }}">
                  <img src="{{ header_banner | image_url }}" alt="">
                </a>
              {% else %}
                <img src="{{ header_banner | image_url }}" alt="">
              {% endif %}
            </div>
          {% endfor %}
        </div>
      </div>
      <style>
        .site-header__banners-wrapper {
          overflow: hidden;
        }
        .site-header__banners-wrapper:hover .site-header__banners {
          animation-play-state: paused;
        }
        .site-header__banners {
          display: flex;
          flex-wrap: nowrap;
          animation: animation var(--duration) linear infinite;
          
        }
        .site-header__banner {
          flex: 0 0 auto;
        }
        @keyframes animation {
          from { 
            transform: translateX(0);
          }
          to {
            transform: translateX(var(--length))
          }
        }
      </style>
      <script>
        document.addEventListener('DOMContentLoaded', () => {
          const bannersWrapper = document.querySelector('.site-header__banners-wrapper');
          const bannersWrapperWidth = bannersWrapper.offsetWidth;

          const banners = document.querySelector('.site-header__banners');

          const bannersArray = Array.from(document.querySelectorAll('.site-header__banner'));

          let bannersWidth = bannersArray.reduce((bannersWidth, banner) => bannersWidth + banner.offsetWidth, 0);
          
          const duration = bannersWidth / 100;

          document.documentElement.style.setProperty('--duration', `${duration}s`);
          document.documentElement.style.setProperty('--length', `-${bannersWidth}px`);

          let index = 0;

          while (bannersWidth < bannersWrapperWidth * 2) {
            const cloneBanner = bannersArray[index % bannersArray.length].cloneNode(true);
            banners.appendChild(cloneBanner);
            bannersWidth += cloneBanner.offsetWidth;
            index++;
          }
        });
      </script>

However I have an issue with iPhone, every few seconds an animation blinks like a whole marquee disappears for a tiny fraction of a time.

You can check an issue there: https://sveikatospasaulis.lt/

Please help me to understand the reason and to fix it.

Three.js vers 133 trying to add SSAO and change renderer to composer

I’m trying to add SSAO to my three.js model, but when I change renderer.render() into composer.render() orbit control stops working and zoom of model switch to max.enter image description here
one image is before adding composer and another is after
enter image description here

here is my init function
func.init = (set) => {

    func.floorTexture = new THREE.TextureLoader().load('/images/grass.jpeg');   
    scissorTexture = new THREE.TextureLoader().load('/images/scissor3.png');

    func.data.selector = set.div_id;
    func.data.resizable = set.resizable;
    func.data.boundingSphere = set.initBoundingSphere;

    if (set.is_damping != undefined) func.data.is_damping = set.is_damping;

    func.data.persp_cam_angle_xy = set.cam_angle[0];
    func.data.persp_cam_angle_xz = set.cam_angle[1];

    func.data.win_width = jQuery(`#${func.data.selector}`).width();
    func.data.win_height = jQuery(`#${func.data.selector}`).height();

    func.data.renderer = new THREE.WebGLRenderer({
        antialias: true,
        alpha: true,
        logarithmicDepthBuffer: false,//true
        powerPreference: 'high-performance',
        precision: 'highp',
    });

    func.data.autoClear = true;//true
    func.data.renderer.setPixelRatio(window.devicePixelRatio);
    func.data.renderer.physicallyCorrectLights = true;
    func.data.renderer.outputEncoding = THREE.sRGBEncoding;
    func.data.renderer.sortObjects = true;
    func.data.renderer.shadowMap.enabled = true;
    func.data.renderer.shadowMap.type = THREE.PCFSoftShadowMap; //
    func.data.renderer.shadowMap.autoUpdate = false;
    func.data.renderer.setSize(func.data.win_width, func.data.win_height);
    func.data.renderer.domElement.classList.add(`${func.data.selector}-visualizer`);

    // 
    let canvasContainer = document.getElementById(func.data.selector);
    if (canvasContainer.querySelector(`.${func.data.selector}-visualizer`)) {

        canvasContainer.querySelector(`.${func.data.selector}-visualizer`).remove();

    }

    document.getElementById(func.data.selector).appendChild(func.data.renderer.domElement);

    func.data.scene = new THREE.Scene();
    func.ambientLight = new THREE.AmbientLight(0xffffff, 1.5);//3
    func.data.scene.add(func.ambientLight);
    func.data.renderer.setClearColor(set.background_color[0], set.background_color[1]);

    if (set.light_type[0] == "HemisphereLight") {
        let hemiSphere = new THREE.HemisphereLight(set.light_type[1], set.light_type[2], set.light_type[3]);
    }
    else if (set.light_type[0] == "AmbientLight") {
        let ambientLight = new THREE.AmbientLight(set.light_type[1], set.light_type[2]);
    }

    if (func.data.renderer.domElement.classList.contains(`${func.data.selector}-visualizer`) && !func.data.renderer.domElement.classList.contains('three-win-axis-visualizer') && !func.data.renderer.domElement.classList.contains('three-win-side-axis-visualizer') && typeof ThreePerf == 'function') {
        func.perf = new ThreePerf({
            showGraph: true,
            anchorX: 'right',
            anchorY: 'top',
            domElement: $(`#${func.data.selector}`).get(0), // or other canvas rendering wrapper
            renderer: func.data.renderer, // three js renderer instance you use for rendering
            scale: 1,
            guiVisible: false,
            actionToCallUI: "gui"
        });
        var isPerfVisiblity = localStorage.getItem(`${func.data.selector}-PerfomanceTableVisible`);
        if (isPerfVisiblity != 'false' && isPerfVisiblity != null)
            $(`#${func.data.selector}`).find('#three-perf-ui').removeClass('d-none');
        else
            $(`#${func.data.selector}`).find('#three-perf-ui').addClass('d-none');
    }
    func.data.camera = createPerspectiveCamera()
    func.data.controls = new THREE.OrbitControls(func.data.camera, func.data.renderer.domElement);
    // 1. Creating EffectComposer іand save it in func.data
    func.data.composer = new THREE.EffectComposer(func.data.renderer);
    func.data.composer.setSize(func.data.win_width, func.data.win_height);
    // 2. Add RenderPass (main scene render)
    const renderPass = new THREE.RenderPass(func.data.scene, func.data.camera);
    //renderPass.clear = true; 
    func.data.composer.addPass(renderPass);
    // 3. Create and setup SSAOPass
    const ssaoPass = new THREE.SSAOPass(
        func.data.scene,
        func.data.camera,
        func.data.win_width,
        func.data.win_height
    );
    ssaoPass.kernelRadius = 10;     // Effect raduis. Try values from 8 to 32
    ssaoPass.minDistance = 0.005;   // Min distance for effect
    ssaoPass.maxDistance = 0.1;     // Max distance
    func.data.composer.addPass(ssaoPass);

    //// 4. Add GammaCorrection for right visibility of colors
    const gammaPass = new THREE.ShaderPass(THREE.GammaCorrectionShader);
    //gammaPass.clear = false; 
    gammaPass.renderToScreen = true;
    func.data.composer.addPass(gammaPass);

    //var copyPass = new THREE.ShaderPass(THREE.CopyShader);
    //copyPass.renderToScreen = true;
    //func.data.composer.addPass(copyPass);

    // --- End implement SSAO ---

    func.addOrbitEvents(func.data.controls);
    if (func.data.is_damping) func.controlDamping();
    func.data.controls.addEventListener('change', requestRenderIfNotRequested);

    if (!set.is_isometric) func.initPerspectiveCamera('ortho');
    else func.initIsometricCamera('ortho');

    if (func.data.resizable) {

        window.addEventListener('resize', func.onWindowResize);
        window.addEventListener('resize', func.controlFunc);
    }

    boundingBoxConst = func.data.boundingSphere.radius;
};
and here is my render function
function requestRenderIfNotRequested() {
    if (!func.data.renderRequested) {
        func.data.renderRequested = true;
        requestAnimationFrame(render);
    }
};

function render() {
    //requestAnimationFrame(render);

    func.data.renderRequested = false;

    if (func.data.timeout !== null) clearTimeout(func.data.timeout);
    func.data.timeout = setTimeout(function () {
        func.controlFuncEnd();
    }, 100);
    //func.data.controls.update();

    // Check if controls zoomIn/Out
    let controls = func.data.controls;
    let camera = func.data.camera;
    let lastZoom = camera.zoom;
    let newDistance = camera.position.distanceTo(controls.target);
    let epsilon = 0.0001;

    func.isZoomingIn = false;
    func.isZoomingOut = false;

    if (camera.isPerspectiveCamera) {
        if (Math.abs(newDistance - lastDistance) > epsilon && visualizer) {
            func.isZoomingIn = newDistance < lastDistance;
            func.isZoomingOut = newDistance > lastDistance;
        }
        lastDistance = newDistance;
    }

    if (camera.isOrthographicCamera) {
        if (Math.abs(camera.zoom - lastZoom) > epsilon && visualizer) {
            func.isZoomingIn = camera.zoom > lastZoom;
            func.isZoomingOut = camera.zoom < lastZoom;
        }
        lastZoom = camera.zoom;
    }

    func.isZoomingInOut = func.isZoomingIn || func.isZoomingOut;

    func.data.controls.update();

    if (clippingMovePlaneState && clippingMovePlaneState()) {
        func.updateClippingPlane();
        updateLableSizes();
    }

    if (func.data.renderer.domElement.classList.contains(`${func.data.selector}-visualizer`) && !func.data.renderer.domElement.classList.contains('three-win-axis-visualizer') && !func.data.renderer.domElement.classList.contains('three-win-side-axis-visualizer') && typeof ThreePerf == 'function')
        func.perf.begin();

    //func.data.renderer.render(func.data.scene, func.data.camera);
    //if (func.data.composer) {
        func.data.composer.render();
    //} else {
    //  //if composer is not initted
    //  func.data.renderer.render(func.data.scene, func.data.camera);
    //}

    if (func.data.renderer.domElement.classList.contains(`${func.data.selector}-visualizer`) && !func.data.renderer.domElement.classList.contains('three-win-axis-visualizer') && !func.data.renderer.domElement.classList.contains('three-win-side-axis-visualizer') && typeof ThreePerf == 'function')
        func.perf.end();

    func.controlFunc();
    func.controlFuncStart();
    if (visualizer && (visualizer.toolIsActive('pick') || visualizer.toolIsActive('measure') || (visualizer.positionAssemblyManager && visualizer.positionAssemblyManager.mode == 'order')) && !func.data.isRotating) {
        if (func.isZoomingInOut) return;
        func.controlFuncEnd();
    }
};

I’ve also gismo cube that uses this function to init to and removed it, it want helped.
Also tried to add renderToScreen to the last pass of composer. Nothing helped me!

Uncaught ReferenceError: require is not defined, in my Vercel app

Problem

I have a React app using Leaflet.js (v.1.9.0) and I host it in Vercel. Building works OK, but when visiting my app online logs this message in console:

Uncaught ReferenceError: require is not defined.

Where it happens

The file & line happening is ...assets/index-BKsOcw9k.js:67 where index-BKsOcw9k.js is a build file inside the dist/ folder. Locating it the code, it has this: ...QT.exports=e(require("leaflet"));e... and the problem is in the require.

My search

Searching around and asking AI, I understand that there is a problem with ESM and Leaflet (maybe, Rollup is included in the problem). I thought upgrading to Leaflet v.2 where it says it has Fully ESM support and that may solve the problem but there are conflicts with other packages (e.g. leaflet-draw, leaflet-geoman, etc…).

I import leaflet in my main component like that:
import L from "leaflet";. I’ve also tried import * as L from "leaflet";. None of them working when re-deploying in Vercel.

Thanks in advance!

Whenever I select the dropdowns in iframe, it soft scrolls to the top of the form

In a React app, the sign-up component behaves correctly. However, when embedded in an iframe, choosing any option in a dropdown causes the viewport to scroll to the top of the form.

Here is the react code with MUI

      <Stack direction={{ xs: 'column', sm: 'row' }} alignItems="center" spacing={2}>
        <Stack width={1}>
          <Typography>How would you like to pay?</Typography>
        </Stack>
        <Stack width={1}>
          <Field.Select name="paymentMethod" label="Payment Method" required>
            {payments.map((option) => (
              <MenuItem key={option.id} value={`${option.id}::${option.name}`}>
                {option.name}
              </MenuItem>
            ))}
          </Field.Select>
        </Stack>
      </Stack>

It works well in react, but not working in iframe

Dialog closes when parent is rerendered in React/NextJS/Shadcn

I have the following page:

'use client';
import { use } from 'react';

import { useCourseNode } from '@/api/course/hooks';
import { Loader } from '@/components/loaders/loader';
import { DefaultTreeNodeBox } from '@/components/tree/renderers/boxes/node-box';
import { EntityTargetType } from '@/lib/enums';
import { useDocumentTitle } from '@uidotdev/usehooks';
import { notFound } from 'next/navigation';

export default function ContentPage(props: {
  params: Promise<{ name: string; node: string }>;
}) {
  const params = use(props.params);

  const queryNode = useCourseNode(params.node);

  useDocumentTitle(
    queryNode.data?.name
      ? queryNode.data.name + ' | ' + queryNode.data.target.name
      : ''
  );

  if (queryNode.isLoading) return <Loader />;
  if (!queryNode.data) return notFound();

  const node = queryNode.data;

  return (
    <DefaultTreeNodeBox
      node={node}
      options={{
        pagination: {
          enabled: true,
        },
        comments: {
          enabled: true,
          targetType: EntityTargetType.COURSE_NODE,
          targetAuthor: node.target.author,
        },
      }}
    />
  );
}


In DefaultTreeNodeBox I render various things, including Dialog. Here is that component:

import { ExamAttemptResultBox } from '@/app/(app)/account/activity/exam-attempt-card';
import { SolveExamDialog } from '@/app/(public)/exams/[id]/solve-exam/solve-exam-dialog';
import { SolveExamProvider } from '@/app/(public)/exams/[id]/solve-exam/solve-exam-provider';
import { RemoveExamAttemptDialog } from '@/app/(public)/exams/remove-exam-attempt-dialog';
import { CardActionsContainer } from '@/components/card-actions-container';
import { PlayIcon } from '@/components/icons/play-icon';
import { Button } from '@/components/ui/button';
import { TextGradient } from '@/components/ui/text-gradient';
import { Role } from '@/lib/enums';
import { getUserOrGuest } from '@/lib/utils';
import { Exam, ExamAttempt } from '@/types';
import { Eye } from 'lucide-react';

export const SolveExamBox = ({
  exam,
  examAttempt,
}: {
  exam: Exam;
  examAttempt?: ExamAttempt;
}) => {
  const user = getUserOrGuest();
  if (examAttempt) examAttempt.exam = exam;

  if (examAttempt?.result)
    return (
      <SolveExamProvider exam={exam} examAttempt={examAttempt}>
        <div className='relative w-full'>
          <CardActionsContainer>
            <div className='ml-auto flex items-center gap-2'>
              <SolveExamDialog
                trigger={
                  <Button variant='ghost' size='icon'>
                    <Eye />
                  </Button>
                }
              />
              <RemoveExamAttemptDialog examAttempt={examAttempt} />
            </div>
          </CardActionsContainer>
          <div className='flex w-full flex-col gap-2 rounded border bg-card p-3'>
            <div className='flex justify-between gap-3'>
              <TextGradient color='tricolor-gold' className='text-lg'>
                Wynik
              </TextGradient>
            </div>

            <ExamAttemptResultBox examAttempt={examAttempt} />
          </div>
        </div>
      </SolveExamProvider>
    );

  if (user && user.role !== Role.USER) return null;

  return (
    <div className='flex w-full flex-col gap-2 rounded border bg-card p-4'>
      <div className='flex items-center gap-2'>
        <PlayIcon className='mw-fill-gradient-gold h-10 w-10 shrink-0' />
        <h3 className='relative z-10 line-clamp-1 text-2xl font-bold duration-300'>
          <TextGradient color='black'>Rozwiąż online</TextGradient>
        </h3>
      </div>
      <SolveExamProvider exam={exam} examAttempt={examAttempt}>
        <SolveExamDialog />
      </SolveExamProvider>
    </div>
  );
};

Initially there is no result in examAttempt so user canclick to solve exam and it opens dialog. However, when user ends the exam, the node in main page is invalidated and because of that, the entire page rerenders and that closes the dialog. I would like to keep it open and only in background rerender things – is it possible? I tried to add the same keys to SolveExamProvider and SolveExam components in SolveExamBox but still context is completely rerendered when node is invalidated. Any ideas how to fix that?