Enhance the ui/ux of edit product... improve the font, colors and everything... fix the typescripts errors between editproduct and productspage... make the design responsive. Also there is a bug where editing product doesn't show the sizes inside the color...
A color may contain a size inside it...
Improve the performance of edit product as well... and when pressing edit show editing... and close the button...
focus on make the design more friendly and robust...
EditProduct.tsx:
"use client";
import { X, Plus, Trash2 } from "lucide-react";
import { MultipartFileUploader } from "@/components/MultipartFileUploader";
import { toast } from "react-toastify";
import React, { useEffect, useState } from "react";
import { getToken } from "@/app/auth";

interface Category {
  id: number;
  name: string;
}

interface EditProductProps {
  isOpen: boolean;
  onClose: () => void;
  product: Product;
}

interface Brand {
  id: number;
  name: string;
}

interface Size {
  id?: number;
  name: string;
  price: string;
  qty: string;
  images: string[];
  inheritImages?: boolean;
}

interface Color {
  inheritImages?: boolean;
  id?: number;
  name: string;
  price: string | null;
  qty: string | null;
  sizes: Size[];
  images: string[];
}

interface Product {
  id: number;
  name: string;
  description: string;
  brand_id: number;
  has_color: boolean;
  has_size: boolean;
  categories: Category[];
  colors: Color[];
  sizes: Size[];
  price: string | null;
  qty: string | null;
  images: string[];
}

