ifixkart-storefront/components/SearchBar.tsx

143 lines
5.4 KiB
TypeScript

"use client";
import React, { useEffect, useRef, useState } from 'react';
import { useRouter } from 'next/navigation';
import { Check, ChevronDown, LayoutGrid, Search } from 'lucide-react';
import { catalogService } from '@/services/api/catalogService';
export const SearchBar: React.FC = () => {
const router = useRouter();
const [category, setCategory] = useState('All Categories');
const [categories, setCategories] = useState<string[]>(['All Categories']);
const [searchQuery, setSearchQuery] = useState('');
const [open, setOpen] = useState(false);
const [catQuery, setCatQuery] = useState('');
const rootRef = useRef<HTMLDivElement>(null);
useEffect(() => {
catalogService.getCategories().then((res) => {
if (res && res.length > 0) {
setCategories(['All Categories', ...res.map((c) => c.name)]);
}
});
}, []);
useEffect(() => {
const onDoc = (event: MouseEvent) => {
if (!rootRef.current?.contains(event.target as Node)) setOpen(false);
};
const onKey = (event: KeyboardEvent) => {
if (event.key === 'Escape') setOpen(false);
};
document.addEventListener('mousedown', onDoc);
document.addEventListener('keydown', onKey);
return () => {
document.removeEventListener('mousedown', onDoc);
document.removeEventListener('keydown', onKey);
};
}, []);
const filtered = catQuery.trim()
? categories.filter((name) =>
name.toLowerCase().includes(catQuery.trim().toLowerCase())
)
: categories;
const handleSearchSubmit = (e: React.FormEvent) => {
e.preventDefault();
const catQueryParam =
category === 'All Categories' ? '' : `category=${encodeURIComponent(category)}`;
const searchQueryStr = searchQuery.trim()
? `search=${encodeURIComponent(searchQuery.trim())}`
: '';
const queryParts = [catQueryParam, searchQueryStr].filter(Boolean).join('&');
const path = queryParts ? `/shop?${queryParts}` : '/shop';
router.push(path);
};
return (
<form
onSubmit={handleSearchSubmit}
className="flex flex-1 max-w-[720px] items-center bg-white rounded-lg border border-gray-200 overflow-visible shadow-sm h-[46px] relative"
>
<div ref={rootRef} className="relative h-full hidden lg:block">
<button
type="button"
onClick={() => setOpen((value) => !value)}
className={`h-full min-w-[160px] max-w-[200px] px-3.5 border-r border-gray-200 rounded-l-lg inline-flex items-center gap-2 text-left transition ${
open
? 'bg-primary/5 text-primary'
: 'bg-gray-50 text-[#1a1a1a] hover:bg-gray-100'
}`}
>
<LayoutGrid className="w-3.5 h-3.5 shrink-0 text-primary" />
<span className="flex-1 text-[12px] font-semibold truncate">{category}</span>
<ChevronDown
size={14}
className={`shrink-0 transition-transform ${
open ? 'rotate-180 text-primary' : 'text-gray-400'
}`}
/>
</button>
{open && (
<div className="absolute left-0 top-[calc(100%+8px)] w-[280px] bg-white border border-gray-200 rounded-xl shadow-[0_12px_32px_rgba(15,23,42,0.12)] overflow-hidden z-[130]">
<div className="p-2 border-b border-gray-100">
<div className="relative">
<Search className="w-3.5 h-3.5 text-gray-400 absolute left-3 top-1/2 -translate-y-1/2" />
<input
type="text"
value={catQuery}
onChange={(e) => setCatQuery(e.target.value)}
placeholder="Search categories..."
className="w-full h-9 pl-8 pr-3 rounded-lg bg-gray-50 border border-gray-200 text-[12px] outline-none focus:border-primary focus:ring-2 focus:ring-primary/15"
/>
</div>
</div>
<ul className="max-h-72 overflow-y-auto py-1">
{filtered.map((cat) => {
const isSelected = category === cat;
return (
<li key={cat}>
<button
type="button"
onClick={() => {
setCategory(cat);
setOpen(false);
setCatQuery('');
}}
className={`w-full px-3.5 py-2.5 flex items-center gap-2.5 text-left text-[13px] transition ${
isSelected
? 'bg-primary/5 text-primary font-semibold'
: 'text-[#1a1a1a] hover:bg-gray-50'
}`}
>
<span className="flex-1 truncate">{cat}</span>
{isSelected ? <Check className="w-4 h-4 shrink-0" /> : null}
</button>
</li>
);
})}
</ul>
</div>
)}
</div>
<input
type="text"
placeholder="Search products..."
value={searchQuery}
onChange={(e) => setSearchQuery(e.target.value)}
className="flex-1 px-4 text-[13px] text-gray-800 placeholder-gray-400 focus:outline-none h-full font-medium"
/>
<button
type="submit"
className="h-full bg-primary hover:brightness-95 text-white px-7 flex items-center justify-center font-bold text-sm transition-colors rounded-r-lg"
title="Search"
>
Search
</button>
</form>
);
};