import { useEffect, useMemo, useState } from "react"; import { useQuery } from "@tanstack/react-query"; import type { ActivityEvent, Agent } from "@paperclipai/shared"; import { activityApi } from "../api/activity"; import { accessApi } from "../api/access"; import { agentsApi } from "../api/agents"; import { buildCompanyUserProfileMap } from "../lib/company-members"; import { useCompany } from "../context/CompanyContext"; import { useBreadcrumbs } from "../context/BreadcrumbContext"; import { queryKeys } from "../lib/queryKeys"; import { EmptyState } from "../components/EmptyState"; import { ActivityRow } from "../components/ActivityRow"; import { PageSkeleton } from "../components/PageSkeleton"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from "@/components/ui/select"; import { History } from "lucide-react"; const ACTIVITY_PAGE_LIMIT = 200; function detailString(event: ActivityEvent, ...keys: string[]) { const details = event.details; for (const key of keys) { const value = details?.[key]; if (typeof value === "string" && value.trim()) return value; } return null; } function activityEntityName(event: ActivityEvent) { if (event.entityType === "issue") return detailString(event, "identifier", "issueIdentifier"); if (event.entityType === "project") return detailString(event, "projectName", "name", "title"); if (event.entityType === "goal") return detailString(event, "goalTitle", "title", "name"); return detailString(event, "name", "title"); } function activityEntityTitle(event: ActivityEvent) { if (event.entityType === "issue") return detailString(event, "issueTitle", "title"); return null; } export function Activity() { const { selectedCompanyId } = useCompany(); const { setBreadcrumbs } = useBreadcrumbs(); const [filter, setFilter] = useState("all"); useEffect(() => { setBreadcrumbs([{ label: "Activity" }]); }, [setBreadcrumbs]); const { data, isLoading, error } = useQuery({ queryKey: [...queryKeys.activity(selectedCompanyId!), { limit: ACTIVITY_PAGE_LIMIT }], queryFn: () => activityApi.list(selectedCompanyId!, { limit: ACTIVITY_PAGE_LIMIT }), enabled: !!selectedCompanyId, }); const { data: agents } = useQuery({ queryKey: queryKeys.agents.list(selectedCompanyId!), queryFn: () => agentsApi.list(selectedCompanyId!), enabled: !!selectedCompanyId, }); const { data: companyMembers } = useQuery({ queryKey: queryKeys.access.companyUserDirectory(selectedCompanyId!), queryFn: () => accessApi.listUserDirectory(selectedCompanyId!), enabled: !!selectedCompanyId, }); const userProfileMap = useMemo( () => buildCompanyUserProfileMap(companyMembers?.users), [companyMembers?.users], ); const agentMap = useMemo(() => { const map = new Map(); for (const a of agents ?? []) map.set(a.id, a); return map; }, [agents]); const entityNameMap = useMemo(() => { const map = new Map(); for (const a of agents ?? []) map.set(`agent:${a.id}`, a.name); for (const event of data ?? []) { const name = activityEntityName(event); if (name) map.set(`${event.entityType}:${event.entityId}`, name); } return map; }, [data, agents]); const entityTitleMap = useMemo(() => { const map = new Map(); for (const event of data ?? []) { const title = activityEntityTitle(event); if (title) map.set(`${event.entityType}:${event.entityId}`, title); } return map; }, [data]); if (!selectedCompanyId) { return ; } if (isLoading) { return ; } const filtered = data && filter !== "all" ? data.filter((e) => e.entityType === filter) : data; const entityTypes = data ? [...new Set(data.map((e) => e.entityType))].sort() : []; return (
{error &&

{error.message}

} {filtered && filtered.length === 0 && ( )} {filtered && filtered.length > 0 && (
{filtered.map((event) => ( ))}
)}
); }