"use client"; import React, { useState, useEffect, useCallback } from "react"; import { useRouter } from "next/navigation"; import Select from "../reuseableUI/select"; import InputField from "../reuseableUI/defaultInputField"; import { SearchIcon } from "@/app/utils/svgs/searchIcon"; import PrimaryButton from "../reuseableUI/primaryButton"; import { CrossIcon } from "@/app/utils/svgs/crossIcon"; import { useYmmStore } from "@/store/useYmmStore"; import { partsLogicClient, type PLSearchProductsResponse, } from "@/lib/client/partslogic"; import { saleorGlobalSearch, type GlobalSearchResponse } from "@/lib/client/saleor"; import { getFullImageUrl } from "@/app/utils/functions"; interface GlobalSearchProps { setShowSearch: (show: boolean) => void; } interface SearchProduct { id: string; name: string; slug: string; thumbnail?: { url: string; alt?: string | null } | null; category?: { id: string; name: string } | null; } interface SearchCategory { id: string; name: string; slug: string; backgroundImage?: { url: string; alt?: string | null } | null; productCount?: number; } interface SearchProductType { id: string; name: string; slug: string; } const GlobalSearch: React.FC = ({ setShowSearch }) => { const router = useRouter(); const isYmmActive = useYmmStore((state) => state.isYmmActive); const [searchQuery, setSearchQuery] = useState(""); const [category, setCategory] = useState(""); const [categories, setCategories] = useState< Array<{ value: string; label: string }> >([]); const [searchResults, setSearchResults] = useState<{ products: SearchProduct[]; categories: SearchCategory[]; productTypes: SearchProductType[]; } | null>(null); const [isSearching, setIsSearching] = useState(false); const [showDropdown, setShowDropdown] = useState(false); // Debounced search - uses REST API if YMM is active, GraphQL otherwise const performSearch = useCallback( async (query: string) => { if (!query || query.trim().length < 2) { setSearchResults(null); setShowDropdown(false); return; } setIsSearching(true); try { // If YMM status is OK/Active → Use PartsLogic search products API // If YMM status is NOT OK → Use GraphQL search if (isYmmActive) { // Use PartsLogic search products API const response: PLSearchProductsResponse = await partsLogicClient.searchProducts({ q: query.trim(), page: 1, per_page: 10, }); // Transform PartsLogic response to match component interface setSearchResults({ products: response.products.map((product) => ({ ...product, // Use primary_image from PartsLogic API or thumbnail from GraphQL thumbnail: product.thumbnail || (product.primary_image ? { url: product.primary_image, alt: product.name, } : null), // Map category from PartsLogic format category: product.category || (product.category_name ? { id: product.category_id || "", name: product.category_name, } : null), })), categories: response.facets.categories.map((cat) => ({ id: cat.id, name: cat.value, slug: cat.value.toLowerCase().replace(/\s+/g, "-"), backgroundImage: cat.media ? { url: cat.media, alt: cat.value } : null, productCount: cat.count, })), productTypes: response.facets.brands.map((brand) => ({ id: brand.id, name: brand.value, slug: brand.value.toLowerCase().replace(/\s+/g, "-"), })), }); setShowDropdown(true); } else { // Use GraphQL search (Saleor API) as fallback const response: GlobalSearchResponse = await saleorGlobalSearch({ q: query.trim(), channel: "default-channel", includeProducts: true, includeCategories: true, includeCollections: false, includeProductTypes: true, }); setSearchResults({ products: response.products?.edges.map((edge) => edge.node) || [], categories: response.categories?.edges.map((edge) => edge.node) || [], productTypes: response.productTypes?.edges.map((edge) => edge.node) || [], }); setShowDropdown(true); } } catch (error) { // If PartsLogic API fails, try GraphQL as fallback try { const response: GlobalSearchResponse = await saleorGlobalSearch({ q: query.trim(), channel: "default-channel", includeProducts: true, includeCategories: true, includeCollections: false, includeProductTypes: true, }); setSearchResults({ products: response.products?.edges.map((edge) => edge.node) || [], categories: response.categories?.edges.map((edge) => edge.node) || [], productTypes: response.productTypes?.edges.map((edge) => edge.node) || [], }); setShowDropdown(true); } catch (fallbackError) { setSearchResults(null); } } finally { setIsSearching(false); } }, [isYmmActive] ); // Debounce search input and re-run when YMM status changes useEffect(() => { const timer = setTimeout(() => { performSearch(searchQuery); }, 300); return () => clearTimeout(timer); }, [searchQuery, performSearch, isYmmActive]); // Load categories for filter dropdown // If YMM status is OK/Active → Categories loaded from search results (REST API) // If YMM status is NOT OK → Load categories from GraphQL useEffect(() => { const loadCategories = async () => { try { if (isYmmActive) { // Categories will be populated from REST API search results // No need to load separately as they come with fuzzy search response } else { // No dedicated category prefetch; use categories from global search results. setCategories([]); } } catch (error) { // Failed to load categories } }; loadCategories(); }, [isYmmActive]); // Populate category options from current search results (both PL facets and Saleor nodes). useEffect(() => { if (!searchResults?.categories?.length) return; setCategories( searchResults.categories.map((c) => ({ value: c.slug, label: c.name, })) ); }, [searchResults]); const handleSearch = () => { if (!searchQuery.trim()) return; // Navigate to search results page const params = new URLSearchParams(); params.set("q", searchQuery.trim()); if (category) { params.set("category", category); } router.push(`/search?${params.toString()}`); setShowSearch(false); setShowDropdown(false); }; const handleProductClick = (slug: string) => { router.push(`/product/${slug}`); setShowSearch(false); setShowDropdown(false); }; const handleCategoryClick = (slug: string) => { router.push(`/category/${slug}`); setShowSearch(false); setShowDropdown(false); }; return (