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