export default function EditProduct({
  isOpen,
  onClose,
  product,
}: EditProductProps) {
  const [editedProduct, setEditedProduct] = useState<Product>({
    ...product,
    sizes: product.sizes || [], // Ensure sizes is always an array
    colors: product.colors.map((color) => ({
      ...color,
      sizes: color.sizes || [], // Ensure sizes is always an array for each color
    })),
    images: [],
  });
  const [categories, setCategories] = useState<Category[]>([]);
  const [brands, setBrands] = useState<Brand[]>([]);

  useEffect(() => {
    fetchCategories();
    fetchBrands();
  }, []);
  const handleDeleteColor = (colorIndex: number) => {
    setEditedProduct((prevProduct) => {
      const newColors = [...prevProduct.colors];
      newColors.splice(colorIndex, 1);
      return { ...prevProduct, colors: newColors };
    });
  };

  const handleDeleteSize = (colorIndex: number, sizeIndex: number) => {
    setEditedProduct((prevProduct) => {
      if (colorIndex === -1) {
        const newSizes = [...prevProduct.sizes];
        newSizes.splice(sizeIndex, 1);
        return { ...prevProduct, sizes: newSizes };
      } else {
        const newColors = [...prevProduct.colors];
        newColors[colorIndex].sizes.splice(sizeIndex, 1);
        return { ...prevProduct, colors: newColors };
      }
    });
  };

  const handleInheritImagesChange = (
    variantType: "color" | "size",
    colorIndex: number,
    sizeIndex: number,
  ) => {
    setEditedProduct((prevProduct) => {
      const updatedProduct = { ...prevProduct };

      if (variantType === "color") {
        updatedProduct.colors[colorIndex].inheritImages =
          !updatedProduct.colors[colorIndex].inheritImages;

        if (updatedProduct.colors[colorIndex].inheritImages && colorIndex > 0) {
          const prevColor = updatedProduct.colors[colorIndex - 1];
          updatedProduct.colors[colorIndex].images = [...prevColor.images];
        }
      } else if (variantType === "size") {
        if (colorIndex === -1) {
          updatedProduct.sizes[sizeIndex].inheritImages =
            !updatedProduct.sizes[sizeIndex].inheritImages;

          if (updatedProduct.sizes[sizeIndex].inheritImages && sizeIndex > 0) {
            const prevSize = updatedProduct.sizes[sizeIndex - 1];
            updatedProduct.sizes[sizeIndex].images = [...prevSize.images];
          }
        } else {
          updatedProduct.colors[colorIndex].sizes[sizeIndex].inheritImages =
            !updatedProduct.colors[colorIndex].sizes[sizeIndex].inheritImages;

          if (
            updatedProduct.colors[colorIndex].sizes[sizeIndex].inheritImages &&
            sizeIndex > 0
          ) {
            const prevSize =
              updatedProduct.colors[colorIndex].sizes[sizeIndex - 1];
            updatedProduct.colors[colorIndex].sizes[sizeIndex].images = [
              ...prevSize.images,
            ];
          }
        }
      }

      return updatedProduct;
    });
  };

  const fetchCategories = async () => {
    try {
      const response = await fetch(
        "http://localhost:4000/subcategories/non-brands",
      );
      const data = await response.json();
      setCategories(data);
    } catch (error) {
      console.error("Error fetching categories:", error);
    }
  };

  const fetchBrands = async () => {
    try {
      const response = await fetch(
        "http://localhost:4000/subcategories/brands",
      );
      const data = await response.json();
      setBrands(data);
    } catch (error) {
      console.error("Error fetching brands:", error);
    }
  };

  const handleCategoryToggle = (categoryId: number) => {
    // @ts-ignore
    setEditedProduct((prevProduct) => {
      const updatedCategories = prevProduct.categories.some(
        // @ts-ignore
        (cat) => cat.id === categoryId,
      )
        ? prevProduct.categories.filter((cat) => {
            // @ts-ignore
            cat.id !== categoryId;
          })
        : [
            ...prevProduct.categories,
            {
              id: categoryId,
              name: categories.find((cat) => cat.id === categoryId)?.name || "",
            },
          ];
      return { ...prevProduct, categories: updatedCategories };
    });
  };

  const handleInputChange = (e: {
    target: { name: string; value: string };
  }) => {
    const { name, value } = e.target;
    setEditedProduct((prevProduct) => ({
      ...prevProduct,
      [name]: value,
    }));
  };

  const handleColorToggle = () => {
    setEditedProduct((prevProduct) => ({
      ...prevProduct,
      has_color: !prevProduct.has_color,
      colors: !prevProduct.has_color ? [] : prevProduct.colors,
    }));
  };

  const handleBrandChange = (e: React.ChangeEvent<HTMLSelectElement>) => {
    setEditedProduct((prevProduct) => ({
      ...prevProduct,
      brand_id: parseInt(e.target.value),
    }));
  };

  const handleSizeToggle = () => {
    setEditedProduct((prevProduct) => ({
      ...prevProduct,
      has_size: !prevProduct.has_size,
      sizes: !prevProduct.has_size ? [] : prevProduct.sizes,
    }));
  };

  const handleAddColor = () => {
    setEditedProduct((prevProduct) => ({
      ...prevProduct,
      colors: [
        ...prevProduct.colors,
        { name: "", price: null, qty: null, sizes: [], images: [] },
      ],
    }));
  };

  const handleAddSize = (colorIndex: number) => {
    setEditedProduct((prevProduct) => {
      if (colorIndex === -1) {
        return {
          ...prevProduct,
          sizes: [
            ...prevProduct.sizes,
            { name: "", price: "", qty: "", images: [] },
          ],
        };
      } else {
        const newColors = [...prevProduct.colors];
        newColors[colorIndex].sizes.push({
          name: "",
          price: "",
          qty: "",
          images: [],
        });
        return {
          ...prevProduct,
          colors: newColors,
        };
      }
    });
  };

  const handleColorChange = (
    index: number,
    field: keyof Color,
    value: string,
  ) => {
    setEditedProduct((prevProduct) => {
      const newColors = [...prevProduct.colors];
      newColors[index] = {
        ...newColors[index],
        [field]: value,
      };
      return { ...prevProduct, colors: newColors };
    });
  };

  const handleSizeChange = (
    colorIndex: number,
    sizeIndex: number,
    field: keyof Size,
    value: string,
  ) => {
    setEditedProduct((prevProduct) => {
      if (colorIndex === -1) {
        const newSizes = [...prevProduct.sizes];
        newSizes[sizeIndex] = {
          ...newSizes[sizeIndex],
          [field]: value,
          images: newSizes[sizeIndex].images || [], // Ensure images array exists
        };
        return { ...prevProduct, sizes: newSizes };
      } else {
        const newColors = [...prevProduct.colors];
        newColors[colorIndex].sizes[sizeIndex] = {
          ...newColors[colorIndex].sizes[sizeIndex],
          [field]: value,
          images: newColors[colorIndex].sizes[sizeIndex].images || [], // Ensure images array exists
        };
        return { ...prevProduct, colors: newColors };
      }
    });
  };

  const handleImageUpload = (
    fileIds: string[],
    variantType: "color" | "size" | "product",
    colorIndex: number,
    sizeIndex: number,
  ) => {
    setEditedProduct((prevProduct) => {
      const updatedProduct = { ...prevProduct };

      if (variantType === "color") {
        updatedProduct.colors[colorIndex].images = fileIds;
      } else if (variantType === "size") {
        if (colorIndex === -1) {
          updatedProduct.sizes[sizeIndex].images = fileIds;
        } else {
          updatedProduct.colors[colorIndex].sizes[sizeIndex].images = fileIds;
        }
      } else {
        updatedProduct.images = fileIds;
      }

      return updatedProduct;
    });
  };

  const handleSubmit = async (e: React.FormEvent) => {
    e.preventDefault();
    const productType =
      editedProduct.has_color && editedProduct.has_size
        ? "color_size"
        : editedProduct.has_color
          ? "color"
          : editedProduct.has_size
            ? "size"
            : "simple";

    const productData = {
      ...editedProduct,
      product_type: productType,
      category_ids: editedProduct.categories.map((cat) => cat.id),
      hasColor: editedProduct.has_color,
      hasSize: editedProduct.has_size,
      colors: editedProduct.has_color
        ? editedProduct.colors.map((color) => ({
            id: color.id, // Include the color ID if it exists
            name: color.name,
            price: color.price ? parseFloat(color.price) : null,
            qty: color.qty ? parseInt(color.qty) : null,
            hasSize: editedProduct.has_size,
            sizes: editedProduct.has_size
              ? color.sizes.map((size) => ({
                  id: size.id, // Include the size ID if it exists
                  name: size.name,
                  price: parseFloat(size.price),
                  qty: parseInt(size.qty),
                  images: size.images,
                }))
              : [],
            images: color.images,
          }))
        : [],
      sizes:
        editedProduct.has_size && !editedProduct.has_color
          ? editedProduct.sizes.map((size) => ({
              id: size.id, // Include the size ID if it exists
              name: size.name,
              price: parseFloat(size.price),
              qty: parseInt(size.qty),
              images: size.images,
            }))
          : [],
      price: editedProduct.price ? parseFloat(editedProduct.price) : null,
      qty: editedProduct.qty ? parseInt(editedProduct.qty) : null,
      images: editedProduct.images,
    };
    const token = getToken();

    if (!token) {
      toast.error("You must be logged in to edit the product.");
      return;
    }
    try {
      const response = await fetch(
        `http://localhost:4000/products/${editedProduct.id}`,
        {
          method: "PUT",
          headers: {
            "Content-Type": "application/json",
            Authorization: `Bearer ${token}`, // Include the token here
          },
          body: JSON.stringify(productData),
        },
      );

      if (!response.ok) {
        throw new Error("Failed to update product");
      }

      const updatedProduct = await response.json();
      console.log("Product updated:", updatedProduct);
      toast.success("Product updated successfully!");
      onClose();
    } catch (error) {
      console.error("Error updating product:", error);
      toast.error("Failed to update product. Please try again.");
    }
  };

  if (!isOpen) return null;

  return (
    <div className="fixed inset-0 z-[99999999] flex h-screen transform items-center justify-center overflow-y-scroll bg-black bg-opacity-50">
      <div className="relative h-screen w-full max-w-2xl overflow-y-scroll rounded-lg bg-white p-8">
        <button
          onClick={onClose}
          className="absolute right-4 top-4 text-gray-500 hover:text-gray-700"
        >
          <X size={24} />
        </button>

        <h2 className="mb-6 text-2xl font-bold">Edit Product</h2>

        <form onSubmit={handleSubmit} className="space-y-4">
          {/* Product Name */}
          <div>
            <label className="mb-2 block font-bold" htmlFor="name">
              Product Name
            </label>
            <input
              type="text"
              id="name"
              name="name"
              value={editedProduct.name}
              onChange={handleInputChange}
              className="w-full rounded-md border p-2"
              required
            />
          </div>

          {/* Description */}
          <div>
            <label className="mb-2 block font-bold" htmlFor="description">
              Description
            </label>
            <textarea
              id="description"
              name="description"
              value={editedProduct.description}
              onChange={handleInputChange}
              className="w-full rounded-md border p-2"
              style={{ direction: "rtl" }}
              required
            />
          </div>

          {/* Categories */}
          <div>
            <label className="mb-2 block font-bold">Categories</label>
            <div className="flex flex-wrap gap-2">
              {categories.map((category) => (
                <button
                  key={category.id}
                  type="button"
                  onClick={() => handleCategoryToggle(category.id)}
                  className={`rounded-full px-3 py-1 text-sm ${
                    editedProduct.categories.some(
                      // @ts-ignore
                      (cat) => cat.id === category.id,
                    )
                      ? "bg-blue-500 text-white"
                      : "bg-gray-200 text-gray-700"
                  }`}
                >
                  {category.name}
                </button>
              ))}
            </div>
          </div>

          {/* Brand */}
          <div>
            <label className="mb-2 block font-bold" htmlFor="brand">
              Brand
            </label>
            <select
              id="brand"
              name="brand"
              value={editedProduct.brand_id}
              onChange={handleBrandChange}
              className="w-full rounded-md border p-2"
              required
            >
              <option value="">Select a brand</option>
              {brands.map((brand) => (
                <option key={brand.id} value={brand.id}>
                  {brand.name}
                </option>
              ))}
            </select>
          </div>

          {/* Has Color */}
          <div>
            <label className="flex items-center">
              <input
                type="checkbox"
                checked={editedProduct.has_color}
                onChange={handleColorToggle}
                className="mr-2"
              />
              <span className="font-bold">Has Color?</span>
            </label>
          </div>

          {/* Colors */}
          {editedProduct.has_color && (
            <div>
              <label className="mb-2 block font-bold">Colors</label>
              <div className="space-y-4">
                {editedProduct.colors.map((color, colorIndex) => (
                  <div key={colorIndex} className="rounded-md border p-4">
                    <div className="mb-2 flex items-center justify-between">
                      <input
                        type="text"
                        value={color.name}
                        onChange={(e) =>
                          handleColorChange(colorIndex, "name", e.target.value)
                        }
                        className="mr-2 flex-grow rounded-md border p-2"
                        placeholder="Color name"
                      />
                      <button
                        type="button"
                        onClick={() => handleDeleteColor(colorIndex)}
                        className="text-red-500 hover:text-red-700"
                      >
                        <Trash2 size={20} />
                      </button>
                    </div>

                    <div className="mt-2 space-y-2">
                      <div className="flex space-x-2">
                        <input
                          type="number"
                          // @ts-ignore
                          value={color.price}
                          onChange={(e) =>
                            handleColorChange(
                              colorIndex,
                              "price",
                              e.target.value,
                            )
                          }
                          className="w-1/2 rounded-md border p-2"
                          placeholder="Price"
                        />
                        <input
                          type="number"
                          // @ts-ignore
                          value={color.qty}
                          onChange={(e) =>
                            handleColorChange(colorIndex, "qty", e.target.value)
                          }
                          className="w-1/2 rounded-md border p-2"
                          placeholder="Quantity"
                        />
                      </div>
                      <MultipartFileUploader
                        onUploadSuccess={(fileIds) =>
                          // @ts-ignore
                          handleImageUpload(fileIds, "color", colorIndex)
                        }
                        // @ts-ignore
                        existingImages={color.images}
                      />
                    </div>
                  </div>
                ))}
              </div>
              <button
                type="button"
                onClick={handleAddColor}
                className="mt-2 rounded-md bg-blue-500 px-4 py-2 text-white hover:bg-blue-600"
              >
                <Plus className="mr-1 inline-block" size={16} />
                Add Color
              </button>
            </div>
          )}

          {/* Has Size */}
          <div>
            <label className="flex items-center">
              <input
                type="checkbox"
                checked={editedProduct.has_size}
                onChange={handleSizeToggle}
                className="mr-2"
              />
              <span className="font-bold">Has Size?</span>
            </label>
          </div>

          {/* Sizes */}
          {editedProduct.has_size && (
            <div>
              <label className="mb-2 block font-bold">Sizes</label>
              <div className="space-y-2">
                {editedProduct.sizes.map((size, index) => (
                  <div key={index} className="space-y-2 rounded-md border p-2">
                    <div className="flex items-center justify-between">
                      <input
                        type="text"
                        value={size.name}
                        onChange={(e) =>
                          handleSizeChange(-1, index, "name", e.target.value)
                        }
                        className="mr-2 w-full rounded-md border p-2"
                        placeholder="Size name"
                      />
                      <button
                        type="button"
                        onClick={() => handleDeleteSize(-1, index)}
                        className="text-red-500 hover:text-red-700"
                      >
                        <Trash2 size={20} />
                      </button>
                    </div>
                    <div className="flex space-x-2">
                      <input
                        type="number"
                        value={size.price}
                        onChange={(e) =>
                          handleSizeChange(-1, index, "price", e.target.value)
                        }
                        className="w-1/2 rounded-md border p-2"
                        placeholder="Price"
                      />
                      <input
                        type="number"
                        value={size.qty}
                        onChange={(e) =>
                          handleSizeChange(-1, index, "qty", e.target.value)
                        }
                        className="w-1/2 rounded-md border p-2"
                        placeholder="Quantity"
                      />
                    </div>
                    {index > 0 && (
                      <label className="flex items-center">
                        <input
                          type="checkbox"
                          checked={size.inheritImages}
                          onChange={() =>
                            handleInheritImagesChange("size", -1, index)
                          }
                          className="mr-1"
                        />
                        <span>Inherit images</span>
                      </label>
                    )}
                    {!size.inheritImages && (
                      <MultipartFileUploader
                        onUploadSuccess={(fileIds) =>
                          handleImageUpload(fileIds, "size", -1, index)
                        }
                      />
                    )}
                  </div>
                ))}
                <button
                  type="button"
                  onClick={() => handleAddSize(-1)}
                  className="rounded-md bg-blue-500 px-4 py-2 text-white hover:bg-blue-600"
                >
                  <Plus className="mr-1 inline-block" size={16} />
                  Add Size
                </button>
              </div>
            </div>
          )}

          {/* Product Details (when no color and no size) */}
          {!product.has_color && !product.has_size && (
            <div>
              <label className="mb-2 block font-bold">Product Details</label>
              <div className="flex items-center space-x-2">
                <input
                  type="number"
                  // @ts-ignore
                  value={product.price}
                  onChange={(e) =>
                    handleInputChange({
                      target: { name: "price", value: e.target.value },
                    })
                  }
                  className="rounded-md border p-2"
                  placeholder="Price"
                />
                <input
                  type="number"
                  // @ts-ignore
                  value={product.qty}
                  onChange={(e) =>
                    handleInputChange({
                      target: { name: "qty", value: e.target.value },
                    })
                  }
                  className="rounded-md border p-2"
                  placeholder="Quantity"
                />
              </div>
              <div className="mt-2">
                <MultipartFileUploader
                  onUploadSuccess={(fileIds) =>
                    // @ts-ignore
                    handleImageUpload(fileIds, "product")
                  }
                />
              </div>
            </div>
          )}

          <div className="flex justify-end">
            <button
              type="submit"
              className="rounded-md bg-green-500 px-4 py-2 text-white hover:bg-green-600"
            >
              Edit Product
            </button>
          </div>
        </form>
      </div>
    </div>
  );
}
an example of json response:
{"products":[{"id":683,"name":"‏Creat 3D Whitestrip Superme Bright","description":"لصقات تبييض الاسنان مع  كرست بخطوات سهلة وسريعة  للحصول على ابتسامة ناصعة البياض\n-تتكون من عامل التبييض الآمن بالمينا\n-تقنية خالية من الانزلاق تظل ثابتة.\n-سهل الاستخدام للغاية يمكنك التبييض أثناء المشي والتحدث والعمل وحتى شرب الماء\n-طريقة الاستخدام:\nتستخدم مرة واحدة يوميا على اسنان نظيفة ضعي الشرائح على الفك العلوي والسفلي وازيليها بعد 45 دقيقة","brand_id":225,"has_color":false,"has_size":true,"product_type":"size","price":0,"qty":0,"sold":0,"created_at":"2024-09-09T09:40:47.835Z","updated_at":"2024-09-14T11:27:34.532Z","categories":[{"id":226,"name":"Teeth","main_category_id":23,"main_category_name":"Mouth Care"}],"colors":[],"sizes":[{"id":1258,"name":"1 strip","price":5000,"qty":76,"sold":0,"color_id":null,"images":["1795.webp"]},{"id":1259,"name":"20 strips","price":90000,"qty":5,"sold":0,"color_id":null,"images":[]}],"images":[{"id":2172,"url":"1795.webp","color_id":null,"size_id":1258}]},{"id":1237,"name":"test","description":"test","brand_id":73,"has_color":true,"has_size":false,"product_type":"color_size","price":0,"qty":0,"sold":0,"created_at":"2024-09-25T08:05:58.982Z","updated_at":"2024-09-25T08:05:58.982Z","categories":[{"id":178,"name":"Body Cleansers","main_category_id":2,"main_category_name":"Body Care"}],"colors":[{"id":57,"name":"green","price":50000,"qty":9,"sold":0,"has_size":false,"sizes":[],"images":[]},{"id":56,"name":"red","price":0,"qty":0,"sold":0,"has_size":true,"sizes":[{"id":3013,"name":"20ml","price":15000,"qty":10,"sold":0,"color_id":56,"images":["3066.jpg"]},{"id":3014,"name":"30ml","price":40000,"qty":2,"sold":0,"color_id":56,"images":["3066.jpg"]}],"images":["3066.jpg"]}],"sizes":[],"images":[{"id":199,"url":"3066.jpg","color_id":56,"size_id":3013},{"id":200,"url":"3066.jpg","color_id":56,"size_id":3014}]}],"total":2,"page":1,"itemsPerPage":15,"totalPages":1,"hasMore":false,"minPrice":0,"maxPrice":250000}
backend:
export const getProducts = async (req: Request, res: Response): Promise<void> => {
    try {
        // Retrieve cached products
        let cacheData: CacheData | undefined = productCache.get('cacheData');

        if (!cacheData) {
            // Cache miss: Load from DB and cache
            cacheData = await loadAndCacheAllProducts();
            console.log('Loaded products from database and cached them.');
        } else {
            console.log('Loaded products from cache.');
        }

        const { allProducts, minPrice, maxPrice } = cacheData;

        // Log total products before any filtering
        console.log(`Total products before filtering: ${allProducts.length}`);

        // Extract and sanitize query parameters
        let {
            search = '',
            c,
            sc,
            b,
            minPriceA = '0',
            maxPriceA = '',
            availability = 'all',
            sortBy = '',
            page = '1',
            itemsPerPage = '15',
        } = req.query;

        // Parse numerical values
        const pageNum = parseInt(page as string, 10) || 1;
        const itemsPerPageNum = parseInt(itemsPerPage as string, 10) || 15;
        const minPriceANum = parseFloat(minPriceA as string) || 0;
        let maxPriceANum = maxPriceA ? parseFloat(maxPriceA as string) : Infinity;

        // If maxPriceA is less than minPriceA, reset to Infinity
        if (!isNaN(maxPriceANum) && maxPriceANum < minPriceANum) {
            console.warn('Provided maxPriceA is less than minPriceA. Resetting maxPriceANum to Infinity.');
            maxPriceANum = Infinity;
        } else if (isNaN(maxPriceANum)) {
            maxPriceANum = Infinity;
        }

        // Parse c, sc, b as numbers if present
        const cNum = c ? parseInt(c as string, 10) : undefined;
        const scNum = sc ? parseInt(sc as string, 10) : undefined;
        const bNum = b ? parseInt(b as string, 10) : undefined;

        // Initialize brand-related variables if 'b' is provided
        let allBrands: Brand[] = [];
        if (bNum !== undefined && !isNaN(bNum)) {
            // Retrieve cached brands
            let brandsCacheData: BrandsCacheData | undefined = brandsCache.get('allBrands');

            if (!brandsCacheData) {
                // Cache miss: Load from DB and cache
                brandsCacheData = await loadAndCacheAllBrands();
                console.log('Loaded brands from database and cached them.');
            } else {
                console.log('Loaded brands from cache.');
            }
            console.log(brandsCacheData)
            allBrands = brandsCacheData.allBrands;

            // Check if 'bNum' is a valid brand ID
            const isValidBrand = allBrands.some(brand => brand.category_id === bNum);
            if (!isValidBrand) {
                console.warn(`Brand ID ${bNum} is invalid.`);
                // Return zero products since 'b' is invalid
                res.json({
                    products: [],
                    total: 0,
                    page: pageNum,
                    itemsPerPage: itemsPerPageNum,
                    totalPages: 0,
                    hasMore: false,
                    minPrice,
                    maxPrice,
                });
                return;
            }
        }

        // Start with all products
        let filteredProducts = [...allProducts];

        // Apply Search Filter
        if (search && typeof search === 'string') {
            const searchLower = search.toLowerCase();
            const searchWords = searchLower.split(/\s+/).filter(Boolean);
            filteredProducts = filteredProducts.filter(product =>
                searchWords.every(word => product.name.toLowerCase().includes(word))
            );
        }

        // Apply Category Filter (c)
        if (cNum !== undefined && !isNaN(cNum)) {
            filteredProducts = filteredProducts.filter(product =>
                product.categories.some(cat => cat.main_category_id === cNum)
            );
        }

        // Apply Subcategory Filter (sc)
        if (scNum !== undefined && !isNaN(scNum)) {
            filteredProducts = filteredProducts.filter(product =>
                product.brand_id === scNum ||
                product.categories.some(cat => cat.id === scNum)
            );
        }

        // Apply Brand Filter (b)
        if (bNum !== undefined && !isNaN(bNum)) {
            console.log(`Applying Brand Filter: brand_id === ${bNum}`);
            const preFilterCount = filteredProducts.length;
            allBrands = allBrands.filter(brand => brand.category_id === bNum)
            filteredProducts = filteredProducts.filter(product =>
                allBrands.some(brand => brand.id === product.brand_id)
            );
            console.log(`Filtered from ${preFilterCount} to ${filteredProducts.length} products after applying brand filter.`);
        }

        // Apply Price Range Filter
        if (minPriceANum > 0 || maxPriceANum < Infinity) {
            filteredProducts = filteredProducts.filter(product => {
                const productPrices = product.sizes.map(size => size.price);
                // If product has no sizes, exclude it
                if (productPrices.length === 0) return false;
                const productMinPrice = Math.min(...productPrices);
                const productMaxPrice = Math.max(...productPrices);
                return productMinPrice >= minPriceANum && productMaxPrice <= maxPriceANum;
            });
        }

        // Apply Availability Filter
        if (availability === 'in_stock') {
            filteredProducts = filteredProducts.filter(product =>
                product.sizes.some(size => size.qty > 0)
            );
        } else if (availability === 'out_of_stock') {
            filteredProducts = filteredProducts.filter(product =>
                product.sizes.every(size => size.qty === 0)
            );
        }

        // Log total after filtering
        console.log(`Total products after filtering: ${filteredProducts.length}`);

        // Apply Sorting
        if (sortBy && typeof sortBy === 'string') {
            switch (sortBy) {
                case 'Price: Low to High':
                    filteredProducts.sort((a, b) => {
                        const aMin = Math.min(...a.sizes.map(s => s.price));
                        const bMin = Math.min(...b.sizes.map(s => s.price));
                        return aMin - bMin;
                    });
                    break;
                case 'Price: High to Low':
                    filteredProducts.sort((a, b) => {
                        const aMax = Math.max(...a.sizes.map(s => s.price));
                        const bMax = Math.max(...b.sizes.map(s => s.price));
                        return bMax - aMax;
                    });
                    break;
                case 'Name: A to Z':
                    filteredProducts.sort((a, b) => a.name.localeCompare(b.name));
                    break;
                case 'Name: Z to A':
                    filteredProducts.sort((a, b) => b.name.localeCompare(a.name));
                    break;
                case 'Best Selling':
                    filteredProducts.sort((a, b) => b.sold - a.sold);
                    break;
                case 'Newest Arrivals':
                    filteredProducts.sort((a, b) => new Date(b.created_at).getTime() - new Date(a.created_at).getTime());
                    break;
                default:
                    // If sortBy parameter doesn't match any case, do not sort
                    break;
            }
        }

        // Apply Pagination
        const totalFilteredProducts = filteredProducts.length;
        const totalPages = Math.ceil(totalFilteredProducts / itemsPerPageNum);
        const startIdx = (pageNum - 1) * itemsPerPageNum;
        const endIdx = startIdx + itemsPerPageNum;
        const paginatedProducts = filteredProducts.slice(startIdx, endIdx);

        // Construct Response
        const response = {
            products: paginatedProducts,
            total: totalFilteredProducts,
            page: pageNum,
            itemsPerPage: itemsPerPageNum,
            totalPages,
            hasMore: endIdx < totalFilteredProducts,
            minPrice, // Global minPrice across all products
            maxPrice, // Global maxPrice across all products
        };

        // Send Response
        res.json(response);
    } catch (error) {
        console.error('Error fetching products:', error);
        res.status(500).json({ error: 'Internal server error' });
    } finally {
        // Optional: Any cleanup operations can be performed here
        // For example, monitoring memory usage or logging request completion
    }
};

