Potential CSP issue with Safari only devices and Google Tag Manager

I am running into an issue with a eCommerce website that appears to work fine on desktop and Android browsers, however when loading the site on a Apple based device with Safari it is breaking some other javascript functionality that the page uses (e.g such as jQuery performing a page-reload on changing an option from a ‘Sort By’ dropdown menu.

I don’t have an actual iOS phone to test but have put the website in question into an iOS simulator running an ‘iPhone 16’ with Safari and enabled debugging so I can view the console errors directly on my Mac Mini. Note – these issues ONLY happen on iOS devices with Safari and not Android (also no issues with regular desktop browsers).

When loading a particular category page I am getting the following error within the simulator console (note I have changed the site url for security reasons)

Refused to load https://www.googletagmanager.com/static/service_worker/53b0/sw_iframe.html?origin=https%3A%2F%2Fwww.mysite.com  because it does not appear in the frame-src directive of the Content Security Policy.
Refused to load https://metrics.mysite.com/_/service_worker/53b0/sw_iframe.html?origin=https%3A%2F%2Fwww.mysite.com&1p=1 because it does not appear in the frame-src directive of the Content Security Policy.

Would this require me to alter some Content Security Policy (CSP) settings to take this into account properly? I am not too familiar with CSP so any advice is welcomed, but I am reading that the Safari browser ITP (Intelligent Tracking Prevention) is much more aggressive than Android browsers and this can affect how service workers and tracking-related iframes are loaded which maybe effecting the Google Tag Manager in this instance.

So an example of the flow would be :

  • User goes to xxx page and selects ‘Sort by lowest price’ from the dropdown
  • This performs a page reload with the lowest price product
  • On safari devices this breaks so using the dropdown will not actually perform a page reload

I am debugging this using an iOS simulator on my mac, with the following versions if this helps:
Running MacOS 15.3.2
Xcode 16.2
Simulator 16.0 (1038)
Safari browser

Can we use WeakMap to improve garbage collection?

Say I have a class that does a lot of fetch requests.
State of each request is stored in a property of that class, which now is an array of objects.

Objects in that array are not needed once the fetch req completes, so they are removed at that point. This is done by searching the array by some object property, then get the index, splice.

Then I saw WeakMap

At first glance, it looks like that array of objects can be replaced with a WeakMap. Then I would simply call map.delete(object) when fetch req completes, instead of searching an array.

However, I’m a bit confused about the values of WeakMaps. I my case, I don’t need a value. I just need the object as a key. So I don’t really understand the purpose of the value, or maybe WeakMap is the wrong tool for the job?

Change background color when Overflow occurs

I have a page that contains a static/max- height div. My page’s second section’s (id =”middle”) div contains a textarea fields for users to provide a response and the entire div is limited to a height of 3 inches (due to this form being printed on 8.5″x11″ paper). I’d like either the entire page’s or this specific div’s background color to change if what has been entered in to the textarea makes the content of this div overflow.

Is there a way, either via JS or CSS, that I can change the background-color of this div to visually indicate when the contents have overflowed?

Considering I cannot provide my exact code, here is an example that will hopefully assist anyone reviewing my inquiry:

CSS

<style>
    div {
        border: 1px solid #CCC;
        background-color: #FFF;
        margin-bottom: 1rem;
        padding: 1rem;
        width: 8.5in;
        max-height: 7in;
    }

    .static-section {
        display: grid;
        overflow: hidden;
        max-height: 3in;
        width: 7.5in;

        * {
            margin-top: .5rem;
            margin-bottom: .5rem;
            padding: .5rem;
        }
    }

    textarea {
        field-sizing: content;
    }
</style>

HTML:

<form id="entry">
    <section id="top">
        <h1>HEADER</h1>
    </section>

    <section id="middle">
        <div id="overflow" class="static-section">
            <label>This section is locked at a max 3 inches. I want the background color to be red if the anything makes this section overflow.</label>
            <textarea placeholder="type in this section until the following paragraph starts to go off the screen. this is when I want the background color to change."></textarea>
            <P>When this information starts to go off the screen (i.e., enabling overflow - which the scrollbars are being hidden by the static-section class), I want the background color of this div to change. This will provide a visual indication that the provided response is too long.</P>
        </div>
    </section>

    <section id="footer">
        <h1>FOOTER</h1>
    </section>
</form>

If possible, I’d really like the entire form (id=”entry”) have it’s background color be updated (to light red – from white). If that is not possible, I’d like the overflowing section’s (id=”middle”) background to change color when overflow occurs.

How Can I Avoid Race Conditions When Users Try to Buy Tree Upgrades in My “Cookie Clicker” CO₂ Savings Game?

I’ve built the most basic CO₂ Tree Saver Game (still a work in progress, don’t judge). The idea is simple: users save CO₂, earn upgrades, and plant trees. However, there’s a small hiccup — when users try to buy a tree upgrade while their CO₂ savings are still being updated in the background, chaos ensues.

The logic around using CO₂ to buy a tree might be a little… unrefined, but that’s not the problem here. The issue is that when users return after being offline, the local localStorage value for CO₂ is out of sync, and they might end up trying to buy an upgrade they can’t afford.

Here’s a simplified version:

<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Green Game (Beta)</title>
    <style>
        .tree {
            width: 50px;
            height: 50px;
            background-color: green;
            border-radius: 50%;
            margin-top: 20px;
        }
        .tree.upgraded {
            width: 100px;
            height: 100px;
            background-color: #8B4513; /* Tree brown color when upgraded */
        }
    </style>
</head>
<body>
    <h1>Welcome to the Green Game (Beta)</h1>
    <p id="game-status">Collecting CO₂ data...</p>
    <p id="co2-output">Current CO₂: 0kg</p>
    <p id="tree-status">You can plant a tree with 100kg of CO₂ saved.</p>

    <div id="tree" class="tree"></div>

    <button id="plant-tree-btn" disabled>Plant a Tree</button>
    <button id="upgrade-tree-btn" disabled>Upgrade Tree</button>

    <script>
        class GreenGame {
            constructor() {
                // Retrieve saved data from localStorage or use defaults
                this.co2Saved = parseInt(localStorage.getItem("co2Saved")) || 0; // Load CO₂ or default to 0
                this.treeThreshold = 100; // CO₂ needed to plant a tree
                this.treeUpgraded = localStorage.getItem("treeUpgraded") === "true"; // Load tree upgrade status

                this.co2Output = document.getElementById("co2-output");
                this.gameStatus = document.getElementById("game-status");
                this.treeStatus = document.getElementById("tree-status");
                this.treeElement = document.getElementById("tree");
                this.plantTreeBtn = document.getElementById("plant-tree-btn");
                this.upgradeTreeBtn = document.getElementById("upgrade-tree-btn");

                // Reflect saved tree upgrade state
                if (this.treeUpgraded) {
                    this.treeElement.classList.add("upgraded");
                    this.treeStatus.textContent = "Tree upgraded! Now it’s a mighty tree!";
                    this.upgradeTreeBtn.disabled = true; // Disable upgrade after upgrading
                }
            }

            updateCO2() {
                // Simulate receiving new CO₂ data (could be from an API)
                setTimeout(() => {
                    const newCO2 = Math.floor(Math.random() * 20); // Random CO₂ value
                    this.co2Saved += newCO2;
                    this.co2Output.textContent = `Current CO₂: ${this.co2Saved}kg`;

                    if (this.co2Saved >= this.treeThreshold) {
                        this.treeStatus.textContent = "You can now plant a tree!";
                        this.plantTreeBtn.disabled = false; // Enable plant button
                    } else {
                        this.treeStatus.textContent = "You need more CO₂ to plant a tree!";
                        this.plantTreeBtn.disabled = true; // Disable plant button
                    }

                    this.gameStatus.textContent = `New CO₂ input: +${newCO2}kg`;

                    // Save updated CO₂ value to localStorage
                    localStorage.setItem("co2Saved", this.co2Saved);

                    // Recursively simulate data updates
                    this.updateCO2();
                }, 3000); // Updates every 3 seconds
            }

            plantTree() {
                if (this.co2Saved >= this.treeThreshold) {
                    this.treeElement.classList.remove("upgraded"); // Reset upgrade on new tree
                    this.treeElement.style.display = "block";
                    this.treeStatus.textContent = "You planted a tree!";
                    this.co2Saved -= this.treeThreshold; // Subtract the CO₂ used to plant the tree
                    this.co2Output.textContent = `Current CO₂: ${this.co2Saved}kg`;

                    this.upgradeTreeBtn.disabled = false; // Enable upgrade button
                    this.plantTreeBtn.disabled = true; // Disable plant button after planting

                    // Save updated CO₂ value to localStorage
                    localStorage.setItem("co2Saved", this.co2Saved);
                }
            }

            upgradeTree() {
                this.treeElement.classList.add("upgraded");
                this.treeStatus.textContent = "Tree upgraded! Now it’s a mighty tree!";
                this.upgradeTreeBtn.disabled = true; // Disable upgrade button after upgrading

                // Save tree upgrade state to localStorage
                localStorage.setItem("treeUpgraded", "true");
            }
        }

        // Start the game
        const game = new GreenGame();
        game.updateCO2(); // Begin simulation

        // Attach event listeners to buttons
        document.getElementById("plant-tree-btn").addEventListener("click", () => game.plantTree());
        document.getElementById("upgrade-tree-btn").addEventListener("click", () => game.upgradeTree());
    </script>
</body>
</html>

The Issue:

  1. CO₂ savings are updated every few seconds, but when a user returns after being offline, their CO₂ value is out of sync.

  2. If they try to buy an upgrade, the app mistakenly thinks they have enough CO₂, even though it’s outdated.

The Question:

  1. What’s the best way to prevent race conditions when the user is offline and comes back to find their CO₂ savings completely out of whack?

My js:

// Initial CO2 savings and tree planting state
let co2Saved = 10;
let treeCount = 0;

const plantTreeButton = document.getElementById('plant-tree');
const upgradeTreeButton = document.getElementById('upgrade-tree');

const updateCO2 = (newCO2Value) => {
  co2Saved = newCO2Value;
  console.log(`CO₂ Saved: ${co2Saved}kg`);
};

const plantTree = () => {
  console.log('Planting tree...');
  treeCount++;
  console.log(`You have ${treeCount} trees now.`);
};

const upgradeTree = () => {
  console.log('Upgrading tree...');
  treeCount++;
  console.log(`You have ${treeCount} trees now.`);
};

// Simulating multiple clicks with race condition
plantTreeButton.addEventListener('click', () => {
  // Simulate async updates to CO2 savings and tree planting
  setTimeout(() => {
    updateCO2(co2Saved + 10); // Update CO2 after planting tree
    plantTree();
  }, Math.random() * 1000); // Random delay to simulate timing race
});

upgradeTreeButton.addEventListener('click', () => {
  // Simulate async updates to CO2 savings and tree upgrading
  setTimeout(() => {
    updateCO2(co2Saved + 5); // Update CO2 after upgrading tree
    upgradeTree();
  }, Math.random() * 1000); // Random delay to simulate timing race
});

This is what happens:

  1. Process 1 checks the balance and sees 100kg.

  2. Process 2 also checks the balance and sees 100kg.

  3. Both processes try to withdraw 50kg.

  4. After both processes finish, they both update the balance to 50kg, even though 100kg should have been the correct result after two withdrawals.

Why I think this is happening:

  • Multiple threads or processes are running concurrently.

  • These threads/processes share a common resource – the database that pulls in CO₂ live info.

This is a basic version of the game, and yes, it’s a work in progress. But if you can solve this, I’ll plant a tree (in the game, because it’s a work in progress).

Thanks in advance for any advice — or suggestions to fix the CO₂ as currency logic.

Best practices for JS Module Designs

Ok, I understand in JS modules are preferred versus Classes, and that there is a ton of ways to write your modules, and I am having some trouble figuring out which are the accepted best practices for each case…

For example, if i am writing some sort of utilities class, this seems to be a good way to go:

export function a
export function b
export function c

however i already have reached a doubt, use functions or constants? export func a or export const a = () => {} ?

And when we start to think about other scenarios where you will probably want some kind of “Class” like code, or something that you will need to use some dependency injection an so on and so forth, the questions starts to grow, should i still create my modules like utilities as I just mentioned?

Should i create a function that returns an object like this

export default () => {
  function a
  function b

  return { a, b }
}

?

or should i use a constant like this:

const myModule = {}

myModule.a = () => {}
myModule.b = () => {}

export default myModule

or do i take any other approach i haven’t mentioned? Is there a general standard where i should use one or another based on the type of the module? Or any general best practice?

HTML: image name as url parameter does not work?

I have a HTML page which that using an image name as URL parameter. Why doesn’t show the image, what do i wrong?

<!DOCTYPE html>
<html lang="nl">
<head>
    <script src="lib/functions.js"></script>
</head>


<body>

<!-- test03.html?parameter=mountains.jpg -->

<img src="" id="imagename">

<script>
    const queryString = window.location.search;
    const urlParameters = new URLSearchParams(queryString);
    const Parameter = urlParameters.get('parameter');
    document.getElementById("imagename").innerHTML = Parameter;
</script>

</body>

</html>

Telegram requestWriteAccess popup window

Creating the Webapp game as telegram mini app. And stucked with one feature based on the requestWriteAccess.

What i want to achieve is that when i requestWriteAccess from user, it will show pop up as the screen below

popup i want to achieve

I tried this but it shows only the standart telegram bot alert bot as you can see it below

What we have

Here is the code we use

const allowsWriteToPm = window.Telegram.WebApp.initDataUnsafe.user.allows_write_to_pm;
    if (!allowsWriteToPm) {
        window.Telegram.WebApp.requestWriteAccess(function(ctx) {
            console.log("[TG] requestWriteAccess: " + ctx);

            if (!ctx || ctx !== "allowed" && String(ctx) !== "true"){
                return;
            }

            TG.trySendGreetMsg();
        });
    } else {
        TG.trySendGreetMsg();
    }

I checked another products and it seems that they have almost the same code.

NextJS; TypeError: handleComplete is not a function

Although i transferred props properly, i keep getting “is not function” error. I’ve worked a lot on that but i couldn’t find a solution. When I try to move(I do necessary implementings) handleComplete function to ProductAddTemplate.tsx, this time i get setIsSubmitting() is not function error.

enter image description here

AddProduct.tsx:

"use client";
import React, { useState } from "react";
import PageBreadcrumb from "@/components/common/PageBreadCrumb";
import { ProductAddTemplate } from "../templates/ProductAddTemplate";
import { Product } from "../types/types";
import { Step } from "../types/types";
import { motion } from "framer-motion";
import { FileSpreadsheet, Edit, CheckCircle, ArrowRight } from "lucide-react";
import { ProductService } from "@/utils/api/services/productService";
import {toast} from "sonner";

export default function AddProduct(): React.ReactElement {
    const [currentStep, setCurrentStep] = useState<number>(0);
    const [selectedMethod, setSelectedMethod] = useState<"manual" | "excel" | null>(null);
    const [productName, setProductName] = useState<string>("");
    const [selectedProducts, setSelectedProducts] = useState<Product[]>([]);
    const [isSubmitting, setIsSubmitting] = useState<boolean>(false);

    // Adımları tanımlayalım - renkli ve ikonlu
    const steps: Step[] = [
        {
            id: 0,
            title: "Yükleme Yöntemi",
            icon: <ArrowRight className="h-5 w-5" />,
            color: "bg-blue-500"
        },
        {
            id: 1,
            title: "Ürün Bilgileri",
            icon: <Edit className="h-5 w-5" />,
            color: "bg-purple-500"
        },
        {
            id: 2,
            title: "Önizleme",
            icon: <FileSpreadsheet className="h-5 w-5" />,
            color: "bg-amber-500"
        },
        {
            id: 3,
            title: "Tamamlandı",
            icon: <CheckCircle className="h-5 w-5" />,
            color: "bg-green-500"
        }
    ];

    // Yükleme yöntemini seçme işlevi
    const handleSelectMethod = (method: "manual" | "excel"): void => {
        setSelectedMethod(method);
        // Animasyon için timeout
        setTimeout(() => {
            setCurrentStep(1); // Bir sonraki adıma geç
        }, 300);
    };

    // Ürün ekleme
    const handleAddProduct = (): void => {
        if (productName.trim() === "") return;
        // Basit bir ürün oluştur (gerçek uygulamada API'den gelecek)
        const newProduct: Product = {
            id: Date.now(), // Geçici ID
            name: productName
        };
        // Animasyonlu ekleme
        setSelectedProducts(prev => [...prev, newProduct]);
        setProductName(""); // Input'u temizle
    };

    // Ürün kaldırma
    const handleRemoveProduct = (productId: number): void => {
        setSelectedProducts(selectedProducts.filter(p => p.id !== productId));
    };

    // Sıfırlama işlevi
    const handleReset = (): void => {
        setCurrentStep(0);
        setSelectedProducts([]);
        setProductName("");
        setSelectedMethod(null);
    };

    // Son adıma geçildiğinde ürünleri API'ye gönder ve konfeti efekti
    // Ürün ekleme işlemini tamamla
    // Ürün ekleme işlemini tamamla
    const handleComplete = async (): Promise<void> => {
        // Ürün kontrolü
        if (selectedMethod === "manual" && selectedProducts.length === 0) {
            toast.warning('Lütfen en az bir ürün ekleyin.');
            return;
        }
        // Yükleme durumunu başlat
        setIsSubmitting(true);
        // Ürün verilerini hazırla
        interface ProductData {
            productNames: string[];
            method: "manual" | "excel" | null;
        }
        const productData: ProductData = {
            productNames: selectedProducts.map((product: Product) => product.name),
            method: selectedMethod
        };
        try {
            // API çağrısını yap
            let success: boolean = false;
            if (selectedMethod === "manual") {
                // Manuel ekleme için API çağrısı
                interface ApiResponse {
                    isSuccessful: boolean;
                    errorMessages?: string[];
                    data?: any;
                }
                const response: ApiResponse | undefined = await ProductService.create(productData);
                success = Boolean(response && response.isSuccessful);
            } else {
                // Excel yükleme için farklı bir API çağrısı (örnek)
                // const response = await ProductService.uploadExcel(excelFile);
                // success = Boolean(response && response.isSuccessful);
                // Şimdilik Excel yüklemesini başarılı sayalım
                success = true;
            }
            // Sonuca göre işlem yap
            if (success) {
                // Başarılı olursa son adıma geç
                setCurrentStep(3);
                // Konfeti efekti
                // Başarı mesajı
                const productCount: number | string = selectedMethod === "manual"
                    ? selectedProducts.length
                    : "Excel'den yüklenen";
                toast.success(`${productCount} ürün başarıyla eklendi.`);
            } else {
                // Hata mesajı
                toast.error("Ürünler eklenirken bir hata oluştu. Lütfen tekrar deneyin.");
            }
        } catch (error: unknown) {
            // Hata durumunda
            console.error("Ürün ekleme işlemi başarısız:", error);
            // Hata mesajını daha detaylı göster
            if (error instanceof Error) {
                toast.error(`Hata: ${error.message}`);
            } else {
                toast.error("Bir hata oluştu. Lütfen daha sonra tekrar deneyin.");
            }
        } finally {
            // Her durumda yükleme durumunu sonlandır
            setIsSubmitting(false);
        }
    };
    return (
        <motion.div
            initial={{ opacity: 0, y: 20 }}
            animate={{ opacity: 1, y: 0 }}
            transition={{ duration: 0.5 }}
            className="min-h-screen bg-gradient-to-br from-white to-blue-50"
        >
            <PageBreadcrumb pageTitle="Ürün Ekle" />
            <motion.div
                className="space-y-4 max-w-5xl mx-auto p-6"
                initial={{ scale: 0.95 }}
                animate={{ scale: 1 }}
                transition={{ duration: 0.3 }}
            >
                <ProductAddTemplate
                    currentStep={currentStep}
                    steps={steps}
                    selectedMethod={selectedMethod}
                    productName={productName}
                    setProductName={setProductName}
                    selectedProducts={selectedProducts}
                    handleSelectMethod={handleSelectMethod}
                    handleAddProduct={handleAddProduct}
                    handleRemoveProduct={handleRemoveProduct}
                    setCurrentStep={setCurrentStep}
                    handleReset={handleReset}
                    isSubmitting={isSubmitting}
                    handleComplete={handleComplete}
                />
            </motion.div>
        </motion.div>
    );
}

ProductAddTemplate.tsx:

import React from "react";
import { StepIndicator } from "../molecules/StepIndicator";
import { MethodSelection } from "../organisms/MethodSelection";
import { StepHeader } from "../organisms/StepHeader";
import { ManualProductEntry } from "../organisms/ManualProductEntry";
import { ExcelUpload } from "../organisms/ExcelUpload";
import { ProductPreview } from "../organisms/ProductPreview";
import { CompletionMessage } from "../organisms/CompletionMessage";
import ComponentCard from "@/components/common/ComponentCard";
import { Step } from "../types/types";
import { Product } from "../types/types";
import { useRouter } from 'next/navigation';
import { motion, AnimatePresence } from "framer-motion";
import { ArrowRight, ArrowLeft, CheckCircle } from "lucide-react";
import {toast} from "sonner";
import ProductService from "@/utils/api/services/productService";

interface ProductAddTemplateProps {
    currentStep: number;
    steps: Step[];
    selectedMethod: "manual" | "excel" | null;
    productName: string;
    setProductName: (name: string) => void;
    selectedProducts: Product[];
    handleSelectMethod: (method: "manual" | "excel") => void;
    handleAddProduct: () => void;
    handleRemoveProduct: (productId: number) => void;
    setCurrentStep: (step: number) => void;
    handleReset: () => void;
    isSubmitting?: boolean;
    handleComplete: () => Promise<void>;
}

export const ProductAddTemplate: React.FC<ProductAddTemplateProps> = ({
                                                                          currentStep,
                                                                          steps,
                                                                          selectedMethod,
                                                                          productName,
                                                                          setProductName,
                                                                          selectedProducts,
                                                                          handleSelectMethod,
                                                                          handleAddProduct,
                                                                          handleRemoveProduct,
                                                                          setCurrentStep,
                                                                          handleReset,
                                                                          isSubmitting = false,
                                                                          handleComplete
                                                                      }) => {
    const router = useRouter();

    // Adım geçişleri için animasyon varyantları
    const variants = {
        hidden: { opacity: 0, x: 50 },
        visible: { opacity: 1, x: 0 },
        exit: { opacity: 0, x: -50 }
    };

    // Adım başlıklarını ve renklerini belirle
    const getStepColor = (stepId: number) => {
        const colors = ["bg-blue-500", "bg-purple-500", "bg-amber-500", "bg-green-500"];
        return colors[stepId] || colors[0];
    };

    // Adım 3'e geçiş için işlev - async olarak işaretlendi
    const goToFinalStep = async (): Promise<void> => {
        console.log("handleComplete type:", typeof handleComplete);
        await handleComplete();
    };

    return (
        <ComponentCard
            title="Ürün Ekle"
            className="border shadow-lg rounded-xl overflow-hidden"
        >
            {/* Adım göstergesi - renkli ve animasyonlu */}
            <div className="mb-8 px-4">
                <StepIndicator
                    steps={steps}
                    currentStep={currentStep}
                    activeColor={getStepColor(currentStep)}
                />
            </div>

            <AnimatePresence mode="wait">
                {/* Adım 0: Yükleme Yöntemi Seçimi */}
                {currentStep === 0 && (
                    <motion.div
                        key="step0"
                        initial="hidden"
                        animate="visible"
                        exit="exit"
                        variants={variants}
                        transition={{ duration: 0.3 }}
                        className="py-4"
                    >
                        <MethodSelection
                            onSelectMethod={handleSelectMethod}
                        />
                    </motion.div>
                )}

                {/* Adım 1: Ürün Bilgileri */}
                {currentStep === 1 && (
                    <motion.div
                        key="step1"
                        initial="hidden"
                        animate="visible"
                        exit="exit"
                        variants={variants}
                        transition={{ duration: 0.3 }}
                        className="flex flex-col gap-6 w-full py-4"
                    >
                        <StepHeader
                            title={selectedMethod === "manual" ? "Ürün Bilgilerini Girin" : "Excel Dosyasını Yükleyin"}
                            subtitle={selectedMethod === "manual"
                                ? "Eklemek istediğiniz ürünlerin bilgilerini girin"
                                : "Ürün bilgilerini içeren Excel dosyasını yükleyin"}
                            icon={selectedMethod === "manual" ? "edit" : "file-spreadsheet"}
                            color={getStepColor(1)}
                            onBack={() => setCurrentStep(0)}
                        />

                        {selectedMethod === "manual" ? (
                            <ManualProductEntry
                                productName={productName}
                                setProductName={setProductName}
                                selectedProducts={selectedProducts}
                                handleAddProduct={handleAddProduct}
                                handleRemoveProduct={handleRemoveProduct}
                                onContinue={() => setCurrentStep(2)}
                                buttonColor={getStepColor(1)}
                            />
                        ) : (
                            <ExcelUpload
                                onContinue={() => setCurrentStep(2)}
                                buttonColor={getStepColor(1)}
                            />
                        )}
                    </motion.div>
                )}

                {/* Adım 2: Önizleme */}
                {currentStep === 2 && (
                    <motion.div
                        key="step2"
                        initial="hidden"
                        animate="visible"
                        exit="exit"
                        variants={variants}
                        transition={{ duration: 0.3 }}
                        className="flex flex-col gap-6 w-full py-4"
                    >
                        <StepHeader
                            title="Ürün Bilgilerini Önizleyin"
                            subtitle="Eklediğiniz ürünleri kontrol edin ve onaylayın"
                            icon="eye"
                            color={getStepColor(2)}
                            onBack={() => setCurrentStep(1)}
                        />

                        <ProductPreview
                            selectedMethod={selectedMethod}
                            selectedProducts={selectedProducts}
                            onEdit={() => setCurrentStep(1)}
                            onConfirm={goToFinalStep}
                            buttonColor={getStepColor(2)}
                            isSubmitting={isSubmitting}
                        />
                    </motion.div>
                )}

                {/* Adım 3: Tamamlandı */}
                {currentStep === 3 && (
                    <motion.div
                        key="step3"
                        initial="hidden"
                        animate="visible"
                        variants={variants}
                        transition={{ duration: 0.3 }}
                        className="py-4"
                    >
                        <CompletionMessage
                            selectedMethod={selectedMethod}
                            productCount={selectedProducts.length}
                            onAddNew={handleReset}
                            onGoToList={() => router.push('/products')}
                            color={getStepColor(3)}
                            isProcessing={isSubmitting}
                        />
                    </motion.div>
                )}
            </AnimatePresence>

            {/* İlerleme göstergesi */}
            <div className="mt-8 flex justify-between items-center text-sm text-gray-500 border-t pt-4">
                <div>
                    {currentStep > 0 && currentStep < 3 && (
                        <button
                            onClick={() => setCurrentStep(currentStep - 1)}
                            className="flex items-center text-gray-600 hover:text-gray-900 transition-colors"
                            disabled={isSubmitting}
                        >
                            <ArrowLeft className="h-4 w-4 mr-1" />
                            Geri
                        </button>
                    )}
                </div>

                <div className="flex items-center">
                    <span className={`font-medium ${getStepColor(currentStep).replace('bg-', 'text-')}`}>
                        Adım {currentStep + 1}/{steps.length}
                    </span>
                    {currentStep === 3 && (
                        <CheckCircle className="h-4 w-4 ml-2 text-green-500" />
                    )}
                </div>

                <div>
                    {currentStep < 2 && currentStep > 0 && (
                        <button
                            onClick={() => setCurrentStep(currentStep + 1)}
                            className="flex items-center text-gray-600 hover:text-gray-900 transition-colors"
                            disabled={isSubmitting}
                        >
                            İleri
                            <ArrowRight className="h-4 w-4 ml-1" />
                        </button>
                    )}
                </div>
            </div>
        </ComponentCard>
    );
};

Official JSON Schema for npm audit –json Output?

I’m looking for an officially documented JSON schema that defines the structure of the output from the npm audit --json command. While I understand that the output includes keys like actions, advisories, metadata, etc., I couldn’t find a formal schema in the npm documentation or repository.

Is there an official JSON schema or response type definition available? If not, is the CLI source code the only reference for the expected structure? Is the output structure stable, or can it change between versions?

Why do my session variables disappear after calling session_regenerate_id(true)?

I have a method createSession() that calls session_regenerate_id(true); to prevent session fixation:

class Session {
    public string $id;
    public string $username;
    public string $role;

    public function __construct(){
        session_start();
        $this->id = $_SESSION['id'] ?? 0;
        $this->role = $_SESSION['role'] ?? 'guest';
        $this->username = $_SESSION['username']  ?? 'Guest User';
    }

    public function updateSession(array $user){
        $this->createSession($user);
    }

    public function createSession(array $user){
        session_regenerate_id(true);
        $_SESSION['id'] = $user['id'];
        $_SESSION['username'] = strstr($user['email'], '@', true);
        $_SESSION['expire'] = time() + 30 * 60;
        $_SESSION['role'] = $user['role'];
    }

    public function destroySession(){
        $_SESSION = [];
        $cookie_data = session_get_cookie_params();
        setCookie(session_name(), '', time() - 42000, $cookie_data['path'], $cookie_data['domain'], $cookie_data['httponly']);
        session_destroy();
    }
}

After calling this function, all previous session data seems to be lost.

Is this behavior normal?
How can I securely regenerate the session without losing existing data?

Do I need to manually copy session values before regenerating?

I’m using PHP 8.2 and storing sessions in the default file-based handler. Could the session storage settings affect this ?

How to submit a form through a confirmation modal with no or minimal JavaScript in PHP? [closed]

I am trying to implement a confirmation modal in my PHP page that will submit a form when the user confirms an action (like deletion). I want to avoid using custom JavaScript for the submission and rely mainly on HTML and PHP to handle the form submission.

Here’s the flow I want:

  1. User clicks a button to open the modal.
  2. The modal asks for confirmation with two options: Cancel and Yes, Submit.
  3. Clicking “Yes, Submit” should submit the form and trigger PHP logic, without using JavaScript to handle the submission.

Here’s the sample code I am working with:

<form id="generic_form" method="post">
    <button type="button" class="btn btn-danger" data-toggle="modal" data-target="#confirm_modal">
        **Delete Item**
    </button>
</form>

<!-- Confirmation Modal -->
<div class="modal fade" id="confirm_modal" tabindex="-1" role="dialog" data-backdrop="static" aria-hidden="true">
    <div class="modal-dialog">
        <div class="modal-content">
            <div class="modal-header">
                <h4 class="modal-title">**Are you sure?**</h4>
            </div>
            <div class="modal-body">
                **This action will remove the item permanently.**
            </div>
            <div class="modal-footer">
                <button type="button" class="btn btn-secondary" data-dismiss="modal">**Cancel**</button>
                <button type="submit" class="btn btn-danger" name="btn_confirm_delete" value="submit" data-dismiss="modal">
                    **Yes, Submit**
                </button>
            </div>
        </div>
    </div>
</div>

// HERE : This code is Not Executing 
if (isset($_POST["btn_confirm_delete"])) {
    // Call the function to handle the deletion
    **handle_deletion_function**();
}

As far as I know, when a submit button is clicked, the form containing the button is submitted, and its $_POST data is sent to the server. However, in this case, we are not directly submitting the form, so the page does not reload, which is the default behavior when a form is submitted. Also I do not want a separate JavaScript function to handle this submission.

Model Observer issue in nested transaction update of model

class Service A { 

public function approve($user, $data) { 

$apporvedUser = DB::transaction(function () use ($user, $data) {
        if($data['approve_by_admin'] == 1){
            $this->updateAdminStatus($user);
        }

        $user->update(['approved'] => 1); // This fires updated event 
    })
 }

 public function updateAdminStatus($user){
    $user = DB::transaction(function () use ($user, $data) {

        //Some Logic

        $user->update(['status'] => 5); // This doesnt fire event 
    })
 }
}

I have Scenario like above where same model gets updated in nested transactions but observer get only changes of last transaction, i want to get all updates in observer for same model.

Parsing an .odt content.xml with PHP results in an empty object [closed]

I’m trying to parse a libre office writer content.xml file on my server with php simplexml_load_file.

$xml = simplexml_load_file("https://ff-webdesigner.com/erechnung/content.xml");
print_r($xml);

But it always results in an empty object SimpleXMLElement Object ( ). Why?
Checked with file_get_content, setting namespaces and much more. All in vain.
With other xml files it’s working flawlessly…i checked for xml validity and also fixed all minor warnings.

php export data to excel / csv with dynamic column names [duplicate]

Currently I am using following code to export mysql data to csv file

<?php
 include("db.php");
 $query = "SELECT * FROM my_table";

 $delimiter = ","; 
 $filename = "MY-LIST-" . date('d-F-Y-H-i-s') . ".csv";
 
 $f = fopen('php://memory', 'w'); 

 $fields = array('ID', 'FIRST NAME', 'LAST NAME', 'EMAIL', 'GENDER', 'COUNTRY', 'CREATED', 'STATUS');
 fputcsv($f, $fields, $delimiter); 
 
 $result = $database->get_results($query);
  foreach($result as $row){ 
     $lineData = array($row['id'], $row['first_name'], $row['last_name'], $row['email'], $row['gender'],$row['country'], $row['date_created'], $row['member_status']);
     fputcsv($f, $lineData, $delimiter);      
 } 

 fseek($f, 0);

 header('Content-Type: text/csv'); 
 header('Content-Disposition: attachment; filename="' . $filename . '";'); 
 
 //output all remaining data on a file pointer 
 fpassthru($f); 

?>

Above Code is working ok ! and creating csv as expected.

Now I have another mysql table with around 89 columns and I want to export it to csv.

To reduce time consuming typing work, I need to fetch column names and put their values in array.

Current code I am trying is as follows :

<?php
 include("db.php");

 $result1 = $database->list_fields_name_serially('my_table');  
 // Getting all column names as comma separated list as id, first_name, last_name, email, gender, country, date_created, member_status, column_1, column_2, ......, column_89... (there is space after comma and before each column name)

 $result2 = strtoupper(str_replace("_", " ", $result1)); // removing underscore
 $result = strtoupper(str_replace(",", "' , ' ", $result2)); // replacing comaa with comma nad single quotes

 $delimiter = ","; 

 $filename = "MY-LIST-" . date('d-F-Y-H-i-s') . ".csv";
  
 $f = fopen('php://memory', 'w'); 

 $fields = array($result); // output = array('ID', 'FIRST NAME', 'LAST NAME', 'EMAIL', 'GENDER', 'COUNTRY', 'CREATED', 'STATUS');

 fputcsv($f, $fields, $delimiter); 

 $field_name = explode(",", str_replace(" ", "", $result1));

 $resultdata = $database->get_results("select * from my_table");
    foreach($resultdata as $row){
        foreach($field_name as $k => $v){ 
            $lineData[$k] = array($row[$v]);
        }
    
    fputcsv($f, $lineData, $delimiter); 
  }

  fseek($f, 0); 
 
// Set headers to download file rather than displayed 
header('Content-Type: text/csv'); 
header('Content-Disposition: attachment; filename="' . $filename . '";'); 
 
//output all remaining data on a file pointer 
fpassthru($f); 
?>

BUT IT IS NOT WORKING….. SCRIPT RUNS FOR FEW MINUTES AND THEN CREATES A CSV WITH ERRORS IN IT – Warnig : Array to string conversion on line 54 i.e. fputcsv($f, $lineData, $delimiter);