don't let qty exceed the selectedsize qty... or selectedcolor qty...
Also improve the stability and performance of ProductDetail...
Make it more smooth...
also fix the image doesn't appear...
Make it compatible especially with browser like Safari.
example of product prop:
{"product":{"id":204,"name":"‏Round Lab 1025 Dokdo Toner","description":"تونر يومي يساعد على تقشير البشرة وترطيبها.\nيحتوي على مياه البحر العميقة الغنية بالمعادن للحفاظ على المستوى الأمثل في توازن الماء والزيت للبشرة.\nويحتوي على EX-07 يزيل بشكل معتدل خلايا الجلد الميتة والدهون من أجل البشرة صحية.\nيحتوي على البانثينول والألانتوين والبيتين لحماية فعالة\nوتهدئة البشرة المتهيجة.","brand_id":121,"has_color":false,"has_size":true,"product_type":"size","price":"0.00","qty":0,"sold":0,"created_at":"2024-08-26T22:36:20.453Z","updated_at":"2024-09-15T18:13:25.335Z","categories":[{"id":169,"name":"Toners"}],"colors":[],"sizes":[{"id":1053,"name":"200 ml","price":"25000.00","qty":10,"sold":0,"color_id":null,"images":["1257.webp"]}],"images":[{"id":2452,"url":"1257.webp","color_id":null,"size_id":1053}]}}
ProductDetail.jsx:
'use client';
import React, { useState, useEffect, useCallback } from 'react';
import { ArrowLeft, Minus, Plus } from 'lucide-react';
import Slider from 'react-slick';
import 'slick-carousel/slick/slick.css';
import '@/components/NotificationStyles.css';
import 'slick-carousel/slick/slick-theme.css';

