/** biome-ignore-all lint/a11y/noStaticElementInteractions: yes maam */ "use client"; import { FileSearch2, Search, X } from "lucide-react"; import { type ComponentProps, useCallback, useContext, useEffect, useRef, useState, } from "react"; import { b2sClient, CdnTable } from "@/app/(ui)/admin/cdn/table"; import type { cdn } from "@/lib/db/schema"; import { cn } from "@/lib/utils"; import { SimpleTooltip } from "../tooltip"; import { Button } from "../ui/button"; import { Dialog, DialogContent, DialogTitle } from "../ui/dialog"; import { InputGroup, InputGroupAddon, InputGroupInput, } from "../ui/input-group"; import { Kbd } from "../ui/kbd"; import { Spinner } from "../ui/spinner"; import { listFiles } from "./api"; import { CdnChooserContext, type CdnFile } from "./context"; export function CdnChooserProvider({ children, }: { children: React.ReactNode; }) { const [open, setOpen] = useState(false); const [files, setFiles] = useState< Omit[] | null >(null); const [options, setOptions] = useState<{ type?: string }>(); const callback = useRef<((value: CdnFile | null) => void) | null>(null); const [search, setSearch] = useState(""); const filtered = search ? files?.filter( (f) => f.name?.toLowerCase().includes(search) || f.id === search, ) : files; const updateList = useCallback( async (opt = options) => { const list = await listFiles().catch(() => []); setFiles( opt?.type ? list.toReversed().filter((file) => file.type.startsWith(opt.type!)) : list.toReversed(), ); }, [options], ); const call = useCallback( async (options?: { type?: string }): Promise => { setSearch(""); setOpen(true); await updateList(options); setOptions(options); return new Promise((resolve) => { callback.current = resolve; }).finally(() => setOpen(false)); }, [updateList], ); return ( {children} { if (!o) callback.current?.(null); setOpen(o); }} > Choose File{" "} setSearch(ev.target.value.toLowerCase())} /> {filtered?.length || 0} results {files ? (
callback.current?.(value)} onChange={updateList} />
) : (
)}
); } export function CdnChooser({ className, onChange, type, children, defaultValue, value: externalValue, ...props }: ComponentProps<"input"> & { onChange?: (value: string) => void; type?: string; value?: string; }) { const [value, setValue] = useState(`${defaultValue || ""}`); const [meta, setMeta] = useState(); const chooser = useContext(CdnChooserContext); // biome-ignore lint/correctness/useExhaustiveDependencies: first run only useEffect(() => { setValue(externalValue || ""); const newVal = externalValue || defaultValue || ""; if (!newVal) { if (meta) setMeta(undefined); return; } (async () => { const fileList = await listFiles(); const file = fileList.find((f) => f.id === newVal); if (!file) return setValue(""); setMeta(file); })(); // oxlint-disable-next-line react-hooks/exhaustive-deps }, [externalValue]); async function choose() { const res = await chooser?.call({ type }); if (res) { setValue(res.id); onChange?.(res.id); setMeta(res); } } return ( <> ); }