124 lines
5.2 KiB
TypeScript
124 lines
5.2 KiB
TypeScript
"use client";
|
|
|
|
import { useState, useMemo } from "react";
|
|
import { Search } from "lucide-react";
|
|
import { getProducts } from "@/content/products";
|
|
import Link from "next/link";
|
|
import Image from "next/image";
|
|
import { formatCurrency } from "@/lib/utils";
|
|
import { useRouter } from "next/navigation";
|
|
|
|
const allProducts = getProducts();
|
|
|
|
export function GlobalSearch() {
|
|
const [query, setQuery] = useState("");
|
|
const [isOpen, setIsOpen] = useState(false);
|
|
const router = useRouter();
|
|
|
|
const results = useMemo(() => {
|
|
if (query.length < 2) return [];
|
|
const q = query.toLowerCase();
|
|
return allProducts
|
|
.filter(p =>
|
|
p.name.toLowerCase().includes(q) ||
|
|
p.brand.toLowerCase().includes(q) ||
|
|
p.category.toLowerCase().includes(q) ||
|
|
(p.sku && p.sku.toLowerCase().includes(q))
|
|
)
|
|
.slice(0, 20);
|
|
}, [query]);
|
|
|
|
const handleKeyDown = (e: React.KeyboardEvent) => {
|
|
if (e.key === 'Enter' && query.length > 1) {
|
|
router.push(`/sklep?search=${encodeURIComponent(query)}`);
|
|
setIsOpen(false);
|
|
setQuery('');
|
|
}
|
|
};
|
|
|
|
return (
|
|
<>
|
|
<button
|
|
onClick={() => setIsOpen(true)}
|
|
className="p-2 text-primary hover:text-accent hover:bg-background rounded-lg transition-colors outline-none cursor-pointer"
|
|
aria-label="Szukaj na stronie"
|
|
>
|
|
<Search className="size-5" />
|
|
</button>
|
|
|
|
<dialog className={`modal ${isOpen ? "modal-open" : ""}`}>
|
|
<div className="modal-box p-0 max-w-2xl bg-white rounded-2xl overflow-hidden mt-[-20vh]">
|
|
<div className="flex items-center border-b border-border px-4 py-3 bg-slate-50">
|
|
<button aria-label="Szukaj" onClick={() => {
|
|
if (query.length > 1) {
|
|
router.push(`/sklep?search=${encodeURIComponent(query)}`);
|
|
setIsOpen(false);
|
|
setQuery('');
|
|
}
|
|
}}>
|
|
<Search className="size-5 text-accent mr-3 shrink-0 hover:text-primary transition-colors cursor-pointer" />
|
|
</button>
|
|
<input
|
|
autoFocus
|
|
type="text"
|
|
placeholder="Wpisz nazwę klimatyzatora (np. Rotenso, Pular)..."
|
|
className="flex-1 outline-none text-base placeholder:text-text-muted/50 bg-transparent py-2 text-primary font-medium"
|
|
value={query}
|
|
onChange={(e) => setQuery(e.target.value)}
|
|
onKeyDown={handleKeyDown}
|
|
/>
|
|
<button type="button" onClick={() => setIsOpen(false)} className="text-xs font-semibold text-text-muted hover:text-primary transition-colors bg-white px-2 py-1 rounded border border-border shadow-sm">
|
|
ESC
|
|
</button>
|
|
</div>
|
|
|
|
{query.length > 1 ? (
|
|
<div className="max-h-[60vh] overflow-y-auto p-2 bg-white">
|
|
{results.length > 0 ? (
|
|
<div className="flex flex-col gap-1">
|
|
{results.map((product) => (
|
|
<Link
|
|
key={product.slug}
|
|
href={`/sklep/${product.slug}`}
|
|
onClick={() => setIsOpen(false)}
|
|
className="flex items-center gap-4 p-3 hover:bg-slate-50 rounded-lg transition-colors group border border-transparent hover:border-border"
|
|
>
|
|
<div className="w-16 h-16 bg-white border border-border rounded-md overflow-hidden relative shrink-0">
|
|
<Image
|
|
src={product.image || '/images/about/about-story.webp'}
|
|
alt={product.name}
|
|
fill
|
|
className="object-contain p-1 mix-blend-multiply"
|
|
/>
|
|
</div>
|
|
<div className="flex-1 flex flex-col">
|
|
<span className="text-[10px] font-bold text-text-muted uppercase tracking-wider">{product.brand}</span>
|
|
<span className="text-sm font-semibold text-primary group-hover:text-accent transition-colors">{product.name}</span>
|
|
<span className="text-xs text-text-muted mt-0.5">{product.specs?.['Moc chłodnicza'] ? `${product.specs['Moc chłodnicza']} kW • ` : ''}{product.category}</span>
|
|
</div>
|
|
<div className="text-right">
|
|
<span className="text-sm font-bold text-primary block">{product.price !== null ? formatCurrency(product.price) : 'Zapytaj o cenę'}</span>
|
|
</div>
|
|
</Link>
|
|
))}
|
|
</div>
|
|
) : (
|
|
<div className="p-8 text-center text-text-muted">
|
|
Brak wyników dla <span className="font-semibold">"{query}"</span>
|
|
</div>
|
|
)}
|
|
</div>
|
|
) : (
|
|
<div className="p-8 text-center text-text-muted/50 text-sm bg-white">
|
|
Wpisz co najmniej 2 znaki, aby rozpocząć wyszukiwanie w sklepie
|
|
</div>
|
|
)}
|
|
</div>
|
|
<form method="dialog" className="modal-backdrop">
|
|
<button onClick={() => setIsOpen(false)}>close</button>
|
|
</form>
|
|
</dialog>
|
|
</>
|
|
);
|
|
}
|