diff options
| author | FIN-IT_AndriFP <andrifebriyadiputra@gmail.com> | 2025-12-19 16:48:11 +0700 |
|---|---|---|
| committer | FIN-IT_AndriFP <andrifebriyadiputra@gmail.com> | 2025-12-19 16:48:11 +0700 |
| commit | cb447f728d30e31f0cc4f4cb9f7363274925ceef (patch) | |
| tree | 886ab9873ae02010209cb3aafd6d4240d1aa0cb6 /src-migrate | |
| parent | 1876d142f492714c37efdc1eabb72709917a0c1d (diff) | |
(andri) show product ketika cari product masi kosong
Diffstat (limited to 'src-migrate')
| -rw-r--r-- | src-migrate/modules/product-detail/components/ProductComparisonModal.tsx | 38 |
1 files changed, 25 insertions, 13 deletions
diff --git a/src-migrate/modules/product-detail/components/ProductComparisonModal.tsx b/src-migrate/modules/product-detail/components/ProductComparisonModal.tsx index e0685d35..43f43ac4 100644 --- a/src-migrate/modules/product-detail/components/ProductComparisonModal.tsx +++ b/src-migrate/modules/product-detail/components/ProductComparisonModal.tsx @@ -156,30 +156,38 @@ const ProductComparisonModal = ({ isOpen, onClose, mainProduct, selectedVariant // 3. SEARCH LOGIC (MATCHED WITH API JSON) // =========================================================================== useEffect(() => { + // Gunakan timeout untuk debounce (menunggu user selesai ketik) const delayDebounceFn = setTimeout(async () => { - if (searchQuery.length < 3) { + + // LOGIKA BARU: + // Jika ada text tapi kurang dari 3 huruf -> Jangan search (hemat API) + // Jika text KOSONG (0) -> Lanjut search (ini untuk fitur 'klik muncul barang') + if (searchQuery.length > 0 && searchQuery.length < 3) { setSearchResults([]); return; } + // Jangan trigger search kalau slot belum dipilih (mencegah fetch saat modal baru buka) + if (activeSearchSlot === null) return; + setIsSearching(true); try { const attrSetId = selectedVariant?.attribute_set_id || mainProduct?.attribute_set_id; + // Tentukan Query: Kalau kosong pakai bintang (*), kalau ada isi pakai isinya + const queryParam = searchQuery === '' ? '*' : searchQuery; + const params = new URLSearchParams({ source: 'compare', - q: searchQuery, - limit: '5', - // Filter kategori aktif agar Apple-to-Apple + q: queryParam, // <-- Pakai logika wildcard + limit: '20', // <-- Ubah limit jadi 20 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([]); @@ -192,7 +200,7 @@ const ProductComparisonModal = ({ isOpen, onClose, mainProduct, selectedVariant }, 500); return () => clearTimeout(delayDebounceFn); - }, [searchQuery, mainProduct, selectedVariant]); + }, [searchQuery, mainProduct, selectedVariant, activeSearchSlot]); // =========================================================================== // 4. HANDLERS @@ -297,7 +305,7 @@ const ProductComparisonModal = ({ isOpen, onClose, mainProduct, selectedVariant )} <Box h="160px" display="flex" alignItems="center" justifyContent="center" bg="gray.50" borderRadius="md" p={2}> <Image - src={product.image || '/images/noimage.jpeg'} + src={product.image || '/images/no-image-compare.svg'} alt={product.name} maxH="100%" objectFit="contain" onError={(e) => { (e.target as HTMLImageElement).src = '/images/no-image-compare.svg'; }} /> @@ -342,8 +350,10 @@ const ProductComparisonModal = ({ isOpen, onClose, mainProduct, selectedVariant </InputGroup> {/* --- HASIL SEARCH (MAPPING FIX) --- */} - {activeSearchSlot === index && searchQuery.length > 0 && ( + {activeSearchSlot === index && ( <Box position="absolute" top="35px" left={0} right={0} bg="white" boxShadow="lg" zIndex={10} borderRadius="md" border="1px solid" borderColor="gray.200" maxH="250px" overflowY="auto"> + + {/* Tampilkan Loading jika sedang searching */} {isSearching ? ( <Box p={4} textAlign="center"><Spinner size="sm" color="red.500"/></Box> ) : searchResults.length > 0 ? ( @@ -356,11 +366,9 @@ const ProductComparisonModal = ({ isOpen, onClose, mainProduct, selectedVariant onClick={() => handleAddProduct(res, index)} > <Flex align="center" gap={2}> - <Image src={res.image || '/images/noimage.jpeg'} boxSize="30px" objectFit="contain" onError={(e) => { (e.target as HTMLImageElement).src = '/images/noimage.jpeg'; }} /> + <Image src={res.image || '/images/no-image-compare.svg'} boxSize="30px" objectFit="contain" onError={(e) => { (e.target as HTMLImageElement).src = '/images/no-image-compare.svg'; }} /> <Box> - {/* [FIX] Gunakan displayName atau name */} <Text fontSize="xs" fontWeight="bold" noOfLines={1}>{res.displayName || res.name}</Text> - {/* [FIX] Gunakan lowestPrice.price */} <Text fontSize="xs" color="red.500"> {formatPrice(res.lowestPrice?.price || 0)} </Text> @@ -370,7 +378,11 @@ const ProductComparisonModal = ({ isOpen, onClose, mainProduct, selectedVariant ))} </List> ) : ( - <Box p={3} fontSize="xs" color="gray.500" textAlign="center">Tidak ditemukan.</Box> + // Logic tambahan: Jika input kosong tapi hasil 0 (biasanya belum kelar loading awal), jangan tampilkan "Tidak Ditemukan" + // Tapi kalau sudah ngetik dan hasil 0, baru tampilkan "Tidak Ditemukan" + <Box p={3} fontSize="xs" color="gray.500" textAlign="center"> + {searchQuery === '' ? 'Menampilkan rekomendasi...' : 'Tidak ditemukan.'} + </Box> )} </Box> )} |
