import { useEffect, useMemo, useRef, useState } from "react"; import { useInfiniteQuery } from "@tanstack/react-query"; import { Package, Search, X } from "lucide-react"; import { artifactsApi, type ArtifactKindFilter } from "../api/artifacts"; import { useCompany } from "../context/CompanyContext"; import { useBreadcrumbs } from "../context/BreadcrumbContext"; import { queryKeys } from "../lib/queryKeys"; import { EmptyState } from "../components/EmptyState"; import { PageSkeleton } from "../components/PageSkeleton"; import { ArtifactCard } from "../components/artifacts/ArtifactCard"; import { cn } from "@/lib/utils"; import { Input } from "@/components/ui/input"; const ARTIFACTS_PAGE_SIZE = 30; const SEARCH_DEBOUNCE_MS = 250; const KIND_FILTERS: { value: ArtifactKindFilter; label: string }[] = [ { value: "all", label: "All" }, { value: "image", label: "Images" }, { value: "video", label: "Videos" }, { value: "document", label: "Documents" }, { value: "text", label: "Text" }, { value: "file", label: "Files" }, ]; export function Artifacts() { const { selectedCompanyId } = useCompany(); const { setBreadcrumbs } = useBreadcrumbs(); const [kind, setKind] = useState("all"); const [draftQuery, setDraftQuery] = useState(""); const [query, setQuery] = useState(""); const loadMoreRef = useRef(null); useEffect(() => { setBreadcrumbs([{ label: "Artifacts" }]); }, [setBreadcrumbs]); useEffect(() => { const handle = window.setTimeout(() => setQuery(draftQuery.trim()), SEARCH_DEBOUNCE_MS); return () => window.clearTimeout(handle); }, [draftQuery]); const { data, isLoading, isFetching, isFetchingNextPage, hasNextPage, fetchNextPage, error, } = useInfiniteQuery({ queryKey: queryKeys.artifacts.list(selectedCompanyId!, kind, query), queryFn: ({ pageParam }) => artifactsApi.list(selectedCompanyId!, { kind, q: query || undefined, limit: ARTIFACTS_PAGE_SIZE, cursor: pageParam, }), enabled: !!selectedCompanyId, initialPageParam: undefined as string | undefined, getNextPageParam: (lastPage) => lastPage.nextCursor ?? undefined, }); useEffect(() => { const target = loadMoreRef.current; if (!target || !hasNextPage || isFetchingNextPage) return; const observer = new IntersectionObserver((entries) => { if (entries.some((entry) => entry.isIntersecting)) { void fetchNextPage(); } }, { rootMargin: "320px 0px" }); observer.observe(target); return () => observer.disconnect(); }, [fetchNextPage, hasNextPage, isFetchingNextPage]); const artifacts = useMemo(() => data?.pages.flatMap((page) => page.artifacts) ?? [], [data]); const searching = query.length > 0; if (!selectedCompanyId) { return ; } return (
setDraftQuery(event.currentTarget.value)} placeholder="Search artifacts..." aria-label="Search artifacts" className="h-9 pl-9 pr-9 text-sm" /> {draftQuery.length > 0 ? ( ) : null}
{KIND_FILTERS.map((filter) => ( ))}
{error &&

{error.message}

} {isLoading ? ( ) : artifacts.length === 0 ? ( ) : ( <>
{artifacts.map((artifact) => ( ))}
{isFetchingNextPage ? "Loading more artifacts..." : hasNextPage ? null : isFetching ? "Updating artifacts..." : null}
)}
); }