import { useCallback, useEffect, useMemo, useState, type ReactElement } from "react"; import { useNavigate } from "react-router-dom"; import { ChevronDown, SlidersHorizontal } from "lucide-react"; import { Layout } from "@/components/layout/Layout"; import { DataTable, type Column, FilterDropdown, Pagination, PrimaryButton, StatusBadge, } from "@/components/shared"; import { aiService } from "@/services/ai-service"; import { moduleService } from "@/services/module-service"; import { tenantService, type TenantUserDropdownItem } from "@/services/tenant-service"; import type { AICompletion, AIProviderInfo } from "@/types/ai"; import type { MyModule } from "@/types/module"; import { showToast } from "@/utils/toast"; import { cn } from "@/lib/utils"; import { useAppTheme } from "@/hooks/useAppTheme"; const formatListDate = (value?: string | null): string => { if (!value) return "—"; return new Date(value).toLocaleString(undefined, { month: "short", day: "numeric", year: "numeric", hour: "2-digit", minute: "2-digit", }); }; const CompletionHistory = (): ReactElement => { const navigate = useNavigate(); const { primaryColor } = useAppTheme(); const [isLoading, setIsLoading] = useState(false); const [isMetaLoading, setIsMetaLoading] = useState(true); const [providers, setProviders] = useState([]); const [models, setModels] = useState>([]); const [modules, setModules] = useState([]); const [tenantUsers, setTenantUsers] = useState([]); const [completions, setCompletions] = useState([]); const [error, setError] = useState(null); const [expandedId, setExpandedId] = useState(null); const [page, setPage] = useState(1); const [limit, setLimit] = useState(10); const [pagination, setPagination] = useState({ page: 1, limit: 10, total: 0, totalPages: 1, }); const [showMoreFilters, setShowMoreFilters] = useState(false); const [filters, setFilters] = useState({ provider: null as string | null, model: null as string | null, status: null as string | null, moduleId: null as string | null, userId: null as string | null, startDate: "", endDate: "", }); const providerOptions = useMemo( () => providers.map((p) => ({ value: p.name, label: p.displayName || p.name })), [providers], ); const modelOptions = useMemo( () => models.map((m) => ({ value: m.id, label: `${m.provider} · ${m.id}`, })), [models], ); const moduleOptions = useMemo( () => modules.map((m) => ({ value: m.id, label: m.name })), [modules], ); const userOptions = useMemo( () => tenantUsers.map((u) => ({ value: u.id, label: `${u.name} (${u.role ?? "—"})`, })), [tenantUsers], ); const hasExtraFilters = Boolean( filters.moduleId || filters.userId || filters.startDate || filters.endDate, ); useEffect(() => { if (hasExtraFilters) { setShowMoreFilters(true); } }, [hasExtraFilters]); const loadMeta = useCallback(async (): Promise => { setIsMetaLoading(true); try { const [providerData, modelData, modulesRes, usersData] = await Promise.all([ aiService.getProviders(), aiService.getModels(), moduleService.getMyModules(), tenantService.getCurrentTenantUsersDropdown(), ]); setProviders(providerData); setModels(modelData); setModules(modulesRes.data || []); setTenantUsers(usersData); } catch (err: unknown) { const msg = (err as { response?: { data?: { error?: { message?: string } } } })?.response?.data?.error ?.message || "Failed to load filter options"; showToast.error(msg); } finally { setIsMetaLoading(false); } }, []); const loadCompletions = useCallback(async (): Promise => { setIsLoading(true); setError(null); try { const listData = await aiService.listCompletions({ page, limit, provider: filters.provider || undefined, model: filters.model || undefined, status: filters.status || undefined, user_id: filters.userId || undefined, module_id: filters.moduleId || undefined, start_date: filters.startDate.trim() || undefined, end_date: filters.endDate.trim() || undefined, }); setCompletions(listData.data || []); setExpandedId(null); setPagination({ page: listData.pagination?.page || page, limit: listData.pagination?.limit || limit, total: listData.pagination?.total || 0, totalPages: listData.pagination?.totalPages || 1, }); } catch (err: unknown) { const msg = (err as { response?: { data?: { error?: { message?: string } } } })?.response?.data?.error ?.message || "Failed to load completion history"; setError(msg); showToast.error(msg); } finally { setIsLoading(false); } }, [ page, limit, filters.provider, filters.model, filters.status, filters.userId, filters.moduleId, filters.startDate, filters.endDate, ]); useEffect(() => { void loadMeta(); }, [loadMeta]); useEffect(() => { void loadCompletions(); }, [loadCompletions]); const clearFilters = (): void => { setPage(1); setFilters({ provider: null, model: null, status: null, moduleId: null, userId: null, startDate: "", endDate: "", }); setShowMoreFilters(false); }; const toggleExpand = (id: string): void => { setExpandedId((prev) => (prev === id ? null : id)); }; const renderExpanded = (row: AICompletion): ReactElement => { const total = row.usage?.total_tokens ?? row.total_tokens ?? (row.prompt_tokens ?? 0) + (row.completion_tokens ?? 0); const preview = (row.response || row.content || "").slice(0, 800); return (
{/*

IDs — Module: {row.module_id || "—"} {" · "} User: {row.user_id || "—"}

Correlation — {row.correlation_id || "—"}

*/}

Tokens / cost / latency — {`${total} tokens · USD ${Number(row.cost ?? 0).toFixed(6)} · ${row.latency_ms ?? 0} ms`}

{row.use_case && (

Use case — {row.use_case}

)} {(row.error_message || row.error_code) && (

Error — {[row.error_code, row.error_message].filter(Boolean).join(" · ")}

)}
Response preview

{preview || "—"}

); }; const columns: Column[] = [ { key: "date", label: "Date", render: (row) => {formatListDate(row.created_at)}, }, { key: "module_name", label: "Module", render: (row) => {row.module_name || "Platform"}, }, { key: "user_name", label: "User", render: (row) => {row.user_name || "—"}, }, { key: "provider", label: "Provider", render: (row) => row.provider || "—" }, { key: "model", label: "Model", render: (row) => {row.model || "—"}, }, { key: "status", label: "Status", render: (row) => ( {row.status || "unknown"} ), }, { key: "view", label: "View", align: "right", render: (row) => ( ), }, ]; return ( navigate("/tenant/ai/completions/create")}> Create Completion ), }} >

