1'use client';23import { useRouter } from 'next/navigation';4import { useEffect, useState } from 'react';56interface Suggestion {7 type: string;8 label: string;9 sublabel: string | null;10 href: string;11}1213const SLOTS = ['a', 'b', 'c', 'd'] as const;1415/** Four slot pickers with suggestions; values are asset slugs or index tickers, stored in the URL. */16export function CompareForm({ initial }: { initial: string[] }) {17 const router = useRouter();18 const [values, setValues] = useState<string[]>([...initial, '', '', '', ''].slice(0, 4));19 const [typing, setTyping] = useState<{ i: number; q: string } | null>(null);20 const [items, setItems] = useState<Suggestion[]>([]);2122 useEffect(() => {23 if (!typing || typing.q.trim().length < 2) return;24 const ctrl = new AbortController();25 const t = setTimeout(() => {26 fetch(`/api/search/suggest?q=${encodeURIComponent(typing.q)}`, { signal: ctrl.signal })27 .then((r) => r.json())28 .then((d: { items: Suggestion[] }) => setItems((d.items ?? []).filter((x) => x.type === 'asset' || x.type === 'index')))29 .catch(() => {});30 }, 150);31 return () => {32 clearTimeout(t);33 ctrl.abort();34 };35 }, [typing]);3637 const apply = (vals: string[]) => {38 const sp = new URLSearchParams();39 vals.forEach((v, i) => {40 if (v) sp.set(SLOTS[i]!, v);41 });42 router.push(`/compare?${sp.toString()}`);43 };4445 return (46 <form47 className="card grid gap-2 p-3 sm:grid-cols-4"48 onSubmit={(e) => {49 e.preventDefault();50 apply(values);51 }}52 >53 {SLOTS.map((s, i) => (54 <label key={s} className="relative flex flex-col gap-0.5 text-[10px] font-medium uppercase tracking-wider text-subtle">55 Slot {s.toUpperCase()}56 <input57 value={values[i] ?? ''}58 onChange={(e) => {59 const v = [...values];60 v[i] = e.target.value;61 setValues(v);62 setTyping({ i, q: e.target.value });63 if (e.target.value.trim().length < 2) setItems([]);64 }}65 onBlur={() =>66 setTimeout(() => {67 setTyping(null);68 setItems([]);69 }, 150)70 }71 placeholder="asset slug or RARE-TCG"72 className="h-9 rounded-md border border-border bg-elevated px-2 text-[13px] normal-case tracking-normal text-fg placeholder:text-subtle focus:border-border-strong focus:outline-none"73 />74 {typing?.i === i && items.length ? (75 <ul className="absolute left-0 top-full z-20 mt-1 w-full overflow-hidden rounded-md border border-border bg-elevated text-[12px] normal-case tracking-normal shadow-pop">76 {items.map((it) => {77 const val = it.href.startsWith('/asset/') ? it.href.slice(7) : it.href.startsWith('/rareindex/') ? it.href.slice(11) : it.label;78 return (79 <li key={it.href}>80 <button81 type="button"82 onMouseDown={(e) => e.preventDefault()}83 onClick={() => {84 const v = [...values];85 v[i] = val;86 setValues(v);87 setTyping(null);88 apply(v);89 }}90 className="block w-full truncate px-2 py-1.5 text-left text-fg hover:bg-sunken"91 >92 {it.label} <span className="text-subtle">· {it.sublabel}</span>93 </button>94 </li>95 );96 })}97 </ul>98 ) : null}99 </label>100 ))}101 <div className="sm:col-span-4 flex items-center justify-between text-[11px] text-subtle">102 <span>Tip: paste slugs from asset URLs; tickers: RARE, RARE-TCG, RARE-SPORT, RARE-WATCH, RARE-SNEAKER, RARE-LEGO, RARE-COMIC, RARE-GAME…</span>103 <button type="submit" className="rounded-md bg-accent px-3 py-1.5 text-xs font-medium text-accent-fg">104 Compare105 </button>106 </div>107 </form>108 );109}110