"use client"; import { useMemo } from "react"; import { api } from "@/lib/trpc"; export type SortDirection = "asc" | "desc"; export interface ViewFilter { field: string; operator: "eq" | "neq" | "contains" | "gt" | "lt" | "in" | "isEmpty" | "isNotEmpty"; value: unknown; } export interface ViewSort { field: string; direction: SortDirection; } export interface ViewConfig { filters: ViewFilter[]; sorts: ViewSort[]; groupBy: string | null; } export interface ViewObject { id: string; type: string; title: string; status: string | null; icon: string | null; sortOrder: number; parentId: string | null; createdAt: string; updatedAt: string; assignees?: { user: { id: string; name: string | null; avatarUrl: string | null } }[]; propertyValues?: { propertyDefinition: { id: string; name: string; fieldType: string }; value: unknown }[]; } function applyFilters(objects: ViewObject[], filters: ViewFilter[]): ViewObject[] { return objects.filter((obj) => filters.every((f) => { const val = f.field === "status" ? obj.status : f.field === "title" ? obj.title : null; if (f.operator === "eq") return val === f.value; if (f.operator === "neq") return val !== f.value; if (f.operator === "contains" && typeof val === "string" && typeof f.value === "string") return val.toLowerCase().includes(f.value.toLowerCase()); if (f.operator === "isEmpty") return !val; if (f.operator === "isNotEmpty") return !!val; return true; }), ); } function getField(obj: ViewObject, field: string): unknown { return (obj as unknown as Record)[field]; } function applySorts(objects: ViewObject[], sorts: ViewSort[]): ViewObject[] { if (sorts.length === 0) return objects; return [...objects].sort((a, b) => { for (const s of sorts) { const aVal = getField(a, s.field) ?? ""; const bVal = getField(b, s.field) ?? ""; const cmp = String(aVal).localeCompare(String(bVal)); if (cmp !== 0) return s.direction === "asc" ? cmp : -cmp; } return 0; }); } function applyGroupBy(objects: ViewObject[], groupBy: string | null): Record { if (!groupBy) return { "All Items": objects }; const groups: Record = {}; for (const obj of objects) { const key = String(getField(obj, groupBy) ?? "No Value"); if (!groups[key]) groups[key] = []; groups[key].push(obj); } return groups; } export function useViewData( config: ViewConfig, workspaceId?: string, parentId?: string | null, ) { const { data, isLoading: queryLoading } = api.objects.list.useQuery( { workspaceId: workspaceId!, parentId: parentId ?? undefined, limit: 200 }, { enabled: Boolean(workspaceId) }, ); const objects: ViewObject[] = useMemo(() => { if (!data?.objects) return []; return data.objects.map((row) => ({ id: row.id, type: row.type, title: row.title, status: row.status, icon: row.icon, sortOrder: row.sortOrder, parentId: row.parentId, createdAt: row.createdAt instanceof Date ? row.createdAt.toISOString() : String(row.createdAt), updatedAt: row.updatedAt instanceof Date ? row.updatedAt.toISOString() : String(row.updatedAt), })); }, [data?.objects]); const processed = useMemo(() => { let result = applyFilters(objects, config.filters); result = applySorts(result, config.sorts); const grouped = applyGroupBy(result, config.groupBy); return { items: result, grouped }; }, [objects, config]); return { items: processed.items, grouped: processed.grouped, isLoading: queryLoading, total: processed.items.length, }; }