Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 | 3x 3x 3x 4x 4x 4x 4x 4x 4x 4x 4x 4x 4x 8x 4x 4x 8x 8x 8x 4x 4x 4x 4x | "use client";
import { useDebounce } from "use-debounce";
import { useEffect, useRef, useState } from "react";
import type { ChatThread } from "@/types/thread";
import { getThreadDateGroup, getThreadDateGroupOrder } from "@/utils/date";
export type ThreadGroup = { label: string; threads: ChatThread[] };
export function useSearchChat(allThreads: ChatThread[], onClose: () => void) {
const [query, setQuery] = useState("");
const [debouncedQuery] = useDebounce(query, 500);
const inputRef = useRef<HTMLInputElement>(null);
useEffect(() => {
inputRef.current?.focus();
}, []);
useEffect(() => {
function handleKeyDown(e: KeyboardEvent) {
if (e.key === "Escape") onClose();
}
document.addEventListener("keydown", handleKeyDown);
return () => document.removeEventListener("keydown", handleKeyDown);
}, [onClose]);
const filtered = allThreads.filter((t) => {
Eif (!debouncedQuery.trim()) return true;
const q = debouncedQuery.toLowerCase();
return t.title.toLowerCase().includes(q) || t.preview.toLowerCase().includes(q);
});
const groupMap: ThreadGroup[] = [];
for (const thread of filtered) {
const label = getThreadDateGroup(thread.updatedAt);
const existing = groupMap.find((g) => g.label === label);
if (existing) {
existing.threads.push(thread);
} else {
groupMap.push({ label, threads: [thread] });
}
}
const threadGroups = groupMap.sort((a, b) => getThreadDateGroupOrder(a.label) - getThreadDateGroupOrder(b.label));
return { query, setQuery, threadGroups, inputRef };
}
|