import { CornerDownLeftIcon, SearchIcon } from "lucide-react"; import { FormEvent, useEffect, useState } from "react"; import { useLocation, useNavigate } from "react-router-dom"; import { Button } from "@/components/ui/button"; import { Dialog, DialogContent, DialogDescription, DialogTitle } from "@/components/ui/dialog"; import { Input } from "@/components/ui/input"; import { useAppSidebar } from "@/contexts/AppSidebarContext"; import { type MemoFilter, replaceFiltersByFactor, stringifyFilters, useMemoFilterContext } from "@/contexts/MemoFilterContext"; import { useSpaceContext } from "@/contexts/SpaceContext"; import useCurrentUser from "@/hooks/useCurrentUser"; import { useMemoViews } from "@/hooks/useUserQueries"; import { BUILTIN_TASKS_VIEW_ID, getMemoViewId, isMemoScopeRoute } from "@/lib/memo-views"; import { extractSpaceUidFromName, formatSpaceUidForDisplay } from "@/lib/space-display"; import { useTranslate } from "@/utils/i18n"; import { getRouteActionPolicy, getSidebarRouteKind } from "./routes"; export const buildQuickFindFilters = (query: string, currentFilters: MemoFilter[], preserveCurrentScope: boolean): MemoFilter[] => { const words = Array.from(new Set(query.trim().split(/\s+/).filter(Boolean))); const contentFilters: MemoFilter[] = words.map((value) => ({ factor: "contentSearch", value })); return preserveCurrentScope ? replaceFiltersByFactor(currentFilters, "contentSearch", contentFilters) : contentFilters; }; export interface QuickFindSubmission { filters: MemoFilter[]; destination?: string; switchToAll: boolean; } export const resolveQuickFindSubmission = (pathname: string, query: string, currentFilters: MemoFilter[]): QuickFindSubmission => { const routePolicy = getRouteActionPolicy(pathname); const filters = buildQuickFindFilters(query, currentFilters, routePolicy.searchScope !== "all"); const filterQuery = stringifyFilters(filters); return { filters, destination: routePolicy.searchDestination ? filterQuery ? `${routePolicy.searchDestination}?filter=${filterQuery}` : routePolicy.searchDestination : undefined, switchToAll: routePolicy.searchScope === "all", }; }; const getScopeLabel = (pathname: string, t: ReturnType) => { const routeKind = getSidebarRouteKind(pathname); if (routeKind === "archived") return t("common.archived"); if (routeKind === "explore") return t("common.explore"); if (routeKind === "profile") return t("common.profile"); return t("common.memos"); }; const QuickFindDialog = () => { const t = useTranslate(); const location = useLocation(); const navigate = useNavigate(); const currentUser = useCurrentUser(); const { data: memoViews = [] } = useMemoViews(currentUser?.name); const { filters, setFilters, setMemoView, memoView } = useMemoFilterContext(); const { clearSelectedSpace, duplicateSpaceTitles, selectedSpace, selectedSpaceName } = useSpaceContext(); const { quickFindOpen, setQuickFindOpen } = useAppSidebar(); const [query, setQuery] = useState(""); const viewApplies = isMemoScopeRoute(location.pathname); const selectedMemoView = viewApplies ? memoViews.find((item) => getMemoViewId(item.name) === memoView) : undefined; const lensLabel = viewApplies && memoView === BUILTIN_TASKS_VIEW_ID ? t("common.tasks") : selectedMemoView?.title || getScopeLabel(location.pathname, t); const routePolicy = getRouteActionPolicy(location.pathname); const selectedSpaceUid = selectedSpaceName ? extractSpaceUidFromName(selectedSpaceName) : ""; const selectedSpaceUidDisplay = selectedSpaceName ? formatSpaceUidForDisplay(selectedSpaceName) : ""; const showSelectedSpaceUid = selectedSpace ? duplicateSpaceTitles.has(selectedSpace.title) : Boolean(selectedSpaceName); const selectedSpaceLabel = `${selectedSpace?.title || t("space.current")}${ showSelectedSpaceUid && selectedSpaceUid ? ` (${selectedSpaceUid})` : "" }`; const compactSelectedSpaceLabel = `${selectedSpace?.title || t("space.current")}${ showSelectedSpaceUid && selectedSpaceUidDisplay ? ` (${selectedSpaceUidDisplay})` : "" }`; const scopeLabel = routePolicy.searchScope === "remembered-collection" && selectedSpaceName ? `${selectedSpaceLabel} · ${lensLabel}` : lensLabel; const compactScopeLabel = routePolicy.searchScope === "remembered-collection" && selectedSpaceName ? `${compactSelectedSpaceLabel} · ${lensLabel}` : lensLabel; useEffect(() => { if (!quickFindOpen) return; setQuery( filters .filter((filter) => filter.factor === "contentSearch") .map((filter) => filter.value) .join(" "), ); }, [filters, quickFindOpen]); const submitQuery = () => { const submission = resolveQuickFindSubmission(location.pathname, query, filters); if (submission.switchToAll) { // This is an explicit cross-Space action, so switch the collection state // to All without inserting an intermediate Home history entry. clearSelectedSpace(); } setFilters(submission.filters); if (submission.destination) { setMemoView(undefined); navigate(submission.destination); } setQuickFindOpen(false); }; const handleSubmit = (event: FormEvent) => { event.preventDefault(); submitQuery(); }; return ( {t("common.search")} {t("common.search")} {scopeLabel}
setQuery(event.target.value)} onKeyDown={(event) => { if (event.key !== "Enter") return; event.preventDefault(); submitQuery(); }} className="h-10 border-0 bg-transparent px-0 !text-[14px] shadow-none focus-visible:ring-0" placeholder={`${t("common.search")} ${compactScopeLabel}`} aria-label={`${t("common.search")} ${scopeLabel}`} />
); }; export default QuickFindDialog;