Error fetching products: TypeError: data.pagination is undefined
instead of pagination
the json will return a result like this:
{"products":[{"id":6,"name":"‏Anua Heartleaf Pore Clay Pack","description":"يقوم هذا القناع الطيني الكريمي بأمتصاص الزهم الزائد و إزالة الرؤوس السوداء بشكل فعال داخل المسام بسبب احتوائه Houttuynia Cordata الذي يتحكم في الدهون\nيحتوي على الكاولين لامتصاص الدهون\nيحتوي على مادة البنتونيت لتضييق المسام\nيحتوي على كيرسيتينول و هو المكون الرئيسي لأوراق القلب يوفر تهدئة البشرة ويتحكم في الدهون الزائدة لإزالة مشاكل المسام\nيعمل ايضا على إذابة خلايا الجلد الميتة القديمة على الجلد بلطف دون أي تهيج إضافة إلى تنعيم البشرة","brand_id":117,"has_color":false,"has_size":true,"product_type":"size","price":0,"qty":0,"sold":0,"created_at":"2024-08-23T21:51:27.907Z","updated_at":"2024-09-10T13:58:17.276Z","categories":[{"id":175,"name":"Masks","main_category_id":1,"main_category_name":"Face Care"}],"colors":[],"sizes":[{"id":1418,"name":"100 ML","price":22000,"qty":118,"sold":0,"color_id":null,"images":["1048.webp"]}],"images":[{"id":1588,"url":"1048.webp","color_id":null,"size_id":1418}]},{"id":7,"name":"‏Anua Heartleaf Pore Control CleanSsing Oil","description":"غسول منظف زيتي بالهارت ليف للمسامات من انوا\nمنظف زيتي بتركيبة لا تسبب انسداد المسامات ويحتوي على زيوت نباتية (بما في ذلك زيت الجوجوبا وفاكهة الزيتون وبذور العنب)، ويخلص البشرة من الشوائب بشكل فعال مع ترك لمسة نهائية منتعشة ورطبة. مناسب للبشرة المعرضة للحبوب.\nمميزاته وفوائده:\n‏* non-comedogenic تركيبة لا تسد المسامات مناسبة للبشرة الدهنية والمعرضة للحبوب\n* مستخلص هارتليف (houttuynia cordata) معروف جيدًا بتأثيره المضاد للالتهابات والمهدئ للبشرة.\n* مزيل مكياج خفيف يساعد على إزالة الشوائب في المسامات.\n* لا يحتوي على أي مواد مهيجة.\n* يحافظ على رطوبة بشرتك بعد التنظيف.\n* يناسب جميع انواع البشرات حتى الحساسة.","brand_id":117,"has_color":false,"has_size":true,"product_type":"size","price":0,"qty":0,"sold":0,"created_at":"2024-08-23T21:54:49.385Z","updated_at":"2024-09-23T15:58:27.136Z","categories":[{"id":168,"name":"Face Cleansers","main_category_id":1,"main_category_name":"Face Care"}],"colors":[],"sizes":[{"id":1428,"name":"200 ML","price":25000,"qty":100,"sold":0,"color_id":null,"images":["1049.webp"]}],"images":[{"id":24,"url":"1049.webp","color_id":null,"size_id":1428}]},{"id":8,"name":"‏ANUA Heartleaf Quercerinol Pore Deep Cleansing Foam","description":"غسول رغوي بالهارت ليف كيرسيتينول للتنظيف العميق للمسام من انوا \nتم تصميم رغوة التنظيف هذه خصيصا لأنواع البشرة المختلطة والدهنية ، واستهداف الدهون الزائدة وتنظيف المسام بشكل فعال عن طريق إزالة خلايا الجلد الميتة المتراكمة والشوائب\nمميزات وفوائد:\nيحتوي على مسحوق أوراق القلب المطحون ناعما ، مما يساعد على تطهير الأوساخ وخلايا الجلد الميتة من زوايا المسام.\nغني بالمكون المضاد للدهون الحاصل على براءة اختراع ، فهو يحافظ على شعور البشرة بالانتعاش بعد التنظيف ويساعد على معالجة مخاوف الدهون الزائدة.","brand_id":117,"has_color":false,"has_size":true,"product_type":"size","price":0,"qty":0,"sold":0,"created_at":"2024-08-23T21:59:34.747Z","updated_at":"2024-09-24T10:58:39.386Z","categories":[{"id":168,"name":"Face Cleansers","main_category_id":1,"main_category_name":"Face Care"}],"colors":[],"sizes":[{"id":1429,"name":"150 ML","price":25000,"qty":126,"sold":0,"color_id":null,"images":["1050.webp"]}],"images":[{"id":59,"url":"1050.webp","color_id":null,"size_id":1429}]},{"id":9,"name":"‏La Roche Effaclar Astringent Lotion","description":"تونر للبشرة الدهنية و المعرضة للحبوب من la roche \n-يعمل على تقليل حجم المسام بشكل ملحوظ بعد إستخدامه بفضل مكوناته الفعٌالة التي تعمل على تنظيم الإفراز الدهني للوجه و تقشيره بلطف ويقلل من انسداد المسام المسببة لحب الشباب.\n-تلطيف البشرة وموازنة درجة الحموضة بعد خطوة التنظيف مما يعمل معادلة للبشره ولا يسبب جفاف للبشره \n-تنظيف عميق للمسام وإزالة بقايا الجلد الميت من مناطق الجلد التي غالبًا ما تُترك عند غسل وجهك.\n-تساعد المياه المعدنية La Roche-Posay على تهدئة البشرة وحمايتها ومضادات الأكسدة.","brand_id":70,"has_color":false,"has_size":true,"product_type":"size","price":0,"qty":0,"sold":0,"created_at":"2024-08-24T12:29:54.092Z","updated_at":"2024-09-18T06:42:49.283Z","categories":[{"id":169,"name":"Toners","main_category_id":1,"main_category_name":"Face Care"}],"colors":[],"sizes":[{"id":1431,"name":"200 ml","price":25000,"qty":19,"sold":0,"color_id":null,"images":["1052.jpeg"]}],"images":[{"id":3283,"url":"1052.jpeg","color_id":null,"size_id":1431}]},{"id":11,"name":"Aveeno Daily Moisturising Hand Cream","description":"مرطب يد يومي من أفينو\nيتكون من دقيق الشوفان، تعمل هذه التركيبة سريعة الامتصاص على ترطيب البشرة لمدة 24 ساعة، فهو يساعد على حماية وتغذية اليد العادية إلى الجافة. يمنحك بشرة صحية وأكثر مرونة من الاستخدام الأول، لا يحتوي عطور و مناسب لبشرة اليد الحساسة.","brand_id":86,"has_color":false,"has_size":true,"product_type":"size","price":0,"qty":0,"sold":0,"created_at":"2024-08-24T12:43:56.173Z","updated_at":"2024-09-10T18:04:29.869Z","categories":[{"id":163,"name":"Hand moisturiser","main_category_id":6,"main_category_name":"Hand Care"}],"colors":[],"sizes":[{"id":1430,"name":"75 ml","price":12000,"qty":10,"sold":0,"color_id":null,"images":["1056.jpeg"]}],"images":[{"id":1600,"url":"1056.jpeg","color_id":null,"size_id":1430}]},{"id":12,"name":"La Roche Posay Thermal Spring Water","description":"‏سبري ملطف ومرطب للبشره الحساسة المتهيجة بسبب العوامل الخارجية (الشمس ووسائل العناية بالبشرة وغيرها...) ويساعد على منع تقدم عمر الجلد. مضاد طبيعي للأكسدة.يمنح المزيج الفريد من المعادن والعناصر النادرة مثل السيلينيوم، ومياه الينابيع الحرارية من لاروش بوزيه خصائص مثبتة علميًا في الترطيب والنعومة ومضاد للأكسدة. تركيبة دقيقة. مناسب للكبار والأطفال.","brand_id":70,"has_color":false,"has_size":true,"product_type":"size","price":0,"qty":0,"sold":0,"created_at":"2024-08-24T12:50:28.619Z","updated_at":"2024-09-17T18:17:11.779Z","categories":[{"id":193,"name":"Mist","main_category_id":1,"main_category_name":"Face Care"}],"colors":[],"sizes":[{"id":899,"name":"150 ml","price":15000,"qty":51,"sold":0,"color_id":null,"images":["1057.jpeg"]}],"images":[{"id":3232,"url":"1057.jpeg","color_id":null,"size_id":899}]},{"id":14,"name":"La Roche Posay Effaclar Medicated Acne Face Wash","description":"غسول منظف لحب الشباب من la roche posay.\nيزيل الزيوت الزائدة ويعمل على إزالة حب الشباب. \nيحتوي على:\n2٪ حمض الساليسيليك: معروف بخصائصه الفعالة في التقشير للمساعدة في تنظيف وتنقية ظهور المسام.\nحمض ليبو هيدروكسي: المعروف أيضًا باسم LHA ، وهو مشتق من حمض الساليسيليك ، وله خصائص تقشير وتجديد البشرة.\nالجلسرين: مشتق من مصادر نباتية ، وهو مرطب ممتاز. يساعد على ترطيب البشرة عن طريق امتصاص الماء من البيئة المحيطة.\nمناسب لجميع انواع البشرة","brand_id":70,"has_color":false,"has_size":true,"product_type":"size","price":0,"qty":0,"sold":0,"created_at":"2024-08-24T13:02:33.887Z","updated_at":"2024-09-17T18:29:30.996Z","categories":[{"id":168,"name":"Face Cleansers","main_category_id":1,"main_category_name":"Face Care"}],"colors":[],"sizes":[{"id":1433,"name":"200 ml","price":30000,"qty":12,"sold":0,"color_id":null,"images":["1062.jpeg"]}],"images":[{"id":3234,"url":"1062.jpeg","color_id":null,"size_id":1433}]},{"id":21,"name":"La Roche Posay Anthelios Anti Shine Fresh Mist Spf50 Facial Sunscreen","description":"واقي شمس سبري شفاف يعطي أقصى حماية للوجه من الأشعة فوق البنفسجية الضارة, بعامل وقايه spf 50 يثبت المكياج و يقاوم المياه, يمتص في ثلاث ثواني و لا يترك علامات بيضاء ومضاد للدهون والتعرق \nيناسب جميع أنواع البشرة والبشرة الحساسة والبشرة التي لا تحتمل التعرض للشمس والمعروفة باسم حساسية الشمس.","brand_id":70,"has_color":false,"has_size":true,"product_type":"size","price":0,"qty":0,"sold":0,"created_at":"2024-08-24T13:49:25.525Z","updated_at":"2024-09-23T12:12:41.239Z","categories":[{"id":173,"name":"Face Sunscreens","main_category_id":1,"main_category_name":"Face Care"}],"colors":[],"sizes":[{"id":586,"name":"75 ml","price":25000,"qty":73,"sold":0,"color_id":null,"images":["1069.jpeg"]}],"images":[{"id":7,"url":"1069.jpeg","color_id":null,"size_id":586}]},{"id":24,"name":"La Roche Posay Cicaplast Balm B5","description":"كريم سيكابلاست من لاروش بوساي\n-تهدئة البشرة المتهيجة خاصة بعد جلسات الديرما بن الديرما رولر وجلسات ليزر \n-تعمل على الاصلاح والحماية\nويساعد البشرة على التعافي من (التهيج ،التشقق ، والبقع الخشنه )\nمميزات المنتج :\nيعرف بانه كريم معالج سريع عند حدوث اي شي يسبب في تهيج او احمرار للبشره.. \nمناسب للحروق ولتحسس.","brand_id":70,"has_color":false,"has_size":true,"product_type":"size","price":0,"qty":0,"sold":0,"created_at":"2024-08-24T13:58:32.728Z","updated_at":"2024-09-17T18:19:42.086Z","categories":[{"id":172,"name":"Face moisturiser","main_category_id":1,"main_category_name":"Face Care"}],"colors":[],"sizes":[{"id":587,"name":"40 ml","price":25000,"qty":141,"sold":-6,"color_id":null,"images":["1071.jpeg"]}],"images":[{"id":3233,"url":"1071.jpeg","color_id":null,"size_id":587}]},{"id":25,"name":"La Roche posay Cicaplast levres","description":"بلسم ملطف للشفاه من الجفاف ويحميها ويلطفها\nلعلاج التهاب و تشقق الشفتين الناتج من الجفاف حيث يقوم بترطيب واعادة نمو الطبقة الواقية للشفتين وإزالة الإسمرار واللون الغامق للشفتين\nحيث أنه يعمل على تكوين حاجز بتركيبته الفريدة المحتوية على 5% بانثينول لمنحك إنتعاش سريع، و البروتين الدهني (Mp_lipids) الذي يساعد على ترميم الحاجز الحامي للبشرة\nيمكن استخدامها للاطفال والكبار","brand_id":70,"has_color":false,"has_size":true,"product_type":"size","price":0,"qty":0,"sold":0,"created_at":"2024-08-24T14:01:07.105Z","updated_at":"2024-09-17T07:47:45.902Z","categories":[{"id":153,"name":"Lip Balm","main_category_id":5,"main_category_name":"Lip Care"}],"colors":[],"sizes":[{"id":588,"name":"7.5 ml","price":15000,"qty":24,"sold":0,"color_id":null,"images":["1072.jpeg"]}],"images":[{"id":2914,"url":"1072.jpeg","color_id":null,"size_id":588}]},{"id":26,"name":"La Roche Posay Pure Vitamin C10 Serum","description":"سيروم فيتامين بتركيزC10 من الفيتامين النقي، محلول مضاد للتجاعيد ، يحتوي على فيتامين C  النقي ، وحمض الساليسيليك والنيوسينسين للكشف عن النضارة الكاملة للبشرة الحساسة .\nيعالج فقدان النضارة ، والبشرة الغير ،مستوية التجاعيد.\nسيروم فريد من نوعه مضاد لعلامات تقدم سن البشرة ومركّز بمكونات عالية من فيتامين C النقي ، مع حمض الساليسيليك والنسوسينسين الملطف ، مع درجة حموضة فسيولوجية ، للكشف عن النضارة الكاملة للبشرة الحساسة.\nعلى الفور، تبدو البشرة أكثر نعومة، نضارة و ترطيب.\nتقل التجاعيد والخطوط الدقيقة. كما لو تحولت، يبدو ملمس البشرة ولونها أكثر تناسقًا و تستعيد البشرة إشراقتها الكاملة.\nيطبق في الصباح على الوجه والعنق. تجنب منطقة العين. يستخدم مع واقي من الشمس يومي.","brand_id":70,"has_color":false,"has_size":true,"product_type":"size","price":0,"qty":0,"sold":0,"created_at":"2024-08-24T14:04:30.261Z","updated_at":"2024-09-17T18:43:24.198Z","categories":[{"id":170,"name":"Serums","main_category_id":1,"main_category_name":"Face Care"}],"colors":[],"sizes":[{"id":1653,"name":"30 ml","price":55000,"qty":23,"sold":0,"color_id":null,"images":["1968.jpeg"]}],"images":[{"id":3241,"url":"1968.jpeg","color_id":null,"size_id":1653}]},{"id":27,"name":"La Roche Posay Hyalu B5 Serum","description":"سيروم الهيالورونيك أسيد وفيتامين B5 من لاروش \nمضاد للتجاعيد، وفقدان الحجم والمرونة، للعناية بالبشرة الضعيفة والمتعبة\n⁣\nيتعلق الأمر بوصفة فريدة لإعادة الحيوية للبشرة تمزج بين نوعين من حمض الهياليرونيك الخالص، وفيتامين B5، ومادة الماديكاسوزيد، لإعادة إشراق البشرة، وإصلاح حاجزها الجلدي، وبالتالي تحسين عملية تجديد ⁣خلايا البشرة\n⁣يحفز انتاج الكولاجين ويحافظ على رطوبة ومرونة البشرة من اول استعمال⁣","brand_id":70,"has_color":false,"has_size":true,"product_type":"size","price":0,"qty":0,"sold":0,"created_at":"2024-08-24T14:08:42.412Z","updated_at":"2024-09-17T18:33:03.986Z","categories":[{"id":170,"name":"Serums","main_category_id":1,"main_category_name":"Face Care"}],"colors":[],"sizes":[{"id":31,"name":"30 ml","price":55000,"qty":32,"sold":0,"color_id":null,"images":["1074.jpeg"]}],"images":[{"id":3236,"url":"1074.jpeg","color_id":null,"size_id":31}]},{"id":28,"name":"La Roche Posay Retinol B3 Serum","description":"سيروم الريتنول من La roche \n-يعمل الريتنول على منع ظهور علامات التقدم بالسن حيث يعمل فيتامين A على اختراق طبقات الجلد ويعمل على تحفيز الجلد والكولاجين وبالتالي يقلل من ظهور التجاعيد والخطوط الدقيقه \n-يعمل الريتنول على البقع الداكنه حيث يعمل على تقليل التصبغات والبقع الداكنه وبذلك يعمل على توحيد لون البشره \n-يعمل على ترطيب الجلد ويقلل من تهيج البشره ويقلل من ظهور حب الشباب وكذلك يعمل على زيادة اشراقه البشره","brand_id":70,"has_color":false,"has_size":true,"product_type":"size","price":0,"qty":0,"sold":0,"created_at":"2024-08-24T14:11:37.469Z","updated_at":"2024-09-23T15:51:16.057Z","categories":[{"id":170,"name":"Serums","main_category_id":1,"main_category_name":"Face Care"}],"colors":[],"sizes":[{"id":1652,"name":"30 ml","price":55000,"qty":1,"sold":0,"color_id":null,"images":["1967.jpeg"]}],"images":[{"id":21,"url":"1967.jpeg","color_id":null,"size_id":1652}]},{"id":31,"name":"La Roche Posay Nutritic Lips","description":"مرطب الشفاه من لاروش \n-مرطب للشفاه حيث يمتاز بفعاليته الكبرى على ترطيب الشفاه وتخليصها من الجفاف والتشققات\n-يوفر مرطب الشفاه التغذيه اللازمه من الفيتامينات والعناصر اللازمه\n-يعطي شفاه جميله ورطبة ومحميه لمده ٢٤ساعه","brand_id":70,"has_color":false,"has_size":true,"product_type":"size","price":0,"qty":0,"sold":0,"created_at":"2024-08-24T15:45:00.777Z","updated_at":"2024-09-17T18:44:29.075Z","categories":[{"id":153,"name":"Lip Balm","main_category_id":5,"main_category_name":"Lip Care"}],"colors":[],"sizes":[{"id":585,"name":"4.7","price":15000,"qty":3,"sold":0,"color_id":null,"images":["1084.jpeg"]}],"images":[{"id":3243,"url":"1084.jpeg","color_id":null,"size_id":585}]},{"id":34,"name":"Acm Depiwhite Eye Contour Gel","description":"جل يمتاز بفعاليته لمعالجة مشاكل حول العين من ACM\n-يعمل على التخلص من الهالات السوداء والانتفاخ تحت العين \n-يحتوي على عناصر طبيعية لإزالة البقع الداكنة \n-يقوم بأزالة الخطوط الرفيعه تحت العين التي تسبب مظهر التجاعيد والتقدم بالعمر عن طريق تقويه الشعيرات الدمويه \n- يحتوي على احماض البرتقال والجلسرين وزيت الخروع والمستخلصات الطبيعية","brand_id":73,"has_color":false,"has_size":true,"product_type":"size","price":0,"qty":0,"sold":0,"created_at":"2024-08-24T15:56:35.130Z","updated_at":"2024-09-17T18:37:17.704Z","categories":[{"id":159,"name":"Eye Cream","main_category_id":4,"main_category_name":"Eye Care"}],"colors":[],"sizes":[{"id":790,"name":"15 ml","price":22000,"qty":6,"sold":0,"color_id":null,"images":["1697.jpeg"]}],"images":[{"id":3239,"url":"1697.jpeg","color_id":null,"size_id":790}]}],"total":810,"page":1,"itemsPerPage":15,"totalPages":54,"hasMore":true,"minPrice":0,"maxPrice":250000}
there is no pagination...
Also optimize the performance and reduce re renders...
except when editing or adding or removing a new product of course the api should fetch again... as it is now I guess...
"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 } from "lucide-react";
import AddProductDialog from "@/components/AddProductDialog";
import { ToastContainer, toast } from "react-toastify";
import "react-toastify/dist/ReactToastify.css";
import debounce from "lodash/debounce";
import EditProduct from "@/components/EditProduct";
import { getToken } from "@/app/auth";

