From 629133beeb7f5668b63db61e415cf844d513cde7 Mon Sep 17 00:00:00 2001
From: FIN-IT_AndriFP <andrifebriyadiputra@gmail.com>
Date: Thu, 27 Nov 2025 14:30:30 +0700
Subject: (andri) view from magento

---
 .../product-detail/components/ProductDetail.tsx    | 127 +++++++++++++++++----
 1 file changed, 103 insertions(+), 24 deletions(-)

(limited to 'src-migrate/modules/product-detail/components/ProductDetail.tsx')

diff --git a/src-migrate/modules/product-detail/components/ProductDetail.tsx b/src-migrate/modules/product-detail/components/ProductDetail.tsx
index e4ba2b2f..1bacd2e2 100644
--- a/src-migrate/modules/product-detail/components/ProductDetail.tsx
+++ b/src-migrate/modules/product-detail/components/ProductDetail.tsx
@@ -4,9 +4,22 @@ import Link from 'next/link';
 import { useRouter } from 'next/router';
 import { useEffect, useRef, useState, UIEvent } from 'react';
 
-import { Button } from '@chakra-ui/react';
+// Import komponen Chakra UI yang dibutuhkan
+import { 
+  Button, 
+  Tabs, 
+  TabList, 
+  TabPanels, 
+  Tab, 
+  TabPanel, 
+  Table, 
+  Tbody, 
+  Tr, 
+  Td,
+  Box
+} from '@chakra-ui/react';
+
 import {
-  AlertCircle,
   AlertTriangle,
   MessageCircleIcon,
   Share2Icon,
@@ -62,7 +75,6 @@ const ProductDetail = ({ product }: Props) => {
     setIsApproval,
     isApproval,
     setSelectedVariant,
-    setSla,
   } = useProductDetail();
 
   useEffect(() => {
@@ -136,11 +148,15 @@ const ProductDetail = ({ product }: Props) => {
   const scrollToIndex = (i: number) => {
     const el = sliderRef.current;
     if (!el) return;
-    el.scrollTo({ left: i * el.clientWidth, behavior: 'smooth' });
+    const elRef = sliderRef.current;
+    elRef.scrollTo({ left: i * elRef.clientWidth, behavior: 'smooth' });
     setCurrentIdx(i);
     setMainImage(allImages[i] || '');
   };
 
+  console.log('detail product render');
+  console.log('product: ', product);
+
   return (
     <>
       <div className='relative'>
@@ -195,7 +211,6 @@ const ProductDetail = ({ product }: Props) => {
                           key={i}
                           className='w-full flex-shrink-0 snap-center flex justify-center items-center'
                         >
-                          {/* gambar diperkecil */}
                           <img
                             src={img}
                             alt={`Gambar ${i + 1}`}
@@ -218,7 +233,6 @@ const ProductDetail = ({ product }: Props) => {
                     )}
                   </div>
 
-                  {/* Dots indicator */}
                   {allImages.length > 1 && (
                     <div className='absolute bottom-2 left-0 right-0 flex justify-center gap-2'>
                       {allImages.map((_, i) => (
@@ -238,8 +252,6 @@ const ProductDetail = ({ product }: Props) => {
                 <>
                   {/* === DESKTOP: Tetap seperti sebelumnya === */}
                   <ProductImage product={{ ...product, image: mainImage }} />
-
-                  {/* Carousel horizontal (thumbnail) – hanya desktop */}
                   {allImages.length > 0 && (
                     <div className='mt-4 overflow-x-auto'>
                       <div className='flex space-x-3 pb-3'>
@@ -271,7 +283,6 @@ const ProductDetail = ({ product }: Props) => {
                 </>
               )}
             </div>
-            {/* <<=== TUTUP kolom kiri */}
 
             {/* ===== Kolom kanan: info ===== */}
             {isDesktop && (
@@ -332,21 +343,89 @@ const ProductDetail = ({ product }: Props) => {
 
             <div className='h-0 md:h-6' />
 
+            {/* === SECTION TABS: DESKRIPSI & SPESIFIKASI === */}
             <div className={style['section-card']}>
-              <h2 className={style['heading']}>Informasi Produk</h2>
-              <div className='h-4' />
-              <div className='overflow-x-auto'>
-                <div
-                  className={style['description']}
-                  dangerouslySetInnerHTML={{
-                    __html:
-                      !product.description ||
-                      product.description == '<p><br></p>'
-                        ? 'Belum ada deskripsi'
-                        : product.description,
-                  }}
-                />
-              </div>
+              <Tabs variant="unstyled">
+                {/* Header Tabs */}
+                <TabList borderBottom="1px solid" borderColor="gray.200">
+                  <Tab 
+                    _selected={{ 
+                      color: 'red.600', 
+                      borderColor: 'red.600', 
+                      borderBottomWidth: '3px', 
+                      fontWeight: 'bold',
+                      marginBottom: '-1.5px' 
+                    }}
+                    color="gray.500"
+                    fontWeight="medium"
+                    fontSize="sm"
+                    px={4}
+                    py={3}
+                  >
+                    Deskripsi
+                  </Tab>
+                  <Tab 
+                    _selected={{ 
+                      color: 'red.600', 
+                      borderColor: 'red.600', 
+                      borderBottomWidth: '3px', 
+                      fontWeight: 'bold',
+                      marginBottom: '-1.5px' 
+                    }}
+                    color="gray.500"
+                    fontWeight="medium"
+                    fontSize="sm"
+                    px={4}
+                    py={3}
+                  >
+                    Spesifikasi
+                  </Tab>
+                  <Tab 
+                    _selected={{ 
+                      color: 'red.600', 
+                      borderColor: 'red.600', 
+                      borderBottomWidth: '3px', 
+                      fontWeight: 'bold',
+                      marginBottom: '-1.5px' 
+                    }}
+                    color="gray.500"
+                    fontWeight="medium"
+                    fontSize="sm"
+                    px={4}
+                    py={3}
+                  >
+                    Detail Lainnya
+                  </Tab>
+                </TabList>
+
+                <TabPanels>
+                  {/* PANEL 1: DESKRIPSI */}
+                  <TabPanel px={0} py={6}>
+                    <div className='overflow-x-auto text-sm text-gray-700'>
+                      <div
+                        className={style['description']}
+                        dangerouslySetInnerHTML={{
+                          __html:
+                            !product.description || product.description === '<p><br></p>'
+                              ? '<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>'
+                              : product.description,
+                        }}
+                      />
+                    </div>
+                  </TabPanel>
+
+                  {/* PANEL 2: SPESIFIKASI (Sesuai Gambar) */}
+                  <TabPanel px={0} py={6}>
+                      <p className="text-gray-500 text-sm">Informasi tambahan belum tersedia.</p>
+                  </TabPanel>
+                  
+                   {/* PANEL 3: DETAIL LAINNYA */}
+                   <TabPanel px={0} py={6}>
+                        <p className="text-gray-500 text-sm">Informasi tambahan belum tersedia.</p>
+                   </TabPanel>
+
+                </TabPanels>
+              </Tabs>
             </div>
           </div>
         </div>
@@ -422,4 +501,4 @@ const ProductDetail = ({ product }: Props) => {
   );
 };
 
-export default ProductDetail;
+export default ProductDetail;
\ No newline at end of file
-- 
cgit v1.2.3


From a5e695f82e03577cc85c4a1dded9f6021f0235fc Mon Sep 17 00:00:00 2001
From: FIN-IT_AndriFP <andrifebriyadiputra@gmail.com>
Date: Fri, 28 Nov 2025 09:36:15 +0700
Subject: (andri) try get detail product from magento

---
 .../product-detail/components/ProductDetail.tsx    | 114 ++++++++++++++++++---
 1 file changed, 102 insertions(+), 12 deletions(-)

(limited to 'src-migrate/modules/product-detail/components/ProductDetail.tsx')

diff --git a/src-migrate/modules/product-detail/components/ProductDetail.tsx b/src-migrate/modules/product-detail/components/ProductDetail.tsx
index 1bacd2e2..b0950194 100644
--- a/src-migrate/modules/product-detail/components/ProductDetail.tsx
+++ b/src-migrate/modules/product-detail/components/ProductDetail.tsx
@@ -4,7 +4,7 @@ import Link from 'next/link';
 import { useRouter } from 'next/router';
 import { useEffect, useRef, useState, UIEvent } from 'react';
 
-// Import komponen Chakra UI yang dibutuhkan
+// Import komponen Chakra UI
 import { 
   Button, 
   Tabs, 
@@ -16,7 +16,10 @@ import {
   Tbody, 
   Tr, 
   Td,
-  Box
+  Box,
+  Spinner,
+  Center,
+  Text
 } from '@chakra-ui/react';
 
 import {
@@ -58,6 +61,12 @@ const ProductDetail = ({ product }: Props) => {
   const { isDesktop, isMobile } = useDevice();
   const router = useRouter();
   const [auth, setAuth] = useState<any>(null);
+  
+  // State untuk Spesifikasi dari Magento
+  const [specs, setSpecs] = useState<{ label: string; value: string }[]>([]);
+  const [loadingSpecs, setLoadingSpecs] = useState(false);
+  const [errorSpecs, setErrorSpecs] = useState(false);
+
   useEffect(() => {
     try {
       setAuth(getAuth() ?? null);
@@ -74,6 +83,7 @@ const ProductDetail = ({ product }: Props) => {
     activeVariantId,
     setIsApproval,
     isApproval,
+    selectedVariant, 
     setSelectedVariant,
   } = useProductDetail();
 
@@ -99,12 +109,65 @@ const ProductDetail = ({ product }: Props) => {
     if (typeof auth === 'object') {
       setIsApproval(auth?.feature?.soApproval);
     }
-    const selectedVariant =
+    const variantInit =
       product?.variants?.find((variant) => variant.is_in_bu) ||
       product?.variants?.[0];
-    setSelectedVariant(selectedVariant);
+    setSelectedVariant(variantInit);
   }, []);
 
+  // =========================================================================
+  // LOGIC FETCH: MENGGUNAKAN ID VARIANT
+  // =========================================================================
+  useEffect(() => {
+    const fetchMagentoSpecs = async () => {
+      // MENGGUNAKAN ID VARIANT SESUAI REQUEST
+      const skuToFetch = selectedVariant?.id; 
+
+      if (!skuToFetch) return;
+
+      setLoadingSpecs(true);
+      setErrorSpecs(false);
+      
+      try {
+        console.log("Fetching Magento specs via Proxy for Variant ID:", skuToFetch);
+        
+        // Pastikan dikonversi ke string
+        const endpoint = `/api/magento-product?sku=${encodeURIComponent(String(skuToFetch))}`;
+
+        const response = await fetch(endpoint, {
+            method: 'GET',
+            headers: {
+                'Content-Type': 'application/json',
+            }
+        });
+
+        if (!response.ok) {
+            console.warn(`Spec API status: ${response.status}`);
+            setSpecs([]);
+            return;
+        }
+
+        const data = await response.json();
+
+        if (data.specs && Array.isArray(data.specs)) {
+           setSpecs(data.specs);
+        } else {
+           setSpecs([]);
+        }
+
+      } catch (error) {
+        console.error("Gagal mengambil data spesifikasi:", error);
+        setErrorSpecs(true);
+        setSpecs([]);
+      } finally {
+        setLoadingSpecs(false);
+      }
+    };
+
+    fetchMagentoSpecs();
+  }, [selectedVariant]); 
+
+
   const allImages = (() => {
     const arr: string[] = [];
     if (product?.image) arr.push(product.image);
@@ -154,9 +217,6 @@ const ProductDetail = ({ product }: Props) => {
     setMainImage(allImages[i] || '');
   };
 
-  console.log('detail product render');
-  console.log('product: ', product);
-
   return (
     <>
       <div className='relative'>
@@ -192,7 +252,7 @@ const ProductDetail = ({ product }: Props) => {
           <div className='md:flex md:flex-wrap'>
             {/* ===== Kolom kiri: gambar ===== */}
             <div className='md:w-4/12'>
-              {/* === MOBILE: Slider swipeable, tanpa thumbnail carousel === */}
+              {/* === MOBILE: Slider swipeable === */}
               {isMobile ? (
                 <div className='relative'>
                   <div
@@ -233,6 +293,7 @@ const ProductDetail = ({ product }: Props) => {
                     )}
                   </div>
 
+                  {/* Dots indicator */}
                   {allImages.length > 1 && (
                     <div className='absolute bottom-2 left-0 right-0 flex justify-center gap-2'>
                       {allImages.map((_, i) => (
@@ -250,7 +311,7 @@ const ProductDetail = ({ product }: Props) => {
                 </div>
               ) : (
                 <>
-                  {/* === DESKTOP: Tetap seperti sebelumnya === */}
+                  {/* === DESKTOP === */}
                   <ProductImage product={{ ...product, image: mainImage }} />
                   {allImages.length > 0 && (
                     <div className='mt-4 overflow-x-auto'>
@@ -414,9 +475,38 @@ const ProductDetail = ({ product }: Props) => {
                     </div>
                   </TabPanel>
 
-                  {/* PANEL 2: SPESIFIKASI (Sesuai Gambar) */}
-                  <TabPanel px={0} py={6}>
-                      <p className="text-gray-500 text-sm">Informasi tambahan belum tersedia.</p>
+                  {/* PANEL 2: SPESIFIKASI DARI MAGENTO */}
+                  <TabPanel px={0} py={2}>
+                    <Box border="1px solid" borderColor="gray.200" borderRadius="sm">
+                        {loadingSpecs ? (
+                            <Center py={6}>
+                                <Spinner color='red.500' />
+                            </Center>
+                        ) : errorSpecs ? (
+                            <Box p={4} color="red.500" fontSize="sm">
+                                Gagal memuat data spesifikasi. Silakan coba lagi nanti.
+                            </Box>
+                        ) : specs.length > 0 ? (
+                            <Table variant="simple" size="md">
+                                <Tbody>
+                                    {specs.map((item, index) => (
+                                        <Tr key={index}>
+                                            <Td fontWeight="bold" width="30%" verticalAlign="top" borderColor="gray.200">
+                                                {item.label}
+                                            </Td>
+                                            <Td verticalAlign="top" borderColor="gray.200">
+                                                {item.value}
+                                            </Td>
+                                        </Tr>
+                                    ))}
+                                </Tbody>
+                            </Table>
+                        ) : (
+                            <Box p={4} color="gray.500" fontSize="sm">
+                                <Text>Spesifikasi teknis belum tersedia untuk varian ID: <b>{selectedVariant?.id}</b></Text>
+                            </Box>
+                        )}
+                    </Box>
                   </TabPanel>
                   
                    {/* PANEL 3: DETAIL LAINNYA */}
-- 
cgit v1.2.3


From 825d86bb50f48f9a21d740d474c0dddee858dffb Mon Sep 17 00:00:00 2001
From: FIN-IT_AndriFP <andrifebriyadiputra@gmail.com>
Date: Mon, 1 Dec 2025 11:31:30 +0700
Subject: (andri) show upsells product from magento in similarbottom product

---
 .../product-detail/components/ProductDetail.tsx    | 183 +++++++++------------
 1 file changed, 77 insertions(+), 106 deletions(-)

(limited to 'src-migrate/modules/product-detail/components/ProductDetail.tsx')

diff --git a/src-migrate/modules/product-detail/components/ProductDetail.tsx b/src-migrate/modules/product-detail/components/ProductDetail.tsx
index b0950194..5f930117 100644
--- a/src-migrate/modules/product-detail/components/ProductDetail.tsx
+++ b/src-migrate/modules/product-detail/components/ProductDetail.tsx
@@ -22,11 +22,13 @@ import {
   Text
 } from '@chakra-ui/react';
 
+// Import Icons
 import {
   AlertTriangle,
   MessageCircleIcon,
   Share2Icon,
 } from 'lucide-react';
+
 import { LazyLoadComponent } from 'react-lazy-load-image-component';
 
 import useDevice from '@/core/hooks/useDevice';
@@ -62,8 +64,9 @@ const ProductDetail = ({ product }: Props) => {
   const router = useRouter();
   const [auth, setAuth] = useState<any>(null);
   
-  // State untuk Spesifikasi dari Magento
-  const [specs, setSpecs] = useState<{ label: string; value: string }[]>([]);
+  // State Data dari Magento
+  const [specs, setSpecs] = useState<{ code: string; label: string; value: string }[]>([]);
+  const [upsellIds, setUpsellIds] = useState<number[]>([]);
   const [loadingSpecs, setLoadingSpecs] = useState(false);
   const [errorSpecs, setErrorSpecs] = useState(false);
 
@@ -105,6 +108,9 @@ const ProductDetail = ({ product }: Props) => {
     setAskAdminUrl(createdAskUrl);
   }, [router.asPath, product.manufacture.name, product.name, setAskAdminUrl]);
 
+  // =========================================================================
+  // LOGIC INISIALISASI VARIANT (HANDLE NAVIGASI)
+  // =========================================================================
   useEffect(() => {
     if (typeof auth === 'object') {
       setIsApproval(auth?.feature?.soApproval);
@@ -112,60 +118,95 @@ const ProductDetail = ({ product }: Props) => {
     const variantInit =
       product?.variants?.find((variant) => variant.is_in_bu) ||
       product?.variants?.[0];
+    
     setSelectedVariant(variantInit);
-  }, []);
+
+    // Reset data Magento saat produk berubah
+    setSpecs([]);
+    setUpsellIds([]);
+    
+  }, [product, auth]); 
 
   // =========================================================================
-  // LOGIC FETCH: MENGGUNAKAN ID VARIANT
+  // LOGIC FETCH: SPECS & UPSELLS
   // =========================================================================
   useEffect(() => {
-    const fetchMagentoSpecs = async () => {
-      // MENGGUNAKAN ID VARIANT SESUAI REQUEST
-      const skuToFetch = selectedVariant?.id; 
+    const fetchMagentoData = async () => {
+      // Gunakan ID Variant (SKU Odoo)
+      const idToFetch = selectedVariant?.id; 
 
-      if (!skuToFetch) return;
+      if (!idToFetch) return;
 
       setLoadingSpecs(true);
       setErrorSpecs(false);
       
       try {
-        console.log("Fetching Magento specs via Proxy for Variant ID:", skuToFetch);
+        console.log("Fetching Magento data via Proxy for ID:", idToFetch);
         
-        // Pastikan dikonversi ke string
-        const endpoint = `/api/magento-product?sku=${encodeURIComponent(String(skuToFetch))}`;
+        const endpoint = `/api/magento-product?sku=${encodeURIComponent(String(idToFetch))}`;
 
         const response = await fetch(endpoint, {
             method: 'GET',
-            headers: {
-                'Content-Type': 'application/json',
-            }
+            headers: { 'Content-Type': 'application/json' }
         });
 
         if (!response.ok) {
-            console.warn(`Spec API status: ${response.status}`);
+            console.warn(`Magento API status: ${response.status}`);
             setSpecs([]);
+            setUpsellIds([]);
             return;
         }
 
         const data = await response.json();
 
+        // 1. Simpan Data Spesifikasi
         if (data.specs && Array.isArray(data.specs)) {
            setSpecs(data.specs);
         } else {
            setSpecs([]);
         }
 
+        // 2. Simpan Data Up-Sells (ID)
+        if (data.upsell_ids && Array.isArray(data.upsell_ids)) {
+            setUpsellIds(data.upsell_ids);
+        } else {
+            setUpsellIds([]);
+        }
+
       } catch (error) {
-        console.error("Gagal mengambil data spesifikasi:", error);
+        console.error("Gagal mengambil data Magento:", error);
         setErrorSpecs(true);
         setSpecs([]);
+        setUpsellIds([]);
       } finally {
         setLoadingSpecs(false);
       }
     };
 
-    fetchMagentoSpecs();
-  }, [selectedVariant]); 
+    fetchMagentoData();
+  }, [selectedVariant, product.id]); 
+
+
+  // =========================================================================
+  // HELPER: RENDER SPEC VALUE (SIMPLE TEXT/HTML ONLY)
+  // =========================================================================
+  const renderSpecValue = (item: { code: string; label: string; value: string }) => {
+    const val = item.value;
+    if (!val) return '-';
+    
+    // Cek apakah mengandung tag HTML sederhana (<p>, <a>, <ul>, dll)
+    if (val.includes('<') && val.includes('>')) {
+       return (
+         <div 
+           className="prose prose-sm text-gray-700"
+           dangerouslySetInnerHTML={{ __html: val }}
+         />
+       );
+    }
+
+    // Default: Teks Biasa
+    return val;
+  };
 
 
   const allImages = (() => {
@@ -404,63 +445,32 @@ const ProductDetail = ({ product }: Props) => {
 
             <div className='h-0 md:h-6' />
 
-            {/* === SECTION TABS: DESKRIPSI & SPESIFIKASI === */}
+            {/* === SECTION TABS === */}
             <div className={style['section-card']}>
               <Tabs variant="unstyled">
-                {/* Header Tabs */}
                 <TabList borderBottom="1px solid" borderColor="gray.200">
                   <Tab 
-                    _selected={{ 
-                      color: 'red.600', 
-                      borderColor: 'red.600', 
-                      borderBottomWidth: '3px', 
-                      fontWeight: 'bold',
-                      marginBottom: '-1.5px' 
-                    }}
-                    color="gray.500"
-                    fontWeight="medium"
-                    fontSize="sm"
-                    px={4}
-                    py={3}
+                    _selected={{ color: 'red.600', borderColor: 'red.600', borderBottomWidth: '3px', fontWeight: 'bold', marginBottom: '-1.5px' }}
+                    color="gray.500" fontWeight="medium" fontSize="sm" px={4} py={3}
                   >
                     Deskripsi
                   </Tab>
                   <Tab 
-                    _selected={{ 
-                      color: 'red.600', 
-                      borderColor: 'red.600', 
-                      borderBottomWidth: '3px', 
-                      fontWeight: 'bold',
-                      marginBottom: '-1.5px' 
-                    }}
-                    color="gray.500"
-                    fontWeight="medium"
-                    fontSize="sm"
-                    px={4}
-                    py={3}
+                    _selected={{ color: 'red.600', borderColor: 'red.600', borderBottomWidth: '3px', fontWeight: 'bold', marginBottom: '-1.5px' }}
+                    color="gray.500" fontWeight="medium" fontSize="sm" px={4} py={3}
                   >
                     Spesifikasi
                   </Tab>
                   <Tab 
-                    _selected={{ 
-                      color: 'red.600', 
-                      borderColor: 'red.600', 
-                      borderBottomWidth: '3px', 
-                      fontWeight: 'bold',
-                      marginBottom: '-1.5px' 
-                    }}
-                    color="gray.500"
-                    fontWeight="medium"
-                    fontSize="sm"
-                    px={4}
-                    py={3}
+                    _selected={{ color: 'red.600', borderColor: 'red.600', borderBottomWidth: '3px', fontWeight: 'bold', marginBottom: '-1.5px' }}
+                    color="gray.500" fontWeight="medium" fontSize="sm" px={4} py={3}
                   >
                     Detail Lainnya
                   </Tab>
                 </TabList>
 
                 <TabPanels>
-                  {/* PANEL 1: DESKRIPSI */}
+                  {/* DESKRIPSI */}
                   <TabPanel px={0} py={6}>
                     <div className='overflow-x-auto text-sm text-gray-700'>
                       <div
@@ -468,24 +478,18 @@ const ProductDetail = ({ product }: Props) => {
                         dangerouslySetInnerHTML={{
                           __html:
                             !product.description || product.description === '<p><br></p>'
-                              ? '<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>'
+                              ? '<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</p>'
                               : product.description,
                         }}
                       />
                     </div>
                   </TabPanel>
 
-                  {/* PANEL 2: SPESIFIKASI DARI MAGENTO */}
+                  {/* SPESIFIKASI */}
                   <TabPanel px={0} py={2}>
                     <Box border="1px solid" borderColor="gray.200" borderRadius="sm">
                         {loadingSpecs ? (
-                            <Center py={6}>
-                                <Spinner color='red.500' />
-                            </Center>
-                        ) : errorSpecs ? (
-                            <Box p={4} color="red.500" fontSize="sm">
-                                Gagal memuat data spesifikasi. Silakan coba lagi nanti.
-                            </Box>
+                            <Center py={6}><Spinner color='red.500' /></Center>
                         ) : specs.length > 0 ? (
                             <Table variant="simple" size="md">
                                 <Tbody>
@@ -495,7 +499,7 @@ const ProductDetail = ({ product }: Props) => {
                                                 {item.label}
                                             </Td>
                                             <Td verticalAlign="top" borderColor="gray.200">
-                                                {item.value}
+                                                {renderSpecValue(item)}
                                             </Td>
                                         </Tr>
                                     ))}
@@ -503,13 +507,13 @@ const ProductDetail = ({ product }: Props) => {
                             </Table>
                         ) : (
                             <Box p={4} color="gray.500" fontSize="sm">
-                                <Text>Spesifikasi teknis belum tersedia untuk varian ID: <b>{selectedVariant?.id}</b></Text>
+                                <Text>Spesifikasi teknis belum tersedia.</Text>
                             </Box>
                         )}
                     </Box>
                   </TabPanel>
                   
-                   {/* PANEL 3: DETAIL LAINNYA */}
+                   {/* DETAIL LAINNYA */}
                    <TabPanel px={0} py={6}>
                         <p className="text-gray-500 text-sm">Informasi tambahan belum tersedia.</p>
                    </TabPanel>
@@ -524,64 +528,31 @@ const ProductDetail = ({ product }: Props) => {
           <div className='md:w-3/12'>
             <PriceAction product={product} />
             <div className='flex gap-x-5 items-center justify-center'>
-              <Button
-                as={Link}
-                href={askAdminUrl}
-                variant='link'
-                target='_blank'
-                colorScheme='gray'
-                leftIcon={<MessageCircleIcon size={18} />}
-                isDisabled={!hasPrice}
-              >
-                Ask Admin
-              </Button>
-
+              <Button as={Link} href={askAdminUrl} variant='link' target='_blank' colorScheme='gray' leftIcon={<MessageCircleIcon size={18} />} isDisabled={!hasPrice}>Ask Admin</Button>
               <span>|</span>
-
               <div className={hasPrice ? '' : 'opacity-40 pointer-events-none'}>
                 <AddToWishlist productId={product.id} />
               </div>
-
               <span>|</span>
-
               {canShare && (
-                <RWebShare
-                  data={{
-                    text: 'Check out this product',
-                    title: `${product.name} - Indoteknik.com`,
-                    url:
-                      (process.env.NEXT_PUBLIC_SELF_HOST || '') +
-                      (router?.asPath || '/'),
-                  }}
-                >
-                  <Button
-                    variant='link'
-                    colorScheme='gray'
-                    leftIcon={<Share2Icon size={18} />}
-                    isDisabled={!hasPrice}
-                  >
-                    Share
-                  </Button>
+                <RWebShare data={{ text: 'Check out this product', title: `${product.name} - Indoteknik.com`, url: (process.env.NEXT_PUBLIC_SELF_HOST || '') + (router?.asPath || '/'), }}>
+                  <Button variant='link' colorScheme='gray' leftIcon={<Share2Icon size={18} />} isDisabled={!hasPrice}>Share</Button>
                 </RWebShare>
               )}
             </div>
 
             <div className='h-6' />
             <div className={style['heading']}>Produk Serupa</div>
-
             <div className='h-4' />
-
             <SimilarSide product={product} />
           </div>
         )}
 
         <div className='md:w-full pt-4 md:py-10 px-4 md:px-0'>
           <div className={style['heading']}>Kamu Mungkin Juga Suka</div>
-
           <div className='h-6' />
-
           <LazyLoadComponent>
-            <SimilarBottom product={product} />
+            <SimilarBottom product={product} upsellIds={upsellIds} />
           </LazyLoadComponent>
         </div>
 
-- 
cgit v1.2.3


From 219c61c5c14e3a8dfed3d7158d59d11c476e3586 Mon Sep 17 00:00:00 2001
From: FIN-IT_AndriFP <andrifebriyadiputra@gmail.com>
Date: Wed, 3 Dec 2025 11:49:18 +0700
Subject: (andri) fix search for similar product side dan bottom pada detail
 product

---
 .../product-detail/components/ProductDetail.tsx    | 55 ++++++++++++++--------
 1 file changed, 36 insertions(+), 19 deletions(-)

(limited to 'src-migrate/modules/product-detail/components/ProductDetail.tsx')

diff --git a/src-migrate/modules/product-detail/components/ProductDetail.tsx b/src-migrate/modules/product-detail/components/ProductDetail.tsx
index 5f930117..cfe73628 100644
--- a/src-migrate/modules/product-detail/components/ProductDetail.tsx
+++ b/src-migrate/modules/product-detail/components/ProductDetail.tsx
@@ -67,6 +67,8 @@ const ProductDetail = ({ product }: Props) => {
   // State Data dari Magento
   const [specs, setSpecs] = useState<{ code: string; label: string; value: string }[]>([]);
   const [upsellIds, setUpsellIds] = useState<number[]>([]);
+  const [relatedIds, setRelatedIds] = useState<number[]>([]); 
+  
   const [loadingSpecs, setLoadingSpecs] = useState(false);
   const [errorSpecs, setErrorSpecs] = useState(false);
 
@@ -109,7 +111,7 @@ const ProductDetail = ({ product }: Props) => {
   }, [router.asPath, product.manufacture.name, product.name, setAskAdminUrl]);
 
   // =========================================================================
-  // LOGIC INISIALISASI VARIANT (HANDLE NAVIGASI)
+  // LOGIC INISIALISASI VARIANT (RESET SAAT NAVIGASI)
   // =========================================================================
   useEffect(() => {
     if (typeof auth === 'object') {
@@ -121,28 +123,29 @@ const ProductDetail = ({ product }: Props) => {
     
     setSelectedVariant(variantInit);
 
-    // Reset data Magento saat produk berubah
+    // Reset data Magento
     setSpecs([]);
     setUpsellIds([]);
+    setRelatedIds([]);
     
   }, [product, auth]); 
 
   // =========================================================================
-  // LOGIC FETCH: SPECS & UPSELLS
+  // LOGIC FETCH: SPECS, UPSELLS, RELATED
   // =========================================================================
   useEffect(() => {
     const fetchMagentoData = async () => {
-      // Gunakan ID Variant (SKU Odoo)
-      const idToFetch = selectedVariant?.id; 
+      // Validasi kepemilikan varian
+      if (!selectedVariant?.id) return;
+      const isVariantOwner = product.variants.some(v => Number(v.id) === Number(selectedVariant.id));
+      if (!isVariantOwner) return;
 
-      if (!idToFetch) return;
+      const idToFetch = selectedVariant.id;
 
       setLoadingSpecs(true);
       setErrorSpecs(false);
       
       try {
-        console.log("Fetching Magento data via Proxy for ID:", idToFetch);
-        
         const endpoint = `/api/magento-product?sku=${encodeURIComponent(String(idToFetch))}`;
 
         const response = await fetch(endpoint, {
@@ -151,61 +154,75 @@ const ProductDetail = ({ product }: Props) => {
         });
 
         if (!response.ok) {
-            console.warn(`Magento API status: ${response.status}`);
             setSpecs([]);
             setUpsellIds([]);
+            setRelatedIds([]);
             return;
         }
 
         const data = await response.json();
 
-        // 1. Simpan Data Spesifikasi
+        // Double Check
+        if (Number(idToFetch) !== Number(selectedVariant.id)) return;
+
+        // 1. Specs
         if (data.specs && Array.isArray(data.specs)) {
            setSpecs(data.specs);
         } else {
            setSpecs([]);
         }
 
-        // 2. Simpan Data Up-Sells (ID)
+        // 2. Upsell
         if (data.upsell_ids && Array.isArray(data.upsell_ids)) {
             setUpsellIds(data.upsell_ids);
         } else {
             setUpsellIds([]);
         }
 
+        // 3. Related
+        if (data.related_ids && Array.isArray(data.related_ids)) {
+            setRelatedIds(data.related_ids);
+        } else {
+            setRelatedIds([]);
+        }
+
       } catch (error) {
         console.error("Gagal mengambil data Magento:", error);
         setErrorSpecs(true);
         setSpecs([]);
         setUpsellIds([]);
+        setRelatedIds([]);
       } finally {
         setLoadingSpecs(false);
       }
     };
 
     fetchMagentoData();
-  }, [selectedVariant, product.id]); 
+  }, [selectedVariant, product]); 
 
 
   // =========================================================================
-  // HELPER: RENDER SPEC VALUE (SIMPLE TEXT/HTML ONLY)
+  // HELPER: RENDER SPEC VALUE (SIMPLE - NO LINK DETECT)
   // =========================================================================
   const renderSpecValue = (item: { code: string; label: string; value: string }) => {
     const val = item.value;
     if (!val) return '-';
     
-    // Cek apakah mengandung tag HTML sederhana (<p>, <a>, <ul>, dll)
-    if (val.includes('<') && val.includes('>')) {
+    const cleanVal = val.trim();
+
+    // 1. JIKA HTML (Legacy Data)
+    // Deteksi tag HTML sederhana
+    if (cleanVal.includes('<') && cleanVal.includes('>')) {
        return (
          <div 
            className="prose prose-sm text-gray-700"
-           dangerouslySetInnerHTML={{ __html: val }}
+           dangerouslySetInnerHTML={{ __html: cleanVal }}
          />
        );
     }
 
-    // Default: Teks Biasa
-    return val;
+    // 2. TEKS BIASA
+    return cleanVal;
   };
 
 
@@ -544,7 +561,7 @@ const ProductDetail = ({ product }: Props) => {
             <div className='h-6' />
             <div className={style['heading']}>Produk Serupa</div>
             <div className='h-4' />
-            <SimilarSide product={product} />
+            <SimilarSide product={product} relatedIds={relatedIds} />
           </div>
         )}
 
-- 
cgit v1.2.3


From 43b2ce4d59c153655eb9b7a2190b83050fd48855 Mon Sep 17 00:00:00 2001
From: FIN-IT_AndriFP <andrifebriyadiputra@gmail.com>
Date: Wed, 3 Dec 2025 17:06:01 +0700
Subject: (andri) table spek untuk product dengan variant lebih dari 1

---
 .../product-detail/components/ProductDetail.tsx    | 385 +++++++++++----------
 1 file changed, 193 insertions(+), 192 deletions(-)

(limited to 'src-migrate/modules/product-detail/components/ProductDetail.tsx')

diff --git a/src-migrate/modules/product-detail/components/ProductDetail.tsx b/src-migrate/modules/product-detail/components/ProductDetail.tsx
index cfe73628..3beb75b4 100644
--- a/src-migrate/modules/product-detail/components/ProductDetail.tsx
+++ b/src-migrate/modules/product-detail/components/ProductDetail.tsx
@@ -16,6 +16,8 @@ import {
   Tbody, 
   Tr, 
   Td,
+  Th, 
+  Thead,
   Box,
   Spinner,
   Center,
@@ -27,6 +29,7 @@ import {
   AlertTriangle,
   MessageCircleIcon,
   Share2Icon,
+  ExternalLink
 } from 'lucide-react';
 
 import { LazyLoadComponent } from 'react-lazy-load-image-component';
@@ -65,12 +68,11 @@ const ProductDetail = ({ product }: Props) => {
   const [auth, setAuth] = useState<any>(null);
   
   // State Data dari Magento
-  const [specs, setSpecs] = useState<{ code: string; label: string; value: string }[]>([]);
+  const [specsMatrix, setSpecsMatrix] = useState<any[]>([]); 
   const [upsellIds, setUpsellIds] = useState<number[]>([]);
   const [relatedIds, setRelatedIds] = useState<number[]>([]); 
   
   const [loadingSpecs, setLoadingSpecs] = useState(false);
-  const [errorSpecs, setErrorSpecs] = useState(false);
 
   useEffect(() => {
     try {
@@ -111,7 +113,7 @@ const ProductDetail = ({ product }: Props) => {
   }, [router.asPath, product.manufacture.name, product.name, setAskAdminUrl]);
 
   // =========================================================================
-  // LOGIC INISIALISASI VARIANT (RESET SAAT NAVIGASI)
+  // 1. LOGIC INISIALISASI VARIANT
   // =========================================================================
   useEffect(() => {
     if (typeof auth === 'object') {
@@ -123,30 +125,32 @@ const ProductDetail = ({ product }: Props) => {
     
     setSelectedVariant(variantInit);
 
-    // Reset data Magento
-    setSpecs([]);
+    setSpecsMatrix([]);
     setUpsellIds([]);
     setRelatedIds([]);
     
   }, [product, auth]); 
 
   // =========================================================================
-  // LOGIC FETCH: SPECS, UPSELLS, RELATED
+  // 2. LOGIC FETCH DATA
   // =========================================================================
   useEffect(() => {
     const fetchMagentoData = async () => {
-      // Validasi kepemilikan varian
-      if (!selectedVariant?.id) return;
-      const isVariantOwner = product.variants.some(v => Number(v.id) === Number(selectedVariant.id));
-      if (!isVariantOwner) return;
+      const allVariantIds = product.variants.map(v => v.id);
+      
+      if (allVariantIds.length === 0) return;
 
-      const idToFetch = selectedVariant.id;
+      const mainId = allVariantIds[0];
 
       setLoadingSpecs(true);
-      setErrorSpecs(false);
       
       try {
-        const endpoint = `/api/magento-product?sku=${encodeURIComponent(String(idToFetch))}`;
+        const params = new URLSearchParams({
+            skus: allVariantIds.join(','),
+            main_sku: String(mainId)
+        });
+
+        const endpoint = `/api/magento-product?${params.toString()}`;
 
         const response = await fetch(endpoint, {
             method: 'GET',
@@ -154,7 +158,7 @@ const ProductDetail = ({ product }: Props) => {
         });
 
         if (!response.ok) {
-            setSpecs([]);
+            setSpecsMatrix([]);
             setUpsellIds([]);
             setRelatedIds([]);
             return;
@@ -162,67 +166,108 @@ const ProductDetail = ({ product }: Props) => {
 
         const data = await response.json();
 
-        // Double Check
-        if (Number(idToFetch) !== Number(selectedVariant.id)) return;
-
-        // 1. Specs
-        if (data.specs && Array.isArray(data.specs)) {
-           setSpecs(data.specs);
+        // 1. Specs Matrix (Processed Grouping)
+        if (data.specsMatrix && Array.isArray(data.specsMatrix)) {
+           const processed = processMatrixData(data.specsMatrix);
+           setSpecsMatrix(processed);
         } else {
-           setSpecs([]);
+           setSpecsMatrix([]);
         }
 
-        // 2. Upsell
-        if (data.upsell_ids && Array.isArray(data.upsell_ids)) {
-            setUpsellIds(data.upsell_ids);
-        } else {
-            setUpsellIds([]);
-        }
+        // 2. Upsell & Related
+        if (data.upsell_ids && Array.isArray(data.upsell_ids)) setUpsellIds(data.upsell_ids);
+        else setUpsellIds([]);
 
-        // 3. Related
-        if (data.related_ids && Array.isArray(data.related_ids)) {
-            setRelatedIds(data.related_ids);
-        } else {
-            setRelatedIds([]);
-        }
+        if (data.related_ids && Array.isArray(data.related_ids)) setRelatedIds(data.related_ids);
+        else setRelatedIds([]);
 
       } catch (error) {
         console.error("Gagal mengambil data Magento:", error);
-        setErrorSpecs(true);
-        setSpecs([]);
-        setUpsellIds([]);
-        setRelatedIds([]);
+        setSpecsMatrix([]);
       } finally {
         setLoadingSpecs(false);
       }
     };
 
     fetchMagentoData();
-  }, [selectedVariant, product]); 
 
+  }, [product.id]); 
 
   // =========================================================================
-  // HELPER: RENDER SPEC VALUE (SIMPLE - NO LINK DETECT)
+  // HELPER 1: GROUPING DATA BY LABEL (Separator ':')
   // =========================================================================
-  const renderSpecValue = (item: { code: string; label: string; value: string }) => {
-    const val = item.value;
+  const processMatrixData = (rawMatrix: any[]) => {
+      const groups: any = {};
+      const result: any[] = [];
+
+      rawMatrix.forEach(item => {
+          // Cek Label: "Group Name : Sub Label"
+          if (item.label && item.label.includes(' : ')) {
+              const parts = item.label.split(' : ');
+              const groupName = parts[0].trim(); 
+              const childLabel = parts.slice(1).join(' : ').trim();
+
+              if (!groups[groupName]) {
+                  groups[groupName] = {
+                      type: 'group',
+                      label: groupName,
+                      children: []
+                  };
+                  result.push(groups[groupName]);
+              }
+              
+              groups[groupName].children.push({
+                  ...item,
+                  label: childLabel // Override label jadi pendek
+              });
+
+          } else {
+              result.push({ ...item, type: 'single' });
+          }
+      });
+
+      return result;
+  };
+
+
+  // =========================================================================
+  // HELPER 2: RENDER SPEC VALUE
+  // =========================================================================
+  const renderSpecValue = (val: any) => {
     if (!val) return '-';
-    
-    const cleanVal = val.trim();
+    const strVal = String(val).trim();
+
+    // URL Link
+    const isUrl = !strVal.includes(' ') && (
+      strVal.startsWith('http') || 
+      strVal.startsWith('www.')
+    );
+    if (isUrl) {
+      const href = strVal.startsWith('http') ? strVal : `https://${strVal}`;
+      return (
+        <a 
+          href={href} 
+          target="_blank" 
+          rel="noopener noreferrer"
+          className="text-red-600 hover:underline inline-flex items-center gap-1"
+        >
+          <ExternalLink size={14} /> Link
+        </a>
+      );
+    }
 
-    // 1. JIKA HTML (Legacy Data)
-    // Deteksi tag HTML sederhana
-    if (cleanVal.includes('<') && cleanVal.includes('>')) {
+    // HTML
+    if (strVal.includes('<') && strVal.includes('>')) {
        return (
          <div 
            className="prose prose-sm text-gray-700"
-           dangerouslySetInnerHTML={{ __html: cleanVal }}
+           dangerouslySetInnerHTML={{ __html: strVal }}
          />
        );
     }
 
-    // 2. TEKS BIASA
-    return cleanVal;
+    // Teks Biasa
+    return strVal;
   };
 
 
@@ -310,90 +355,39 @@ const ProductDetail = ({ product }: Props) => {
           <div className='md:flex md:flex-wrap'>
             {/* ===== Kolom kiri: gambar ===== */}
             <div className='md:w-4/12'>
-              {/* === MOBILE: Slider swipeable === */}
+              {/* ... Image Slider ... */}
               {isMobile ? (
                 <div className='relative'>
-                  <div
-                    ref={sliderRef}
-                    onScroll={handleMobileScroll}
-                    className='flex overflow-x-auto snap-x snap-mandatory scroll-smooth no-scrollbar'
-                    style={{
-                      scrollBehavior: 'smooth',
-                      msOverflowStyle: 'none',
-                      scrollbarWidth: 'none',
-                    }}
-                  >
+                  <div ref={sliderRef} onScroll={handleMobileScroll} className='flex overflow-x-auto snap-x snap-mandatory scroll-smooth no-scrollbar' style={{ scrollBehavior: 'smooth', msOverflowStyle: 'none', scrollbarWidth: 'none' }}>
                     {allImages.length > 0 ? (
                       allImages.map((img, i) => (
-                        <div
-                          key={i}
-                          className='w-full flex-shrink-0 snap-center flex justify-center items-center'
-                        >
-                          <img
-                            src={img}
-                            alt={`Gambar ${i + 1}`}
-                            className='w-[85%] aspect-square object-contain'
-                            onError={(e) => {
-                              (e.target as HTMLImageElement).src =
-                                '/images/noimage.jpeg';
-                            }}
-                          />
+                        <div key={i} className='w-full flex-shrink-0 snap-center flex justify-center items-center'>
+                          <img src={img} alt={`Gambar ${i + 1}`} className='w-[85%] aspect-square object-contain' onError={(e) => { (e.target as HTMLImageElement).src = '/images/noimage.jpeg'; }} />
                         </div>
                       ))
                     ) : (
                       <div className='w-full flex-shrink-0 snap-center flex justify-center items-center'>
-                        <img
-                          src={mainImage || '/images/noimage.jpeg'}
-                          alt='Gambar produk'
-                          className='w-[85%] aspect-square object-contain'
-                        />
+                        <img src={mainImage || '/images/noimage.jpeg'} alt='Gambar produk' className='w-[85%] aspect-square object-contain' />
                       </div>
                     )}
                   </div>
-
-                  {/* Dots indicator */}
                   {allImages.length > 1 && (
                     <div className='absolute bottom-2 left-0 right-0 flex justify-center gap-2'>
                       {allImages.map((_, i) => (
-                        <button
-                          key={i}
-                          aria-label={`Ke slide ${i + 1}`}
-                          className={`w-2 h-2 rounded-full ${
-                            currentIdx === i ? 'bg-gray-800' : 'bg-gray-300'
-                          }`}
-                          onClick={() => scrollToIndex(i)}
-                        />
+                        <button key={i} aria-label={`Ke slide ${i + 1}`} className={`w-2 h-2 rounded-full ${currentIdx === i ? 'bg-gray-800' : 'bg-gray-300'}`} onClick={() => scrollToIndex(i)} />
                       ))}
                     </div>
                   )}
                 </div>
               ) : (
                 <>
-                  {/* === DESKTOP === */}
                   <ProductImage product={{ ...product, image: mainImage }} />
                   {allImages.length > 0 && (
                     <div className='mt-4 overflow-x-auto'>
                       <div className='flex space-x-3 pb-3'>
                         {allImages.map((img, index) => (
-                          <div
-                            key={index}
-                            className={`flex-shrink-0 w-16 h-16 cursor-pointer border-2 rounded-md transition-colors ${
-                              mainImage === img
-                                ? 'border-red-500 ring-2 ring-red-200'
-                                : 'border-gray-200 hover:border-gray-300'
-                            }`}
-                            onClick={() => setMainImage(img)}
-                          >
-                            <img
-                              src={img}
-                              alt={`Thumbnail ${index + 1}`}
-                              className='w-full h-full object-cover rounded-sm'
-                              loading='lazy'
-                              onError={(e) => {
-                                (e.target as HTMLImageElement).src =
-                                  '/images/noimage.jpeg';
-                              }}
-                            />
+                          <div key={index} className={`flex-shrink-0 w-16 h-16 cursor-pointer border-2 rounded-md transition-colors ${mainImage === img ? 'border-red-500 ring-2 ring-red-200' : 'border-gray-200 hover:border-gray-300'}`} onClick={() => setMainImage(img)}>
+                            <img src={img} alt={`Thumbnail ${index + 1}`} className='w-full h-full object-cover rounded-sm' loading='lazy' onError={(e) => { (e.target as HTMLImageElement).src = '/images/noimage.jpeg'; }} />
                           </div>
                         ))}
                       </div>
@@ -408,13 +402,8 @@ const ProductDetail = ({ product }: Props) => {
               <div className='md:w-8/12 px-4 md:pl-6'>
                 {!hasPrice && (
                   <div className='bg-red-50 p-2 py-1.5 rounded-lg border border-red-500 flex gap-1 items-center '>
-                    <AlertTriangle
-                      size={18}
-                      className='text-red-600 shrink-0 mx-2'
-                    />
-                    <h1 className='text-red-600 font-normal text-h-sm'>
-                      Maaf untuk saat ini Produk yang anda cari tidak tersedia
-                    </h1>
+                    <AlertTriangle size={18} className='text-red-600 shrink-0 mx-2' />
+                    <h1 className='text-red-600 font-normal text-h-sm'>Maaf untuk saat ini Produk yang anda cari tidak tersedia</h1>
                   </div>
                 )}
                 <div className='h-6 md:h-0' />
@@ -428,13 +417,8 @@ const ProductDetail = ({ product }: Props) => {
               <div className='md:w-8/12 px-4 md:pl-6 relative'>
                 {!hasPrice && (
                   <div className='bg-red-50 p-2 py-1.5 border-b border-red-500 flex gap-1 items-center w-screen relative left-1/2 right-1/2 -translate-x-1/2'>
-                    <AlertTriangle
-                      size={18}
-                      className='text-red-600 shrink-0 mx-2'
-                    />
-                    <h1 className='text-red-600 font-normal text-h-sm'>
-                      Maaf untuk saat ini Produk yang anda cari tidak tersedia
-                    </h1>
+                    <AlertTriangle size={18} className='text-red-600 shrink-0 mx-2' />
+                    <h1 className='text-red-600 font-normal text-h-sm'>Maaf untuk saat ini Produk yang anda cari tidak tersedia</h1>
                   </div>
                 )}
                 <h1 className={style['title']}>{product.name}</h1>
@@ -454,110 +438,128 @@ const ProductDetail = ({ product }: Props) => {
 
             <div className='h-4 md:h-10' />
             {!!activeVariantId && !isApproval && (
-              <ProductPromoSection
-                product={product}
-                productId={activeVariantId}
-              />
+              <ProductPromoSection product={product} productId={activeVariantId} />
             )}
 
             <div className='h-0 md:h-6' />
 
-            {/* === SECTION TABS === */}
+            {/* === SECTION TABS: DESKRIPSI & SPESIFIKASI === */}
             <div className={style['section-card']}>
               <Tabs variant="unstyled">
                 <TabList borderBottom="1px solid" borderColor="gray.200">
-                  <Tab 
-                    _selected={{ color: 'red.600', borderColor: 'red.600', borderBottomWidth: '3px', fontWeight: 'bold', marginBottom: '-1.5px' }}
-                    color="gray.500" fontWeight="medium" fontSize="sm" px={4} py={3}
-                  >
-                    Deskripsi
-                  </Tab>
-                  <Tab 
-                    _selected={{ color: 'red.600', borderColor: 'red.600', borderBottomWidth: '3px', fontWeight: 'bold', marginBottom: '-1.5px' }}
-                    color="gray.500" fontWeight="medium" fontSize="sm" px={4} py={3}
-                  >
-                    Spesifikasi
-                  </Tab>
-                  <Tab 
-                    _selected={{ color: 'red.600', borderColor: 'red.600', borderBottomWidth: '3px', fontWeight: 'bold', marginBottom: '-1.5px' }}
-                    color="gray.500" fontWeight="medium" fontSize="sm" px={4} py={3}
-                  >
-                    Detail Lainnya
-                  </Tab>
+                  <Tab _selected={{ color: 'red.600', borderColor: 'red.600', borderBottomWidth: '3px', fontWeight: 'bold', marginBottom: '-1.5px' }} color="gray.500" fontWeight="medium" fontSize="sm" px={4} py={3}>Deskripsi</Tab>
+                  <Tab _selected={{ color: 'red.600', borderColor: 'red.600', borderBottomWidth: '3px', fontWeight: 'bold', marginBottom: '-1.5px' }} color="gray.500" fontWeight="medium" fontSize="sm" px={4} py={3}>Spesifikasi</Tab>
+                  <Tab _selected={{ color: 'red.600', borderColor: 'red.600', borderBottomWidth: '3px', fontWeight: 'bold', marginBottom: '-1.5px' }} color="gray.500" fontWeight="medium" fontSize="sm" px={4} py={3}>Detail Lainnya</Tab>
                 </TabList>
 
                 <TabPanels>
                   {/* DESKRIPSI */}
                   <TabPanel px={0} py={6}>
                     <div className='overflow-x-auto text-sm text-gray-700'>
-                      <div
-                        className={style['description']}
-                        dangerouslySetInnerHTML={{
-                          __html:
-                            !product.description || product.description === '<p><br></p>'
-                              ? '<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</p>'
-                              : product.description,
-                        }}
-                      />
+                      <div className={style['description']} dangerouslySetInnerHTML={{ __html: !product.description || product.description === '<p><br></p>' ? '<p>Lorem ipsum dolor sit amet.</p>' : product.description, }} />
                     </div>
                   </TabPanel>
 
-                  {/* SPESIFIKASI */}
+                  {/* SPESIFIKASI (LOGIKA GROUPING + RATA TENGAH) */}
                   <TabPanel px={0} py={2}>
-                    <Box border="1px solid" borderColor="gray.200" borderRadius="sm">
+                    <Box border="1px solid" borderColor="gray.200" borderRadius="sm" overflowX="auto">
                         {loadingSpecs ? (
                             <Center py={6}><Spinner color='red.500' /></Center>
-                        ) : specs.length > 0 ? (
-                            <Table variant="simple" size="md">
-                                <Tbody>
-                                    {specs.map((item, index) => (
-                                        <Tr key={index}>
-                                            <Td fontWeight="bold" width="30%" verticalAlign="top" borderColor="gray.200">
-                                                {item.label}
-                                            </Td>
-                                            <Td verticalAlign="top" borderColor="gray.200">
-                                                {renderSpecValue(item)}
-                                            </Td>
-                                        </Tr>
-                                    ))}
-                                </Tbody>
-                            </Table>
+                        ) : specsMatrix.length > 0 ? (
+                            (() => {
+                                const isSingleVariant = product.variants.length === 1;
+                                const globalAlign = isSingleVariant ? "left" : "center";
+                                
+                                return (
+                                    <Table variant="simple" size="md">
+                                        <Thead bg="red.600">
+                                            <Tr>
+                                                <Th width={isSingleVariant ? "30%" : "20%"} borderColor="whiteAlpha.300" color="white" fontSize="sm" textTransform="none" verticalAlign="middle">
+                                                    Spesifikasi
+                                                </Th>
+                                                {product.variants.map(v => (
+                                                    <Th key={v.id} borderColor="whiteAlpha.300" color="white" textAlign={globalAlign} fontSize="sm" textTransform="none" verticalAlign="middle">
+                                                        {isSingleVariant ? 'Detail' : (v.attributes && v.attributes.length > 0 ? v.attributes.join(' - ') : v.code)}
+                                                    </Th>
+                                                ))}
+                                            </Tr>
+                                        </Thead>
+                                        <Tbody>
+                                            {specsMatrix.map((row, i) => {
+                                                
+                                                // CASE 1: GROUPING (Label punya ' : ')
+                                                if (row.type === 'group') {
+                                                    return (
+                                                        <Tr key={i}>
+                                                            {/* Header Group Kiri */}
+                                                            <Td fontWeight="bold" borderColor="gray.200" fontSize="sm" verticalAlign="middle">{row.label}</Td>
+                                                            
+                                                            {/* Content Group Kanan */}
+                                                            {product.variants.map(v => (
+                                                                <Td key={v.id} borderColor="gray.200" textAlign={globalAlign} fontSize="sm" verticalAlign="middle">
+                                                                    <div className={`inline-block text-left`}>
+                                                                        <div className="flex flex-col gap-0">
+                                                                            {row.children.map((child: any, idx: number) => {
+                                                                                const rawVal = child.values[v.id];
+                                                                                if (!rawVal || rawVal === '-') return null;
+                                                                                
+                                                                                return (
+                                                                                    <div key={idx} className="grid grid-cols-[auto_auto] gap-x-2">
+                                                                                        <span className="font-semibold text-gray-600 whitespace-nowrap">
+                                                                                            {child.label}:
+                                                                                        </span>
+                                                                                        <span>{renderSpecValue(rawVal)}</span>
+                                                                                    </div>
+                                                                                );
+                                                                            })}
+                                                                        </div>
+                                                                    </div>
+                                                                </Td>
+                                                            ))}
+                                                        </Tr>
+                                                    );
+                                                }
+
+                                                // CASE 2: SINGLE ITEM
+                                                return (
+                                                    <Tr key={i}>
+                                                        <Td fontWeight="bold" borderColor="gray.200" fontSize="sm" verticalAlign="middle">{row.label}</Td>
+                                                        {product.variants.map(v => {
+                                                            const rawValue = row.values[v.id] || '-';
+                                                            return (
+                                                                <Td key={v.id} borderColor="gray.200" textAlign={globalAlign} fontSize="sm" verticalAlign="middle">
+                                                                    {renderSpecValue(rawValue)}
+                                                                </Td>
+                                                            );
+                                                        })}
+                                                    </Tr>
+                                                );
+                                            })}
+                                        </Tbody>
+                                    </Table>
+                                );
+                            })()
                         ) : (
-                            <Box p={4} color="gray.500" fontSize="sm">
-                                <Text>Spesifikasi teknis belum tersedia.</Text>
-                            </Box>
+                            <Box p={4} color="gray.500" fontSize="sm"><Text>Spesifikasi teknis belum tersedia.</Text></Box>
                         )}
                     </Box>
                   </TabPanel>
                   
                    {/* DETAIL LAINNYA */}
-                   <TabPanel px={0} py={6}>
-                        <p className="text-gray-500 text-sm">Informasi tambahan belum tersedia.</p>
-                   </TabPanel>
-
+                   <TabPanel px={0} py={6}><p className="text-gray-500 text-sm">Informasi tambahan belum tersedia.</p></TabPanel>
                 </TabPanels>
               </Tabs>
             </div>
           </div>
         </div>
 
+        {/* ... (Bagian Sidebar & Bottom SAMA) ... */}
         {isDesktop && (
           <div className='md:w-3/12'>
             <PriceAction product={product} />
-            <div className='flex gap-x-5 items-center justify-center'>
-              <Button as={Link} href={askAdminUrl} variant='link' target='_blank' colorScheme='gray' leftIcon={<MessageCircleIcon size={18} />} isDisabled={!hasPrice}>Ask Admin</Button>
-              <span>|</span>
-              <div className={hasPrice ? '' : 'opacity-40 pointer-events-none'}>
-                <AddToWishlist productId={product.id} />
-              </div>
-              <span>|</span>
-              {canShare && (
-                <RWebShare data={{ text: 'Check out this product', title: `${product.name} - Indoteknik.com`, url: (process.env.NEXT_PUBLIC_SELF_HOST || '') + (router?.asPath || '/'), }}>
-                  <Button variant='link' colorScheme='gray' leftIcon={<Share2Icon size={18} />} isDisabled={!hasPrice}>Share</Button>
-                </RWebShare>
-              )}
+            <div className='flex gap-x-5 items-center justify-center py-4'>
+                {/* ... Buttons ... */}
             </div>
-
             <div className='h-6' />
             <div className={style['heading']}>Produk Serupa</div>
             <div className='h-4' />
@@ -572,7 +574,6 @@ const ProductDetail = ({ product }: Props) => {
             <SimilarBottom product={product} upsellIds={upsellIds} />
           </LazyLoadComponent>
         </div>
-
         <div className='h-6 md:h-0' />
       </div>
     </>
-- 
cgit v1.2.3


From d2fb20c30fa3440369807c05d01897eb19483f4c Mon Sep 17 00:00:00 2001
From: FIN-IT_AndriFP <andrifebriyadiputra@gmail.com>
Date: Mon, 8 Dec 2025 14:55:49 +0700
Subject: (andri) modal compare without data

---
 .../product-detail/components/ProductDetail.tsx    | 95 ++++++++++++++++++----
 1 file changed, 80 insertions(+), 15 deletions(-)

(limited to 'src-migrate/modules/product-detail/components/ProductDetail.tsx')

diff --git a/src-migrate/modules/product-detail/components/ProductDetail.tsx b/src-migrate/modules/product-detail/components/ProductDetail.tsx
index fab5ecf3..f06f958a 100644
--- a/src-migrate/modules/product-detail/components/ProductDetail.tsx
+++ b/src-migrate/modules/product-detail/components/ProductDetail.tsx
@@ -49,6 +49,9 @@ import SimilarBottom from './SimilarBottom';
 import SimilarSide from './SimilarSide';
 import dynamic from 'next/dynamic';
 
+// 1. IMPORT MODAL (Baru)
+import ProductComparisonModal from './ProductComparisonModal';
+
 import { gtagProductDetail } from '@/core/utils/googleTag';
 
 type Props = {
@@ -74,6 +77,9 @@ const ProductDetail = ({ product }: Props) => {
   
   const [loadingSpecs, setLoadingSpecs] = useState(false);
 
+  // 2. STATE MODAL COMPARE (Baru)
+  const [isCompareOpen, setCompareOpen] = useState(false);
+
   useEffect(() => {
     try {
       setAuth(getAuth() ?? null);
@@ -322,6 +328,13 @@ const ProductDetail = ({ product }: Props) => {
 
   return (
     <>
+      {/* 3. MODAL POPUP DIRENDER DISINI */}
+      {/* Render di luar layout utama agar tidak tertutup elemen lain */}
+      <ProductComparisonModal 
+        isOpen={isCompareOpen} 
+        onClose={() => setCompareOpen(false)} 
+      />
+
       <div className='relative'>
         {isDesktop && !hasPrice && (
           <div className='absolute inset-0 z-[20] flex items-center justify-center pointer-events-none select-none'>
@@ -406,9 +419,9 @@ const ProductDetail = ({ product }: Props) => {
                       size={18}
                       className='text-red-600 shrink-0 mx-2'
                     />
-                    <div className='text-red-600 font-normal text-h-sm p-2'>
+                    <h1 className='text-red-600 font-normal text-h-sm'>
                       Maaf untuk saat ini Produk yang anda cari tidak tersedia
-                    </div>
+                    </h1>
                   </div>
                 )}
                 <div className='h-6 md:h-0' />
@@ -426,9 +439,9 @@ const ProductDetail = ({ product }: Props) => {
                       size={18}
                       className='text-red-600 shrink-0 mx-2'
                     />
-                    <div className='text-red-600 font-normal text-h-sm p-2'>
+                    <h1 className='text-red-600 font-normal text-h-sm'>
                       Maaf untuk saat ini Produk yang anda cari tidak tersedia
-                    </div>
+                    </h1>
                   </div>
                 )}
                 <h1 className={style['title']}>{product.name}</h1>
@@ -448,7 +461,10 @@ const ProductDetail = ({ product }: Props) => {
 
             <div className='h-4 md:h-10' />
             {!!activeVariantId && !isApproval && (
-              <ProductPromoSection product={product} productId={activeVariantId} />
+              <ProductPromoSection
+                product={product}
+                productId={activeVariantId}
+              />
             )}
 
             <div className='h-0 md:h-6' />
@@ -457,25 +473,49 @@ const ProductDetail = ({ product }: Props) => {
             <div className={style['section-card']}>
               <Tabs variant="unstyled">
                 <TabList borderBottom="1px solid" borderColor="gray.200">
-                  <Tab _selected={{ color: 'red.600', borderColor: 'red.600', borderBottomWidth: '3px', fontWeight: 'bold', marginBottom: '-1.5px' }} color="gray.500" fontWeight="medium" fontSize="sm" px={4} py={3}>Deskripsi</Tab>
-                  <Tab _selected={{ color: 'red.600', borderColor: 'red.600', borderBottomWidth: '3px', fontWeight: 'bold', marginBottom: '-1.5px' }} color="gray.500" fontWeight="medium" fontSize="sm" px={4} py={3}>Spesifikasi</Tab>
-                  <Tab _selected={{ color: 'red.600', borderColor: 'red.600', borderBottomWidth: '3px', fontWeight: 'bold', marginBottom: '-1.5px' }} color="gray.500" fontWeight="medium" fontSize="sm" px={4} py={3}>Detail Lainnya</Tab>
+                  <Tab 
+                    _selected={{ color: 'red.600', borderColor: 'red.600', borderBottomWidth: '3px', fontWeight: 'bold', marginBottom: '-1.5px' }}
+                    color="gray.500" fontWeight="medium" fontSize="sm" px={4} py={3}
+                  >
+                    Deskripsi
+                  </Tab>
+                  <Tab 
+                    _selected={{ color: 'red.600', borderColor: 'red.600', borderBottomWidth: '3px', fontWeight: 'bold', marginBottom: '-1.5px' }}
+                    color="gray.500" fontWeight="medium" fontSize="sm" px={4} py={3}
+                  >
+                    Spesifikasi
+                  </Tab>
+                  <Tab 
+                    _selected={{ color: 'red.600', borderColor: 'red.600', borderBottomWidth: '3px', fontWeight: 'bold', marginBottom: '-1.5px' }}
+                    color="gray.500" fontWeight="medium" fontSize="sm" px={4} py={3}
+                  >
+                    Detail Lainnya
+                  </Tab>
                 </TabList>
 
                 <TabPanels>
                   {/* DESKRIPSI */}
                   <TabPanel px={0} py={6}>
                     <div className='overflow-x-auto text-sm text-gray-700'>
-                      <div className={style['description']} dangerouslySetInnerHTML={{ __html: !product.description || product.description === '<p><br></p>' ? '<p>Lorem ipsum dolor sit amet.</p>' : product.description, }} />
+                      <div
+                        className={style['description']}
+                        dangerouslySetInnerHTML={{
+                          __html:
+                            !product.description || product.description === '<p><br></p>'
+                              ? '<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</p>'
+                              : product.description,
+                        }}
+                      />
                     </div>
                   </TabPanel>
 
-                  {/* SPESIFIKASI (LOGIKA GROUPING + RATA TENGAH) */}
+                  {/* SPESIFIKASI (MATRIKS & SPLIT PIPA) */}
                   <TabPanel px={0} py={2}>
                     <Box border="1px solid" borderColor="gray.200" borderRadius="sm" overflowX="auto">
                         {loadingSpecs ? (
                             <Center py={6}><Spinner color='red.500' /></Center>
                         ) : specsMatrix.length > 0 ? (
+                            // Cek Single vs Multi Variant
                             (() => {
                                 const isSingleVariant = product.variants.length === 1;
                                 const globalAlign = isSingleVariant ? "left" : "center";
@@ -484,11 +524,27 @@ const ProductDetail = ({ product }: Props) => {
                                     <Table variant="simple" size="md">
                                         <Thead bg="red.600">
                                             <Tr>
-                                                <Th width={isSingleVariant ? "30%" : "20%"} borderColor="whiteAlpha.300" color="white" fontSize="sm" textTransform="none" verticalAlign="middle">
+                                                <Th 
+                                                    width={isSingleVariant ? "30%" : "20%"} 
+                                                    borderColor="whiteAlpha.300" 
+                                                    color="white" 
+                                                    fontSize="sm" 
+                                                    textTransform="none"
+                                                    verticalAlign="middle"
+                                                >
                                                     Spesifikasi
                                                 </Th>
+                                                
                                                 {product.variants.map(v => (
-                                                    <Th key={v.id} borderColor="whiteAlpha.300" color="white" textAlign={globalAlign} fontSize="sm" textTransform="none" verticalAlign="middle">
+                                                    <Th 
+                                                        key={v.id} 
+                                                        borderColor="whiteAlpha.300" 
+                                                        color="white" 
+                                                        textAlign={globalAlign}
+                                                        fontSize="sm" 
+                                                        textTransform="none"
+                                                        verticalAlign="middle"
+                                                    >
                                                         {isSingleVariant ? 'Detail' : (v.attributes && v.attributes.length > 0 ? v.attributes.join(' - ') : v.code)}
                                                     </Th>
                                                 ))}
@@ -563,13 +619,22 @@ const ProductDetail = ({ product }: Props) => {
           </div>
         </div>
 
-        {/* ... (Bagian Sidebar & Bottom SAMA) ... */}
         {isDesktop && (
           <div className='md:w-3/12'>
-            <PriceAction product={product} />
+            {/* 4. INTEGRASI: PASSING HANDLER MODAL KE PRICE ACTION */}
+            <PriceAction 
+                product={product} 
+                onCompare={() => setCompareOpen(true)}
+            />
+            
             <div className='flex gap-x-5 items-center justify-center py-4'>
-                {/* ... Buttons ... */}
+              <Button as={Link} href={askAdminUrl} variant='link' target='_blank' colorScheme='gray' leftIcon={<MessageCircleIcon size={18} />} isDisabled={!hasPrice}>Ask Admin</Button>
+              <span>|</span>
+              <div className={hasPrice ? '' : 'opacity-40 pointer-events-none'}><AddToWishlist productId={product.id} /></div>
+              <span>|</span>
+              {canShare && (<RWebShare data={{ text: 'Check out this product', title: `${product.name} - Indoteknik.com`, url: (process.env.NEXT_PUBLIC_SELF_HOST || '') + (router?.asPath || '/'), }}><Button variant='link' colorScheme='gray' leftIcon={<Share2Icon size={18} />} isDisabled={!hasPrice}>Share</Button></RWebShare>)}
             </div>
+
             <div className='h-6' />
             <div className={style['heading']}>Produk Serupa</div>
             <div className='h-4' />
-- 
cgit v1.2.3


From f77a4beee4e668b26f69a50e318a74ca8dcbbf33 Mon Sep 17 00:00:00 2001
From: FIN-IT_AndriFP <andrifebriyadiputra@gmail.com>
Date: Thu, 11 Dec 2025 16:23:00 +0700
Subject: (andri) fix mapping solr

---
 src-migrate/modules/product-detail/components/ProductDetail.tsx | 2 ++
 1 file changed, 2 insertions(+)

(limited to 'src-migrate/modules/product-detail/components/ProductDetail.tsx')

diff --git a/src-migrate/modules/product-detail/components/ProductDetail.tsx b/src-migrate/modules/product-detail/components/ProductDetail.tsx
index f06f958a..0f851560 100644
--- a/src-migrate/modules/product-detail/components/ProductDetail.tsx
+++ b/src-migrate/modules/product-detail/components/ProductDetail.tsx
@@ -69,6 +69,8 @@ const ProductDetail = ({ product }: Props) => {
   const { isDesktop, isMobile } = useDevice();
   const router = useRouter();
   const [auth, setAuth] = useState<any>(null);
+
+  console.log('Render ProductDetail for product ID:', product);
   
   // State Data dari Magento
   const [specsMatrix, setSpecsMatrix] = useState<any[]>([]); 
-- 
cgit v1.2.3


From 31853dc731c6e4105c9cf9bd373c63e6e989caa4 Mon Sep 17 00:00:00 2001
From: FIN-IT_AndriFP <andrifebriyadiputra@gmail.com>
Date: Tue, 16 Dec 2025 14:35:33 +0700
Subject: (andri) try compare with data

---
 src-migrate/modules/product-detail/components/ProductDetail.tsx | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

(limited to 'src-migrate/modules/product-detail/components/ProductDetail.tsx')

diff --git a/src-migrate/modules/product-detail/components/ProductDetail.tsx b/src-migrate/modules/product-detail/components/ProductDetail.tsx
index 0f851560..58276f3c 100644
--- a/src-migrate/modules/product-detail/components/ProductDetail.tsx
+++ b/src-migrate/modules/product-detail/components/ProductDetail.tsx
@@ -334,7 +334,9 @@ const ProductDetail = ({ product }: Props) => {
       {/* Render di luar layout utama agar tidak tertutup elemen lain */}
       <ProductComparisonModal 
         isOpen={isCompareOpen} 
-        onClose={() => setCompareOpen(false)} 
+        onClose={() => setCompareOpen(false)}
+        mainProduct={product}
+        selectedVariant={selectedVariant}
       />
 
       <div className='relative'>
-- 
cgit v1.2.3


From fbbff6a25ed39b721927a79ce905f4d1e06e522b Mon Sep 17 00:00:00 2001
From: FIN-IT_AndriFP <andrifebriyadiputra@gmail.com>
Date: Tue, 23 Dec 2025 14:44:11 +0700
Subject: (andri) fix sticky kolom pertama specs

---
 .../product-detail/components/ProductDetail.tsx    | 198 ++++++++++++---------
 1 file changed, 118 insertions(+), 80 deletions(-)

(limited to 'src-migrate/modules/product-detail/components/ProductDetail.tsx')

diff --git a/src-migrate/modules/product-detail/components/ProductDetail.tsx b/src-migrate/modules/product-detail/components/ProductDetail.tsx
index 3beb75b4..1c9c39e0 100644
--- a/src-migrate/modules/product-detail/components/ProductDetail.tsx
+++ b/src-migrate/modules/product-detail/components/ProductDetail.tsx
@@ -460,88 +460,126 @@ const ProductDetail = ({ product }: Props) => {
                     </div>
                   </TabPanel>
 
-                  {/* SPESIFIKASI (LOGIKA GROUPING + RATA TENGAH) */}
+                  {/* SPESIFIKASI (LOGIKA GROUPING + RATA TENGAH + STICKY FIRST COLUMN) */}
                   <TabPanel px={0} py={2}>
                     <Box border="1px solid" borderColor="gray.200" borderRadius="sm" overflowX="auto">
-                        {loadingSpecs ? (
-                            <Center py={6}><Spinner color='red.500' /></Center>
-                        ) : specsMatrix.length > 0 ? (
-                            (() => {
-                                const isSingleVariant = product.variants.length === 1;
-                                const globalAlign = isSingleVariant ? "left" : "center";
-                                
-                                return (
-                                    <Table variant="simple" size="md">
-                                        <Thead bg="red.600">
-                                            <Tr>
-                                                <Th width={isSingleVariant ? "30%" : "20%"} borderColor="whiteAlpha.300" color="white" fontSize="sm" textTransform="none" verticalAlign="middle">
-                                                    Spesifikasi
-                                                </Th>
-                                                {product.variants.map(v => (
-                                                    <Th key={v.id} borderColor="whiteAlpha.300" color="white" textAlign={globalAlign} fontSize="sm" textTransform="none" verticalAlign="middle">
-                                                        {isSingleVariant ? 'Detail' : (v.attributes && v.attributes.length > 0 ? v.attributes.join(' - ') : v.code)}
-                                                    </Th>
-                                                ))}
-                                            </Tr>
-                                        </Thead>
-                                        <Tbody>
-                                            {specsMatrix.map((row, i) => {
-                                                
-                                                // CASE 1: GROUPING (Label punya ' : ')
-                                                if (row.type === 'group') {
-                                                    return (
-                                                        <Tr key={i}>
-                                                            {/* Header Group Kiri */}
-                                                            <Td fontWeight="bold" borderColor="gray.200" fontSize="sm" verticalAlign="middle">{row.label}</Td>
-                                                            
-                                                            {/* Content Group Kanan */}
-                                                            {product.variants.map(v => (
-                                                                <Td key={v.id} borderColor="gray.200" textAlign={globalAlign} fontSize="sm" verticalAlign="middle">
-                                                                    <div className={`inline-block text-left`}>
-                                                                        <div className="flex flex-col gap-0">
-                                                                            {row.children.map((child: any, idx: number) => {
-                                                                                const rawVal = child.values[v.id];
-                                                                                if (!rawVal || rawVal === '-') return null;
-                                                                                
-                                                                                return (
-                                                                                    <div key={idx} className="grid grid-cols-[auto_auto] gap-x-2">
-                                                                                        <span className="font-semibold text-gray-600 whitespace-nowrap">
-                                                                                            {child.label}:
-                                                                                        </span>
-                                                                                        <span>{renderSpecValue(rawVal)}</span>
-                                                                                    </div>
-                                                                                );
-                                                                            })}
-                                                                        </div>
-                                                                    </div>
-                                                                </Td>
-                                                            ))}
-                                                        </Tr>
-                                                    );
-                                                }
-
-                                                // CASE 2: SINGLE ITEM
-                                                return (
-                                                    <Tr key={i}>
-                                                        <Td fontWeight="bold" borderColor="gray.200" fontSize="sm" verticalAlign="middle">{row.label}</Td>
-                                                        {product.variants.map(v => {
-                                                            const rawValue = row.values[v.id] || '-';
-                                                            return (
-                                                                <Td key={v.id} borderColor="gray.200" textAlign={globalAlign} fontSize="sm" verticalAlign="middle">
-                                                                    {renderSpecValue(rawValue)}
-                                                                </Td>
-                                                            );
-                                                        })}
-                                                    </Tr>
-                                                );
-                                            })}
-                                        </Tbody>
-                                    </Table>
-                                );
-                            })()
-                        ) : (
-                            <Box p={4} color="gray.500" fontSize="sm"><Text>Spesifikasi teknis belum tersedia.</Text></Box>
-                        )}
+                      {loadingSpecs ? (
+                        <Center py={6}><Spinner color='red.500' /></Center>
+                      ) : specsMatrix.length > 0 ? (
+                        (() => {
+                          const isSingleVariant = product.variants.length === 1;
+                          const globalAlign = isSingleVariant ? "left" : "center";
+
+                          return (
+                            <Table variant="simple" size="md">
+                              <Thead bg="red.600">
+                                <Tr>
+                                  {/* 1. STICKY HEADER KOLOM PERTAMA */}
+                                  <Th 
+                                      position="sticky" 
+                                      left={0} 
+                                      zIndex={10} 
+                                      bg="red.600"
+                                      width={isSingleVariant ? "30%" : "20%"} 
+                                      borderColor="whiteAlpha.300" 
+                                      color="white" 
+                                      fontSize="sm" 
+                                      textTransform="none" 
+                                      verticalAlign="middle"
+                                      boxShadow="2px 0 5px -2px rgba(0,0,0,0.1)" // Optional: bayangan tipis pembatas
+                                  >
+                                    Spesifikasi
+                                  </Th>
+                                  {product.variants.map(v => (
+                                    <Th key={v.id} borderColor="whiteAlpha.300" color="white" textAlign={globalAlign} fontSize="sm" textTransform="none" verticalAlign="middle">
+                                      {isSingleVariant ? 'Detail' : (v.attributes && v.attributes.length > 0 ? v.attributes.join(' - ') : v.code)}
+                                    </Th>
+                                  ))}
+                                </Tr>
+                              </Thead>
+                              <Tbody>
+                                {specsMatrix.map((row, i) => {
+
+                                  // CASE 1: GROUPING
+                                  if (row.type === 'group') {
+                                    return (
+                                      <Tr key={i}>
+                                        {/* 2. STICKY BODY KOLOM PERTAMA (GROUP) */}
+                                        <Td 
+                                          position="sticky" 
+                                          left={0} 
+                                          zIndex={5} 
+                                          bg="white"
+                                          fontWeight="bold" 
+                                          borderColor="gray.200" 
+                                          fontSize="sm" 
+                                          verticalAlign="middle"
+                                          boxShadow="2px 0 5px -2px rgba(0,0,0,0.05)"
+                                        >
+                                          {row.label}
+                                        </Td>
+
+                                        {product.variants.map(v => (
+                                          <Td key={v.id} borderColor="gray.200" textAlign={globalAlign} fontSize="sm" verticalAlign="middle">
+                                            <div className={`inline-block text-left`}>
+                                              <div className="flex flex-col gap-0">
+                                                {row.children.map((child: any, idx: number) => {
+                                                  const rawVal = child.values[v.id];
+                                                  if (!rawVal || rawVal === '-') return null;
+
+                                                  return (
+                                                    <div key={idx} className="grid grid-cols-[auto_auto] gap-x-2">
+                                                      <span className="font-semibold text-gray-600 whitespace-nowrap">
+                                                        {child.label}:
+                                                      </span>
+                                                      <span>{renderSpecValue(rawVal)}</span>
+                                                    </div>
+                                                  );
+                                                })}
+                                              </div>
+                                            </div>
+                                          </Td>
+                                        ))}
+                                      </Tr>
+                                    );
+                                  }
+
+                                  // CASE 2: SINGLE ITEM
+                                  return (
+                                    <Tr key={i}>
+                                      {/* 3. STICKY BODY KOLOM PERTAMA (SINGLE) */}
+                                      <Td 
+                                          position="sticky" 
+                                          left={0} 
+                                          zIndex={5} 
+                                          bg="white"
+                                          fontWeight="bold" 
+                                          borderColor="gray.200" 
+                                          fontSize="sm" 
+                                          verticalAlign="middle"
+                                          boxShadow="2px 0 5px -2px rgba(0,0,0,0.05)"
+                                      >
+                                          {row.label}
+                                      </Td>
+                                      
+                                      {product.variants.map(v => {
+                                        const rawValue = row.values[v.id] || '-';
+                                        return (
+                                          <Td key={v.id} borderColor="gray.200" textAlign={globalAlign} fontSize="sm" verticalAlign="middle">
+                                            {renderSpecValue(rawValue)}
+                                          </Td>
+                                        );
+                                      })}
+                                    </Tr>
+                                  );
+                                })}
+                              </Tbody>
+                            </Table>
+                          );
+                        })()
+                      ) : (
+                        <Box p={4} color="gray.500" fontSize="sm"><Text>Spesifikasi teknis belum tersedia.</Text></Box>
+                      )}
                     </Box>
                   </TabPanel>
                   
-- 
cgit v1.2.3


From ddc308aa4e5da482763f97e16ab92fe777e8dfeb Mon Sep 17 00:00:00 2001
From: FIN-IT_AndriFP <andrifebriyadiputra@gmail.com>
Date: Tue, 23 Dec 2025 14:48:48 +0700
Subject: (andri) fix scrolltoindex

---
 src-migrate/modules/product-detail/components/ProductDetail.tsx | 7 +++----
 1 file changed, 3 insertions(+), 4 deletions(-)

(limited to 'src-migrate/modules/product-detail/components/ProductDetail.tsx')

diff --git a/src-migrate/modules/product-detail/components/ProductDetail.tsx b/src-migrate/modules/product-detail/components/ProductDetail.tsx
index 1c9c39e0..82b99697 100644
--- a/src-migrate/modules/product-detail/components/ProductDetail.tsx
+++ b/src-migrate/modules/product-detail/components/ProductDetail.tsx
@@ -312,10 +312,9 @@ const ProductDetail = ({ product }: Props) => {
   };
 
   const scrollToIndex = (i: number) => {
-    const el = sliderRef.current;
-    if (!el) return;
-    const elRef = sliderRef.current;
-    elRef.scrollTo({ left: i * elRef.clientWidth, behavior: 'smooth' });
+    const el = sliderRef.current; 
+    if (!el) return; 
+    el.scrollTo({ left: i * el.clientWidth, behavior: 'smooth' });
     setCurrentIdx(i);
     setMainImage(allImages[i] || '');
   };
-- 
cgit v1.2.3


From fd50180ac301916c6feb5e93598f3fc59ecb78a8 Mon Sep 17 00:00:00 2001
From: FIN-IT_AndriFP <andrifebriyadiputra@gmail.com>
Date: Mon, 5 Jan 2026 10:41:39 +0700
Subject: (andri) get desc variant product from magento

---
 .../modules/product-detail/components/ProductDetail.tsx       | 11 ++++++++++-
 1 file changed, 10 insertions(+), 1 deletion(-)

(limited to 'src-migrate/modules/product-detail/components/ProductDetail.tsx')

diff --git a/src-migrate/modules/product-detail/components/ProductDetail.tsx b/src-migrate/modules/product-detail/components/ProductDetail.tsx
index 82b99697..4cc082d8 100644
--- a/src-migrate/modules/product-detail/components/ProductDetail.tsx
+++ b/src-migrate/modules/product-detail/components/ProductDetail.tsx
@@ -71,6 +71,7 @@ const ProductDetail = ({ product }: Props) => {
   const [specsMatrix, setSpecsMatrix] = useState<any[]>([]); 
   const [upsellIds, setUpsellIds] = useState<number[]>([]);
   const [relatedIds, setRelatedIds] = useState<number[]>([]); 
+  const [descriptionMap, setDescriptionMap] = useState<Record<string, string>>({});
   
   const [loadingSpecs, setLoadingSpecs] = useState(false);
 
@@ -174,6 +175,10 @@ const ProductDetail = ({ product }: Props) => {
            setSpecsMatrix([]);
         }
 
+        if (data.descriptions){
+          setDescriptionMap(data.descriptions);
+        }
+
         // 2. Upsell & Related
         if (data.upsell_ids && Array.isArray(data.upsell_ids)) setUpsellIds(data.upsell_ids);
         else setUpsellIds([]);
@@ -319,6 +324,10 @@ const ProductDetail = ({ product }: Props) => {
     setMainImage(allImages[i] || '');
   };
 
+  const activeMagentoDesc = selectedVariant?.id ? descriptionMap[String(selectedVariant.id)] : '';
+  const finalDescription = activeMagentoDesc || product.description || 'Deskripsi produk tidak tersedia.';
+  const cleanDescription = finalDescription === '<p><br></p>' ? 'Deskripsi produk tidak tersedia.' : finalDescription;
+
   return (
     <>
       <div className='relative'>
@@ -455,7 +464,7 @@ const ProductDetail = ({ product }: Props) => {
                   {/* DESKRIPSI */}
                   <TabPanel px={0} py={6}>
                     <div className='overflow-x-auto text-sm text-gray-700'>
-                      <div className={style['description']} dangerouslySetInnerHTML={{ __html: !product.description || product.description === '<p><br></p>' ? '<p>Lorem ipsum dolor sit amet.</p>' : product.description, }} />
+                      <div className={style['description']} dangerouslySetInnerHTML={{ __html: cleanDescription }} />
                     </div>
                   </TabPanel>
 
-- 
cgit v1.2.3


From 1e4aa525ec325a23d7617133c5532ad874fe309f Mon Sep 17 00:00:00 2001
From: FIN-IT_AndriFP <andrifebriyadiputra@gmail.com>
Date: Thu, 8 Jan 2026 10:08:55 +0700
Subject: (andri) fix table spec desktop

---
 .../product-detail/components/ProductDetail.tsx    | 204 ++++++++++++---------
 1 file changed, 116 insertions(+), 88 deletions(-)

(limited to 'src-migrate/modules/product-detail/components/ProductDetail.tsx')

diff --git a/src-migrate/modules/product-detail/components/ProductDetail.tsx b/src-migrate/modules/product-detail/components/ProductDetail.tsx
index 4cc082d8..3a4d9c7e 100644
--- a/src-migrate/modules/product-detail/components/ProductDetail.tsx
+++ b/src-migrate/modules/product-detail/components/ProductDetail.tsx
@@ -468,119 +468,147 @@ const ProductDetail = ({ product }: Props) => {
                     </div>
                   </TabPanel>
 
-                  {/* SPESIFIKASI (LOGIKA GROUPING + RATA TENGAH + STICKY FIRST COLUMN) */}
+                  {/* SPESIFIKASI */}
                   <TabPanel px={0} py={2}>
-                    <Box border="1px solid" borderColor="gray.200" borderRadius="sm" overflowX="auto">
+                    <Box 
+                      border="1px solid" 
+                      borderColor="gray.200" 
+                      borderRadius="sm" 
+                      overflowX="auto"
+                      overflowY="auto"   
+                      maxHeight="500px"  
+                      css={{
+                        '&::-webkit-scrollbar': {
+                          width: '12px',  
+                          height: '12px', 
+                        },
+                        '&::-webkit-scrollbar-track': {
+                          background: '#f1f1f1',
+                        },
+                        '&::-webkit-scrollbar-thumb': {
+                          backgroundColor: '#a0aec0', 
+                          borderRadius: '8px',
+                          border: '4px solid transparent',
+                          backgroundClip: 'content-box',
+                        },
+                        '&::-webkit-scrollbar-thumb:hover': {
+                          backgroundColor: '#718096', 
+                        },
+                      }}
+                    >
                       {loadingSpecs ? (
                         <Center py={6}><Spinner color='red.500' /></Center>
                       ) : specsMatrix.length > 0 ? (
                         (() => {
-                          const isSingleVariant = product.variants.length === 1;
-                          const globalAlign = isSingleVariant ? "left" : "center";
+                          const topHeaders: any[] = [];
+                          const subHeaders: any[] = [];
+                          const flatSpecs: any[] = [];
+
+                          specsMatrix.forEach(row => {
+                            if (row.type === 'group') {
+                                topHeaders.push({ 
+                                    label: row.label, 
+                                    type: 'group', 
+                                    colSpan: row.children.length, 
+                                    rowSpan: 1 
+                                });
+                                row.children.forEach((child: any) => {
+                                    subHeaders.push(child);
+                                    flatSpecs.push(child);
+                                });
+                            } else {
+                                topHeaders.push({ 
+                                    label: row.label, 
+                                    type: 'single', 
+                                    colSpan: 1, 
+                                    rowSpan: 2 
+                                });
+                                flatSpecs.push(row);
+                            }
+                          });
 
                           return (
                             <Table variant="simple" size="md">
-                              <Thead bg="red.600">
+                              <Thead bg="red.600" position="sticky" top={0} zIndex={20}>
                                 <Tr>
-                                  {/* 1. STICKY HEADER KOLOM PERTAMA */}
                                   <Th 
-                                      position="sticky" 
-                                      left={0} 
-                                      zIndex={10} 
-                                      bg="red.600"
-                                      width={isSingleVariant ? "30%" : "20%"} 
-                                      borderColor="whiteAlpha.300" 
+                                    position="sticky" left={0} top={0} zIndex={21} bg="red.600"
+                                    rowSpan={2}
+                                    width="25%" 
+                                    borderColor="whiteAlpha.300" color="white" 
+                                    fontSize="sm" textTransform="none" verticalAlign="middle"
+                                    boxShadow="2px 0 5px -2px rgba(0,0,0,0.1)"
+                                  >
+                                    Tipe / Variant
+                                  </Th>
+
+                                  {topHeaders.map((th, idx) => (
+                                    <Th 
+                                      key={`top-${idx}`}
+                                      position="sticky" top={0} zIndex={20} bg="red.600" 
+                                      colSpan={th.colSpan}
+                                      rowSpan={th.rowSpan}
+                                      // borderColor="whiteAlpha.300" 
                                       color="white" 
+                                      textAlign="center" 
                                       fontSize="sm" 
                                       textTransform="none" 
+                                      fontWeight="800"
+                                      letterSpacing="wide"
                                       verticalAlign="middle"
-                                      boxShadow="2px 0 5px -2px rgba(0,0,0,0.1)" // Optional: bayangan tipis pembatas
-                                  >
-                                    Spesifikasi
-                                  </Th>
-                                  {product.variants.map(v => (
-                                    <Th key={v.id} borderColor="whiteAlpha.300" color="white" textAlign={globalAlign} fontSize="sm" textTransform="none" verticalAlign="middle">
-                                      {isSingleVariant ? 'Detail' : (v.attributes && v.attributes.length > 0 ? v.attributes.join(' - ') : v.code)}
+                                    >
+                                      {th.label}
+                                    </Th>
+                                  ))}
+                                </Tr>
+                                <Tr>
+                                  {subHeaders.map((sub, idx) => (
+                                    <Th 
+                                      key={`sub-${idx}`}
+                                      // borderColor="whiteAlpha.300" 
+                                      color="white" 
+                                      textAlign="center" 
+                                      fontSize="xs"
+                                      textTransform="none" 
+                                      verticalAlign="middle"
+                                      whiteSpace="nowrap"
+                                      bg="red.600"
+                                      pt={1} pb={1}
+                                    >
+                                      {sub.label}
                                     </Th>
                                   ))}
                                 </Tr>
                               </Thead>
+                              
                               <Tbody>
-                                {specsMatrix.map((row, i) => {
-
-                                  // CASE 1: GROUPING
-                                  if (row.type === 'group') {
-                                    return (
-                                      <Tr key={i}>
-                                        {/* 2. STICKY BODY KOLOM PERTAMA (GROUP) */}
+                                {product.variants.map((v, vIdx) => (
+                                  <Tr key={v.id} bg={vIdx % 2 === 0 ? 'white' : 'gray.50'}>
+                                    <Td 
+                                      position="sticky" left={0} zIndex={15} 
+                                      bg={vIdx % 2 === 0 ? 'white' : 'gray.50'}
+                                      fontWeight="bold" borderColor="gray.200" fontSize="sm" verticalAlign="middle" textAlign="center" textTransform="uppercase"
+                                      boxShadow="2px 0 5px -2px rgba(0,0,0,0.05)"
+                                    >
+                                      {v.attributes && v.attributes.length > 0 ? v.attributes.join(' - ') : v.code}
+                                    </Td>
+
+                                    {flatSpecs.map((spec, sIdx) => {
+                                      const rawValue = spec.values[v.id] || '-';
+                                      return (
                                         <Td 
-                                          position="sticky" 
-                                          left={0} 
-                                          zIndex={5} 
-                                          bg="white"
-                                          fontWeight="bold" 
+                                          key={sIdx} 
                                           borderColor="gray.200" 
+                                          textAlign="center" 
                                           fontSize="sm" 
                                           verticalAlign="middle"
-                                          boxShadow="2px 0 5px -2px rgba(0,0,0,0.05)"
                                         >
-                                          {row.label}
+                                          {renderSpecValue(rawValue)}
                                         </Td>
-
-                                        {product.variants.map(v => (
-                                          <Td key={v.id} borderColor="gray.200" textAlign={globalAlign} fontSize="sm" verticalAlign="middle">
-                                            <div className={`inline-block text-left`}>
-                                              <div className="flex flex-col gap-0">
-                                                {row.children.map((child: any, idx: number) => {
-                                                  const rawVal = child.values[v.id];
-                                                  if (!rawVal || rawVal === '-') return null;
-
-                                                  return (
-                                                    <div key={idx} className="grid grid-cols-[auto_auto] gap-x-2">
-                                                      <span className="font-semibold text-gray-600 whitespace-nowrap">
-                                                        {child.label}:
-                                                      </span>
-                                                      <span>{renderSpecValue(rawVal)}</span>
-                                                    </div>
-                                                  );
-                                                })}
-                                              </div>
-                                            </div>
-                                          </Td>
-                                        ))}
-                                      </Tr>
-                                    );
-                                  }
-
-                                  // CASE 2: SINGLE ITEM
-                                  return (
-                                    <Tr key={i}>
-                                      {/* 3. STICKY BODY KOLOM PERTAMA (SINGLE) */}
-                                      <Td 
-                                          position="sticky" 
-                                          left={0} 
-                                          zIndex={5} 
-                                          bg="white"
-                                          fontWeight="bold" 
-                                          borderColor="gray.200" 
-                                          fontSize="sm" 
-                                          verticalAlign="middle"
-                                          boxShadow="2px 0 5px -2px rgba(0,0,0,0.05)"
-                                      >
-                                          {row.label}
-                                      </Td>
-                                      
-                                      {product.variants.map(v => {
-                                        const rawValue = row.values[v.id] || '-';
-                                        return (
-                                          <Td key={v.id} borderColor="gray.200" textAlign={globalAlign} fontSize="sm" verticalAlign="middle">
-                                            {renderSpecValue(rawValue)}
-                                          </Td>
-                                        );
-                                      })}
-                                    </Tr>
-                                  );
-                                })}
+                                      );
+                                    })}
+                                  </Tr>
+                                ))}
                               </Tbody>
                             </Table>
                           );
-- 
cgit v1.2.3


From 8004947c70f9e963f942aed75e6e99c7c6e82b65 Mon Sep 17 00:00:00 2001
From: FIN-IT_AndriFP <andrifebriyadiputra@gmail.com>
Date: Thu, 8 Jan 2026 13:16:35 +0700
Subject: (andri) add minmax width td body

---
 .../modules/product-detail/components/ProductDetail.tsx  | 16 ++++++++++++++--
 1 file changed, 14 insertions(+), 2 deletions(-)

(limited to 'src-migrate/modules/product-detail/components/ProductDetail.tsx')

diff --git a/src-migrate/modules/product-detail/components/ProductDetail.tsx b/src-migrate/modules/product-detail/components/ProductDetail.tsx
index 3a4d9c7e..a18e70bb 100644
--- a/src-migrate/modules/product-detail/components/ProductDetail.tsx
+++ b/src-migrate/modules/product-detail/components/ProductDetail.tsx
@@ -535,6 +535,7 @@ const ProductDetail = ({ product }: Props) => {
                                     position="sticky" left={0} top={0} zIndex={21} bg="red.600"
                                     rowSpan={2}
                                     width="25%" 
+                                    minW="100px" 
                                     borderColor="whiteAlpha.300" color="white" 
                                     fontSize="sm" textTransform="none" verticalAlign="middle"
                                     boxShadow="2px 0 5px -2px rgba(0,0,0,0.1)"
@@ -584,15 +585,20 @@ const ProductDetail = ({ product }: Props) => {
                               <Tbody>
                                 {product.variants.map((v, vIdx) => (
                                   <Tr key={v.id} bg={vIdx % 2 === 0 ? 'white' : 'gray.50'}>
+                                    {/* 1. KOLOM JUDUL VARIANT (Sticky Kiri) */}
                                     <Td 
                                       position="sticky" left={0} zIndex={15} 
                                       bg={vIdx % 2 === 0 ? 'white' : 'gray.50'}
-                                      fontWeight="bold" borderColor="gray.200" fontSize="sm" verticalAlign="middle" textAlign="center" textTransform="uppercase"
+                                      fontWeight="bold" borderColor="gray.200" fontSize="sm" 
+                                      verticalAlign="middle"
                                       boxShadow="2px 0 5px -2px rgba(0,0,0,0.05)"
+                                      minW="100px"         
+                                      whiteSpace="normal" 
+                                      py={4}               
                                     >
                                       {v.attributes && v.attributes.length > 0 ? v.attributes.join(' - ') : v.code}
                                     </Td>
-
+                                    {/* 2. KOLOM DATA SPESIFIKASI */}
                                     {flatSpecs.map((spec, sIdx) => {
                                       const rawValue = spec.values[v.id] || '-';
                                       return (
@@ -602,6 +608,12 @@ const ProductDetail = ({ product }: Props) => {
                                           textAlign="center" 
                                           fontSize="sm" 
                                           verticalAlign="middle"
+                                          px={2}
+                                          py={3} 
+                                          minW="100px"   
+                                          maxW="150px"        
+                                          whiteSpace="normal" 
+                                          overflowWrap="break-word"
                                         >
                                           {renderSpecValue(rawValue)}
                                         </Td>
-- 
cgit v1.2.3


From 3a93af1298a725f4f399659be88bac15b8a7ca82 Mon Sep 17 00:00:00 2001
From: FIN-IT_AndriFP <andrifebriyadiputra@gmail.com>
Date: Thu, 8 Jan 2026 13:20:21 +0700
Subject: fix

---
 src-migrate/modules/product-detail/components/ProductDetail.tsx | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

(limited to 'src-migrate/modules/product-detail/components/ProductDetail.tsx')

diff --git a/src-migrate/modules/product-detail/components/ProductDetail.tsx b/src-migrate/modules/product-detail/components/ProductDetail.tsx
index a18e70bb..2652106c 100644
--- a/src-migrate/modules/product-detail/components/ProductDetail.tsx
+++ b/src-migrate/modules/product-detail/components/ProductDetail.tsx
@@ -538,9 +538,10 @@ const ProductDetail = ({ product }: Props) => {
                                     minW="100px" 
                                     borderColor="whiteAlpha.300" color="white" 
                                     fontSize="sm" textTransform="none" verticalAlign="middle"
+                                    textAlign="center"
                                     boxShadow="2px 0 5px -2px rgba(0,0,0,0.1)"
                                   >
-                                    Tipe / Variant
+                                    Variant
                                   </Th>
 
                                   {topHeaders.map((th, idx) => (
@@ -593,6 +594,7 @@ const ProductDetail = ({ product }: Props) => {
                                       verticalAlign="middle"
                                       boxShadow="2px 0 5px -2px rgba(0,0,0,0.05)"
                                       minW="100px"         
+                                      textAlign="center"
                                       whiteSpace="normal" 
                                       py={4}               
                                     >
-- 
cgit v1.2.3


From e7faa6bb5dc33f576cb53cd1f4716bf2c6b03571 Mon Sep 17 00:00:00 2001
From: FIN-IT_AndriFP <andrifebriyadiputra@gmail.com>
Date: Thu, 8 Jan 2026 13:27:25 +0700
Subject: (andri) hide brand in specs

---
 src-migrate/modules/product-detail/components/ProductDetail.tsx | 9 +++++++--
 1 file changed, 7 insertions(+), 2 deletions(-)

(limited to 'src-migrate/modules/product-detail/components/ProductDetail.tsx')

diff --git a/src-migrate/modules/product-detail/components/ProductDetail.tsx b/src-migrate/modules/product-detail/components/ProductDetail.tsx
index 2652106c..a98cb0a4 100644
--- a/src-migrate/modules/product-detail/components/ProductDetail.tsx
+++ b/src-migrate/modules/product-detail/components/ProductDetail.tsx
@@ -169,8 +169,13 @@ const ProductDetail = ({ product }: Props) => {
 
         // 1. Specs Matrix (Processed Grouping)
         if (data.specsMatrix && Array.isArray(data.specsMatrix)) {
-           const processed = processMatrixData(data.specsMatrix);
-           setSpecsMatrix(processed);
+            const filteredMatrix = data.specsMatrix.filter((item: any) => {
+            const code = item.code || '';
+            return !code.includes('z_brand');
+        });
+
+        const processed = processMatrixData(filteredMatrix);
+        setSpecsMatrix(processed);
         } else {
            setSpecsMatrix([]);
         }
-- 
cgit v1.2.3


From cc12fccc972dc4f5533a05742090bd0f1c5a3d4b Mon Sep 17 00:00:00 2001
From: FIN-IT_AndriFP <andrifebriyadiputra@gmail.com>
Date: Thu, 8 Jan 2026 14:42:37 +0700
Subject: (andri) fix sort table spec

---
 .../product-detail/components/ProductDetail.tsx    | 37 ++++++++++++++++++++--
 1 file changed, 35 insertions(+), 2 deletions(-)

(limited to 'src-migrate/modules/product-detail/components/ProductDetail.tsx')

diff --git a/src-migrate/modules/product-detail/components/ProductDetail.tsx b/src-migrate/modules/product-detail/components/ProductDetail.tsx
index a98cb0a4..387a7e5f 100644
--- a/src-migrate/modules/product-detail/components/ProductDetail.tsx
+++ b/src-migrate/modules/product-detail/components/ProductDetail.tsx
@@ -2,7 +2,8 @@ import style from '../styles/product-detail.module.css';
 
 import Link from 'next/link';
 import { useRouter } from 'next/router';
-import { useEffect, useRef, useState, UIEvent } from 'react';
+// Import useMemo
+import { useEffect, useRef, useState, UIEvent, useMemo } from 'react';
 
 // Import komponen Chakra UI
 import { 
@@ -329,6 +330,37 @@ const ProductDetail = ({ product }: Props) => {
     setMainImage(allImages[i] || '');
   };
 
+  const sortedVariants = useMemo(() => {
+    if (!product?.variants) return [];
+    
+    return [...product.variants].sort((a, b) => {
+      const labelA = a.attributes && a.attributes.length > 0 
+        ? a.attributes.join(' - ') 
+        : a.code || '';
+        
+      const labelB = b.attributes && b.attributes.length > 0 
+        ? b.attributes.join(' - ') 
+        : b.code || '';
+
+      const getNumber = (str: string) => {
+        const match = String(str).match(/(\d+(\.\d+)?)/);
+        return match ? parseFloat(match[0]) : null;
+      };
+
+      const numA = getNumber(labelA);
+      const numB = getNumber(labelB);
+
+      if (numA !== null && numB !== null && numA !== numB) {
+        return numA - numB;
+      }
+
+      return String(labelA).localeCompare(String(labelB), undefined, { 
+        numeric: true, 
+        sensitivity: 'base' 
+      });
+    });
+  }, [product.variants]);
+
   const activeMagentoDesc = selectedVariant?.id ? descriptionMap[String(selectedVariant.id)] : '';
   const finalDescription = activeMagentoDesc || product.description || 'Deskripsi produk tidak tersedia.';
   const cleanDescription = finalDescription === '<p><br></p>' ? 'Deskripsi produk tidak tersedia.' : finalDescription;
@@ -589,7 +621,8 @@ const ProductDetail = ({ product }: Props) => {
                               </Thead>
                               
                               <Tbody>
-                                {product.variants.map((v, vIdx) => (
+                                {/* MENGGUNAKAN sortedVariants HASIL REVISI */}
+                                {sortedVariants.map((v, vIdx) => (
                                   <Tr key={v.id} bg={vIdx % 2 === 0 ? 'white' : 'gray.50'}>
                                     {/* 1. KOLOM JUDUL VARIANT (Sticky Kiri) */}
                                     <Td 
-- 
cgit v1.2.3


From b45835a01655b67f52ebd933f3d2c07d803f6aaf Mon Sep 17 00:00:00 2001
From: FIN-IT_AndriFP <andrifebriyadiputra@gmail.com>
Date: Fri, 9 Jan 2026 10:33:14 +0700
Subject: (andri) ganti sticky variant kolom pertama menjadi attribute code
 pertama dari magento

---
 .../product-detail/components/ProductDetail.tsx    | 58 ++++++++++------------
 1 file changed, 25 insertions(+), 33 deletions(-)

(limited to 'src-migrate/modules/product-detail/components/ProductDetail.tsx')

diff --git a/src-migrate/modules/product-detail/components/ProductDetail.tsx b/src-migrate/modules/product-detail/components/ProductDetail.tsx
index 387a7e5f..983cb843 100644
--- a/src-migrate/modules/product-detail/components/ProductDetail.tsx
+++ b/src-migrate/modules/product-detail/components/ProductDetail.tsx
@@ -567,27 +567,20 @@ const ProductDetail = ({ product }: Props) => {
                           return (
                             <Table variant="simple" size="md">
                               <Thead bg="red.600" position="sticky" top={0} zIndex={20}>
+                                {/* Baris 1: Header Utama */}
                                 <Tr>
-                                  <Th 
-                                    position="sticky" left={0} top={0} zIndex={21} bg="red.600"
-                                    rowSpan={2}
-                                    width="25%" 
-                                    minW="100px" 
-                                    borderColor="whiteAlpha.300" color="white" 
-                                    fontSize="sm" textTransform="none" verticalAlign="middle"
-                                    textAlign="center"
-                                    boxShadow="2px 0 5px -2px rgba(0,0,0,0.1)"
-                                  >
-                                    Variant
-                                  </Th>
-
                                   {topHeaders.map((th, idx) => (
                                     <Th 
                                       key={`top-${idx}`}
-                                      position="sticky" top={0} zIndex={20} bg="red.600" 
+                                      // STICKY HEADER BARIS 1 
+                                      position={idx === 0 ? "sticky" : "static"}
+                                      left={idx === 0 ? 0 : undefined}
+                                      zIndex={idx === 0 ? 22 : 20} 
+                                      boxShadow={idx === 0 ? "2px 0 5px -2px rgba(0,0,0,0.2)" : "none"}
+                                      
+                                      bg="red.600" 
                                       colSpan={th.colSpan}
                                       rowSpan={th.rowSpan}
-                                      // borderColor="whiteAlpha.300" 
                                       color="white" 
                                       textAlign="center" 
                                       fontSize="sm" 
@@ -600,11 +593,16 @@ const ProductDetail = ({ product }: Props) => {
                                     </Th>
                                   ))}
                                 </Tr>
+
+                                {/* Baris 2: Sub Header */}
                                 <Tr>
                                   {subHeaders.map((sub, idx) => (
                                     <Th 
                                       key={`sub-${idx}`}
-                                      // borderColor="whiteAlpha.300" 
+                                      position={idx === 0 ? "sticky" : "static"}
+                                      left={idx === 0 ? 0 : undefined}
+                                      zIndex={idx === 0 ? 21 : 1} 
+                                      boxShadow={idx === 0 ? "2px 0 5px -2px rgba(0,0,0,0.2)" : "none"}
                                       color="white" 
                                       textAlign="center" 
                                       fontSize="xs"
@@ -621,39 +619,33 @@ const ProductDetail = ({ product }: Props) => {
                               </Thead>
                               
                               <Tbody>
-                                {/* MENGGUNAKAN sortedVariants HASIL REVISI */}
                                 {sortedVariants.map((v, vIdx) => (
                                   <Tr key={v.id} bg={vIdx % 2 === 0 ? 'white' : 'gray.50'}>
-                                    {/* 1. KOLOM JUDUL VARIANT (Sticky Kiri) */}
-                                    <Td 
-                                      position="sticky" left={0} zIndex={15} 
-                                      bg={vIdx % 2 === 0 ? 'white' : 'gray.50'}
-                                      fontWeight="bold" borderColor="gray.200" fontSize="sm" 
-                                      verticalAlign="middle"
-                                      boxShadow="2px 0 5px -2px rgba(0,0,0,0.05)"
-                                      minW="100px"         
-                                      textAlign="center"
-                                      whiteSpace="normal" 
-                                      py={4}               
-                                    >
-                                      {v.attributes && v.attributes.length > 0 ? v.attributes.join(' - ') : v.code}
-                                    </Td>
-                                    {/* 2. KOLOM DATA SPESIFIKASI */}
                                     {flatSpecs.map((spec, sIdx) => {
                                       const rawValue = spec.values[v.id] || '-';
+                                      const isFirstCol = sIdx === 0; 
                                       return (
                                         <Td 
                                           key={sIdx} 
+                                          // === LOGIC STICKY DATA PERTAMA ===
+                                          position={isFirstCol ? "sticky" : "static"}
+                                          left={isFirstCol ? 0 : undefined}
+                                          zIndex={isFirstCol ? 10 : 1}
+                                          bg={vIdx % 2 === 0 ? 'white' : 'gray.50'} 
+                                          boxShadow={isFirstCol ? "2px 0 5px -2px rgba(0,0,0,0.1)" : "none"}
+                                          // =================================
+                                          
                                           borderColor="gray.200" 
                                           textAlign="center" 
                                           fontSize="sm" 
                                           verticalAlign="middle"
                                           px={2}
                                           py={3} 
-                                          minW="100px"   
+                                          minW="100px"
                                           maxW="150px"        
                                           whiteSpace="normal" 
                                           overflowWrap="break-word"
+                                          fontWeight={isFirstCol ? "bold" : "normal"} 
                                         >
                                           {renderSpecValue(rawValue)}
                                         </Td>
-- 
cgit v1.2.3


From bab9bfaeeab2ba13bba1d7ed02e25b5384919bf9 Mon Sep 17 00:00:00 2001
From: FIN-IT_AndriFP <andrifebriyadiputra@gmail.com>
Date: Fri, 9 Jan 2026 10:57:14 +0700
Subject: (andri) fix sticky header

---
 .../product-detail/components/ProductDetail.tsx    | 46 ++++++++++++----------
 1 file changed, 25 insertions(+), 21 deletions(-)

(limited to 'src-migrate/modules/product-detail/components/ProductDetail.tsx')

diff --git a/src-migrate/modules/product-detail/components/ProductDetail.tsx b/src-migrate/modules/product-detail/components/ProductDetail.tsx
index 983cb843..5a2ad093 100644
--- a/src-migrate/modules/product-detail/components/ProductDetail.tsx
+++ b/src-migrate/modules/product-detail/components/ProductDetail.tsx
@@ -572,10 +572,9 @@ const ProductDetail = ({ product }: Props) => {
                                   {topHeaders.map((th, idx) => (
                                     <Th 
                                       key={`top-${idx}`}
-                                      // STICKY HEADER BARIS 1 
                                       position={idx === 0 ? "sticky" : "static"}
                                       left={idx === 0 ? 0 : undefined}
-                                      zIndex={idx === 0 ? 22 : 20} 
+                                      zIndex={idx === 0 ? 22 : 20}
                                       boxShadow={idx === 0 ? "2px 0 5px -2px rgba(0,0,0,0.2)" : "none"}
                                       
                                       bg="red.600" 
@@ -596,25 +595,30 @@ const ProductDetail = ({ product }: Props) => {
 
                                 {/* Baris 2: Sub Header */}
                                 <Tr>
-                                  {subHeaders.map((sub, idx) => (
-                                    <Th 
-                                      key={`sub-${idx}`}
-                                      position={idx === 0 ? "sticky" : "static"}
-                                      left={idx === 0 ? 0 : undefined}
-                                      zIndex={idx === 0 ? 21 : 1} 
-                                      boxShadow={idx === 0 ? "2px 0 5px -2px rgba(0,0,0,0.2)" : "none"}
-                                      color="white" 
-                                      textAlign="center" 
-                                      fontSize="xs"
-                                      textTransform="none" 
-                                      verticalAlign="middle"
-                                      whiteSpace="nowrap"
-                                      bg="red.600"
-                                      pt={1} pb={1}
-                                    >
-                                      {sub.label}
-                                    </Th>
-                                  ))}
+                                  {subHeaders.map((sub, idx) => { 
+                                    const isFirstHeaderGroup = topHeaders[0]?.type === 'group';
+                                    const shouldSticky = idx === 0 && isFirstHeaderGroup;
+                                    return (
+                                      <Th 
+                                        key={`sub-${idx}`}
+                                        position={shouldSticky ? "sticky" : "static"}
+                                        left={shouldSticky ? 0 : undefined}
+                                        zIndex={shouldSticky ? 21 : 1}
+                                        boxShadow={shouldSticky ? "2px 0 5px -2px rgba(0,0,0,0.2)" : "none"}
+                                        
+                                        color="white" 
+                                        textAlign="center" 
+                                        fontSize="xs"
+                                        textTransform="none" 
+                                        verticalAlign="middle"
+                                        whiteSpace="nowrap"
+                                        bg="red.600"
+                                        pt={1} pb={1}
+                                      >
+                                        {sub.label}
+                                      </Th>
+                                    );
+                                  })}
                                 </Tr>
                               </Thead>
                               
-- 
cgit v1.2.3


From 6c2de1aa1cc655b1da525015ac0280fd4c72731f Mon Sep 17 00:00:00 2001
From: FIN-IT_AndriFP <andrifebriyadiputra@gmail.com>
Date: Fri, 9 Jan 2026 14:29:26 +0700
Subject: border bottom none

---
 src-migrate/modules/product-detail/components/ProductDetail.tsx | 1 +
 1 file changed, 1 insertion(+)

(limited to 'src-migrate/modules/product-detail/components/ProductDetail.tsx')

diff --git a/src-migrate/modules/product-detail/components/ProductDetail.tsx b/src-migrate/modules/product-detail/components/ProductDetail.tsx
index 5a2ad093..7ca2f9a7 100644
--- a/src-migrate/modules/product-detail/components/ProductDetail.tsx
+++ b/src-migrate/modules/product-detail/components/ProductDetail.tsx
@@ -587,6 +587,7 @@ const ProductDetail = ({ product }: Props) => {
                                       fontWeight="800"
                                       letterSpacing="wide"
                                       verticalAlign="middle"
+                                      borderBottom="none"
                                     >
                                       {th.label}
                                     </Th>
-- 
cgit v1.2.3


From ab4819716063f4d7eb4578cbcb0d66077145bdab Mon Sep 17 00:00:00 2001
From: FIN-IT_AndriFP <andrifebriyadiputra@gmail.com>
Date: Mon, 12 Jan 2026 13:33:39 +0700
Subject: (andri) fix index table spek & fix view detail information di mobile

---
 .../product-detail/components/ProductDetail.tsx    | 106 +++++++++++++--------
 1 file changed, 67 insertions(+), 39 deletions(-)

(limited to 'src-migrate/modules/product-detail/components/ProductDetail.tsx')

diff --git a/src-migrate/modules/product-detail/components/ProductDetail.tsx b/src-migrate/modules/product-detail/components/ProductDetail.tsx
index 7ca2f9a7..04bf5533 100644
--- a/src-migrate/modules/product-detail/components/ProductDetail.tsx
+++ b/src-migrate/modules/product-detail/components/ProductDetail.tsx
@@ -60,6 +60,45 @@ const RWebShare = dynamic(
   () => import('react-web-share').then((m) => m.RWebShare),
   { ssr: false }
 );
+// 1. STYLE DESKTOP (Tebal, Jelas, dengan Border/Padding)
+const cssScrollbarDesktop = {
+  '&::-webkit-scrollbar': {
+    width: '10px',
+    height: '10px',
+  },
+  '&::-webkit-scrollbar-track': {
+    background: '#f1f1f1',
+    borderRadius: '4px',
+  },
+  '&::-webkit-scrollbar-thumb': {
+    backgroundColor: '#9ca3af', // Gray-400
+    borderRadius: '6px',
+    border: '2px solid #f1f1f1', // Efek padding
+  },
+  '&::-webkit-scrollbar-thumb:hover': {
+    backgroundColor: '#6b7280',
+  },
+};
+
+// 2. STYLE MOBILE (Tipis, Minimalis, Tanpa Border)
+const cssScrollbarMobile = {
+  '&::-webkit-scrollbar': {
+    width: '8px',   // Sangat tipis vertikal
+    height: '8px',  // Sangat tipis horizontal
+  },
+    '&::-webkit-scrollbar-track': {
+    background: '#f1f1f1',
+    borderRadius: '4px',
+  },
+  '&::-webkit-scrollbar-thumb': {
+    backgroundColor: '#9ca3af', // Gray-400
+    borderRadius: '6px',
+    border: '2px solid #f1f1f1', // Efek padding
+  },
+  '&::-webkit-scrollbar-thumb:hover': {
+    backgroundColor: '#6b7280',
+  },
+};
 
 const SELF_HOST = process.env.NEXT_PUBLIC_SELF_HOST;
 
@@ -494,7 +533,7 @@ const ProductDetail = ({ product }: Props) => {
                 <TabList borderBottom="1px solid" borderColor="gray.200">
                   <Tab _selected={{ color: 'red.600', borderColor: 'red.600', borderBottomWidth: '3px', fontWeight: 'bold', marginBottom: '-1.5px' }} color="gray.500" fontWeight="medium" fontSize="sm" px={4} py={3}>Deskripsi</Tab>
                   <Tab _selected={{ color: 'red.600', borderColor: 'red.600', borderBottomWidth: '3px', fontWeight: 'bold', marginBottom: '-1.5px' }} color="gray.500" fontWeight="medium" fontSize="sm" px={4} py={3}>Spesifikasi</Tab>
-                  <Tab _selected={{ color: 'red.600', borderColor: 'red.600', borderBottomWidth: '3px', fontWeight: 'bold', marginBottom: '-1.5px' }} color="gray.500" fontWeight="medium" fontSize="sm" px={4} py={3}>Detail Lainnya</Tab>
+                  {/* <Tab _selected={{ color: 'red.600', borderColor: 'red.600', borderBottomWidth: '3px', fontWeight: 'bold', marginBottom: '-1.5px' }} color="gray.500" fontWeight="medium" fontSize="sm" px={4} py={3}>Detail Lainnya</Tab> */}
                 </TabList>
 
                 <TabPanels>
@@ -514,29 +553,13 @@ const ProductDetail = ({ product }: Props) => {
                       overflowX="auto"
                       overflowY="auto"   
                       maxHeight="500px"  
-                      css={{
-                        '&::-webkit-scrollbar': {
-                          width: '12px',  
-                          height: '12px', 
-                        },
-                        '&::-webkit-scrollbar-track': {
-                          background: '#f1f1f1',
-                        },
-                        '&::-webkit-scrollbar-thumb': {
-                          backgroundColor: '#a0aec0', 
-                          borderRadius: '8px',
-                          border: '4px solid transparent',
-                          backgroundClip: 'content-box',
-                        },
-                        '&::-webkit-scrollbar-thumb:hover': {
-                          backgroundColor: '#718096', 
-                        },
-                      }}
+                      css={isMobile ? cssScrollbarMobile : cssScrollbarDesktop}
                     >
                       {loadingSpecs ? (
                         <Center py={6}><Spinner color='red.500' /></Center>
                       ) : specsMatrix.length > 0 ? (
                         (() => {
+                          // --- 1. PROSES DATA ---
                           const topHeaders: any[] = [];
                           const subHeaders: any[] = [];
                           const flatSpecs: any[] = [];
@@ -564,17 +587,19 @@ const ProductDetail = ({ product }: Props) => {
                             }
                           });
 
+                          // --- 2. RENDER TABLE (Z-INDEX DITURUNKAN) ---
                           return (
-                            <Table variant="simple" size="md">
-                              <Thead bg="red.600" position="sticky" top={0} zIndex={20}>
-                                {/* Baris 1: Header Utama */}
+                            <Table variant="simple" size={isMobile ? "sm" : "md"}>
+                              <Thead bg="red.600" position="sticky" top={0} zIndex={3}> {/* Turun dari 20 ke 3 */}
+                                {/* Row 1: Header Utama */}
                                 <Tr>
                                   {topHeaders.map((th, idx) => (
                                     <Th 
                                       key={`top-${idx}`}
+                                      // LOGIC STICKY: Index 0 Selalu Sticky
                                       position={idx === 0 ? "sticky" : "static"}
                                       left={idx === 0 ? 0 : undefined}
-                                      zIndex={idx === 0 ? 22 : 20}
+                                      zIndex={idx === 0 ? 4 : 3} // Turun dari 22 -> 4, dan 20 -> 3
                                       boxShadow={idx === 0 ? "2px 0 5px -2px rgba(0,0,0,0.2)" : "none"}
                                       
                                       bg="red.600" 
@@ -582,29 +607,31 @@ const ProductDetail = ({ product }: Props) => {
                                       rowSpan={th.rowSpan}
                                       color="white" 
                                       textAlign="center" 
-                                      fontSize="sm" 
+                                      fontSize={isMobile ? "xs" : "sm"} 
                                       textTransform="none" 
                                       fontWeight="800"
                                       letterSpacing="wide"
                                       verticalAlign="middle"
                                       borderBottom="none"
+                                      px={isMobile ? 2 : 4}
                                     >
                                       {th.label}
                                     </Th>
                                   ))}
                                 </Tr>
-
-                                {/* Baris 2: Sub Header */}
+                                
+                                {/* Row 2: Sub Header */}
                                 <Tr>
-                                  {subHeaders.map((sub, idx) => { 
+                                  {subHeaders.map((sub, idx) => {
                                     const isFirstHeaderGroup = topHeaders[0]?.type === 'group';
                                     const shouldSticky = idx === 0 && isFirstHeaderGroup;
                                     return (
                                       <Th 
                                         key={`sub-${idx}`}
+                                        // LOGIC STICKY: Aktif jika Header Utama Group & Index 0
                                         position={shouldSticky ? "sticky" : "static"}
                                         left={shouldSticky ? 0 : undefined}
-                                        zIndex={shouldSticky ? 21 : 1}
+                                        zIndex={shouldSticky ? 4 : 1} // Turun dari 21 -> 4
                                         boxShadow={shouldSticky ? "2px 0 5px -2px rgba(0,0,0,0.2)" : "none"}
                                         
                                         color="white" 
@@ -614,7 +641,9 @@ const ProductDetail = ({ product }: Props) => {
                                         verticalAlign="middle"
                                         whiteSpace="nowrap"
                                         bg="red.600"
+                                        borderBottom="none"
                                         pt={1} pb={1}
+                                        px={isMobile ? 2 : 4}
                                       >
                                         {sub.label}
                                       </Th>
@@ -622,35 +651,34 @@ const ProductDetail = ({ product }: Props) => {
                                   })}
                                 </Tr>
                               </Thead>
-                              
+
                               <Tbody>
                                 {sortedVariants.map((v, vIdx) => (
                                   <Tr key={v.id} bg={vIdx % 2 === 0 ? 'white' : 'gray.50'}>
                                     {flatSpecs.map((spec, sIdx) => {
                                       const rawValue = spec.values[v.id] || '-';
-                                      const isFirstCol = sIdx === 0; 
+                                      const isFirstCol = sIdx === 0;
                                       return (
                                         <Td 
                                           key={sIdx} 
-                                          // === LOGIC STICKY DATA PERTAMA ===
+                                          // LOGIC STICKY: Data Kolom Pertama Selalu Sticky
                                           position={isFirstCol ? "sticky" : "static"}
                                           left={isFirstCol ? 0 : undefined}
-                                          zIndex={isFirstCol ? 10 : 1}
+                                          zIndex={isFirstCol ? 2 : 1} // Turun dari 10 -> 2
                                           bg={vIdx % 2 === 0 ? 'white' : 'gray.50'} 
                                           boxShadow={isFirstCol ? "2px 0 5px -2px rgba(0,0,0,0.1)" : "none"}
-                                          // =================================
                                           
                                           borderColor="gray.200" 
                                           textAlign="center" 
-                                          fontSize="sm" 
+                                          fontSize={isMobile ? "xs" : "sm"} 
                                           verticalAlign="middle"
-                                          px={2}
+                                          px={isMobile ? 1 : 2} 
                                           py={3} 
-                                          minW="100px"
-                                          maxW="150px"        
+                                          minW={isMobile ? "100px" : "120px"} 
+                                          maxW="200px"        
                                           whiteSpace="normal" 
                                           overflowWrap="break-word"
-                                          fontWeight={isFirstCol ? "bold" : "normal"} 
+                                          fontWeight={isFirstCol ? "bold" : "normal"}
                                         >
                                           {renderSpecValue(rawValue)}
                                         </Td>
@@ -669,7 +697,7 @@ const ProductDetail = ({ product }: Props) => {
                   </TabPanel>
                   
                    {/* DETAIL LAINNYA */}
-                   <TabPanel px={0} py={6}><p className="text-gray-500 text-sm">Informasi tambahan belum tersedia.</p></TabPanel>
+                   {/* <TabPanel px={0} py={6}><p className="text-gray-500 text-sm">Informasi tambahan belum tersedia.</p></TabPanel> */}
                 </TabPanels>
               </Tabs>
             </div>
-- 
cgit v1.2.3


From 0befdef251386bd026d53721e5cb2173aebd41f2 Mon Sep 17 00:00:00 2001
From: FIN-IT_AndriFP <andrifebriyadiputra@gmail.com>
Date: Mon, 12 Jan 2026 15:28:52 +0700
Subject: (andri) fix detail informasi mobile

---
 src-migrate/modules/product-detail/components/ProductDetail.tsx | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

(limited to 'src-migrate/modules/product-detail/components/ProductDetail.tsx')

diff --git a/src-migrate/modules/product-detail/components/ProductDetail.tsx b/src-migrate/modules/product-detail/components/ProductDetail.tsx
index 04bf5533..fbfe262d 100644
--- a/src-migrate/modules/product-detail/components/ProductDetail.tsx
+++ b/src-migrate/modules/product-detail/components/ProductDetail.tsx
@@ -508,19 +508,19 @@ const ProductDetail = ({ product }: Props) => {
                 <h1 className={style['title']}>{product.name}</h1>
                 <div className='h-3 md:h-0' />
                 <Information product={product} />
-                <div className='h-6' />
+                <div className='h-2' />
               </div>
             )}
           </div>
 
           <div className='h-full'>
             {isMobile && (
-              <div className='px-4 pt-6'>
+              <div className='px-4 pt-2'>
                 <PriceAction product={product} />
               </div>
             )}
 
-            <div className='h-4 md:h-10' />
+            <div className='h-2 md:h-10' />
             {!!activeVariantId && !isApproval && (
               <ProductPromoSection product={product} productId={activeVariantId} />
             )}
-- 
cgit v1.2.3


From 8033f86a4c87241a6cdc24f84772754ee3719145 Mon Sep 17 00:00:00 2001
From: FIN-IT_AndriFP <andrifebriyadiputra@gmail.com>
Date: Mon, 12 Jan 2026 15:37:11 +0700
Subject: (andri) fix table specs jika variannya hanya ada q

---
 .../product-detail/components/ProductDetail.tsx    | 106 +++++++++++++--------
 1 file changed, 65 insertions(+), 41 deletions(-)

(limited to 'src-migrate/modules/product-detail/components/ProductDetail.tsx')

diff --git a/src-migrate/modules/product-detail/components/ProductDetail.tsx b/src-migrate/modules/product-detail/components/ProductDetail.tsx
index fbfe262d..7b166942 100644
--- a/src-migrate/modules/product-detail/components/ProductDetail.tsx
+++ b/src-migrate/modules/product-detail/components/ProductDetail.tsx
@@ -2,7 +2,6 @@ import style from '../styles/product-detail.module.css';
 
 import Link from 'next/link';
 import { useRouter } from 'next/router';
-// Import useMemo
 import { useEffect, useRef, useState, UIEvent, useMemo } from 'react';
 
 // Import komponen Chakra UI
@@ -60,6 +59,7 @@ const RWebShare = dynamic(
   () => import('react-web-share').then((m) => m.RWebShare),
   { ssr: false }
 );
+
 // 1. STYLE DESKTOP (Tebal, Jelas, dengan Border/Padding)
 const cssScrollbarDesktop = {
   '&::-webkit-scrollbar': {
@@ -83,20 +83,15 @@ const cssScrollbarDesktop = {
 // 2. STYLE MOBILE (Tipis, Minimalis, Tanpa Border)
 const cssScrollbarMobile = {
   '&::-webkit-scrollbar': {
-    width: '8px',   // Sangat tipis vertikal
-    height: '8px',  // Sangat tipis horizontal
+    width: '3px',   // Sangat tipis vertikal
+    height: '3px',  // Sangat tipis horizontal
   },
-    '&::-webkit-scrollbar-track': {
-    background: '#f1f1f1',
-    borderRadius: '4px',
+  '&::-webkit-scrollbar-track': {
+    background: 'transparent',
   },
   '&::-webkit-scrollbar-thumb': {
-    backgroundColor: '#9ca3af', // Gray-400
-    borderRadius: '6px',
-    border: '2px solid #f1f1f1', // Efek padding
-  },
-  '&::-webkit-scrollbar-thumb:hover': {
-    backgroundColor: '#6b7280',
+    backgroundColor: '#cbd5e1', // Gray-300
+    borderRadius: '3px',
   },
 };
 
@@ -244,14 +239,13 @@ const ProductDetail = ({ product }: Props) => {
   }, [product.id]); 
 
   // =========================================================================
-  // HELPER 1: GROUPING DATA BY LABEL (Separator ':')
+  // HELPER 1: GROUPING DATA BY LABEL
   // =========================================================================
   const processMatrixData = (rawMatrix: any[]) => {
       const groups: any = {};
       const result: any[] = [];
 
       rawMatrix.forEach(item => {
-          // Cek Label: "Group Name : Sub Label"
           if (item.label && item.label.includes(' : ')) {
               const parts = item.label.split(' : ');
               const groupName = parts[0].trim(); 
@@ -268,7 +262,7 @@ const ProductDetail = ({ product }: Props) => {
               
               groups[groupName].children.push({
                   ...item,
-                  label: childLabel // Override label jadi pendek
+                  label: childLabel 
               });
 
           } else {
@@ -287,7 +281,6 @@ const ProductDetail = ({ product }: Props) => {
     if (!val) return '-';
     const strVal = String(val).trim();
 
-    // URL Link
     const isUrl = !strVal.includes(' ') && (
       strVal.startsWith('http') || 
       strVal.startsWith('www.')
@@ -306,7 +299,6 @@ const ProductDetail = ({ product }: Props) => {
       );
     }
 
-    // HTML
     if (strVal.includes('<') && strVal.includes('>')) {
        return (
          <div 
@@ -316,7 +308,6 @@ const ProductDetail = ({ product }: Props) => {
        );
     }
 
-    // Teks Biasa
     return strVal;
   };
 
@@ -533,7 +524,6 @@ const ProductDetail = ({ product }: Props) => {
                 <TabList borderBottom="1px solid" borderColor="gray.200">
                   <Tab _selected={{ color: 'red.600', borderColor: 'red.600', borderBottomWidth: '3px', fontWeight: 'bold', marginBottom: '-1.5px' }} color="gray.500" fontWeight="medium" fontSize="sm" px={4} py={3}>Deskripsi</Tab>
                   <Tab _selected={{ color: 'red.600', borderColor: 'red.600', borderBottomWidth: '3px', fontWeight: 'bold', marginBottom: '-1.5px' }} color="gray.500" fontWeight="medium" fontSize="sm" px={4} py={3}>Spesifikasi</Tab>
-                  {/* <Tab _selected={{ color: 'red.600', borderColor: 'red.600', borderBottomWidth: '3px', fontWeight: 'bold', marginBottom: '-1.5px' }} color="gray.500" fontWeight="medium" fontSize="sm" px={4} py={3}>Detail Lainnya</Tab> */}
                 </TabList>
 
                 <TabPanels>
@@ -559,7 +549,55 @@ const ProductDetail = ({ product }: Props) => {
                         <Center py={6}><Spinner color='red.500' /></Center>
                       ) : specsMatrix.length > 0 ? (
                         (() => {
-                          // --- 1. PROSES DATA ---
+                          const variantCount = sortedVariants.length;
+                          const isSingleVariant = variantCount === 1;
+
+                          // === LOGIC 1: SINGLE VARIANT (VERTICAL TABLE) ===
+                          if (isSingleVariant) {
+                             const singleVariantId = sortedVariants[0].id;
+                             // Flatten data untuk list vertical
+                             const rows: any[] = [];
+                             specsMatrix.forEach(row => {
+                                if (row.type === 'group') {
+                                    row.children.forEach((child: any) => rows.push(child));
+                                } else {
+                                    rows.push(row);
+                                }
+                             });
+
+                             return (
+                               <Table variant="simple" size={isMobile ? "sm" : "md"}>
+                                 <Tbody>
+                                   {rows.map((row, idx) => (
+                                     <Tr key={idx} bg={idx % 2 === 0 ? 'white' : 'gray.50'}>
+                                       {/* Kolom Label (Kiri) */}
+                                       <Td 
+                                         width="40%" 
+                                         fontWeight="bold" 
+                                         color="gray.600"
+                                         borderColor="gray.200"
+                                         verticalAlign="top"
+                                         py={3}
+                                       >
+                                         {row.label}
+                                       </Td>
+                                       {/* Kolom Value (Kanan) */}
+                                       <Td 
+                                         color="gray.800"
+                                         borderColor="gray.200"
+                                         verticalAlign="top"
+                                         py={3}
+                                       >
+                                         {renderSpecValue(row.values[singleVariantId])}
+                                       </Td>
+                                     </Tr>
+                                   ))}
+                                 </Tbody>
+                               </Table>
+                             );
+                          }
+
+                          // === LOGIC 2: MULTIPLE VARIANTS (MATRIX TABLE HORIZONTAL) ===
                           const topHeaders: any[] = [];
                           const subHeaders: any[] = [];
                           const flatSpecs: any[] = [];
@@ -587,21 +625,17 @@ const ProductDetail = ({ product }: Props) => {
                             }
                           });
 
-                          // --- 2. RENDER TABLE (Z-INDEX DITURUNKAN) ---
                           return (
                             <Table variant="simple" size={isMobile ? "sm" : "md"}>
-                              <Thead bg="red.600" position="sticky" top={0} zIndex={3}> {/* Turun dari 20 ke 3 */}
-                                {/* Row 1: Header Utama */}
+                              <Thead bg="red.600" position="sticky" top={0} zIndex={3}>
                                 <Tr>
                                   {topHeaders.map((th, idx) => (
                                     <Th 
                                       key={`top-${idx}`}
-                                      // LOGIC STICKY: Index 0 Selalu Sticky
                                       position={idx === 0 ? "sticky" : "static"}
                                       left={idx === 0 ? 0 : undefined}
-                                      zIndex={idx === 0 ? 4 : 3} // Turun dari 22 -> 4, dan 20 -> 3
+                                      zIndex={idx === 0 ? 4 : 3}
                                       boxShadow={idx === 0 ? "2px 0 5px -2px rgba(0,0,0,0.2)" : "none"}
-                                      
                                       bg="red.600" 
                                       colSpan={th.colSpan}
                                       rowSpan={th.rowSpan}
@@ -619,21 +653,17 @@ const ProductDetail = ({ product }: Props) => {
                                     </Th>
                                   ))}
                                 </Tr>
-                                
-                                {/* Row 2: Sub Header */}
                                 <Tr>
                                   {subHeaders.map((sub, idx) => {
-                                    const isFirstHeaderGroup = topHeaders[0]?.type === 'group';
-                                    const shouldSticky = idx === 0 && isFirstHeaderGroup;
-                                    return (
+                                     const isFirstHeaderGroup = topHeaders[0]?.type === 'group';
+                                     const shouldSticky = idx === 0 && isFirstHeaderGroup;
+                                     return (
                                       <Th 
                                         key={`sub-${idx}`}
-                                        // LOGIC STICKY: Aktif jika Header Utama Group & Index 0
                                         position={shouldSticky ? "sticky" : "static"}
                                         left={shouldSticky ? 0 : undefined}
-                                        zIndex={shouldSticky ? 4 : 1} // Turun dari 21 -> 4
+                                        zIndex={shouldSticky ? 4 : 1} 
                                         boxShadow={shouldSticky ? "2px 0 5px -2px rgba(0,0,0,0.2)" : "none"}
-                                        
                                         color="white" 
                                         textAlign="center" 
                                         fontSize="xs"
@@ -641,7 +671,6 @@ const ProductDetail = ({ product }: Props) => {
                                         verticalAlign="middle"
                                         whiteSpace="nowrap"
                                         bg="red.600"
-                                        borderBottom="none"
                                         pt={1} pb={1}
                                         px={isMobile ? 2 : 4}
                                       >
@@ -661,13 +690,11 @@ const ProductDetail = ({ product }: Props) => {
                                       return (
                                         <Td 
                                           key={sIdx} 
-                                          // LOGIC STICKY: Data Kolom Pertama Selalu Sticky
                                           position={isFirstCol ? "sticky" : "static"}
                                           left={isFirstCol ? 0 : undefined}
-                                          zIndex={isFirstCol ? 2 : 1} // Turun dari 10 -> 2
+                                          zIndex={isFirstCol ? 2 : 1}
                                           bg={vIdx % 2 === 0 ? 'white' : 'gray.50'} 
                                           boxShadow={isFirstCol ? "2px 0 5px -2px rgba(0,0,0,0.1)" : "none"}
-                                          
                                           borderColor="gray.200" 
                                           textAlign="center" 
                                           fontSize={isMobile ? "xs" : "sm"} 
@@ -695,9 +722,6 @@ const ProductDetail = ({ product }: Props) => {
                       )}
                     </Box>
                   </TabPanel>
-                  
-                   {/* DETAIL LAINNYA */}
-                   {/* <TabPanel px={0} py={6}><p className="text-gray-500 text-sm">Informasi tambahan belum tersedia.</p></TabPanel> */}
                 </TabPanels>
               </Tabs>
             </div>
-- 
cgit v1.2.3


From 2843980c8bfe25d67bd70e176c546b5e2fe66975 Mon Sep 17 00:00:00 2001
From: FIN-IT_AndriFP <andrifebriyadiputra@gmail.com>
Date: Tue, 13 Jan 2026 16:29:58 +0700
Subject: on brand

---
 .../modules/product-detail/components/ProductDetail.tsx     | 13 +++++++------
 1 file changed, 7 insertions(+), 6 deletions(-)

(limited to 'src-migrate/modules/product-detail/components/ProductDetail.tsx')

diff --git a/src-migrate/modules/product-detail/components/ProductDetail.tsx b/src-migrate/modules/product-detail/components/ProductDetail.tsx
index 7b166942..05b84260 100644
--- a/src-migrate/modules/product-detail/components/ProductDetail.tsx
+++ b/src-migrate/modules/product-detail/components/ProductDetail.tsx
@@ -204,13 +204,14 @@ const ProductDetail = ({ product }: Props) => {
 
         // 1. Specs Matrix (Processed Grouping)
         if (data.specsMatrix && Array.isArray(data.specsMatrix)) {
-            const filteredMatrix = data.specsMatrix.filter((item: any) => {
-            const code = item.code || '';
-            return !code.includes('z_brand');
-        });
-
-        const processed = processMatrixData(filteredMatrix);
+        //     const filteredMatrix = data.specsMatrix.filter((item: any) => {
+        //     const code = item.code || '';
+        //     return !code.includes('z_brand');
+        // });
+        const processed = processMatrixData(data.specsMatrix);
         setSpecsMatrix(processed);
+        // const processed = processMatrixData(filteredMatrix);
+        // setSpecsMatrix(processed);
         } else {
            setSpecsMatrix([]);
         }
-- 
cgit v1.2.3


From f56cc888934d4b4ef962e967d40533ab5ded2414 Mon Sep 17 00:00:00 2001
From: FIN-IT_AndriFP <andrifebriyadiputra@gmail.com>
Date: Mon, 19 Jan 2026 09:39:25 +0700
Subject: (andri) fix view mobile compare

---
 src-migrate/modules/product-detail/components/ProductDetail.tsx | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

(limited to 'src-migrate/modules/product-detail/components/ProductDetail.tsx')

diff --git a/src-migrate/modules/product-detail/components/ProductDetail.tsx b/src-migrate/modules/product-detail/components/ProductDetail.tsx
index 54a0fb52..d63eb365 100644
--- a/src-migrate/modules/product-detail/components/ProductDetail.tsx
+++ b/src-migrate/modules/product-detail/components/ProductDetail.tsx
@@ -565,12 +565,12 @@ const ProductDetail = ({ product }: Props) => {
                   >
                     Spesifikasi
                   </Tab>
-                  <Tab 
+                  {/* <Tab 
                     _selected={{ color: 'red.600', borderColor: 'red.600', borderBottomWidth: '3px', fontWeight: 'bold', marginBottom: '-1.5px' }}
                     color="gray.500" fontWeight="medium" fontSize="sm" px={4} py={3}
                   >
                     Detail Lainnya
-                  </Tab>
+                  </Tab> */}
                 </TabList>
 
                 <TabPanels>
-- 
cgit v1.2.3


From 4a58bb303ce8dadc6b9d56c7558539c69d3fdb01 Mon Sep 17 00:00:00 2001
From: FIN-IT_AndriFP <andrifebriyadiputra@gmail.com>
Date: Thu, 29 Jan 2026 16:24:11 +0700
Subject: (andri) fix table spec jika attribute mengandung html

---
 .../product-detail/components/ProductDetail.tsx    | 23 +++++++++++++++++++++-
 1 file changed, 22 insertions(+), 1 deletion(-)

(limited to 'src-migrate/modules/product-detail/components/ProductDetail.tsx')

diff --git a/src-migrate/modules/product-detail/components/ProductDetail.tsx b/src-migrate/modules/product-detail/components/ProductDetail.tsx
index d63eb365..03089afa 100644
--- a/src-migrate/modules/product-detail/components/ProductDetail.tsx
+++ b/src-migrate/modules/product-detail/components/ProductDetail.tsx
@@ -310,8 +310,29 @@ const ProductDetail = ({ product }: Props) => {
 
     if (strVal.includes('<') && strVal.includes('>')) {
        return (
-         <div 
+         <Box 
            className="prose prose-sm text-gray-700"
+           sx={{
+             '& ul, & ol': { 
+                paddingLeft: '1.2rem', 
+                margin: 0,
+                textAlign: 'left'
+             },
+             '& li': { 
+                fontWeight: 'normal',
+                marginBottom: '4px',
+                textAlign: 'left'
+             },
+             '& strong': { 
+                display: 'block', 
+                marginBottom: '2px',
+                fontWeight: 'bold'
+             },
+             '& p': { 
+                margin: 0,
+                textAlign: 'left'
+             }
+           }}
            dangerouslySetInnerHTML={{ __html: strVal }}
          />
        );
-- 
cgit v1.2.3


From 5061031d3e2be4efb501809d725c3287fa1ba5e2 Mon Sep 17 00:00:00 2001
From: FIN-IT_AndriFP <andrifebriyadiputra@gmail.com>
Date: Fri, 30 Jan 2026 09:36:09 +0700
Subject: fix

---
 src-migrate/modules/product-detail/components/ProductDetail.tsx | 1 -
 1 file changed, 1 deletion(-)

(limited to 'src-migrate/modules/product-detail/components/ProductDetail.tsx')

diff --git a/src-migrate/modules/product-detail/components/ProductDetail.tsx b/src-migrate/modules/product-detail/components/ProductDetail.tsx
index b6db3f69..832694f6 100644
--- a/src-migrate/modules/product-detail/components/ProductDetail.tsx
+++ b/src-migrate/modules/product-detail/components/ProductDetail.tsx
@@ -185,7 +185,6 @@ const ProductDetail = ({ product }: Props) => {
     
   }, [product, auth]); 
 
-
   // 2. LOGIC FETCH DATA
   useEffect(() => {
     const fetchMagentoData = async () => {
-- 
cgit v1.2.3


From adecb2faf9bef2bb6f1740a8c8c5eb732117fc3d Mon Sep 17 00:00:00 2001
From: FIN-IT_AndriFP <andrifebriyadiputra@gmail.com>
Date: Sat, 31 Jan 2026 10:41:30 +0700
Subject: fix description tag list html

---
 .../product-detail/components/ProductDetail.tsx    | 27 +++++++++++++++++++++-
 1 file changed, 26 insertions(+), 1 deletion(-)

(limited to 'src-migrate/modules/product-detail/components/ProductDetail.tsx')

diff --git a/src-migrate/modules/product-detail/components/ProductDetail.tsx b/src-migrate/modules/product-detail/components/ProductDetail.tsx
index 832694f6..13350433 100644
--- a/src-migrate/modules/product-detail/components/ProductDetail.tsx
+++ b/src-migrate/modules/product-detail/components/ProductDetail.tsx
@@ -602,7 +602,32 @@ const ProductDetail = ({ product }: Props) => {
                   {/* DESKRIPSI */}
                   <TabPanel px={0} py={6}>
                     <div className='overflow-x-auto text-sm text-gray-700'>
-                      <div className={style['description']} dangerouslySetInnerHTML={{ __html: cleanDescription }} />
+                      <Box 
+                        className={style['description']} 
+                        sx={{
+                          'ul, ol': { 
+                              marginTop: '0.5em !important',
+                              marginBottom: '1em !important',
+                              marginLeft: '0 !important',
+                              
+                              listStylePosition: 'outside !important', 
+                              paddingLeft: '1.5em !important'         
+                          },
+                          'ul': {
+                              listStyleType: 'disc !important'
+                          },
+                          'ol': {
+                              listStyleType: 'decimal !important'
+                          },
+                          
+                          'li': { 
+                              marginBottom: '0.4em !important',
+                              paddingLeft: '0.3em !important',  
+                              lineHeight: '1.6 !important'      
+                          }
+                        }}
+                        dangerouslySetInnerHTML={{ __html: cleanDescription }} 
+                      />
                     </div>
                   </TabPanel>
 
-- 
cgit v1.2.3


From 99aa3500fc5bbb3bb24d73461639e6fc88042a85 Mon Sep 17 00:00:00 2001
From: FIN-IT_AndriFP <andrifebriyadiputra@gmail.com>
Date: Sat, 31 Jan 2026 13:55:14 +0700
Subject: fix description blink

---
 .../product-detail/components/ProductDetail.tsx    | 62 ++++++++++++----------
 1 file changed, 34 insertions(+), 28 deletions(-)

(limited to 'src-migrate/modules/product-detail/components/ProductDetail.tsx')

diff --git a/src-migrate/modules/product-detail/components/ProductDetail.tsx b/src-migrate/modules/product-detail/components/ProductDetail.tsx
index 13350433..35726437 100644
--- a/src-migrate/modules/product-detail/components/ProductDetail.tsx
+++ b/src-migrate/modules/product-detail/components/ProductDetail.tsx
@@ -21,7 +21,8 @@ import {
   Box,
   Spinner,
   Center,
-  Text
+  Text,
+  Stack
 } from '@chakra-ui/react';
 
 // Import Icons
@@ -53,6 +54,7 @@ import dynamic from 'next/dynamic';
 import ProductComparisonModal from './ProductComparisonModal';
 
 import { gtagProductDetail } from '@/core/utils/googleTag';
+import Skeleton from 'react-loading-skeleton';
 
 type Props = {
   product: IProductDetail;
@@ -601,33 +603,37 @@ const ProductDetail = ({ product }: Props) => {
                 <TabPanels>
                   {/* DESKRIPSI */}
                   <TabPanel px={0} py={6}>
-                    <div className='overflow-x-auto text-sm text-gray-700'>
-                      <Box 
-                        className={style['description']} 
-                        sx={{
-                          'ul, ol': { 
-                              marginTop: '0.5em !important',
-                              marginBottom: '1em !important',
-                              marginLeft: '0 !important',
-                              
-                              listStylePosition: 'outside !important', 
-                              paddingLeft: '1.5em !important'         
-                          },
-                          'ul': {
-                              listStyleType: 'disc !important'
-                          },
-                          'ol': {
-                              listStyleType: 'decimal !important'
-                          },
-                          
-                          'li': { 
-                              marginBottom: '0.4em !important',
-                              paddingLeft: '0.3em !important',  
-                              lineHeight: '1.6 !important'      
-                          }
-                        }}
-                        dangerouslySetInnerHTML={{ __html: cleanDescription }} 
-                      />
+                    <div className='overflow-x-auto text-sm text-gray-700'>   
+                      {loadingSpecs ? (
+                        <Stack spacing={4}>
+                          <Skeleton height='20px' width="100%" />
+                          <Skeleton height='20px' width="90%" />
+                          <Skeleton height='20px' width="95%" />
+                          <Skeleton height='20px' width="70%" />                  
+                        </Stack>
+                      ) : (
+                        <Box 
+                          className={style['description']} 
+                          sx={{
+                             'ul, ol': { 
+                                marginTop: '0.5em !important',
+                                marginBottom: '1em !important',
+                                marginLeft: '0 !important',
+                                listStylePosition: 'outside !important', 
+                                paddingLeft: '1.5em !important'        
+                             },
+                             'ul': { listStyleType: 'disc !important' },
+                             'ol': { listStyleType: 'decimal !important' },
+                             'li': { 
+                                marginBottom: '0.4em !important',
+                                paddingLeft: '0.3em !important',  
+                                lineHeight: '1.6 !important'      
+                             }
+                          }}
+                          dangerouslySetInnerHTML={{ __html: cleanDescription }} 
+                        />
+                      )}
+
                     </div>
                   </TabPanel>
 
-- 
cgit v1.2.3


From dc14a5fd2c97d50b19b043a44d61786d98fda48b Mon Sep 17 00:00:00 2001
From: Mqdd <ahmadmiqdad27@gmail.com>
Date: Sat, 31 Jan 2026 23:48:37 +0700
Subject: <Miqdad> remove console log

---
 .../product-detail/components/ProductDetail.tsx    | 741 ++++++++++++---------
 1 file changed, 444 insertions(+), 297 deletions(-)

(limited to 'src-migrate/modules/product-detail/components/ProductDetail.tsx')

diff --git a/src-migrate/modules/product-detail/components/ProductDetail.tsx b/src-migrate/modules/product-detail/components/ProductDetail.tsx
index 35726437..de205c41 100644
--- a/src-migrate/modules/product-detail/components/ProductDetail.tsx
+++ b/src-migrate/modules/product-detail/components/ProductDetail.tsx
@@ -5,24 +5,24 @@ import { useRouter } from 'next/router';
 import { useEffect, useRef, useState, UIEvent, useMemo } from 'react';
 
 // Import komponen Chakra UI
-import { 
-  Button, 
-  Tabs, 
-  TabList, 
-  TabPanels, 
-  Tab, 
-  TabPanel, 
-  Table, 
-  Tbody, 
-  Tr, 
+import {
+  Button,
+  Tabs,
+  TabList,
+  TabPanels,
+  Tab,
+  TabPanel,
+  Table,
+  Tbody,
+  Tr,
   Td,
-  Th, 
+  Th,
   Thead,
   Box,
   Spinner,
   Center,
   Text,
-  Stack
+  Stack,
 } from '@chakra-ui/react';
 
 // Import Icons
@@ -30,7 +30,7 @@ import {
   AlertTriangle,
   MessageCircleIcon,
   Share2Icon,
-  ExternalLink
+  ExternalLink,
 } from 'lucide-react';
 
 import { LazyLoadComponent } from 'react-lazy-load-image-component';
@@ -62,7 +62,7 @@ type Props = {
 
 const RWebShare = dynamic(
   () => import('react-web-share').then((m) => m.RWebShare),
-  { ssr: false }
+  { ssr: false },
 );
 
 // 1. STYLE DESKTOP (Tebal, Jelas, dengan Border/Padding)
@@ -88,8 +88,8 @@ const cssScrollbarDesktop = {
 // 2. STYLE MOBILE (Tipis, Minimalis, Tanpa Border)
 const cssScrollbarMobile = {
   '&::-webkit-scrollbar': {
-    width: '3px',   // Sangat tipis vertikal
-    height: '3px',  // Sangat tipis horizontal
+    width: '3px', // Sangat tipis vertikal
+    height: '3px', // Sangat tipis horizontal
   },
   '&::-webkit-scrollbar-track': {
     background: 'transparent',
@@ -107,14 +107,16 @@ const ProductDetail = ({ product }: Props) => {
   const router = useRouter();
   const [auth, setAuth] = useState<any>(null);
 
-  console.log('Render ProductDetail for product ID:', product);
-  
+  // console.log('Render ProductDetail for product ID:', product);
+
   // State Data dari Magento
-  const [specsMatrix, setSpecsMatrix] = useState<any[]>([]); 
+  const [specsMatrix, setSpecsMatrix] = useState<any[]>([]);
   const [upsellIds, setUpsellIds] = useState<number[]>([]);
-  const [relatedIds, setRelatedIds] = useState<number[]>([]); 
-  const [descriptionMap, setDescriptionMap] = useState<Record<string, string>>({});
-  
+  const [relatedIds, setRelatedIds] = useState<number[]>([]);
+  const [descriptionMap, setDescriptionMap] = useState<Record<string, string>>(
+    {},
+  );
+
   const [loadingSpecs, setLoadingSpecs] = useState(false);
 
   // 2. STATE MODAL COMPARE (Baru)
@@ -136,7 +138,7 @@ const ProductDetail = ({ product }: Props) => {
     activeVariantId,
     setIsApproval,
     isApproval,
-    selectedVariant, 
+    selectedVariant,
     setSelectedVariant,
   } = useProductDetail();
 
@@ -178,75 +180,75 @@ const ProductDetail = ({ product }: Props) => {
     const variantInit =
       product?.variants?.find((variant) => variant.is_in_bu) ||
       product?.variants?.[0];
-    
+
     setSelectedVariant(variantInit);
 
     setSpecsMatrix([]);
     setUpsellIds([]);
     setRelatedIds([]);
-    
-  }, [product, auth]); 
+  }, [product, auth]);
 
   // 2. LOGIC FETCH DATA
   useEffect(() => {
     const fetchMagentoData = async () => {
-      const allVariantIds = product.variants.map(v => v.id);
-      
+      const allVariantIds = product.variants.map((v) => v.id);
+
       if (allVariantIds.length === 0) return;
 
       const mainId = allVariantIds[0];
 
       setLoadingSpecs(true);
-      
+
       try {
         const params = new URLSearchParams({
-            skus: allVariantIds.join(','),
-            main_sku: String(mainId)
+          skus: allVariantIds.join(','),
+          main_sku: String(mainId),
         });
 
         const endpoint = `/api/magento-product?${params.toString()}`;
 
         const response = await fetch(endpoint, {
-            method: 'GET',
-            headers: { 'Content-Type': 'application/json' }
+          method: 'GET',
+          headers: { 'Content-Type': 'application/json' },
         });
 
         if (!response.ok) {
-            setSpecsMatrix([]);
-            setUpsellIds([]);
-            setRelatedIds([]);
-            return;
+          setSpecsMatrix([]);
+          setUpsellIds([]);
+          setRelatedIds([]);
+          return;
         }
 
         const data = await response.json();
 
         // 1. Specs Matrix (Processed Grouping)
         if (data.specsMatrix && Array.isArray(data.specsMatrix)) {
-        //     const filteredMatrix = data.specsMatrix.filter((item: any) => {
-        //     const code = item.code || '';
-        //     return !code.includes('z_brand');
-        // });
-        const processed = processMatrixData(data.specsMatrix);
-        setSpecsMatrix(processed);
-        // const processed = processMatrixData(filteredMatrix);
-        // setSpecsMatrix(processed);
+          //     const filteredMatrix = data.specsMatrix.filter((item: any) => {
+          //     const code = item.code || '';
+          //     return !code.includes('z_brand');
+          // });
+          const processed = processMatrixData(data.specsMatrix);
+          setSpecsMatrix(processed);
+          // const processed = processMatrixData(filteredMatrix);
+          // setSpecsMatrix(processed);
         } else {
-           setSpecsMatrix([]);
+          setSpecsMatrix([]);
         }
 
-        if (data.descriptions){
+        if (data.descriptions) {
           setDescriptionMap(data.descriptions);
         }
 
         // 2. Upsell & Related
-        if (data.upsell_ids && Array.isArray(data.upsell_ids)) setUpsellIds(data.upsell_ids);
+        if (data.upsell_ids && Array.isArray(data.upsell_ids))
+          setUpsellIds(data.upsell_ids);
         else setUpsellIds([]);
 
-        if (data.related_ids && Array.isArray(data.related_ids)) setRelatedIds(data.related_ids);
+        if (data.related_ids && Array.isArray(data.related_ids))
+          setRelatedIds(data.related_ids);
         else setRelatedIds([]);
-
       } catch (error) {
-        console.error("Gagal mengambil data Magento:", error);
+        console.error('Gagal mengambil data Magento:', error);
         setSpecsMatrix([]);
       } finally {
         setLoadingSpecs(false);
@@ -254,60 +256,56 @@ const ProductDetail = ({ product }: Props) => {
     };
 
     fetchMagentoData();
-
-  }, [product.id]); 
+  }, [product.id]);
 
   // HELPER 1: GROUPING DATA BY LABEL
   const processMatrixData = (rawMatrix: any[]) => {
-      const groups: any = {};
-      const result: any[] = [];
-
-      rawMatrix.forEach(item => {
-          if (item.label && item.label.includes(' : ')) {
-              const parts = item.label.split(' : ');
-              const groupName = parts[0].trim(); 
-              const childLabel = parts.slice(1).join(' : ').trim();
-
-              if (!groups[groupName]) {
-                  groups[groupName] = {
-                      type: 'group',
-                      label: groupName,
-                      children: []
-                  };
-                  result.push(groups[groupName]);
-              }
-              
-              groups[groupName].children.push({
-                  ...item,
-                  label: childLabel 
-              });
-
-          } else {
-              result.push({ ...item, type: 'single' });
-          }
-      });
+    const groups: any = {};
+    const result: any[] = [];
+
+    rawMatrix.forEach((item) => {
+      if (item.label && item.label.includes(' : ')) {
+        const parts = item.label.split(' : ');
+        const groupName = parts[0].trim();
+        const childLabel = parts.slice(1).join(' : ').trim();
+
+        if (!groups[groupName]) {
+          groups[groupName] = {
+            type: 'group',
+            label: groupName,
+            children: [],
+          };
+          result.push(groups[groupName]);
+        }
 
-      return result;
-  };
+        groups[groupName].children.push({
+          ...item,
+          label: childLabel,
+        });
+      } else {
+        result.push({ ...item, type: 'single' });
+      }
+    });
 
+    return result;
+  };
 
   // HELPER 2: RENDER SPEC VALUE
   const renderSpecValue = (val: any) => {
     if (!val) return '-';
     const strVal = String(val).trim();
 
-    const isUrl = !strVal.includes(' ') && (
-      strVal.startsWith('http') || 
-      strVal.startsWith('www.')
-    );
+    const isUrl =
+      !strVal.includes(' ') &&
+      (strVal.startsWith('http') || strVal.startsWith('www.'));
     if (isUrl) {
       const href = strVal.startsWith('http') ? strVal : `https://${strVal}`;
       return (
-        <a 
-          href={href} 
-          target="_blank" 
-          rel="noopener noreferrer"
-          className="text-red-600 hover:underline inline-flex items-center gap-1"
+        <a
+          href={href}
+          target='_blank'
+          rel='noopener noreferrer'
+          className='text-red-600 hover:underline inline-flex items-center gap-1'
         >
           <ExternalLink size={14} /> Link
         </a>
@@ -315,39 +313,38 @@ const ProductDetail = ({ product }: Props) => {
     }
 
     if (strVal.includes('<') && strVal.includes('>')) {
-       return (
-         <Box 
-           className="prose prose-sm text-gray-700"
-           sx={{
-             '& ul, & ol': { 
-                paddingLeft: '1.2rem', 
-                margin: 0,
-                textAlign: 'left'
-             },
-             '& li': { 
-                fontWeight: 'normal',
-                marginBottom: '4px',
-                textAlign: 'left'
-             },
-             '& strong': { 
-                display: 'block', 
-                marginBottom: '2px',
-                fontWeight: 'bold'
-             },
-             '& p': { 
-                margin: 0,
-                textAlign: 'left'
-             }
-           }}
-           dangerouslySetInnerHTML={{ __html: strVal }}
-         />
-       );
+      return (
+        <Box
+          className='prose prose-sm text-gray-700'
+          sx={{
+            '& ul, & ol': {
+              paddingLeft: '1.2rem',
+              margin: 0,
+              textAlign: 'left',
+            },
+            '& li': {
+              fontWeight: 'normal',
+              marginBottom: '4px',
+              textAlign: 'left',
+            },
+            '& strong': {
+              display: 'block',
+              marginBottom: '2px',
+              fontWeight: 'bold',
+            },
+            '& p': {
+              margin: 0,
+              textAlign: 'left',
+            },
+          }}
+          dangerouslySetInnerHTML={{ __html: strVal }}
+        />
+      );
     }
 
     return strVal;
   };
 
-
   const allImages = (() => {
     const arr: string[] = [];
     if (product?.image) arr.push(product.image);
@@ -389,8 +386,8 @@ const ProductDetail = ({ product }: Props) => {
   };
 
   const scrollToIndex = (i: number) => {
-    const el = sliderRef.current; 
-    if (!el) return; 
+    const el = sliderRef.current;
+    if (!el) return;
     el.scrollTo({ left: i * el.clientWidth, behavior: 'smooth' });
     setCurrentIdx(i);
     setMainImage(allImages[i] || '');
@@ -398,15 +395,17 @@ const ProductDetail = ({ product }: Props) => {
 
   const sortedVariants = useMemo(() => {
     if (!product?.variants) return [];
-    
+
     return [...product.variants].sort((a, b) => {
-      const labelA = a.attributes && a.attributes.length > 0 
-        ? a.attributes.join(' - ') 
-        : a.code || '';
-        
-      const labelB = b.attributes && b.attributes.length > 0 
-        ? b.attributes.join(' - ') 
-        : b.code || '';
+      const labelA =
+        a.attributes && a.attributes.length > 0
+          ? a.attributes.join(' - ')
+          : a.code || '';
+
+      const labelB =
+        b.attributes && b.attributes.length > 0
+          ? b.attributes.join(' - ')
+          : b.code || '';
 
       const getNumber = (str: string) => {
         const match = String(str).match(/(\d+(\.\d+)?)/);
@@ -420,23 +419,31 @@ const ProductDetail = ({ product }: Props) => {
         return numA - numB;
       }
 
-      return String(labelA).localeCompare(String(labelB), undefined, { 
-        numeric: true, 
-        sensitivity: 'base' 
+      return String(labelA).localeCompare(String(labelB), undefined, {
+        numeric: true,
+        sensitivity: 'base',
       });
     });
   }, [product.variants]);
 
-  const activeMagentoDesc = selectedVariant?.id ? descriptionMap[String(selectedVariant.id)] : '';
-  const finalDescription = activeMagentoDesc || product.description || 'Deskripsi produk tidak tersedia.';
-  const cleanDescription = finalDescription === '<p><br></p>' ? 'Deskripsi produk tidak tersedia.' : finalDescription;
+  const activeMagentoDesc = selectedVariant?.id
+    ? descriptionMap[String(selectedVariant.id)]
+    : '';
+  const finalDescription =
+    activeMagentoDesc ||
+    product.description ||
+    'Deskripsi produk tidak tersedia.';
+  const cleanDescription =
+    finalDescription === '<p><br></p>'
+      ? 'Deskripsi produk tidak tersedia.'
+      : finalDescription;
 
   return (
     <>
       {/* 3. MODAL POPUP DIRENDER DISINI */}
       {/* Render di luar layout utama agar tidak tertutup elemen lain */}
-      <ProductComparisonModal 
-        isOpen={isCompareOpen} 
+      <ProductComparisonModal
+        isOpen={isCompareOpen}
         onClose={() => setCompareOpen(false)}
         mainProduct={product}
         selectedVariant={selectedVariant}
@@ -478,23 +485,52 @@ const ProductDetail = ({ product }: Props) => {
               {/* ... Image Slider ... */}
               {isMobile ? (
                 <div className='relative'>
-                  <div ref={sliderRef} onScroll={handleMobileScroll} className='flex overflow-x-auto snap-x snap-mandatory scroll-smooth no-scrollbar' style={{ scrollBehavior: 'smooth', msOverflowStyle: 'none', scrollbarWidth: 'none' }}>
+                  <div
+                    ref={sliderRef}
+                    onScroll={handleMobileScroll}
+                    className='flex overflow-x-auto snap-x snap-mandatory scroll-smooth no-scrollbar'
+                    style={{
+                      scrollBehavior: 'smooth',
+                      msOverflowStyle: 'none',
+                      scrollbarWidth: 'none',
+                    }}
+                  >
                     {allImages.length > 0 ? (
                       allImages.map((img, i) => (
-                        <div key={i} className='w-full flex-shrink-0 snap-center flex justify-center items-center'>
-                          <img src={img} alt={`Gambar ${i + 1}`} className='w-[85%] aspect-square object-contain' onError={(e) => { (e.target as HTMLImageElement).src = '/images/noimage.jpeg'; }} />
+                        <div
+                          key={i}
+                          className='w-full flex-shrink-0 snap-center flex justify-center items-center'
+                        >
+                          <img
+                            src={img}
+                            alt={`Gambar ${i + 1}`}
+                            className='w-[85%] aspect-square object-contain'
+                            onError={(e) => {
+                              (e.target as HTMLImageElement).src =
+                                '/images/noimage.jpeg';
+                            }}
+                          />
                         </div>
                       ))
                     ) : (
                       <div className='w-full flex-shrink-0 snap-center flex justify-center items-center'>
-                        <img src={mainImage || '/images/noimage.jpeg'} alt='Gambar produk' className='w-[85%] aspect-square object-contain' />
+                        <img
+                          src={mainImage || '/images/noimage.jpeg'}
+                          alt='Gambar produk'
+                          className='w-[85%] aspect-square object-contain'
+                        />
                       </div>
                     )}
                   </div>
                   {allImages.length > 1 && (
                     <div className='absolute bottom-2 left-0 right-0 flex justify-center gap-2'>
                       {allImages.map((_, i) => (
-                        <button key={i} aria-label={`Ke slide ${i + 1}`} className={`w-2 h-2 rounded-full ${currentIdx === i ? 'bg-gray-800' : 'bg-gray-300'}`} onClick={() => scrollToIndex(i)} />
+                        <button
+                          key={i}
+                          aria-label={`Ke slide ${i + 1}`}
+                          className={`w-2 h-2 rounded-full ${currentIdx === i ? 'bg-gray-800' : 'bg-gray-300'}`}
+                          onClick={() => scrollToIndex(i)}
+                        />
                       ))}
                     </div>
                   )}
@@ -506,8 +542,21 @@ const ProductDetail = ({ product }: Props) => {
                     <div className='mt-4 overflow-x-auto'>
                       <div className='flex space-x-3 pb-3'>
                         {allImages.map((img, index) => (
-                          <div key={index} className={`flex-shrink-0 w-16 h-16 cursor-pointer border-2 rounded-md transition-colors ${mainImage === img ? 'border-red-500 ring-2 ring-red-200' : 'border-gray-200 hover:border-gray-300'}`} onClick={() => setMainImage(img)}>
-                            <img src={img} alt={`Thumbnail ${index + 1}`} className='w-full h-full object-cover rounded-sm' loading='lazy' onError={(e) => { (e.target as HTMLImageElement).src = '/images/noimage.jpeg'; }} />
+                          <div
+                            key={index}
+                            className={`flex-shrink-0 w-16 h-16 cursor-pointer border-2 rounded-md transition-colors ${mainImage === img ? 'border-red-500 ring-2 ring-red-200' : 'border-gray-200 hover:border-gray-300'}`}
+                            onClick={() => setMainImage(img)}
+                          >
+                            <img
+                              src={img}
+                              alt={`Thumbnail ${index + 1}`}
+                              className='w-full h-full object-cover rounded-sm'
+                              loading='lazy'
+                              onError={(e) => {
+                                (e.target as HTMLImageElement).src =
+                                  '/images/noimage.jpeg';
+                              }}
+                            />
                           </div>
                         ))}
                       </div>
@@ -578,17 +627,37 @@ const ProductDetail = ({ product }: Props) => {
 
             {/* === SECTION TABS: DESKRIPSI & SPESIFIKASI === */}
             <div className={style['section-card']}>
-              <Tabs variant="unstyled">
-                <TabList borderBottom="1px solid" borderColor="gray.200">
-                  <Tab 
-                    _selected={{ color: 'red.600', borderColor: 'red.600', borderBottomWidth: '3px', fontWeight: 'bold', marginBottom: '-1.5px' }}
-                    color="gray.500" fontWeight="medium" fontSize="sm" px={4} py={3}
+              <Tabs variant='unstyled'>
+                <TabList borderBottom='1px solid' borderColor='gray.200'>
+                  <Tab
+                    _selected={{
+                      color: 'red.600',
+                      borderColor: 'red.600',
+                      borderBottomWidth: '3px',
+                      fontWeight: 'bold',
+                      marginBottom: '-1.5px',
+                    }}
+                    color='gray.500'
+                    fontWeight='medium'
+                    fontSize='sm'
+                    px={4}
+                    py={3}
                   >
                     Deskripsi
                   </Tab>
-                  <Tab 
-                    _selected={{ color: 'red.600', borderColor: 'red.600', borderBottomWidth: '3px', fontWeight: 'bold', marginBottom: '-1.5px' }}
-                    color="gray.500" fontWeight="medium" fontSize="sm" px={4} py={3}
+                  <Tab
+                    _selected={{
+                      color: 'red.600',
+                      borderColor: 'red.600',
+                      borderBottomWidth: '3px',
+                      fontWeight: 'bold',
+                      marginBottom: '-1.5px',
+                    }}
+                    color='gray.500'
+                    fontWeight='medium'
+                    fontSize='sm'
+                    px={4}
+                    py={3}
                   >
                     Spesifikasi
                   </Tab>
@@ -603,53 +672,54 @@ const ProductDetail = ({ product }: Props) => {
                 <TabPanels>
                   {/* DESKRIPSI */}
                   <TabPanel px={0} py={6}>
-                    <div className='overflow-x-auto text-sm text-gray-700'>   
+                    <div className='overflow-x-auto text-sm text-gray-700'>
                       {loadingSpecs ? (
                         <Stack spacing={4}>
-                          <Skeleton height='20px' width="100%" />
-                          <Skeleton height='20px' width="90%" />
-                          <Skeleton height='20px' width="95%" />
-                          <Skeleton height='20px' width="70%" />                  
+                          <Skeleton height='20px' width='100%' />
+                          <Skeleton height='20px' width='90%' />
+                          <Skeleton height='20px' width='95%' />
+                          <Skeleton height='20px' width='70%' />
                         </Stack>
                       ) : (
-                        <Box 
-                          className={style['description']} 
+                        <Box
+                          className={style['description']}
                           sx={{
-                             'ul, ol': { 
-                                marginTop: '0.5em !important',
-                                marginBottom: '1em !important',
-                                marginLeft: '0 !important',
-                                listStylePosition: 'outside !important', 
-                                paddingLeft: '1.5em !important'        
-                             },
-                             'ul': { listStyleType: 'disc !important' },
-                             'ol': { listStyleType: 'decimal !important' },
-                             'li': { 
-                                marginBottom: '0.4em !important',
-                                paddingLeft: '0.3em !important',  
-                                lineHeight: '1.6 !important'      
-                             }
+                            'ul, ol': {
+                              marginTop: '0.5em !important',
+                              marginBottom: '1em !important',
+                              marginLeft: '0 !important',
+                              listStylePosition: 'outside !important',
+                              paddingLeft: '1.5em !important',
+                            },
+                            ul: { listStyleType: 'disc !important' },
+                            ol: { listStyleType: 'decimal !important' },
+                            li: {
+                              marginBottom: '0.4em !important',
+                              paddingLeft: '0.3em !important',
+                              lineHeight: '1.6 !important',
+                            },
                           }}
-                          dangerouslySetInnerHTML={{ __html: cleanDescription }} 
+                          dangerouslySetInnerHTML={{ __html: cleanDescription }}
                         />
                       )}
-
                     </div>
                   </TabPanel>
 
                   {/* SPESIFIKASI */}
                   <TabPanel px={0} py={2}>
-                    <Box 
-                      border="1px solid" 
-                      borderColor="gray.200" 
-                      borderRadius="sm" 
-                      overflowX="auto"
-                      overflowY="auto"   
-                      maxHeight="500px"  
+                    <Box
+                      border='1px solid'
+                      borderColor='gray.200'
+                      borderRadius='sm'
+                      overflowX='auto'
+                      overflowY='auto'
+                      maxHeight='500px'
                       css={isMobile ? cssScrollbarMobile : cssScrollbarDesktop}
                     >
                       {loadingSpecs ? (
-                        <Center py={6}><Spinner color='red.500' /></Center>
+                        <Center py={6}>
+                          <Spinner color='red.500' />
+                        </Center>
                       ) : specsMatrix.length > 0 ? (
                         (() => {
                           const variantCount = sortedVariants.length;
@@ -657,47 +727,57 @@ const ProductDetail = ({ product }: Props) => {
 
                           // === LOGIC 1: SINGLE VARIANT (VERTICAL TABLE) ===
                           if (isSingleVariant) {
-                             const singleVariantId = sortedVariants[0].id;
-                             // Flatten data untuk list vertical
-                             const rows: any[] = [];
-                             specsMatrix.forEach(row => {
-                                if (row.type === 'group') {
-                                    row.children.forEach((child: any) => rows.push(child));
-                                } else {
-                                    rows.push(row);
-                                }
-                             });
-
-                             return (
-                               <Table variant="simple" size={isMobile ? "sm" : "md"}>
-                                 <Tbody>
-                                   {rows.map((row, idx) => (
-                                     <Tr key={idx} bg={idx % 2 === 0 ? 'white' : 'gray.50'}>
-                                       {/* Kolom Label (Kiri) */}
-                                       <Td 
-                                         width="40%" 
-                                         fontWeight="bold" 
-                                         color="gray.600"
-                                         borderColor="gray.200"
-                                         verticalAlign="top"
-                                         py={3}
-                                       >
-                                         {row.label}
-                                       </Td>
-                                       {/* Kolom Value (Kanan) */}
-                                       <Td 
-                                         color="gray.800"
-                                         borderColor="gray.200"
-                                         verticalAlign="top"
-                                         py={3}
-                                       >
-                                         {renderSpecValue(row.values[singleVariantId])}
-                                       </Td>
-                                     </Tr>
-                                   ))}
-                                 </Tbody>
-                               </Table>
-                             );
+                            const singleVariantId = sortedVariants[0].id;
+                            // Flatten data untuk list vertical
+                            const rows: any[] = [];
+                            specsMatrix.forEach((row) => {
+                              if (row.type === 'group') {
+                                row.children.forEach((child: any) =>
+                                  rows.push(child),
+                                );
+                              } else {
+                                rows.push(row);
+                              }
+                            });
+
+                            return (
+                              <Table
+                                variant='simple'
+                                size={isMobile ? 'sm' : 'md'}
+                              >
+                                <Tbody>
+                                  {rows.map((row, idx) => (
+                                    <Tr
+                                      key={idx}
+                                      bg={idx % 2 === 0 ? 'white' : 'gray.50'}
+                                    >
+                                      {/* Kolom Label (Kiri) */}
+                                      <Td
+                                        width='40%'
+                                        fontWeight='bold'
+                                        color='gray.600'
+                                        borderColor='gray.200'
+                                        verticalAlign='top'
+                                        py={3}
+                                      >
+                                        {row.label}
+                                      </Td>
+                                      {/* Kolom Value (Kanan) */}
+                                      <Td
+                                        color='gray.800'
+                                        borderColor='gray.200'
+                                        verticalAlign='top'
+                                        py={3}
+                                      >
+                                        {renderSpecValue(
+                                          row.values[singleVariantId],
+                                        )}
+                                      </Td>
+                                    </Tr>
+                                  ))}
+                                </Tbody>
+                              </Table>
+                            );
                           }
 
                           // === LOGIC 2: MULTIPLE VARIANTS (MATRIX TABLE HORIZONTAL) ===
@@ -705,51 +785,63 @@ const ProductDetail = ({ product }: Props) => {
                           const subHeaders: any[] = [];
                           const flatSpecs: any[] = [];
 
-                          specsMatrix.forEach(row => {
+                          specsMatrix.forEach((row) => {
                             if (row.type === 'group') {
-                                topHeaders.push({ 
-                                    label: row.label, 
-                                    type: 'group', 
-                                    colSpan: row.children.length, 
-                                    rowSpan: 1 
-                                });
-                                row.children.forEach((child: any) => {
-                                    subHeaders.push(child);
-                                    flatSpecs.push(child);
-                                });
+                              topHeaders.push({
+                                label: row.label,
+                                type: 'group',
+                                colSpan: row.children.length,
+                                rowSpan: 1,
+                              });
+                              row.children.forEach((child: any) => {
+                                subHeaders.push(child);
+                                flatSpecs.push(child);
+                              });
                             } else {
-                                topHeaders.push({ 
-                                    label: row.label, 
-                                    type: 'single', 
-                                    colSpan: 1, 
-                                    rowSpan: 2 
-                                });
-                                flatSpecs.push(row);
+                              topHeaders.push({
+                                label: row.label,
+                                type: 'single',
+                                colSpan: 1,
+                                rowSpan: 2,
+                              });
+                              flatSpecs.push(row);
                             }
                           });
 
                           return (
-                            <Table variant="simple" size={isMobile ? "sm" : "md"}>
-                              <Thead bg="red.600" position="sticky" top={0} zIndex={3}>
+                            <Table
+                              variant='simple'
+                              size={isMobile ? 'sm' : 'md'}
+                            >
+                              <Thead
+                                bg='red.600'
+                                position='sticky'
+                                top={0}
+                                zIndex={3}
+                              >
                                 <Tr>
                                   {topHeaders.map((th, idx) => (
-                                    <Th 
+                                    <Th
                                       key={`top-${idx}`}
-                                      position={idx === 0 ? "sticky" : "static"}
+                                      position={idx === 0 ? 'sticky' : 'static'}
                                       left={idx === 0 ? 0 : undefined}
                                       zIndex={idx === 0 ? 4 : 3}
-                                      boxShadow={idx === 0 ? "2px 0 5px -2px rgba(0,0,0,0.2)" : "none"}
-                                      bg="red.600" 
+                                      boxShadow={
+                                        idx === 0
+                                          ? '2px 0 5px -2px rgba(0,0,0,0.2)'
+                                          : 'none'
+                                      }
+                                      bg='red.600'
                                       colSpan={th.colSpan}
                                       rowSpan={th.rowSpan}
-                                      color="white" 
-                                      textAlign="center" 
-                                      fontSize={isMobile ? "xs" : "sm"} 
-                                      textTransform="none" 
-                                      fontWeight="800"
-                                      letterSpacing="wide"
-                                      verticalAlign="middle"
-                                      borderBottom="none"
+                                      color='white'
+                                      textAlign='center'
+                                      fontSize={isMobile ? 'xs' : 'sm'}
+                                      textTransform='none'
+                                      fontWeight='800'
+                                      letterSpacing='wide'
+                                      verticalAlign='middle'
+                                      borderBottom='none'
                                       px={isMobile ? 2 : 4}
                                     >
                                       {th.label}
@@ -758,23 +850,32 @@ const ProductDetail = ({ product }: Props) => {
                                 </Tr>
                                 <Tr>
                                   {subHeaders.map((sub, idx) => {
-                                     const isFirstHeaderGroup = topHeaders[0]?.type === 'group';
-                                     const shouldSticky = idx === 0 && isFirstHeaderGroup;
-                                     return (
-                                      <Th 
+                                    const isFirstHeaderGroup =
+                                      topHeaders[0]?.type === 'group';
+                                    const shouldSticky =
+                                      idx === 0 && isFirstHeaderGroup;
+                                    return (
+                                      <Th
                                         key={`sub-${idx}`}
-                                        position={shouldSticky ? "sticky" : "static"}
+                                        position={
+                                          shouldSticky ? 'sticky' : 'static'
+                                        }
                                         left={shouldSticky ? 0 : undefined}
-                                        zIndex={shouldSticky ? 4 : 1} 
-                                        boxShadow={shouldSticky ? "2px 0 5px -2px rgba(0,0,0,0.2)" : "none"}
-                                        color="white" 
-                                        textAlign="center" 
-                                        fontSize="xs"
-                                        textTransform="none" 
-                                        verticalAlign="middle"
-                                        whiteSpace="nowrap"
-                                        bg="red.600"
-                                        pt={1} pb={1}
+                                        zIndex={shouldSticky ? 4 : 1}
+                                        boxShadow={
+                                          shouldSticky
+                                            ? '2px 0 5px -2px rgba(0,0,0,0.2)'
+                                            : 'none'
+                                        }
+                                        color='white'
+                                        textAlign='center'
+                                        fontSize='xs'
+                                        textTransform='none'
+                                        verticalAlign='middle'
+                                        whiteSpace='nowrap'
+                                        bg='red.600'
+                                        pt={1}
+                                        pb={1}
                                         px={isMobile ? 2 : 4}
                                       >
                                         {sub.label}
@@ -786,29 +887,42 @@ const ProductDetail = ({ product }: Props) => {
 
                               <Tbody>
                                 {sortedVariants.map((v, vIdx) => (
-                                  <Tr key={v.id} bg={vIdx % 2 === 0 ? 'white' : 'gray.50'}>
+                                  <Tr
+                                    key={v.id}
+                                    bg={vIdx % 2 === 0 ? 'white' : 'gray.50'}
+                                  >
                                     {flatSpecs.map((spec, sIdx) => {
                                       const rawValue = spec.values[v.id] || '-';
                                       const isFirstCol = sIdx === 0;
                                       return (
-                                        <Td 
-                                          key={sIdx} 
-                                          position={isFirstCol ? "sticky" : "static"}
+                                        <Td
+                                          key={sIdx}
+                                          position={
+                                            isFirstCol ? 'sticky' : 'static'
+                                          }
                                           left={isFirstCol ? 0 : undefined}
                                           zIndex={isFirstCol ? 2 : 1}
-                                          bg={vIdx % 2 === 0 ? 'white' : 'gray.50'} 
-                                          boxShadow={isFirstCol ? "2px 0 5px -2px rgba(0,0,0,0.1)" : "none"}
-                                          borderColor="gray.200" 
-                                          textAlign="center" 
-                                          fontSize={isMobile ? "xs" : "sm"} 
-                                          verticalAlign="middle"
-                                          px={isMobile ? 1 : 2} 
-                                          py={3} 
-                                          minW={isMobile ? "100px" : "120px"} 
-                                          maxW="200px"        
-                                          whiteSpace="normal" 
-                                          overflowWrap="break-word"
-                                          fontWeight={isFirstCol ? "bold" : "normal"}
+                                          bg={
+                                            vIdx % 2 === 0 ? 'white' : 'gray.50'
+                                          }
+                                          boxShadow={
+                                            isFirstCol
+                                              ? '2px 0 5px -2px rgba(0,0,0,0.1)'
+                                              : 'none'
+                                          }
+                                          borderColor='gray.200'
+                                          textAlign='center'
+                                          fontSize={isMobile ? 'xs' : 'sm'}
+                                          verticalAlign='middle'
+                                          px={isMobile ? 1 : 2}
+                                          py={3}
+                                          minW={isMobile ? '100px' : '120px'}
+                                          maxW='200px'
+                                          whiteSpace='normal'
+                                          overflowWrap='break-word'
+                                          fontWeight={
+                                            isFirstCol ? 'bold' : 'normal'
+                                          }
                                         >
                                           {renderSpecValue(rawValue)}
                                         </Td>
@@ -821,7 +935,9 @@ const ProductDetail = ({ product }: Props) => {
                           );
                         })()
                       ) : (
-                        <Box p={4} color="gray.500" fontSize="sm"><Text>Spesifikasi teknis belum tersedia.</Text></Box>
+                        <Box p={4} color='gray.500' fontSize='sm'>
+                          <Text>Spesifikasi teknis belum tersedia.</Text>
+                        </Box>
                       )}
                     </Box>
                   </TabPanel>
@@ -834,17 +950,48 @@ const ProductDetail = ({ product }: Props) => {
         {isDesktop && (
           <div className='md:w-3/12'>
             {/* 4. INTEGRASI: PASSING HANDLER MODAL KE PRICE ACTION */}
-            <PriceAction 
-                product={product} 
-                onCompare={() => setCompareOpen(true)}
+            <PriceAction
+              product={product}
+              onCompare={() => setCompareOpen(true)}
             />
-            
+
             <div className='flex gap-x-5 items-center justify-center py-4'>
-              <Button as={Link} href={askAdminUrl} variant='link' target='_blank' colorScheme='gray' leftIcon={<MessageCircleIcon size={18} />} isDisabled={!hasPrice}>Ask Admin</Button>
+              <Button
+                as={Link}
+                href={askAdminUrl}
+                variant='link'
+                target='_blank'
+                colorScheme='gray'
+                leftIcon={<MessageCircleIcon size={18} />}
+                isDisabled={!hasPrice}
+              >
+                Ask Admin
+              </Button>
               <span>|</span>
-              <div className={hasPrice ? '' : 'opacity-40 pointer-events-none'}><AddToWishlist productId={product.id} /></div>
+              <div className={hasPrice ? '' : 'opacity-40 pointer-events-none'}>
+                <AddToWishlist productId={product.id} />
+              </div>
               <span>|</span>
-              {canShare && (<RWebShare data={{ text: 'Check out this product', title: `${product.name} - Indoteknik.com`, url: (process.env.NEXT_PUBLIC_SELF_HOST || '') + (router?.asPath || '/'), }}><Button variant='link' colorScheme='gray' leftIcon={<Share2Icon size={18} />} isDisabled={!hasPrice}>Share</Button></RWebShare>)}
+              {canShare && (
+                <RWebShare
+                  data={{
+                    text: 'Check out this product',
+                    title: `${product.name} - Indoteknik.com`,
+                    url:
+                      (process.env.NEXT_PUBLIC_SELF_HOST || '') +
+                      (router?.asPath || '/'),
+                  }}
+                >
+                  <Button
+                    variant='link'
+                    colorScheme='gray'
+                    leftIcon={<Share2Icon size={18} />}
+                    isDisabled={!hasPrice}
+                  >
+                    Share
+                  </Button>
+                </RWebShare>
+              )}
             </div>
 
             <div className='h-6' />
@@ -867,4 +1014,4 @@ const ProductDetail = ({ product }: Props) => {
   );
 };
 
-export default ProductDetail;
\ No newline at end of file
+export default ProductDetail;
-- 
cgit v1.2.3