import Image from "next/image";
import { useRouter } from "next/navigation";
import Lightbox from "yet-another-react-lightbox";
import Zoom from "yet-another-react-lightbox/plugins/zoom";
import Fullscreen from "yet-another-react-lightbox/plugins/fullscreen";
import "yet-another-react-lightbox/styles.css";
import { useNotification } from "@/components/NotificationContext";
import Link from "next/link";
import WishlistHeart from "@/components/WishlistHeart";
const formatPrice = (price) => {
    const formattedPrice = price >= 10000 ? price.toLocaleString('en-US') : price.toString();
    return `${formattedPrice} IQD`;
};
export default function ProductDetail({ product }) {
    const [selectedColor, setSelectedColor] = useState(null);
    const [selectedSize, setSelectedSize] = useState(null);
    const [quantity, setQuantity] = useState(1);
    const [currentPrice, setCurrentPrice] = useState(product.price);
    const [lightboxOpen, setLightboxOpen] = useState(false);
    const [lightboxIndex, setLightboxIndex] = useState(0);
    const { addNotification } = useNotification();
    const [cartItems, setCartItems] = useState([]);
    const router = useRouter();
    const images = product.images.map(img => img.url || img);

    useEffect(() => {
        window.scrollTo(0, 0);
    }, []);

    const updatePrice = useCallback(() => {
        let price = product.price;
        if (selectedSize && selectedSize.price) {
            price = selectedSize.price;
        } else if (selectedColor && selectedColor.price) {
            price = selectedColor.price;
        }
        setCurrentPrice(parseFloat(price));
    }, [product, selectedColor, selectedSize]);

    useEffect(() => {
        const cart = JSON.parse(localStorage.getItem('cart')) || [];
        setCartItems(cart);

        // Set initial color and size if available
        if (product.has_color && product.colors.length > 0) {
            setSelectedColor(product.colors[0]);
        }
        if (product.has_size && product.sizes.length > 0) {
            setSelectedSize(product.sizes[0]);
        }
        updatePrice();
    }, []);

    useEffect(() => {
        updatePrice();
    }, [selectedColor, selectedSize, updatePrice]);

    const handleColorChange = (color) => {
        setSelectedColor(color);
        if (color.sizes && color.sizes.length > 0) {
            setSelectedSize(color.sizes[0]);
        } else {
            setSelectedSize(null);
        }
    };

    const handleSizeChange = (e) => {
        const sizeId = parseInt(e.target.value);
        const newSize = product.sizes.find(size => size.id === sizeId);
        setSelectedSize(newSize);
    };

    const isInCart = () => {
        return cartItems.some(item =>
            item.product_id === product.id &&
            item.color_id === selectedColor?.id &&
            item.size_id === selectedSize?.id
        );
    };

    const handleAddToCart = () => {
        const cartItem = {
            product_id: product.id,
            color_id: selectedColor?.id,
            size_id: selectedSize?.id,
            qty: quantity
        };

        let updatedCart = [...cartItems];
        const existingItemIndex = updatedCart.findIndex(item =>
            item.product_id === cartItem.product_id &&
            item.color_id === cartItem.color_id &&
            item.size_id === cartItem.size_id
        );

        if (existingItemIndex > -1) {
            updatedCart[existingItemIndex].qty += quantity;
        } else {
            updatedCart.push(cartItem);
        }

        localStorage.setItem('cart', JSON.stringify(updatedCart));
        setCartItems(updatedCart);
        addNotification('success', 'Product Added To Cart');
    };

    const sliderSettings = {
        dots: images.length > 1,
        infinite: false,
        speed: 500,
        slidesToShow: 1,
        slidesToScroll: 1,
        customPaging: function (i) {
            return (
                <div
                    style={{
                        width: '12px',
                        height: '12px',
                        background: i === this.currentSlide ? '#695C5C' : '#D9D9D9',
                        borderRadius: '50%',
                        padding: 0,
                        margin: '0 4px'
                    }}
                />
            );
        },
    };

    const lightboxSlides = images.map(src => ({
        src: `https://storage.naayiq.com/resources/${src}`
}));

    // Determine if the product is out of stock
    const isOutOfStock = (() => {
        if (product.has_size && selectedSize) {
            return selectedSize.qty === 0;
        } else if (product.has_color && selectedColor) {
            return selectedColor.qty === 0;
        } else {
            return product.qty === 0;
        }
    })();

    return (
        <div className="flex overflow-x-hidden font-serif relative z-50 font-medium flex-col -mt-4 -mx-4 bg-white">
            <Slider {...sliderSettings} className="w-full mb-2 h-[55vh]">
                {images.map((image, index) => (
                    <div key={index} className="relative w-full h-[60vh]" onClick={() => { setLightboxIndex(index); setLightboxOpen(true); }}>
                        <Image
                            src={`https://storage.naayiq.com/resources/${image}`}
                                alt={`Product image ${index + 1}`}
                                fill={true}
                                unoptimized={true}
                                className="w-full object-cover cursor-pointer"
                                priority={index === 0}
                                />
                                </div>
                                ))}
                    </Slider>

                    <Lightbox
                    open={lightboxOpen}
                    close={() => setLightboxOpen(false)}
                    index={lightboxIndex}
                    slides={lightboxSlides}
                    plugins={[Zoom, Fullscreen]}
                    carousel={{
                        finite: images.length <= 1,
                        navigationDisabled: images.length <= 1
                    }}
                    animation={{ zoom: 500 }}
                    zoom={{
                        maxZoomPixelRatio: 5,
                        zoomInMultiplier: 2,
                        doubleTapDelay: 300,
                        doubleClickDelay: 300,
                        doubleClickMaxStops: 2,
                        keyboardMoveDistance: 50,
                        wheelZoomDistanceFactor: 100,
                        pinchZoomDistanceFactor: 100,
                        scrollToZoom: true,
                    }}
            />

            <button
                className="absolute h-12 rounded-[100%] w-12 bg-white-gradient flex justify-center items-center top-4 left-4 z-10"
                onClick={router.back}
            >
                <ArrowLeft width={30} height={30} strokeWidth={1} />
            </button>
            <button
                className="h-12 rounded-[100%] w-12 absolute top-4 right-4 z-10 bg-white-gradient flex justify-center items-center"
            >
                <WishlistHeart
                    product={product}
                />
            </button>

            <div
                className="flex-grow bg-white rounded-t-xl shadow-[0px_-4px_8px_3px_rgba(105,92,92,0.1)] p-6 mt-2 relative z-30">
                <div className="w-9 h-1 bg-black opacity-70 rounded-full mx-auto mb-6"/>
                <h1 className="text-xl font-semibold mb-1 capitalize">{product.name}</h1>

                {isOutOfStock && (
                    <p className="text-red-500 mt-2 text-lg font-semibold">Out of Stock</p>
                )}

                {product.has_color && product.colors.length > 0 && (
                    <div className="mb-10 mt-6">
                        <h2 className="text-xl font-medium mb-2">Color</h2>
                        <div className="flex space-x-4 overflow-x-auto pb-2">
                            {product.colors.map((color) => (
                                <div key={color.id} className="flex flex-col items-center">
                                    <button
                                        className={`w-20 h-20 rounded-full border-2 ${selectedColor?.id === color.id ? 'border-[#3B5345]' : 'border-[#695C5C] border-opacity-50'} mb-2 overflow-hidden`}
                                        onClick={() => handleColorChange(color)}
                                        disabled={color.qty === 0}
                                    >
                                        {color.images && color.images.length > 0 && (
                                            <Image
                                                src={color.images[0]}
                                                alt={color.name}
                                                width={80}
                                                height={80}
                                                className="object-cover"
                                            />
                                        )}
                                    </button>
                                    <span className="text-sm">{color.name}</span>
                                </div>
                            ))}
                        </div>
                    </div>
                )}

                {((product.has_size && product.sizes.length > 0) || (selectedColor && selectedColor.sizes && selectedColor.sizes.length > 0)) && (
                    <div className="mb-6 font-serif">
                        <select
                            value={selectedSize ? selectedSize.id : ''}
                            onChange={handleSizeChange}
                            className="w-32 p-2 border border-[#E5E7EB] rounded-lg font-serif bg-white"
                        >
                            {(selectedColor && selectedColor.sizes ? selectedColor.sizes : product.sizes).map((size) => (
                                <option key={size.id} value={size.id} disabled={size.qty === 0}>
                                    Size: {size.name} {size.qty === 0 && '(Out of Stock)'}
                                </option>
                            ))}
                        </select>
                    </div>
                )}

                <div className="mb-6 pb-28">
                    <h2 className="text-xl font-semibold w-fit mb-2">Description</h2>
                    <div
                        style={{direction: "rtl"}}
                        className="text-xl mr-2 font-normal text-right font-serif"
                        dangerouslySetInnerHTML={{
                            __html: product.description.split('\n').map((item, index) => {
                                if (index === 0) {
                                    return `<p class="text-xl font-semibold mb-2">${item}</p>`;
                                } else if (item.includes(':')) {
                                    return `<p class="text-lg font-semibold mt-4 mb-2">${item}</p>`;
                                } else if (item.trim().startsWith('-')) {
                                    return `<li>${item.trim().substring(1)}</li>`;
                                } else {
                                    return `<p>${item}</p>`;
                                }
                            }).join('').replace(/(<li>.?<\/li>)+/g, function (match) {
                                return `<ul class="list-disc pl-5 mb-2">${match}</ul>`;
                            })
                        }}
                    />
                </div>

                <footer
                    className="fixed mt-12 border-[#695C5C]/30 shadow-[0_-4px_6px_-1px_rgba(0,0,0,0.05),0_-2px_4px_-1px_rgba(0,0,0,0.06)] bottom-0 bg-white p-4 right-0 left-0 z-50">
                    <div className="flex justify-between items-center mb-6">
                        <span
                            className="text-xl font-serif font-medium">{formatPrice(currentPrice * quantity)}</span>
                        <div className="flex items-center space-x-4">
                            <button
                                onClick={() => setQuantity(Math.max(1, quantity - 1))}
                                className="w-8 h-8 flex items-center justify-center border border-[#E5E7EB] rounded-full"
                                disabled={isOutOfStock}
                            >
                                <Minus className="w-4 h-4 text-[#3B5345]"/>
                            </button>
                            <span className="text-lg font-medium">{quantity}</span>
                            <button
                                onClick={() => setQuantity(quantity + 1)}
                                className="w-8 h-8 flex items-center justify-center border border-[#E5E7EB] rounded-full"
                                disabled={isOutOfStock}
                            >
                                <Plus className="w-4 h-4 text-[#3B5345]"/>
                            </button>
                        </div>
                    </div>

                    {/* Conditionally render the Add to Cart or Buy Now button based on stock status */}
                    {!isOutOfStock && (
                        isInCart() ? (
                            <Link
                                href="/cart"
                                className="w-full font-serif bg-[rgba(59,83,69,0.05)] text-[#3B5345] py-3 rounded-lg font-medium text-lg flex items-center justify-center transition duration-300 border border-[#3B5345]"
                            >
                                <svg className="mr-2" width="29" height="28" viewBox="0 0 29 28" fill="none"
                                     xmlns="http://www.w3.org/2000/svg">
                                    <path
                                        d="M9.50391 8.94834V7.81668C9.50391 5.19168 11.6156 2.61334 14.2406 2.36834C17.3672 2.06501 20.0039 4.52668 20.0039 7.59501V9.20501"
                                        stroke="#3B5345" strokeWidth="1.5" strokeMiterlimit="10" strokeLinecap="round"
                                        strokeLinejoin="round"/>
                                    <path
                                        d="M11.2542 25.6666H18.2542C22.9442 25.6666 23.7842 23.7883 24.0292 21.5016L24.9042 14.5016C25.2192 11.6549 24.4025 9.33325 19.4209 9.33325H10.0875C5.10586 9.33325 4.28919 11.6549 4.60419 14.5016L5.47919 21.5016C5.72419 23.7883 6.56419 25.6666 11.2542 25.6666Z"
                                        stroke="#3B5345" strokeWidth="1.5" strokeMiterlimit="10" strokeLinecap="round"
                                        strokeLinejoin="round"/>
                                    <path d="M18.8318 14.0001H18.8423" stroke="#3B5345" strokeWidth="2"
                                          strokeLinecap="round" strokeLinejoin="round"/>
                                    <path d="M10.6638 14.0001H10.6743" stroke="#3B5345" strokeWidth="2"
                                          strokeLinecap="round" strokeLinejoin="round"/>
                                </svg>
                                Buy Now
                            </Link>
                        ) : (
                            <button
                                onClick={handleAddToCart}
                                className="w-full font-serif bg-[#3B5345] text-white py-3 rounded-lg font-medium text-lg flex items-center justify-center transition duration-300"
                            >
                                <svg className="mr-2" width="29" height="28" viewBox="0 0 29 28" fill="none"
                                     xmlns="http://www.w3.org/2000/svg">
                                    <path
                                        d="M9.50391 8.94834V7.81668C9.50391 5.19168 11.6156 2.61334 14.2406 2.36834C17.3672 2.06501 20.0039 4.52668 20.0039 7.59501V9.20501"
                                        stroke="white" strokeWidth="1.5" strokeMiterlimit="10" strokeLinecap="round"
                                        strokeLinejoin="round"/>
                                    <path
                                        d="M11.2542 25.6666H18.2542C22.9442 25.6666 23.7842 23.7883 24.0292 21.5016L24.9042 14.5016C25.2192 11.6549 24.4025 9.33325 19.4209 9.33325H10.0875C5.10586 9.33325 4.28919 11.6549 4.60419 14.5016L5.47919 21.5016C5.72419 23.7883 6.56419 25.6666 11.2542 25.6666Z"
                                        stroke="white" strokeWidth="1.5" strokeMiterlimit="10" strokeLinecap="round"
                                        strokeLinejoin="round"/>
                                    <path d="M18.8318 14.0001H18.8423" stroke="white" strokeWidth="2"
                                          strokeLinecap="round" strokeLinejoin="round"/>
                                    <path d="M10.6638 14.0001H10.6743" stroke="white" strokeWidth="2"
                                          strokeLinecap="round" strokeLinejoin="round"/>
                                </svg>
                                Add To Cart
                            </button>
                        )
                    )}
                </footer>
            </div>
        </div>
    );
}
products/[id]/page.jsx:
import React, { Suspense } from "react";
import ProductDetail from "@/components/ProductDetail";
import Loading from "@/components/Loading";
import { NotificationProvider } from "@/components/NotificationContext";
export const dynamic = 'force-dynamic'; // Ensures the page is always dynamic
async function fetchProduct(id) {
    const response = await fetch(`${process.env.NEXT_PUBLIC_API}/products/${id}`, {cache: "force-cache"});
    if (!response.ok) {
        throw new Error('Failed to fetch product');
    }
    return response.json();
}
async function ProductContent({ id }) {
    const { product } = await fetchProduct(id);

    return (
        <ProductDetail
            product={product}
        />
    );
}

export default function ProductDetailsPage({ params }) {
    return (
        <NotificationProvider>
            <Suspense fallback={<Loading />}>
                <ProductContent id={params.id} />
            </Suspense>
        </NotificationProvider>
    );
}