From 911c74e00974aaff071bec462981bb8cef901ddb Mon Sep 17 00:00:00 2001 From: FIN-IT_AndriFP Date: Mon, 19 Jan 2026 16:20:12 +0700 Subject: (andri) fix dynamic view compare desktop --- .../product-detail/components/Information.tsx | 2 +- .../components/ProductComparisonModal.tsx | 306 ++++++++++++++------- 2 files changed, 200 insertions(+), 108 deletions(-) diff --git a/src-migrate/modules/product-detail/components/Information.tsx b/src-migrate/modules/product-detail/components/Information.tsx index 6018f6a1..cc16fb6d 100644 --- a/src-migrate/modules/product-detail/components/Information.tsx +++ b/src-migrate/modules/product-detail/components/Information.tsx @@ -213,7 +213,7 @@ const Information = ({ product }: Props) => { {/* === TOMBOL BANDINGKAN PRODUK (HANYA MOBILE) === */}
setIsCompareOpen(true)} >
diff --git a/src-migrate/modules/product-detail/components/ProductComparisonModal.tsx b/src-migrate/modules/product-detail/components/ProductComparisonModal.tsx index 45deabb3..0a81cdba 100644 --- a/src-migrate/modules/product-detail/components/ProductComparisonModal.tsx +++ b/src-migrate/modules/product-detail/components/ProductComparisonModal.tsx @@ -34,7 +34,8 @@ import { useToast, useOutsideClick, useBreakpointValue, - Divider + Divider, + ScaleFade } from '@chakra-ui/react'; import { @@ -44,7 +45,7 @@ import { AutoCompleteList, } from '@choc-ui/chakra-autocomplete'; -import { Search, Trash2, ChevronDown, X } from 'lucide-react'; +import { Search, Trash2, ChevronDown, X, Plus } from 'lucide-react'; // --- HELPER FORMATTING --- const formatPrice = (price: number) => { @@ -90,10 +91,9 @@ type Props = { const ProductComparisonModal = ({ isOpen, onClose, mainProduct, selectedVariant }: Props) => { const toast = useToast(); - // Deteksi Mobile const isMobile = useBreakpointValue({ base: true, md: false }); - const [products, setProducts] = useState<(any | null)[]>([null, null, null, null]); + const [products, setProducts] = useState<(any | null)[]>([null, null]); const [specsMatrix, setSpecsMatrix] = useState([]); const [isLoadingMatrix, setIsLoadingMatrix] = useState(false); @@ -429,15 +429,29 @@ const ProductComparisonModal = ({ isOpen, onClose, mainProduct, selectedVariant const handleRemoveProduct = (index: number) => { const newProducts = [...products]; - newProducts[index] = null; + + if (newProducts.length > 2) { + newProducts.splice(index, 1); + } else { + newProducts[index] = null; + } + setProducts(newProducts); if (newProducts.every(p => p === null)) setSpecsMatrix([]); }; - + const handleAddSlot = () => { + if (products.length < 4) { + setProducts([...products, null]); + } + }; + + // --- RENDER SLOT ITEM (REUSABLE) --- const renderProductSlot = (product: any, index: number) => { + let content; if (product) { - return ( + // TAMPILAN TERISI + content = ( {index !== 0 && ( handleRemoveProduct(index)} zIndex={2} /> )} - + {product.name} ); - } - - return ( - - - - - { setActiveSearchSlot(index); setSearchQuery(''); }} - onChange={(e) => setSearchQuery(e.target.value)} - /> - {activeSearchSlot === index && searchQuery && ( - { setSearchQuery(''); setActiveSearchSlot(null); }}> - - + } else { + // TAMPILAN KOSONG + content = ( + + {index !== 0 && products.length > 2 && ( + } + size="xs" position="absolute" top={-2} right={-2} + colorScheme="gray" variant="solid" borderRadius="full" zIndex={2} + onClick={() => handleRemoveProduct(index)} + /> )} - - - {activeSearchSlot === index && ( - - {!selectedVariant?.attribute_set_id && !mainProduct?.attribute_set_id ? ( - - Perbandingan Tidak Tersedia - Produk utama tidak memiliki data kategori yang valid untuk dibandingkan. - - ) : ( - <> - {isSearching ? ( - - ) : searchResults.length > 0 ? ( - - {searchResults.map((res) => ( - handleAddProduct(res, index)} - > - - { (e.target as HTMLImageElement).src = '/images/no-image-compare.svg'; }} - flexShrink={0} - mt={1} - /> - - - {res.displayName || res.name} - - - {formatPrice(res.lowestPrice?.price || 0)} - - - - - ))} - - ) : ( - - {searchQuery === '' ? 'Menampilkan rekomendasi...' : 'Produk tidak ditemukan.'} + + + + + { setActiveSearchSlot(index); setSearchQuery(''); }} + onChange={(e) => setSearchQuery(e.target.value)} + /> + {activeSearchSlot === index && searchQuery && ( + { setSearchQuery(''); setActiveSearchSlot(null); }}> + + + )} + + + {activeSearchSlot === index && ( + + {!selectedVariant?.attribute_set_id && !mainProduct?.attribute_set_id ? ( + + Perbandingan Tidak Tersedia + Produk utama tidak memiliki data kategori yang valid untuk dibandingkan. + ) : ( + <> + {isSearching ? ( + + ) : searchResults.length > 0 ? ( + + {searchResults.map((res) => ( + handleAddProduct(res, index)} + > + + { (e.target as HTMLImageElement).src = '/images/no-image-compare.svg'; }} + flexShrink={0} + mt={1} + /> + + + {res.displayName || res.name} + + + {formatPrice(res.lowestPrice?.price || 0)} + + + + + ))} + + ) : ( + + {searchQuery === '' ? 'Menampilkan rekomendasi...' : 'Produk tidak ditemukan.'} + + )} + )} - + )} - )} - - - Empty Slot - - Produk Belum Ditambahkan - - - + + Empty Slot + + Produk Belum Ditambahkan + + + + ); + } + + // Animasi Wrapper ScaleFade + return ( + + {content} + ); }; @@ -696,7 +727,6 @@ const ProductComparisonModal = ({ isOpen, onClose, mainProduct, selectedVariant // --- MAIN RENDER --- - // Tampilan Mobile (Drawer 75% + Slim Scrollbar) if (isMobile) { return ( @@ -708,7 +738,8 @@ const ProductComparisonModal = ({ isOpen, onClose, mainProduct, selectedVariant p={4} overflowY="auto" css={{ - '&::-webkit-scrollbar': { width: '9px', height: '10px', }, + '&::-webkit-scrollbar': { width: '4px' }, + '&::-webkit-scrollbar-track': { width: '6px' }, '&::-webkit-scrollbar-thumb': { background: '#cbd5e0', borderRadius: '24px' }, }} > @@ -719,16 +750,37 @@ const ProductComparisonModal = ({ isOpen, onClose, mainProduct, selectedVariant ); } - // Tampilan Desktop (Modal 6XL) + // Tampilan Desktop (Modal 6XL) - DYNAMIC GRID + const totalColumns = 1 + products.length + (products.length < 4 ? 1 : 0); + const productColumnsCount = products.length + (products.length < 4 ? 1 : 0); + + const SLOT_WIDTH_PX = 200; + const LABEL_WIDTH_PX = 200; + const GAP_PX = 16; + const PADDING_PX = 48; + + const calculatedWidth = LABEL_WIDTH_PX + (productColumnsCount * SLOT_WIDTH_PX) + (productColumnsCount * GAP_PX) + PADDING_PX + 'px'; + return ( - + - + + Bandingkan Produk - - {products.filter(p => p !== null).length} Item + + Baru @@ -737,8 +789,14 @@ const ProductComparisonModal = ({ isOpen, onClose, mainProduct, selectedVariant - - + + + {products.map((product, index) => ( @@ -746,7 +804,34 @@ const ProductComparisonModal = ({ isOpen, onClose, mainProduct, selectedVariant ))} - + {/* Render Tombol Tambah Slot (Jika slot < 4) */} + {products.length < 4 && ( + + {/* [TAMBAH] Animasi Wrapper ScaleFade untuk Tombol */} + + s + + + )} + + Spesifikasi Teknis @@ -761,7 +846,7 @@ const ProductComparisonModal = ({ isOpen, onClose, mainProduct, selectedVariant {isLoadingMatrix && specsMatrix.length === 0 ? ( - + Memuat data... @@ -799,10 +884,17 @@ const ProductComparisonModal = ({ isOpen, onClose, mainProduct, selectedVariant ); })} + {products.length < 4 && ( + + )} )) ) : ( - + Data spesifikasi belum tersedia untuk produk ini. )} -- cgit v1.2.3