ProductsPage:
// pages/products.tsx
"use client";

import React, {
  useState,
  useEffect,
  useCallback,
  useMemo,
  ChangeEvent,
} from "react";
import Head from "next/head";
import Image from "next/image";
import {
  Search,
  Grid,
  List,
  Plus,
  Edit,
  Trash2,
  ChevronLeft,
  ChevronRight,
} from "lucide-react";
import AddProductDialog from "@/components/AddProductDialog";
import EditProduct from "@/components/EditProduct";
import LoadingSpinner from "@/components/LoadingSpinner"; // Ensure this component matches the one in OrdersPage
import { ToastContainer, toast } from "react-toastify";
import "react-toastify/dist/ReactToastify.css";
import debounce from "lodash/debounce";
import { getToken } from "@/app/auth";
import {
  Product,
  Brand,
  ApiResponse,
  Category,
  Color,
  Size,
} from "@/components/types";

const formatDate = (dateString: string) => {
  const date = new Date(dateString);
  return date.toLocaleDateString(); // 'MM/DD/YYYY' format
};

const PRODUCTS_PER_PAGE = 15; // Adjusted as per JSON response's itemsPerPage

const ProductsPage: React.FC = () => {
  // State Variables
  const [products, setProducts] = useState<Product[]>([]);
  const [brands, setBrands] = useState<Brand[]>([]);
  const [brandMap, setBrandMap] = useState<{ [key: number]: string }>({});
  const [currentPage, setCurrentPage] = useState<number>(1);
  const [searchTerm, setSearchTerm] = useState<string>("");
  const [viewMode, setViewMode] = useState<"grid" | "list">("grid");
  const [sortBy, setSortBy] = useState<keyof Product>("created_at");
  const [sortOrder, setSortOrder] = useState<"asc" | "desc">("desc");
  const [isAddProductDialogOpen, setIsAddProductDialogOpen] =
    useState<boolean>(false);
  const [isEditProductDialogOpen, setIsEditProductDialogOpen] =
    useState<boolean>(false);
  const [productToEdit, setProductToEdit] = useState<Product | null>(null);
  const [isDeleteConfirmOpen, setIsDeleteConfirmOpen] =
    useState<boolean>(false);
  const [productToDelete, setProductToDelete] = useState<Product | null>(null);
  const [isDeleting, setIsDeleting] = useState<boolean>(false);
  const [totalPages, setTotalPages] = useState<number>(1);
  const [isLoading, setIsLoading] = useState<boolean>(false);
  const [searchInput, setSearchInput] = useState<string>("");

  // Debounce the search input to prevent excessive API calls
  const debouncedSearch = useMemo(
    () =>
      debounce((term: string) => {
        setSearchTerm(term);
        setCurrentPage(1);
      }, 300),
    [],
  );

  useEffect(() => {
    debouncedSearch(searchInput);
    return () => {
      debouncedSearch.cancel();
    };
  }, [searchInput, debouncedSearch]);

  const handleSearchChange = (e: ChangeEvent<HTMLInputElement>) => {
    setSearchInput(e.target.value);
  };

  // Fetch Brand Details
  const fetchBrands = useCallback(async () => {
    const token = getToken(); // Retrieve the token from localStorage

    if (!token) {
      toast.error("You must be logged in.");
      return;
    }

    try {
      const response = await fetch(
        `http://localhost:4000/subcategories/brands`,
        {
          headers: {
            "Content-Type": "application/json",
            Authorization: `Bearer ${token}`, // Include the token here
          },
        },
      );

      if (!response.ok) {
        throw new Error("Failed to fetch brands");
      }

      const data: Brand[] = await response.json();
      setBrands(data);

      // Create a mapping from brand_id to brand_name for easy lookup
      const map: { [key: number]: string } = {};
      data.forEach((brand) => {
        map[brand.id] = brand.name;
      });
      setBrandMap(map);
    } catch (error) {
      console.error("Error fetching brands:", error);
      toast.error("Failed to fetch brands. Please try again.");
    }
  }, []);

  // Fetch Products
  const fetchProducts = useCallback(async () => {
    setIsLoading(true);
    const token = getToken(); // Retrieve the token from localStorage

    if (!token) {
      toast.error("You must be logged in.");
      setIsLoading(false);
      return;
    }
    try {
      const response = await fetch(
        `http://localhost:4000/products?page=${currentPage}&limit=${PRODUCTS_PER_PAGE}&search=${encodeURIComponent(
          searchTerm,
        )}&sortBy=${sortBy}&sortOrder=${sortOrder}`,
        {
          cache: "no-cache",
          headers: {
            "Content-Type": "application/json",
            Authorization: `Bearer ${token}`, // Include the token here
          },
        },
      );
      if (!response.ok) {
        throw new Error("Failed to fetch products");
      }
      const data: ApiResponse = await response.json();
      setProducts(data.products);
      setTotalPages(data.totalPages);
    } catch (error) {
      console.error("Error fetching products:", error);
      toast.error("Failed to fetch products. Please try again.");
    } finally {
      setIsLoading(false);
    }
  }, [currentPage, searchTerm, sortBy, sortOrder]);

  useEffect(() => {
    fetchBrands();
  }, [fetchBrands]);

  useEffect(() => {
    fetchProducts();
  }, [fetchProducts]);

  const filteredProducts = useMemo(() => {
    return products
      .filter((product) =>
        product.name.toLowerCase().includes(searchTerm.toLowerCase()),
      )
      .sort((a, b) => {
        if (a[sortBy] === null) return 1;
        if (b[sortBy] === null) return -1;
        if (sortOrder === "asc") {
          return a[sortBy]!.toString().localeCompare(b[sortBy]!.toString());
        } else {
          return b[sortBy]!.toString().localeCompare(a[sortBy]!.toString());
        }
      });
  }, [products, searchTerm, sortBy, sortOrder]);

  const handleEditClick = useCallback((product: Product) => {
    setProductToEdit(product);
    setIsEditProductDialogOpen(true);
  }, []);

  const handleDeleteClick = useCallback((product: Product) => {
    setProductToDelete(product);
    setIsDeleteConfirmOpen(true);
  }, []);

  const handleDeleteConfirm = useCallback(async () => {
    if (productToDelete) {
      setIsDeleting(true);
      const token = getToken(); // the token from localStorage

      if (!token) {
        toast.error("You must be logged in.");
        setIsDeleting(false);
        return;
      }
      try {
        const response = await fetch(
          `http://localhost:4000/products/${productToDelete.id}`,
          {
            method: "DELETE",
            headers: {
              "Content-Type": "application/json",
              Authorization: `Bearer ${token}`, // Include the token here
            },
          },
        );

        if (!response.ok) {
          throw new Error("Failed to delete product");
        }

        setProducts((prevProducts) =>
          prevProducts.filter((p) => p.id !== productToDelete.id),
        );
        setIsDeleteConfirmOpen(false);
        toast.success("Product deleted successfully");
      } catch (error) {
        console.error("Error deleting product:", error);
        toast.error("Failed to delete product. Please try again.");
      } finally {
        setIsDeleting(false);
      }
    }
  }, [productToDelete]);

  // Helper function to get the first color's first size information
  const getFirstColorSizeInfo = useCallback((product: Product) => {
    if (product.has_color && product.has_size) {
      const firstColor = product.colors[0];
      if (firstColor) {
        const sizesForColor = product.sizes.filter(
          (size) => size.color_id === firstColor.id,
        );
        const firstSize = sizesForColor[0];
        if (firstSize) {
          return {
            colorName: firstColor.name,
            sizeName: firstSize.name,
            price: firstSize.price,
            qty: firstSize.qty,
            sold: Math.abs(firstSize.sold), // Ensuring 'sold' is absolute
          };
        }
      }
    }
    return null;
  }, []);

  // Updated helper functions to accommodate the new logic
  const getProductPrice = useCallback(
    (product: Product): string => {
      const colorSizeInfo = getFirstColorSizeInfo(product);
      if (colorSizeInfo) {
        return `$${colorSizeInfo.price.toLocaleString()}`;
      }
      if (!product.has_color && !product.has_size)
        return `$${product.price.toLocaleString()}`;
      if (product.colors.length > 0 && product.colors[0].price !== null)
        return `$${product.colors[0].price.toLocaleString()}`;
      if (product.sizes.length > 0)
        return `$${product.sizes[0].price.toLocaleString()}`;
      return "N/A";
    },
    [getFirstColorSizeInfo],
  );

  const getProductQuantity = useCallback(
    (product: Product): number | string => {
      const colorSizeInfo = getFirstColorSizeInfo(product);
      if (colorSizeInfo) {
        return colorSizeInfo.qty;
      }
      if (product.qty !== null && product.qty !== 0) return product.qty;
      if (product.colors.length > 0 && product.colors[0].qty !== null)
        return product.colors[0].qty;
      if (product.sizes.length > 0) return product.sizes[0].qty;
      return "N/A";
    },
    [getFirstColorSizeInfo],
  );

  const getProductSold = useCallback((product: Product): number => {
    let total = 0;
    if (product.colors) {
      product.colors.forEach((color) => {
        if (color.sizes.length > 0) {
          color.sizes.forEach((size) => (total += size.sold));
        } else {
          total += color.sold;
        }
      });
    }
    if (product.sizes) {
      product.sizes.forEach((size) => {
        total += size.sold;
      });
    }
    total += product.sold;
    return Math.abs(total);
  }, []);

  // Pagination Handler
  const handlePageChange = useCallback((newPage: number) => {
    setCurrentPage(newPage);
    window.scrollTo({ top: 0, behavior: "smooth" });
  }, []);

  return (
    <div className="font-sans min-h-screen bg-gray-100">
      <Head>
        <title>Products - Naay Store</title>
        <link rel="icon" href="/favicon.ico" />
        {/* Link to a better font, e.g., Inter from Google Fonts */}
        <link
          href="https://fonts.googleapis.com/css2?family=Inter:wght@400;600;700&display=swap"
          rel="stylesheet"
        />
      </Head>

      <main className="container mx-auto px-4 py-8">
        {/* Header Section */}
        <div className="mb-8 flex flex-col items-center justify-between space-y-4 md:flex-row md:space-y-0">
          <h1 className="text-3xl font-bold text-gray-900">All Products</h1>
          <button
            className="flex items-center rounded-md bg-green-500 px-4 py-2 text-white transition duration-300 hover:bg-green-600"
            onClick={() => setIsAddProductDialogOpen(true)}
          >
            <Plus className="mr-2" size={20} />
            Add Product
          </button>
        </div>

        {/* Search and Filters */}
        <div className="mb-8 flex flex-col items-center justify-between space-y-4 md:flex-row md:space-y-0">
          {/* Search */}
          <div className="relative w-full max-w-md">
            <input
              type="text"
              placeholder="Search products..."
              className="w-full rounded-lg border border-gray-300 py-2 pl-10 pr-4 focus:outline-none focus:ring-2 focus:ring-blue-500"
              value={searchInput}
              onChange={handleSearchChange}
            />
            <Search className="absolute left-3 top-2.5 h-5 w-5 text-gray-400" />
          </div>

          {/* Sort & Sort Order & View Modes */}
          <div className="flex items-center space-x-4">
            <select
              className="rounded-md border border-gray-300 px-3 py-2 focus:outline-none focus:ring-2 focus:ring-blue-500"
              value={sortBy}
              onChange={(e) => setSortBy(e.target.value as keyof Product)}
            >
              <option value="name">Sort by Name</option>
              <option value="price">Sort by Price</option>
              <option value="created_at">Sort by Created Date</option>
            </select>

            <select
              className="rounded-md border border-gray-300 px-3 py-2 focus:outline-none focus:ring-2 focus:ring-blue-500"
              value={sortOrder}
              onChange={(e) => setSortOrder(e.target.value as "asc" | "desc")}
            >
              <option value="asc">Ascending</option>
              <option value="desc">Descending</option>
            </select>

            <button
              className={`rounded-md p-2 ${
                viewMode === "grid" ? "bg-blue-500 text-white" : "bg-gray-200"
              }`}
              onClick={() => setViewMode("grid")}
              aria-label="Grid View"
            >
              <Grid className="h-5 w-5" />
            </button>
            <button
              className={`rounded-md p-2 ${
                viewMode === "list" ? "bg-blue-500 text-white" : "bg-gray-200"
              }`}
              onClick={() => setViewMode("list")}
              aria-label="List View"
            >
              <List className="h-5 w-5" />
            </button>
          </div>
        </div>

        {/* Product List */}
        {isLoading ? (
          <div className="flex justify-center">
            <LoadingSpinner /> {/* Same loader as OrdersPage */}
          </div>
        ) : (
          <div
            className={`grid gap-6 ${
              viewMode === "grid"
                ? "grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4"
                : "grid-cols-1"
            }`}
          >
            {filteredProducts.map((product) => {
              const colorSizeInfo = getFirstColorSizeInfo(product);
              // Remove displaying unnecessary fields like id and product_type
              return (
                <div
                  key={product.id}
                  className={`overflow-hidden rounded-lg bg-white shadow-md ${
                    viewMode === "list" ? "flex" : ""
                  } transition-transform hover:scale-105`}
                >
                  {/* Product Image */}
                  <div
                    className={`${
                      viewMode === "list" ? "w-1/3" : "w-full"
                    } relative pb-[100%]`}
                  >
                    {product.images.length > 0 ? (
                      <Image
                        src={`https://storage.naayiq.com/resources/${product.images[0].url}`}
                        alt={product.name}
                        fill={true}
                        className="object-cover"
                        priority={false}
                        loading="lazy"
                      />
                    ) : (
                      <div className="flex items-center justify-center bg-gray-200">
                        <span className="text-gray-500">No Image</span>
                      </div>
                    )}
                  </div>

                  {/* Product Details */}
                  <div className={`p-4 ${viewMode === "list" ? "w-2/3" : ""}`}>
                    <h2 className="mb-2 text-xl font-semibold text-gray-800">
                      {product.name}
                    </h2>
                    <p
                      className="mb-4 text-sm text-gray-700"
                      style={{ direction: "rtl" }}
                      dangerouslySetInnerHTML={{
                        __html: product.description.replace(/\n/g, "<br />"),
                      }}
                    />
                    <div className="mb-4 space-y-1">
                      {/* Display Price */}
                      <p className="text-sm text-gray-600">
                        <span className="font-semibold">Price:</span>{" "}
                        {getProductPrice(product)}
                      </p>
                      {/* Display Quantity */}
                      <p className="text-sm text-gray-600">
                        <span className="font-semibold">Quantity:</span>{" "}
                        {getProductQuantity(product)}
                      </p>
                      {/* Display Sold */}
                      <p className="text-sm text-gray-600">
                        <span className="font-semibold">Sold:</span>{" "}
                        {getProductSold(product)}
                      </p>
                      {/* Display Created At */}
                      <p className="text-sm text-gray-600">
                        <span className="font-semibold">Created at:</span>{" "}
                        {formatDate(product.created_at)}
                      </p>
                      {/* Display Has Color */}
                      <p className="text-sm text-gray-600">
                        <span className="font-semibold">Has Color:</span>{" "}
                        {product.has_color ? "Yes" : "No"}
                      </p>
                      {/* Display Has Size */}
                      <p className="text-sm text-gray-600">
                        <span className="font-semibold">Has Size:</span>{" "}
                        {product.has_size ? "Yes" : "No"}
                      </p>
                      {/* Display Brand */}
                      <p className="text-sm text-gray-600">
                        <span className="font-semibold">Brand:</span>{" "}
                        {brandMap[product.brand_id] ||
                          `ID: ${product.brand_id}`}
                      </p>
                      {/* Display Categories */}
                      <p className="text-sm text-gray-600">
                        <span className="font-semibold">Category:</span>{" "}
                        {product.categories
                          .map((category) => category.name)
                          .join(", ")}
                      </p>
                      {/* Display First Color's First Size Information */}
                      {colorSizeInfo && (
                        <div className="mt-2">
                          <p className="text-sm text-gray-600">
                            <span className="font-semibold">Color:</span>{" "}
                            {colorSizeInfo.colorName}
                          </p>
                          <p className="text-sm text-gray-600">
                            <span className="font-semibold">Size:</span>{" "}
                            {colorSizeInfo.sizeName}
                          </p>
                          <p className="text-sm text-gray-600">
                            <span className="font-semibold">Price:</span> $
                            {colorSizeInfo.price.toLocaleString()}
                          </p>
                          <p className="text-sm text-gray-600">
                            <span className="font-semibold">Quantity:</span>{" "}
                            {colorSizeInfo.qty}
                          </p>
                          <p className="text-sm text-gray-600">
                            <span className="font-semibold">Sold:</span>{" "}
                            {colorSizeInfo.sold}
                          </p>
                        </div>
                      )}
                    </div>

                    {/* Action Buttons */}
                    <div className="flex space-x-2">
                      <button
                        className="flex items-center rounded-md bg-blue-500 px-4 py-2 text-white transition duration-300 hover:bg-blue-600"
                        onClick={() => handleEditClick(product)}
                      >
                        <Edit className="mr-1 inline-block" size={16} />
                        Edit
                      </button>
                      <button
                        className="flex items-center rounded-md bg-red px-4 py-2 text-white transition duration-300 hover:bg-danger"
                        onClick={() => handleDeleteClick(product)}
                      >
                        <Trash2 className="mr-1 inline-block" size={16} />
                        Delete
                      </button>
                    </div>
                  </div>
                </div>
              );
            })}
          </div>
        )}

        {/* Pagination Controls */}
        {!isLoading && totalPages > 1 && (
          <div className="mt-8 flex items-center justify-center space-x-2">
            <button
              className="rounded-md bg-gray-200 px-3 py-1 text-sm text-gray-700 disabled:cursor-not-allowed disabled:opacity-50"
              onClick={() => handlePageChange(Math.max(currentPage - 1, 1))}
              disabled={currentPage === 1}
            >
              Previous
            </button>

            {/* Condensed Pagination with Ellipsis */}
            {Array.from({ length: totalPages }, (_, i) => i + 1)
              .filter(
                (number) =>
                  number === 1 ||
                  number === totalPages ||
                  (number >= currentPage - 1 && number <= currentPage + 1),
              )
              .map((number, index, array) => {
                if (index > 0 && number - array[index - 1] > 1) {
                  return (
                    <span key={`ellipsis-${number}`} className="text-gray-500">
                      ...
                    </span>
                  );
                }
                return (
                  <button
                    key={number}
                    className={`rounded-md px-3 py-1 text-sm ${
                      currentPage === number
                        ? "bg-blue-500 text-white"
                        : "bg-gray-200 text-gray-700"
                    }`}
                    onClick={() => handlePageChange(number)}
                  >
                    {number}
                  </button>
                );
              })}

            <button
              className="rounded-md bg-gray-200 px-3 py-1 text-sm text-gray-700 disabled:cursor-not-allowed disabled:opacity-50"
              onClick={() =>
                handlePageChange(Math.min(currentPage + 1, totalPages))
              }
              disabled={currentPage === totalPages}
            >
              Next
            </button>
          </div>
        )}
      </main>

      {/* Add Product Dialog */}
      {isAddProductDialogOpen && (
        <AddProductDialog
          isOpen={isAddProductDialogOpen}
          onClose={() => setIsAddProductDialogOpen(false)}
          onProductAdded={(newProduct: Product) => {
            setProducts((prevProducts) => [newProduct, ...prevProducts]);
            toast.success("Product added successfully!");
          }}
        />
      )}

      {/* Edit Product Dialog */}
      {isEditProductDialogOpen && productToEdit && (
        <EditProduct
          isOpen={isEditProductDialogOpen}
          onClose={() => {
            setIsEditProductDialogOpen(false);
            setProductToEdit(null);
            fetchProducts(); // Refresh the product list after editing
          }}
          product={productToEdit}
          onProductUpdated={(updatedProduct: Product) => {
            setProducts((prevProducts) =>
              prevProducts.map((prod) =>
                prod.id === updatedProduct.id ? updatedProduct : prod,
              ),
            );
            toast.success("Product updated successfully!");
          }}
        />
      )}

      {/* Delete Confirmation Modal */}
      {isDeleteConfirmOpen && (
        <div className="fixed inset-0 z-50 flex items-center justify-center bg-black bg-opacity-50">
          <div className="w-11/12 max-w-md rounded-lg bg-white p-8">
            <h2 className="mb-4 text-xl font-semibold text-gray-800">
              Confirm Delete
            </h2>
            <p className="mb-8 text-gray-600">
              Are you sure you want to delete{" "}
              <span className="font-semibold">
                {productToDelete?.name ?? "this product"}
              </span>
              ?
            </p>
            <div className="flex justify-end space-x-4">
              <button
                className="flex items-center rounded-md bg-red px-4 py-2 text-white transition duration-300 hover:bg-danger"
                onClick={handleDeleteConfirm}
                disabled={isDeleting}
              >
                <Trash2 className="mr-1 inline-block" size={16} />
                {isDeleting ? "Deleting..." : "Yes, Delete"}
              </button>
              <button
                className="rounded-md bg-gray-300 px-4 py-2 text-gray-700 transition duration-300 hover:bg-gray-400"
                onClick={() => setIsDeleteConfirmOpen(false)}
                disabled={isDeleting}
              >
                Cancel
              </button>
            </div>
          </div>
        </div>
      )}

      {/* Toast Notifications */}
      <ToastContainer />
    </div>
  );
};