const formatDate = (dateString: string) => {
  const date = new Date(dateString);
  return date.toISOString().split("T")[0]; // This will give you 'yyyy-mm-dd'
};

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

interface Color {
  id: number;
  name: string;
  price: number | null;
  qty: number | null;
}

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

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

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

interface ApiResponse {
  products: Product[];
  pagination: {
    currentPage: number;
    totalPages: number;
    totalProducts: number;
    limit: number;
  };
}

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

const PRODUCTS_PER_PAGE = 10;

export default function ProductsPage() {
  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>("name");
  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);
      console.log(brandMap);
    } 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,
        )}`,
        {
          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.pagination.totalPages);
    } catch (error) {
      console.error("Error fetching products:", error);
      toast.error("Failed to fetch products. Please try again.");
    } finally {
      setIsLoading(false);
    }
  }, [currentPage, searchTerm]);

  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;
        return a[sortBy]!.toString().localeCompare(b[sortBy]!.toString());
      });
  }, [products, searchTerm, sortBy]);

  const handleEditClick = (product: Product) => {
    setProductToEdit(product);
    setIsEditProductDialogOpen(true);
  };

  const renderPagination = () => {
    const pageNumbers = [];
    const maxVisiblePages = 5;
    let startPage = Math.max(1, currentPage - Math.floor(maxVisiblePages / 2));
    let endPage = Math.min(totalPages, startPage + maxVisiblePages - 1);

    if (endPage - startPage + 1 < maxVisiblePages) {
      startPage = Math.max(1, endPage - maxVisiblePages + 1);
    }

    for (let i = startPage; i <= endPage; i++) {
      pageNumbers.push(i);
    }

    const handlePageChange = (newPage: number) => {
      setCurrentPage(newPage);
      window.scrollTo({ top: 0, behavior: "smooth" });
    };

    return (
      <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:opacity-50"
          onClick={() => handlePageChange(Math.max(currentPage - 1, 1))}
          disabled={currentPage === 1}
        >
          Previous
        </button>
        {startPage > 1 && (
          <>
            <button
              className="rounded-md px-3 py-1 text-sm text-gray-700"
              onClick={() => handlePageChange(1)}
            >
              1
            </button>
            {startPage > 2 && <span className="text-gray-500">...</span>}
          </>
        )}
        {pageNumbers.map((number) => (
          <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>
        ))}
        {endPage < totalPages && (
          <>
            {endPage < totalPages - 1 && (
              <span className="text-gray-500">...</span>
            )}
            <button
              className="rounded-md px-3 py-1 text-sm text-gray-700"
              onClick={() => handlePageChange(totalPages)}
            >
              {totalPages}
            </button>
          </>
        )}
        <button
          className="rounded-md bg-gray-200 px-3 py-1 text-sm text-gray-700 disabled:opacity-50"
          onClick={() =>
            handlePageChange(Math.min(currentPage + 1, totalPages))
          }
          disabled={currentPage === totalPages}
        >
          Next
        </button>
      </div>
    );
  };

  const handleEditClose = () => {
    setIsEditProductDialogOpen(false);
    setProductToEdit(null);
    fetchProducts(); // Refresh the product list after editing
  };

  const handleDeleteClick = (product: Product) => {
    setProductToDelete(product);
    setIsDeleteConfirmOpen(true);
  };

  const handleDeleteConfirm = 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(products.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);
      }
    }
  };

  // Helper function to get the first color's first size information
  const getFirstColorSizeInfo = (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 = (product: Product): string => {
    const colorSizeInfo = getFirstColorSizeInfo(product);
    if (colorSizeInfo) {
      return `$${colorSizeInfo.price.toLocaleString()}`;
    }
    if (!product.has_color && !product.has_size && product.price !== null)
      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";
  };

  const getProductQuantity = (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";
  };

  const getProductSold = (product: Product): number => {
    // Ensure 'sold' is always positive
    return Math.abs(product.sold);
  };

  return (
    <div className="min-h-screen bg-gray-100">
      <Head>
        <title>Products - Naay Store</title>
        <link rel="icon" href="/favicon.ico" />
      </Head>

      <main className="container mx-auto px-4 py-8">
        <div className="mb-8 flex items-center justify-between">
          <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>

        <div className="mb-8 flex flex-col items-center justify-between md:flex-row">
          <div className="relative mb-4 w-full md:mb-0 md:w-96">
            <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>

          <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="created_at">Sort by Created At</option>
              <option value="product_type">Sort by Product Type</option>
            </select>

            <button
              className={`rounded-md p-2 ${
                viewMode === "grid" ? "bg-blue-500 text-white" : "bg-gray-200"
              }`}
              onClick={() => setViewMode("grid")}
            >
              <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")}
            >
              <List className="h-5 w-5" />
            </button>
          </div>
        </div>

        {isLoading ? (
          <p className="text-center text-gray-700">Loading...</p>
        ) : (
          <div
            className={`grid ${
              viewMode === "grid"
                ? "grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4"
                : "grid-cols-1"
            } gap-6`}
          >
            {filteredProducts.map((product) => {
              const colorSizeInfo = getFirstColorSizeInfo(product);
              return (
                <div
                  key={product.id}
                  className={`overflow-hidden rounded-lg bg-white shadow-md ${
                    viewMode === "list" ? "flex" : ""
                  }`}
                >
                  <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"
                      />
                    )}
                  </div>
                  <div className={`p-4 ${viewMode === "list" ? "w-2/3" : ""}`}>
                    <h2 className="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">
                      {/* 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 Product Type */}
                      <p className="text-sm text-gray-600">
                        <span className="font-semibold">Product Type:</span>{" "}
                        {product.product_type}
                      </p>
                      {/* ===== New Labels ===== */}
                      {/* 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>
                      {/* ===== End of New Labels ===== */}
                      {/* ===== 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">Size Price:</span> $
                            {colorSizeInfo.price.toLocaleString()}
                          </p>
                          <p className="text-sm text-gray-600">
                            <span className="font-semibold">
                              Size Quantity:
                            </span>{" "}
                            {colorSizeInfo.qty}
                          </p>
                          <p className="text-sm text-gray-600">
                            <span className="font-semibold">Size Sold:</span>{" "}
                            {colorSizeInfo.sold}
                          </p>
                        </div>
                      )}
                      {/* ===== End of Color's Size Info ===== */}
                    </div>
                    <div className="space-x-2">
                      <button
                        className="rounded-md bg-blue-500 px-4 py-2 text-white transition duration-300 hover:bg-blue-600"
                        onClick={() => {
                          console.log(product);
                          handleEditClick(product);
                        }}
                      >
                        <Edit className="mr-1 inline-block" size={16} />
                        Edit
                      </button>
                      <button
                        className="bg-red-500 hover:bg-red-600 rounded-md px-4 py-2 text-white transition duration-300"
                        onClick={() => handleDeleteClick(product)}
                      >
                        <Trash2 className="mr-1 inline-block" size={16} />
                        Delete
                      </button>
                    </div>
                  </div>
                </div>
              );
            })}
          </div>
        )}

        {renderPagination()}
      </main>

      {isAddProductDialogOpen && (
        <AddProductDialog
          isOpen={isAddProductDialogOpen}
          onClose={() => setIsAddProductDialogOpen(false)}
        />
      )}

      {isDeleteConfirmOpen && (
        <div className="fixed inset-0 z-50 flex items-center justify-center bg-black bg-opacity-50">
          <div className="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="space-x-4">
              <button
                className="bg-red-500 hover:bg-red-600 rounded-md px-4 py-2 text-white transition duration-300"
                onClick={handleDeleteConfirm}
                disabled={isDeleting}
              >
                {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>
      )}
      {isEditProductDialogOpen && productToEdit && (
        <EditProduct
          isOpen={isEditProductDialogOpen}
          onClose={handleEditClose}
          // @ts-ignore
          product={productToEdit}
        />
      )}

      <ToastContainer />
    </div>
  );
}