Completion List

{ setPage(1); setFilters((prev) => ({ ...prev, provider: value as string | null })); }} /> { setPage(1); setFilters((prev) => ({ ...prev, model: value as string | null })); }} /> { setPage(1); setFilters((prev) => ({ ...prev, status: value as string | null })); }} />
{showMoreFilters && (
{ setPage(1); setFilters((prev) => ({ ...prev, moduleId: value as string | null })); }} /> { setPage(1); setFilters((prev) => ({ ...prev, userId: value as string | null })); }} />
From: { setPage(1); setFilters((prev) => ({ ...prev, startDate: e.target.value })); }} className="text-xs px-2 py-1.5 border border-[rgba(0,0,0,0.08)] rounded focus:outline-none focus:ring-1 focus:ring-[#112868]/20" />
To: { setPage(1); setFilters((prev) => ({ ...prev, endDate: e.target.value })); }} className="text-xs px-2 py-1.5 border border-[rgba(0,0,0,0.08)] rounded focus:outline-none focus:ring-1 focus:ring-[#112868]/20" />
)}
{isMetaLoading && (

Loading filter options…

)}
item.id} isLoading={isLoading} error={error} emptyMessage="No completion records found" expandableRows isRowExpanded={(row) => expandedId === row.id} onRowExpandToggle={(row) => toggleExpand(row.id)} renderExpandedRow={renderExpanded} onRowClick={(row) => toggleExpand(row.id)} /> {pagination.total > 0 && (
{ setLimit(newLimit); setPage(1); }} limitOptions={[ { value: "5", label: "5 per page" }, { value: "10", label: "10 per page" }, { value: "20", label: "20 per page" }, ]} />
)}
); }; export default CompletionHistory;