export default React.memo(ProductsPage);
types.ts:
// pages/products.tsx
"use client";

import React, {
  useState,
  useEffect,
  useCallback,
  useMemo,
  ChangeEvent,
} from "react";
import Head from "next/head";
import Image from "next/image";
import {
  Search,
  Grid,
  List,
  Plus,
  Edit,
  Trash2,
  ChevronLeft,
  ChevronRight,
} from "lucide-react";
import AddProductDialog from "@/components/AddProductDialog";
import EditProduct from "@/components/EditProduct";
import LoadingSpinner from "@/components/LoadingSpinner"; // Ensure this component matches the one in OrdersPage
import { ToastContainer, toast } from "react-toastify";
import "react-toastify/dist/ReactToastify.css";
import debounce from "lodash/debounce";
import { getToken } from "@/app/auth";
import {
  Product,
  Brand,
  ApiResponse,
  Category,
  Color,
  Size,
} from "@/components/types";

const formatDate = (dateString: string) => {
  const date = new Date(dateString);
  return date.toLocaleDateString(); // 'MM/DD/YYYY' format
};

const PRODUCTS_PER_PAGE = 15; // Adjusted as per JSON response's itemsPerPage

const ProductsPage: React.FC = () => {
  // State Variables
  const [products, setProducts] = useState<Product[]>([]);
  const [brands, setBrands] = useState<Brand[]>([]);
  const [brandMap, setBrandMap] = useState<{ [key: number]: string }>({});
  const [currentPage, setCurrentPage] = useState<number>(1);
  const [searchTerm, setSearchTerm] = useState<string>("");
  const [viewMode, setViewMode] = useState<"grid" | "list">("grid");
  const [sortBy, setSortBy] = useState<keyof Product>("created_at");
  const [sortOrder, setSortOrder] = useState<"asc" | "desc">("desc");
  const [isAddProductDialogOpen, setIsAddProductDialogOpen] =
    useState<boolean>(false);
  const [isEditProductDialogOpen, setIsEditProductDialogOpen] =
    useState<boolean>(false);
  const [productToEdit, setProductToEdit] = useState<Product | null>(null);
  const [isDeleteConfirmOpen, setIsDeleteConfirmOpen] =
    useState<boolean>(false);
  const [productToDelete, setProductToDelete] = useState<Product | null>(null);
  const [isDeleting, setIsDeleting] = useState<boolean>(false);
  const [totalPages, setTotalPages] = useState<number>(1);
  const [isLoading, setIsLoading] = useState<boolean>(false);
  const [searchInput, setSearchInput] = useState<string>("");

  // Debounce the search input to prevent excessive API calls
  const debouncedSearch = useMemo(
    () =>
      debounce((term: string) => {
        setSearchTerm(term);
        setCurrentPage(1);
      }, 300),
    [],
  );

  useEffect(() => {
    debouncedSearch(searchInput);
    return () => {
      debouncedSearch.cancel();
    };
  }, [searchInput, debouncedSearch]);

  const handleSearchChange = (e: ChangeEvent<HTMLInputElement>) => {
    setSearchInput(e.target.value);
  };

  // Fetch Brand Details
  const fetchBrands = useCallback(async () => {
    const token = getToken(); // Retrieve the token from localStorage

    if (!token) {
      toast.error("You must be logged in.");
      return;
    }

    try {
      const response = await fetch(
        `http://localhost:4000/subcategories/brands`,
        {
          headers: {
            "Content-Type": "application/json",
            Authorization: `Bearer ${token}`, // Include the token here
          },
        },
      );

      if (!response.ok) {
        throw new Error("Failed to fetch brands");
      }

      const data: Brand[] = await response.json();
      setBrands(data);

      // Create a mapping from brand_id to brand_name for easy lookup
      const map: { [key: number]: string } = {};
      data.forEach((brand) => {
        map[brand.id] = brand.name;
      });
      setBrandMap(map);
    } catch (error) {
      console.error("Error fetching brands:", error);
      toast.error("Failed to fetch brands. Please try again.");
    }
  }, []);

  // Fetch Products
  const fetchProducts = useCallback(async () => {
    setIsLoading(true);
    const token = getToken(); // Retrieve the token from localStorage

    if (!token) {
      toast.error("You must be logged in.");
      setIsLoading(false);
      return;
    }
    try {
      const response = await fetch(
        `http://localhost:4000/products?page=${currentPage}&limit=${PRODUCTS_PER_PAGE}&search=${encodeURIComponent(
          searchTerm,
        )}&sortBy=${sortBy}&sortOrder=${sortOrder}`,
        {
          cache: "no-cache",
          headers: {
            "Content-Type": "application/json",
            Authorization: `Bearer ${token}`, // Include the token here
          },
        },
      );
      if (!response.ok) {
        throw new Error("Failed to fetch products");
      }
      const data: ApiResponse = await response.json();
      setProducts(data.products);
      setTotalPages(data.totalPages);
    } catch (error) {
      console.error("Error fetching products:", error);
      toast.error("Failed to fetch products. Please try again.");
    } finally {
      setIsLoading(false);
    }
  }, [currentPage, searchTerm, sortBy, sortOrder]);

  useEffect(() => {
    fetchBrands();
  }, [fetchBrands]);

  useEffect(() => {
    fetchProducts();
  }, [fetchProducts]);

  const filteredProducts = useMemo(() => {
    return products
      .filter((product) =>
        product.name.toLowerCase().includes(searchTerm.toLowerCase()),
      )
      .sort((a, b) => {
        if (a[sortBy] === null) return 1;
        if (b[sortBy] === null) return -1;
        if (sortOrder === "asc") {
          return a[sortBy]!.toString().localeCompare(b[sortBy]!.toString());
        } else {
          return b[sortBy]!.toString().localeCompare(a[sortBy]!.toString());
        }
      });
  }, [products, searchTerm, sortBy, sortOrder]);

  const handleEditClick = useCallback((product: Product) => {
    setProductToEdit(product);
    setIsEditProductDialogOpen(true);
  }, []);

  const handleDeleteClick = useCallback((product: Product) => {
    setProductToDelete(product);
    setIsDeleteConfirmOpen(true);
  }, []);

  const handleDeleteConfirm = useCallback(async () => {
    if (productToDelete) {
      setIsDeleting(true);
      const token = getToken(); // the token from localStorage

      if (!token) {
        toast.error("You must be logged in.");
        setIsDeleting(false);
        return;
      }
      try {
        const response = await fetch(
          `http://localhost:4000/products/${productToDelete.id}`,
          {
            method: "DELETE",
            headers: {
              "Content-Type": "application/json",
              Authorization: `Bearer ${token}`, // Include the token here
            },
          },
        );

        if (!response.ok) {
          throw new Error("Failed to delete product");
        }

        setProducts((prevProducts) =>
          prevProducts.filter((p) => p.id !== productToDelete.id),
        );
        setIsDeleteConfirmOpen(false);
        toast.success("Product deleted successfully");
      } catch (error) {
        console.error("Error deleting product:", error);
        toast.error("Failed to delete product. Please try again.");
      } finally {
        setIsDeleting(false);
      }
    }
  }, [productToDelete]);

  // Helper function to get the first color's first size information
  const getFirstColorSizeInfo = useCallback((product: Product) => {
    if (product.has_color && product.has_size) {
      const firstColor = product.colors[0];
      if (firstColor) {
        const sizesForColor = product.sizes.filter(
          (size) => size.color_id === firstColor.id,
        );
        const firstSize = sizesForColor[0];
        if (firstSize) {
          return {
            colorName: firstColor.name,
            sizeName: firstSize.name,
            price: firstSize.price,
            qty: firstSize.qty,
            sold: Math.abs(firstSize.sold), // Ensuring 'sold' is absolute
          };
        }
      }
    }
    return null;
  }, []);

  // Updated helper functions to accommodate the new logic
  const getProductPrice = useCallback(
    (product: Product): string => {
      const colorSizeInfo = getFirstColorSizeInfo(product);
      if (colorSizeInfo) {
        return `$${colorSizeInfo.price.toLocaleString()}`;
      }
      if (!product.has_color && !product.has_size)
        return `$${product.price.toLocaleString()}`;
      if (product.colors.length > 0 && product.colors[0].price !== null)
        return `$${product.colors[0].price.toLocaleString()}`;
      if (product.sizes.length > 0)
        return `$${product.sizes[0].price.toLocaleString()}`;
      return "N/A";
    },
    [getFirstColorSizeInfo],
  );

  const getProductQuantity = useCallback(
    (product: Product): number | string => {
      const colorSizeInfo = getFirstColorSizeInfo(product);
      if (colorSizeInfo) {
        return colorSizeInfo.qty;
      }
      if (product.qty !== null && product.qty !== 0) return product.qty;
      if (product.colors.length > 0 && product.colors[0].qty !== null)
        return product.colors[0].qty;
      if (product.sizes.length > 0) return product.sizes[0].qty;
      return "N/A";
    },
    [getFirstColorSizeInfo],
  );

  const getProductSold = useCallback((product: Product): number => {
    let total = 0;
    if (product.colors) {
      product.colors.forEach((color) => {
        if (color.sizes.length > 0) {
          color.sizes.forEach((size) => (total += size.sold));
        } else {
          total += color.sold;
        }
      });
    }
    if (product.sizes) {
      product.sizes.forEach((size) => {
        total += size.sold;
      });
    }
    total += product.sold;
    return Math.abs(total);
  }, []);

  // Pagination Handler
  const handlePageChange = useCallback((newPage: number) => {
    setCurrentPage(newPage);
    window.scrollTo({ top: 0, behavior: "smooth" });
  }, []);

  return (
    <div className="font-sans min-h-screen bg-gray-100">
      <Head>
        <title>Products - Naay Store</title>
        <link rel="icon" href="/favicon.ico" />
        {/* Link to a better font, e.g., Inter from Google Fonts */}
        <link
          href="https://fonts.googleapis.com/css2?family=Inter:wght@400;600;700&display=swap"
          rel="stylesheet"
        />
      </Head>

      <main className="container mx-auto px-4 py-8">
        {/* Header Section */}
        <div className="mb-8 flex flex-col items-center justify-between space-y-4 md:flex-row md:space-y-0">
          <h1 className="text-3xl font-bold text-gray-900">All Products</h1>
          <button
            className="flex items-center rounded-md bg-green-500 px-4 py-2 text-white transition duration-300 hover:bg-green-600"
            onClick={() => setIsAddProductDialogOpen(true)}
          >
            <Plus className="mr-2" size={20} />
            Add Product
          </button>
        </div>

        {/* Search and Filters */}
        <div className="mb-8 flex flex-col items-center justify-between space-y-4 md:flex-row md:space-y-0">
          {/* Search */}
          <div className="relative w-full max-w-md">
            <input
              type="text"
              placeholder="Search products..."
              className="w-full rounded-lg border border-gray-300 py-2 pl-10 pr-4 focus:outline-none focus:ring-2 focus:ring-blue-500"
              value={searchInput}
              onChange={handleSearchChange}
            />
            <Search className="absolute left-3 top-2.5 h-5 w-5 text-gray-400" />
          </div>

          {/* Sort & Sort Order & View Modes */}
          <div className="flex items-center space-x-4">
            <select
              className="rounded-md border border-gray-300 px-3 py-2 focus:outline-none focus:ring-2 focus:ring-blue-500"
              value={sortBy}
              onChange={(e) => setSortBy(e.target.value as keyof Product)}
            >
              <option value="name">Sort by Name</option>
              <option value="price">Sort by Price</option>
              <option value="created_at">Sort by Created Date</option>
            </select>

            <select
              className="rounded-md border border-gray-300 px-3 py-2 focus:outline-none focus:ring-2 focus:ring-blue-500"
              value={sortOrder}
              onChange={(e) => setSortOrder(e.target.value as "asc" | "desc")}
            >
              <option value="asc">Ascending</option>
              <option value="desc">Descending</option>
            </select>

            <button
              className={`rounded-md p-2 ${
                viewMode === "grid" ? "bg-blue-500 text-white" : "bg-gray-200"
              }`}
              onClick={() => setViewMode("grid")}
              aria-label="Grid View"
            >
              <Grid className="h-5 w-5" />
            </button>
            <button
              className={`rounded-md p-2 ${
                viewMode === "list" ? "bg-blue-500 text-white" : "bg-gray-200"
              }`}
              onClick={() => setViewMode("list")}
              aria-label="List View"
            >
              <List className="h-5 w-5" />
            </button>
          </div>
        </div>

        {/* Product List */}
        {isLoading ? (
          <div className="flex justify-center">
            <LoadingSpinner /> {/* Same loader as OrdersPage */}
          </div>
        ) : (
          <div
            className={`grid gap-6 ${
              viewMode === "grid"
                ? "grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4"
                : "grid-cols-1"
            }`}
          >
            {filteredProducts.map((product) => {
              const colorSizeInfo = getFirstColorSizeInfo(product);
              // Remove displaying unnecessary fields like id and product_type
              return (
                <div
                  key={product.id}
                  className={`overflow-hidden rounded-lg bg-white shadow-md ${
                    viewMode === "list" ? "flex" : ""
                  } transition-transform hover:scale-105`}
                >
                  {/* Product Image */}
                  <div
                    className={`${
                      viewMode === "list" ? "w-1/3" : "w-full"
                    } relative pb-[100%]`}
                  >
                    {product.images.length > 0 ? (
                      <Image
                        src={`https://storage.naayiq.com/resources/${product.images[0].url}`}
                        alt={product.name}
                        fill={true}
                        className="object-cover"
                        priority={false}
                        loading="lazy"
                      />
                    ) : (
                      <div className="flex items-center justify-center bg-gray-200">
                        <span className="text-gray-500">No Image</span>
                      </div>
                    )}
                  </div>

                  {/* Product Details */}
                  <div className={`p-4 ${viewMode === "list" ? "w-2/3" : ""}`}>
                    <h2 className="mb-2 text-xl font-semibold text-gray-800">
                      {product.name}
                    </h2>
                    <p
                      className="mb-4 text-sm text-gray-700"
                      style={{ direction: "rtl" }}
                      dangerouslySetInnerHTML={{
                        __html: product.description.replace(/\n/g, "<br />"),
                      }}
                    />
                    <div className="mb-4 space-y-1">
                      {/* Display Price */}
                      <p className="text-sm text-gray-600">
                        <span className="font-semibold">Price:</span>{" "}
                        {getProductPrice(product)}
                      </p>
                      {/* Display Quantity */}
                      <p className="text-sm text-gray-600">
                        <span className="font-semibold">Quantity:</span>{" "}
                        {getProductQuantity(product)}
                      </p>
                      {/* Display Sold */}
                      <p className="text-sm text-gray-600">
                        <span className="font-semibold">Sold:</span>{" "}
                        {getProductSold(product)}
                      </p>
                      {/* Display Created At */}
                      <p className="text-sm text-gray-600">
                        <span className="font-semibold">Created at:</span>{" "}
                        {formatDate(product.created_at)}
                      </p>
                      {/* Display Has Color */}
                      <p className="text-sm text-gray-600">
                        <span className="font-semibold">Has Color:</span>{" "}
                        {product.has_color ? "Yes" : "No"}
                      </p>
                      {/* Display Has Size */}
                      <p className="text-sm text-gray-600">
                        <span className="font-semibold">Has Size:</span>{" "}
                        {product.has_size ? "Yes" : "No"}
                      </p>
                      {/* Display Brand */}
                      <p className="text-sm text-gray-600">
                        <span className="font-semibold">Brand:</span>{" "}
                        {brandMap[product.brand_id] ||
                          `ID: ${product.brand_id}`}
                      </p>
                      {/* Display Categories */}
                      <p className="text-sm text-gray-600">
                        <span className="font-semibold">Category:</span>{" "}
                        {product.categories
                          .map((category) => category.name)
                          .join(", ")}
                      </p>
                      {/* Display First Color's First Size Information */}
                      {colorSizeInfo && (
                        <div className="mt-2">
                          <p className="text-sm text-gray-600">
                            <span className="font-semibold">Color:</span>{" "}
                            {colorSizeInfo.colorName}
                          </p>
                          <p className="text-sm text-gray-600">
                            <span className="font-semibold">Size:</span>{" "}
                            {colorSizeInfo.sizeName}
                          </p>
                          <p className="text-sm text-gray-600">
                            <span className="font-semibold">Price:</span> $
                            {colorSizeInfo.price.toLocaleString()}
                          </p>
                          <p className="text-sm text-gray-600">
                            <span className="font-semibold">Quantity:</span>{" "}
                            {colorSizeInfo.qty}
                          </p>
                          <p className="text-sm text-gray-600">
                            <span className="font-semibold">Sold:</span>{" "}
                            {colorSizeInfo.sold}
                          </p>
                        </div>
                      )}
                    </div>

                    {/* Action Buttons */}
                    <div className="flex space-x-2">
                      <button
                        className="flex items-center rounded-md bg-blue-500 px-4 py-2 text-white transition duration-300 hover:bg-blue-600"
                        onClick={() => handleEditClick(product)}
                      >
                        <Edit className="mr-1 inline-block" size={16} />
                        Edit
                      </button>
                      <button
                        className="flex items-center rounded-md bg-red px-4 py-2 text-white transition duration-300 hover:bg-danger"
                        onClick={() => handleDeleteClick(product)}
                      >
                        <Trash2 className="mr-1 inline-block" size={16} />
                        Delete
                      </button>
                    </div>
                  </div>
                </div>
              );
            })}
          </div>
        )}

        {/* Pagination Controls */}
        {!isLoading && totalPages > 1 && (
          <div className="mt-8 flex items-center justify-center space-x-2">
            <button
              className="rounded-md bg-gray-200 px-3 py-1 text-sm text-gray-700 disabled:cursor-not-allowed disabled:opacity-50"
              onClick={() => handlePageChange(Math.max(currentPage - 1, 1))}
              disabled={currentPage === 1}
            >
              Previous
            </button>

            {/* Condensed Pagination with Ellipsis */}
            {Array.from({ length: totalPages }, (_, i) => i + 1)
              .filter(
                (number) =>
                  number === 1 ||
                  number === totalPages ||
                  (number >= currentPage - 1 && number <= currentPage + 1),
              )
              .map((number, index, array) => {
                if (index > 0 && number - array[index - 1] > 1) {
                  return (
                    <span key={`ellipsis-${number}`} className="text-gray-500">
                      ...
                    </span>
                  );
                }
                return (
                  <button
                    key={number}
                    className={`rounded-md px-3 py-1 text-sm ${
                      currentPage === number
                        ? "bg-blue-500 text-white"
                        : "bg-gray-200 text-gray-700"
                    }`}
                    onClick={() => handlePageChange(number)}
                  >
                    {number}
                  </button>
                );
              })}

            <button
              className="rounded-md bg-gray-200 px-3 py-1 text-sm text-gray-700 disabled:cursor-not-allowed disabled:opacity-50"
              onClick={() =>
                handlePageChange(Math.min(currentPage + 1, totalPages))
              }
              disabled={currentPage === totalPages}
            >
              Next
            </button>
          </div>
        )}
      </main>

      {/* Add Product Dialog */}
      {isAddProductDialogOpen && (
        <AddProductDialog
          isOpen={isAddProductDialogOpen}
          onClose={() => setIsAddProductDialogOpen(false)}
          onProductAdded={(newProduct: Product) => {
            setProducts((prevProducts) => [newProduct, ...prevProducts]);
            toast.success("Product added successfully!");
          }}
        />
      )}

      {/* Edit Product Dialog */}
      {isEditProductDialogOpen && productToEdit && (
        <EditProduct
          isOpen={isEditProductDialogOpen}
          onClose={() => {
            setIsEditProductDialogOpen(false);
            setProductToEdit(null);
            fetchProducts(); // Refresh the product list after editing
          }}
          product={productToEdit}
          onProductUpdated={(updatedProduct: Product) => {
            setProducts((prevProducts) =>
              prevProducts.map((prod) =>
                prod.id === updatedProduct.id ? updatedProduct : prod,
              ),
            );
            toast.success("Product updated successfully!");
          }}
        />
      )}

      {/* Delete Confirmation Modal */}
      {isDeleteConfirmOpen && (
        <div className="fixed inset-0 z-50 flex items-center justify-center bg-black bg-opacity-50">
          <div className="w-11/12 max-w-md rounded-lg bg-white p-8">
            <h2 className="mb-4 text-xl font-semibold text-gray-800">
              Confirm Delete
            </h2>
            <p className="mb-8 text-gray-600">
              Are you sure you want to delete{" "}
              <span className="font-semibold">
                {productToDelete?.name ?? "this product"}
              </span>
              ?
            </p>
            <div className="flex justify-end space-x-4">
              <button
                className="flex items-center rounded-md bg-red px-4 py-2 text-white transition duration-300 hover:bg-danger"
                onClick={handleDeleteConfirm}
                disabled={isDeleting}
              >
                <Trash2 className="mr-1 inline-block" size={16} />
                {isDeleting ? "Deleting..." : "Yes, Delete"}
              </button>
              <button
                className="rounded-md bg-gray-300 px-4 py-2 text-gray-700 transition duration-300 hover:bg-gray-400"
                onClick={() => setIsDeleteConfirmOpen(false)}
                disabled={isDeleting}
              >
                Cancel
              </button>
            </div>
          </div>
        </div>
      )}

      {/* Toast Notifications */}
      <ToastContainer />
    </div>
  );
};

export default React.memo(ProductsPage);
// types.ts
export interface Size {
  id: number;
  name: string;
  price: number;
  qty: number;
  sold: number;
  color_id: number | null;
  images: string[];
}

export interface Color {
  id: number;
  name: string;
  price: number | null;
  qty: number | null;
  sold: number;
  sizes: Size[];
  images: string;
}

export interface ImageType {
  id: number;
  url: string;
  color_id: number | null;
  size_id: number | null;
}

export interface Category {
  id: number;
  name: string;
  main_category_id: number;
  main_category_name: string;
}

export interface Product {
  id: number;
  name: string;
  description: string;
  brand_id: number;
  has_color: boolean;
  has_size: boolean;
  product_type: string;
  price: number;
  qty: number;
  sold: number;
  created_at: string;
  updated_at: string;
  categories: Category[];
  colors: Color[];
  sizes: Size[];
  images: ImageType[];
}

export interface ApiResponse {
  products: Product[];
  total: number;
  page: number;
  itemsPerPage: number;
  totalPages: number;
  hasMore: boolean;
}

export interface Brand {
  id: number;
  name: string;
}