import React, { useEffect, useState } from 'react'; import { Modal, ModalOverlay, ModalContent, ModalHeader, ModalBody, ModalCloseButton, Button, Text, Box, Badge, Grid, GridItem, Image, Input, InputGroup, InputLeftElement, VStack, HStack, IconButton, Flex, Icon, Spinner, List, ListItem, useToast, Select } from '@chakra-ui/react'; import { Search, ShoppingCart, Trash2 } from 'lucide-react'; // --- HELPER FORMATTING --- const formatPrice = (price: number) => { return new Intl.NumberFormat('id-ID', { style: 'currency', currency: 'IDR', minimumFractionDigits: 0, }).format(price); }; const renderSpecValue = (val: any) => { if (!val || val === '-') return '-'; return String(val).replace(/<[^>]*>?/gm, ''); }; type Props = { isOpen: boolean; onClose: () => void; mainProduct: any; selectedVariant: any; }; const ProductComparisonModal = ({ isOpen, onClose, mainProduct, selectedVariant }: Props) => { const toast = useToast(); // --- STATE --- const [products, setProducts] = useState<(any | null)[]>([null, null, null, null]); const [specsMatrix, setSpecsMatrix] = useState([]); const [isLoadingMatrix, setIsLoadingMatrix] = useState(false); // Search State const [activeSearchSlot, setActiveSearchSlot] = useState(null); const [searchQuery, setSearchQuery] = useState(''); const [searchResults, setSearchResults] = useState([]); const [isSearching, setIsSearching] = useState(false); // =========================================================================== // 1. LOGIC UTAMA: ISI SLOT 1 // =========================================================================== useEffect(() => { if (isOpen && mainProduct) { let activeItem = selectedVariant; if (!activeItem && mainProduct.variants && mainProduct.variants.length > 0) { activeItem = mainProduct.variants[0]; } if (!activeItem) { activeItem = mainProduct; } const targetId = activeItem.id; const displayCode = activeItem.default_code || activeItem.code || activeItem.sku || mainProduct.default_code || mainProduct.code; const variantOptions = mainProduct.variants?.map((v: any) => ({ id: v.id, code: v.default_code || v.code || v.sku, name: v.name, price: v.price?.price || v.price || 0, image: v.image })) || []; if (variantOptions.length === 0) { variantOptions.push({ id: targetId, code: displayCode, name: mainProduct.name, price: activeItem.price?.price || activeItem.price || 0, image: activeItem.image || mainProduct.image }); } const productSlot1 = { id: targetId, sku: targetId, // ID untuk API realCode: displayCode, name: mainProduct.name, price: activeItem.price?.price || activeItem.price || mainProduct.lowest_price?.price || 0, image: activeItem.image || mainProduct.image, variants: variantOptions }; setProducts((prev) => { const newSlots = [...prev]; if (!newSlots[0] || String(newSlots[0].id) !== String(targetId)) { newSlots[0] = productSlot1; } return newSlots; }); } }, [isOpen, mainProduct, selectedVariant]); // =========================================================================== // 2. FETCH SPECS // =========================================================================== useEffect(() => { const validProducts = products.filter(p => p !== null); if (!isOpen || validProducts.length === 0) return; const fetchSpecs = async () => { setIsLoadingMatrix(true); try { const allSkus = validProducts.map(p => p.sku).join(','); const mainSku = validProducts[0]?.sku; const res = await fetch(`/api/magento-product?skus=${allSkus}&main_sku=${mainSku}`); if (!res.ok) return; const data = await res.json(); if (data.specsMatrix) { setSpecsMatrix(data.specsMatrix); } } catch (err) { console.error(err); } finally { setIsLoadingMatrix(false); } }; fetchSpecs(); }, [products, isOpen]); // =========================================================================== // 3. SEARCH LOGIC // =========================================================================== useEffect(() => { const delayDebounceFn = setTimeout(async () => { if (searchQuery.length < 3) { setSearchResults([]); return; } setIsSearching(true); try { const attrSetId = selectedVariant?.attribute_set_id || mainProduct?.attribute_set_id; const params = new URLSearchParams({ source: 'compare', q: searchQuery, limit: '5', fq: attrSetId ? `attribute_set_id_i:${attrSetId}` : '' }); const res = await fetch(`/api/search?${params.toString()}`); if (res.ok) { const data = await res.json(); setSearchResults(data.response?.products || []); } else { setSearchResults([]); } } catch (e) { setSearchResults([]); } finally { setIsSearching(false); } }, 500); return () => clearTimeout(delayDebounceFn); }, [searchQuery, mainProduct, selectedVariant]); // =========================================================================== // 4. HANDLERS // =========================================================================== const handleVariantChange = (slotIndex: number, newId: string) => { const currentProduct = products[slotIndex]; if (!currentProduct || !currentProduct.variants) return; const selectedVar = currentProduct.variants.find((v: any) => String(v.id) === String(newId)); if (selectedVar) { const newProducts = [...products]; newProducts[slotIndex] = { ...currentProduct, id: selectedVar.id, sku: selectedVar.id, realCode: selectedVar.code, price: selectedVar.price, image: selectedVar.image }; setProducts(newProducts); } }; const handleAddProduct = (solrProduct: any, slotIndex: number) => { const newProducts = [...products]; const idToAdd = solrProduct.product_id_i || solrProduct.id; const codeToAdd = solrProduct.default_code_s || solrProduct.sku; if (newProducts.find(p => p && String(p.id) === String(idToAdd))) { toast({ title: "Produk sudah ada", status: "warning", position: "top" }); return; } newProducts[slotIndex] = { id: idToAdd, sku: idToAdd, realCode: codeToAdd, name: solrProduct.display_name_s || solrProduct.name_s, price: solrProduct.price_tier1_v2_f || 0, image: solrProduct.image_s, variants: [{ id: idToAdd, code: codeToAdd, name: solrProduct.name_s, price: solrProduct.price_tier1_v2_f, image: solrProduct.image_s }] }; setProducts(newProducts); setActiveSearchSlot(null); setSearchQuery(''); setSearchResults([]); }; const handleRemoveProduct = (index: number) => { const newProducts = [...products]; newProducts[index] = null; setProducts(newProducts); if (newProducts.every(p => p === null)) setSpecsMatrix([]); }; return ( Bandingkan Produk {products.filter(p => p !== null).length} Item Detail Spesifikasi Produk yang kamu pilih {/* Cell 1: Kosong */} {/* Loop Slot Produk */} {products.map((product, index) => ( {product ? ( {/* Tombol Hapus */} {index !== 0 && ( } size="xs" position="absolute" top={-2} right={-2} colorScheme="red" onClick={() => handleRemoveProduct(index)} zIndex={2} /> )} {/* Gambar */} {product.name} { (e.target as HTMLImageElement).src = '/images/noimage.jpeg'; }} /> {/* Info Harga & Nama */} {product.price > 0 ? formatPrice(product.price) : 'Hubungi Admin'} {/* Margin Bottom agar tidak tertutup dropdown */} {product.name} {/* Dropdown Varian */} {/* Tombol */} } variant="outline" colorScheme="red" size="sm" /> ) : ( // SLOT KOSONG { setActiveSearchSlot(index); setSearchQuery(''); }} onChange={(e) => setSearchQuery(e.target.value)} /> {activeSearchSlot === index && searchQuery.length > 0 && ( {isSearching ? ( ) : searchResults.length > 0 ? ( {searchResults.map((res) => ( handleAddProduct(res, index)} > { (e.target as HTMLImageElement).src = '/images/noimage.jpeg'; }} /> {res.display_name_s || res.name_s} {formatPrice(res.price_tier1_v2_f || 0)} ))} ) : ( Tidak ditemukan. )} )} Tambah produk
untuk membandingkan
)}
))} {/* --- BAGIAN SPESIFIKASI --- */} Spesifikasi Teknis {isLoadingMatrix ? ( Memuat data... ) : specsMatrix.length > 0 ? ( specsMatrix.map((row, rowIndex) => ( {/* Label (Kiri) */} {row.label} {/* Value (Rata Tengah) */} {products.map((product, colIndex) => { const val = product ? (row.values[String(product.sku)] || '-') : ''; return ( {renderSpecValue(val)} ); })} )) ) : ( Data spesifikasi belum tersedia untuk produk ini. )}
); }; export default ProductComparisonModal;