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; // Ambil code dari properti yang tersedia 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 & Key realCode: displayCode, // String untuk Tampilan 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 { // Kirim ID ke API 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 (MATCHED WITH API JSON) // =========================================================================== 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: '*', limit: '5', // Filter kategori aktif agar Apple-to-Apple fq: attrSetId ? `attribute_set_id_i:${attrSetId}` : '' }); // Gunakan endpoint yang benar: /api/shop/search const res = await fetch(`/api/shop/search?${params.toString()}`); if (res.ok) { const data = await res.json(); // Data sudah CamelCase dari Backend 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 = (searchItem: any, slotIndex: number) => { const newProducts = [...products]; // [FIX] MAPPING DARI JSON API ANDA (CAMELCASE) // JSON: { id: 88019, code: "RX-SP0006", displayName: "...", lowestPrice: { price: ... } } const idToAdd = searchItem.id; const codeToAdd = searchItem.code; // Langsung 'code', bukan 'default_code_s' const nameToAdd = searchItem.displayName || searchItem.name; const imageToAdd = searchItem.image; const priceToAdd = searchItem.lowestPrice?.price || 0; // Cek Duplikat 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, // ID untuk API realCode: codeToAdd, // Code String untuk Tampilan name: nameToAdd, price: priceToAdd, image: imageToAdd, variants: [{ id: idToAdd, code: codeToAdd, name: nameToAdd, price: priceToAdd, image: imageToAdd }] }; 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 {products.map((product, index) => ( {product ? ( {index !== 0 && ( } size="xs" position="absolute" top={-2} right={-2} colorScheme="red" onClick={() => handleRemoveProduct(index)} zIndex={2} /> )} {product.name} { (e.target as HTMLImageElement).src = '/images/no-image-compare.svg'; }} /> {product.price > 0 ? formatPrice(product.price) : 'Hubungi Admin'} {product.name} } variant="outline" colorScheme="red" size="sm" /> ) : ( { setActiveSearchSlot(index); setSearchQuery(''); }} onChange={(e) => setSearchQuery(e.target.value)} /> {/* --- HASIL SEARCH (MAPPING FIX) --- */} {activeSearchSlot === index && searchQuery.length > 0 && ( {isSearching ? ( ) : searchResults.length > 0 ? ( {searchResults.map((res) => ( handleAddProduct(res, index)} > { (e.target as HTMLImageElement).src = '/images/noimage.jpeg'; }} /> {/* [FIX] Gunakan displayName atau name */} {res.displayName || res.name} {/* [FIX] Gunakan lowestPrice.price */} {formatPrice(res.lowestPrice?.price || 0)} ))} ) : ( Tidak ditemukan. )} )} Tambah produk
untuk membandingkan
)}
))} Spesifikasi Teknis {isLoadingMatrix ? ( Memuat data... ) : specsMatrix.length > 0 ? ( specsMatrix.map((row, rowIndex) => ( {row.label} {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;