@burdenoff/microfe-proserviceworld 2026.720.1 → 2026.728.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"file":"useProServiceWorldApi.js","names":[],"sources":["../../../src/proserviceworld/hooks/useProServiceWorldApi.ts"],"sourcesContent":["/**\n * ProServiceWorld API hooks\n * @module proserviceworld/hooks\n *\n * Real data layer for the ProServiceWorld workspace subgraph (`proserviceworld`\n * Hive service / `wspace-proserviceworld-svc`). Every hook talks to the live\n * workspace GraphQL gateway via {@link graphqlFetch} with inline operations\n * whose fields mirror `.hive-schema.graphql` exactly. No mocks.\n *\n * Conventions (mirror microfe-hookmovies / microfe-collabkin):\n * - `pswQuery` wraps graphqlFetch({ gateway: 'workspace', workspaceToken: true })\n * and throws on GraphQL errors / missing data.\n * - One react-query `useQuery` per read op and `useMutation` per write op.\n * - Strict hand-written result interfaces — no `any`.\n * - Lists paginate by offset (the workspaces gateway strips the cursor arg);\n * `*Connection { items, pageInfo { hasMore cursor }, totalCount }` verbatim.\n * - After any successful mutation we clear fe-libs' short-lived graphqlFetch\n * read cache so the very next refetch is fresh (fleet stale-read fix).\n */\n\nimport { useMutation, useQuery, useQueryClient, type QueryClient } from '@tanstack/react-query';\n\nimport { graphqlFetch } from '@burdenoff/fe-libs/shared/graphql';\nimport { clearGraphqlFetchResponseCache } from '@burdenoff/fe-libs/shared/graphql/fetch';\n\n// ============================================================================\n// Low-level runner\n// ============================================================================\n\nasync function pswQuery<TData>(\n query: string,\n variables: Record<string, unknown> = {}\n): Promise<TData> {\n const response = await graphqlFetch<TData>({\n gateway: 'workspace',\n query,\n variables,\n workspaceToken: true,\n });\n if (response.errors?.length) {\n throw new Error(response.errors[0]?.message ?? 'GraphQL request failed');\n }\n if (!response.data) {\n throw new Error('GraphQL response did not include data');\n }\n if (query.trimStart().startsWith('mutation')) {\n clearGraphqlFetchResponseCache();\n }\n return response.data;\n}\n\nconst QK = 'proserviceworld' as const;\n\n/** Invalidate a set of top-level query keys after a write. */\nfunction invalidate(qc: QueryClient, ...keys: string[]): void {\n for (const key of keys) void qc.invalidateQueries({ queryKey: [QK, key] });\n}\n\n// ============================================================================\n// Shared types (mirror .hive-schema.graphql)\n// ============================================================================\n\nexport interface PswPagination {\n limit?: number;\n offset?: number;\n}\nexport interface PswPageInfo {\n hasMore: boolean;\n cursor: string | null;\n}\nexport interface PswConnection<T> {\n items: T[];\n pageInfo: PswPageInfo;\n totalCount: number;\n}\n\nexport type PswClientType = 'INDIVIDUAL' | 'ORGANIZATION';\nexport type PswClientStatus = 'PROSPECT' | 'ACTIVE' | 'INACTIVE' | 'ARCHIVED';\nexport type PswFeeArrangement = 'FIXED' | 'HOURLY' | 'RETAINER' | 'VALUE_BASED';\nexport type PswEngagementStatus =\n | 'PROPOSAL'\n | 'ACCEPTED'\n | 'IN_PROGRESS'\n | 'REVIEW'\n | 'DELIVERED'\n | 'INVOICED'\n | 'CLOSED'\n | 'CANCELLED';\nexport type PswMatterStatus = 'OPEN' | 'ON_HOLD' | 'CLOSED' | 'ARCHIVED';\nexport type PswMatterPriority = 'LOW' | 'MEDIUM' | 'HIGH' | 'CRITICAL';\nexport type PswDeliverableStatus =\n 'DRAFT' | 'INTERNAL_REVIEW' | 'CLIENT_REVIEW' | 'ACCEPTED' | 'REJECTED';\nexport type PswMilestoneStatus = 'PENDING' | 'IN_PROGRESS' | 'COMPLETED' | 'CANCELLED';\nexport type PswDocumentStatus = 'DRAFT' | 'FINAL' | 'ARCHIVED';\nexport type PswDocumentClassification = 'PUBLIC' | 'INTERNAL' | 'CONFIDENTIAL' | 'PRIVILEGED';\nexport type PswTimeEntryStatus = 'DRAFT' | 'SUBMITTED' | 'APPROVED' | 'REJECTED' | 'BILLED';\nexport type PswInvoiceStatus = 'DRAFT' | 'SENT' | 'PAID' | 'OVERDUE' | 'CANCELLED';\nexport type PswComplianceType =\n | 'ENGAGEMENT_ACCEPTANCE'\n | 'INDEPENDENCE'\n | 'LICENSING'\n | 'CONTINUING_EDUCATION'\n | 'DATA_RETENTION'\n | 'LEGAL_HOLD';\nexport type PswComplianceStatus = 'PENDING' | 'IN_REVIEW' | 'PASSED' | 'FAILED' | 'WAIVED';\nexport type PswConflictCheckStatus =\n 'PENDING' | 'CLEAR' | 'POTENTIAL_CONFLICT' | 'CONFLICT' | 'WAIVED';\nexport type PswTeamRole = 'PARTNER' | 'MANAGER' | 'ASSOCIATE' | 'SPECIALIST' | 'SUPPORT';\n\nexport interface PswClient {\n id: string;\n name: string;\n type: PswClientType;\n status: PswClientStatus;\n industry: string | null;\n contactName: string | null;\n contactEmail: string | null;\n contactPhone: string | null;\n address: string | null;\n relationshipOwnerId: string | null;\n notes: string | null;\n tags: string[];\n createdAt: string;\n updatedAt: string;\n}\nexport interface PswClientDetail extends PswClient {\n engagements: PswEngagement[];\n matters: PswMatter[];\n}\nexport interface PswEngagement {\n id: string;\n clientId: string;\n practiceAreaId: string | null;\n name: string;\n description: string | null;\n status: PswEngagementStatus;\n feeArrangement: PswFeeArrangement;\n feeAmount: number;\n currency: string;\n startDate: string | null;\n endDate: string | null;\n responsiblePartnerId: string | null;\n tags: string[];\n createdAt: string;\n updatedAt: string;\n client?: { id: string; name: string } | null;\n}\nexport interface PswDeliverable {\n id: string;\n engagementId: string;\n name: string;\n description: string | null;\n status: PswDeliverableStatus;\n version: number;\n acceptanceCriteria: string | null;\n dueDate: string | null;\n acceptedAt: string | null;\n createdAt: string;\n}\nexport interface PswMilestone {\n id: string;\n engagementId: string;\n name: string;\n description: string | null;\n status: PswMilestoneStatus;\n dueDate: string | null;\n completedAt: string | null;\n triggerAmount: number;\n triggersInvoice: boolean;\n createdAt: string;\n}\nexport interface PswEngagementDetail extends PswEngagement {\n deliverables: PswDeliverable[];\n milestones: PswMilestone[];\n}\nexport interface PswMatter {\n id: string;\n clientId: string;\n engagementId: string | null;\n practiceAreaId: string | null;\n reference: string | null;\n title: string;\n description: string | null;\n status: PswMatterStatus;\n priority: PswMatterPriority;\n isPrivileged: boolean;\n dueDate: string | null;\n closedAt: string | null;\n leadPractitionerId: string | null;\n tags: string[];\n createdAt: string;\n updatedAt: string;\n client?: { id: string; name: string } | null;\n}\nexport interface PswTimeEntry {\n id: string;\n engagementId: string | null;\n matterId: string | null;\n practitionerId: string;\n date: string;\n minutes: number;\n billable: boolean;\n rate: number;\n narrative: string | null;\n status: PswTimeEntryStatus;\n invoiceId: string | null;\n createdAt: string;\n}\nexport interface PswInvoice {\n id: string;\n clientId: string;\n engagementId: string | null;\n number: string;\n status: PswInvoiceStatus;\n currency: string;\n subtotal: number;\n taxAmount: number;\n total: number;\n issueDate: string | null;\n dueDate: string | null;\n paidAt: string | null;\n notes: string | null;\n createdAt: string;\n}\nexport interface PswComplianceCheck {\n id: string;\n type: PswComplianceType;\n status: PswComplianceStatus;\n subjectType: string;\n subjectId: string;\n title: string;\n details: string | null;\n reviewerId: string | null;\n dueDate: string | null;\n resolvedAt: string | null;\n createdAt: string;\n}\nexport interface PswConflictCheck {\n id: string;\n clientId: string;\n matterId: string | null;\n status: PswConflictCheckStatus;\n searchedParties: string[];\n findings: string | null;\n waiverReason: string | null;\n resolvedAt: string | null;\n createdAt: string;\n}\nexport interface PswPracticeArea {\n id: string;\n name: string;\n code: string | null;\n description: string | null;\n isActive: boolean;\n createdAt: string;\n}\nexport interface PswDocument {\n id: string;\n name: string;\n description: string | null;\n status: PswDocumentStatus;\n classification: PswDocumentClassification;\n version: number;\n legalHold: boolean;\n retainUntil: string | null;\n matterId: string | null;\n engagementId: string | null;\n tags: string[];\n file: { id: string } | null;\n createdAt: string;\n}\nexport interface PswStatusCount {\n status: string;\n count: number;\n}\nexport interface PswMonthlyAmount {\n month: string;\n amount: number;\n}\nexport interface PswDashboardStats {\n totalClients: number;\n activeClients: number;\n activeEngagements: number;\n openMatters: number;\n outstandingInvoiceTotal: number;\n paidInvoiceTotal: number;\n unbilledHours: number;\n billedHours: number;\n pendingComplianceChecks: number;\n openConflictChecks: number;\n engagementsByStatus: PswStatusCount[];\n invoicesByStatus: PswStatusCount[];\n mattersByStatus: PswStatusCount[];\n revenueByMonth: PswMonthlyAmount[];\n}\n\n// ============================================================================\n// GraphQL fragments\n// ============================================================================\n\nconst CLIENT_F = `\n id name type status industry contactName contactEmail contactPhone address\n relationshipOwnerId notes tags createdAt updatedAt`;\nconst ENGAGEMENT_F = `\n id clientId practiceAreaId name description status feeArrangement feeAmount currency\n startDate endDate responsiblePartnerId tags createdAt updatedAt client { id name }`;\nconst DELIVERABLE_F = `id engagementId name description status version acceptanceCriteria dueDate acceptedAt createdAt`;\nconst MILESTONE_F = `id engagementId name description status dueDate completedAt triggerAmount triggersInvoice createdAt`;\nconst MATTER_F = `\n id clientId engagementId practiceAreaId reference title description status priority isPrivileged\n dueDate closedAt leadPractitionerId tags createdAt updatedAt client { id name }`;\nconst TIME_F = `id engagementId matterId practitionerId date minutes billable rate narrative status invoiceId createdAt`;\nconst INVOICE_F = `id clientId engagementId number status currency subtotal taxAmount total issueDate dueDate paidAt notes createdAt`;\nconst COMPLIANCE_F = `id type status subjectType subjectId title details reviewerId dueDate resolvedAt createdAt`;\nconst CONFLICT_F = `id clientId matterId status searchedParties findings waiverReason resolvedAt createdAt`;\nconst PRACTICE_AREA_F = `id name code description isActive createdAt`;\nconst DOCUMENT_F = `id name description status classification version legalHold retainUntil matterId engagementId tags file { id } createdAt`;\n\n// ============================================================================\n// Dashboard\n// ============================================================================\n\nexport function useDashboardStats() {\n return useQuery({\n queryKey: [QK, 'dashboard'],\n queryFn: async () => {\n const data = await pswQuery<{ pswDashboardStats: PswDashboardStats }>(`\n query PswDashboard {\n pswDashboardStats {\n totalClients activeClients activeEngagements openMatters\n outstandingInvoiceTotal paidInvoiceTotal unbilledHours billedHours\n pendingComplianceChecks openConflictChecks\n engagementsByStatus { status count }\n invoicesByStatus { status count }\n mattersByStatus { status count }\n revenueByMonth { month amount }\n }\n }`);\n return data.pswDashboardStats;\n },\n });\n}\n\n// ============================================================================\n// Clients\n// ============================================================================\n\nexport function useClients(\n args: { status?: PswClientStatus; search?: string; pagination?: PswPagination } = {}\n) {\n return useQuery({\n queryKey: [QK, 'clients', args],\n queryFn: async () => {\n const data = await pswQuery<{ pswListClients: PswConnection<PswClient> }>(\n `query PswClients($status: PswClientStatus, $search: String, $pagination: PaginationInput) {\n pswListClients(status: $status, search: $search, pagination: $pagination) {\n items { ${CLIENT_F} } pageInfo { hasMore cursor } totalCount\n }\n }`,\n {\n status: args.status ?? null,\n search: args.search ?? null,\n pagination: args.pagination ?? { limit: 100 },\n }\n );\n return data.pswListClients;\n },\n });\n}\n\nexport function useClient(id: string | null) {\n return useQuery({\n queryKey: [QK, 'client', id],\n enabled: Boolean(id),\n queryFn: async () => {\n const data = await pswQuery<{ pswClient: PswClientDetail | null }>(\n `query PswClient($id: ID!) {\n pswClient(id: $id) {\n ${CLIENT_F}\n engagements { ${ENGAGEMENT_F} }\n matters { ${MATTER_F} }\n }\n }`,\n { id }\n );\n return data.pswClient;\n },\n });\n}\n\nexport function useCreateClient() {\n const qc = useQueryClient();\n return useMutation({\n mutationFn: (input: Record<string, unknown>) =>\n pswQuery<{ pswCreateClient: PswClient }>(\n `mutation PswCreateClient($input: PswCreateClientInput!) { pswCreateClient(input: $input) { ${CLIENT_F} } }`,\n { input }\n ),\n onSuccess: () => invalidate(qc, 'clients', 'dashboard'),\n });\n}\nexport function useUpdateClient() {\n const qc = useQueryClient();\n return useMutation({\n mutationFn: (vars: { id: string; input: Record<string, unknown> }) =>\n pswQuery(\n `mutation PswUpdateClient($id: ID!, $input: PswUpdateClientInput!) { pswUpdateClient(id: $id, input: $input) { ${CLIENT_F} } }`,\n vars\n ),\n onSuccess: (_d, v) => {\n invalidate(qc, 'clients', 'dashboard');\n void qc.invalidateQueries({ queryKey: [QK, 'client', v.id] });\n },\n });\n}\nexport function useArchiveClient() {\n const qc = useQueryClient();\n return useMutation({\n mutationFn: (id: string) =>\n pswQuery(`mutation PswArchiveClient($id: ID!) { pswArchiveClient(id: $id) }`, { id }),\n onSuccess: () => invalidate(qc, 'clients', 'dashboard'),\n });\n}\n\n// ============================================================================\n// Engagements\n// ============================================================================\n\nexport function useEngagements(\n args: {\n clientId?: string;\n status?: PswEngagementStatus;\n search?: string;\n pagination?: PswPagination;\n } = {}\n) {\n return useQuery({\n queryKey: [QK, 'engagements', args],\n queryFn: async () => {\n const data = await pswQuery<{ pswListEngagements: PswConnection<PswEngagement> }>(\n `query PswEngagements($clientId: ID, $status: PswEngagementStatus, $search: String, $pagination: PaginationInput) {\n pswListEngagements(clientId: $clientId, status: $status, search: $search, pagination: $pagination) {\n items { ${ENGAGEMENT_F} } pageInfo { hasMore cursor } totalCount\n }\n }`,\n {\n clientId: args.clientId ?? null,\n status: args.status ?? null,\n search: args.search ?? null,\n pagination: args.pagination ?? { limit: 100 },\n }\n );\n return data.pswListEngagements;\n },\n });\n}\n\nexport function useEngagement(id: string | null) {\n return useQuery({\n queryKey: [QK, 'engagement', id],\n enabled: Boolean(id),\n queryFn: async () => {\n const data = await pswQuery<{ pswEngagement: PswEngagementDetail | null }>(\n `query PswEngagement($id: ID!) {\n pswEngagement(id: $id) {\n ${ENGAGEMENT_F}\n deliverables { ${DELIVERABLE_F} }\n milestones { ${MILESTONE_F} }\n }\n }`,\n { id }\n );\n return data.pswEngagement;\n },\n });\n}\n\nexport function useCreateEngagement() {\n const qc = useQueryClient();\n return useMutation({\n mutationFn: (input: Record<string, unknown>) =>\n pswQuery(\n `mutation PswCreateEngagement($input: PswCreateEngagementInput!) { pswCreateEngagement(input: $input) { ${ENGAGEMENT_F} } }`,\n { input }\n ),\n onSuccess: () => invalidate(qc, 'engagements', 'dashboard'),\n });\n}\nexport function useUpdateEngagement() {\n const qc = useQueryClient();\n return useMutation({\n mutationFn: (vars: { id: string; input: Record<string, unknown> }) =>\n pswQuery(\n `mutation PswUpdateEngagement($id: ID!, $input: PswUpdateEngagementInput!) { pswUpdateEngagement(id: $id, input: $input) { ${ENGAGEMENT_F} } }`,\n vars\n ),\n onSuccess: (_d, v) => {\n invalidate(qc, 'engagements');\n void qc.invalidateQueries({ queryKey: [QK, 'engagement', v.id] });\n },\n });\n}\nexport function useTransitionEngagement() {\n const qc = useQueryClient();\n return useMutation({\n mutationFn: (vars: { id: string; status: PswEngagementStatus }) =>\n pswQuery(\n `mutation PswTransitionEngagement($id: ID!, $status: PswEngagementStatus!) { pswTransitionEngagement(id: $id, status: $status) { ${ENGAGEMENT_F} } }`,\n vars\n ),\n onSuccess: (_d, v) => {\n invalidate(qc, 'engagements', 'dashboard');\n void qc.invalidateQueries({ queryKey: [QK, 'engagement', v.id] });\n },\n });\n}\n\n// ============================================================================\n// Deliverables & Milestones (engagement delivery)\n// ============================================================================\n\nexport function useCreateDeliverable() {\n const qc = useQueryClient();\n return useMutation({\n mutationFn: (input: Record<string, unknown>) =>\n pswQuery(\n `mutation PswCreateDeliverable($input: PswCreateDeliverableInput!) { pswCreateDeliverable(input: $input) { ${DELIVERABLE_F} } }`,\n { input }\n ),\n onSuccess: (_d, input) =>\n qc.invalidateQueries({\n queryKey: [QK, 'engagement', (input as { engagementId: string }).engagementId],\n }),\n });\n}\nexport function useTransitionDeliverable() {\n const qc = useQueryClient();\n return useMutation({\n mutationFn: (vars: { id: string; status: PswDeliverableStatus; engagementId: string }) =>\n pswQuery(\n `mutation PswTransitionDeliverable($id: ID!, $status: PswDeliverableStatus!) { pswTransitionDeliverable(id: $id, status: $status) { ${DELIVERABLE_F} } }`,\n {\n id: vars.id,\n status: vars.status,\n }\n ),\n onSuccess: (_d, v) => qc.invalidateQueries({ queryKey: [QK, 'engagement', v.engagementId] }),\n });\n}\nexport function useCreateMilestone() {\n const qc = useQueryClient();\n return useMutation({\n mutationFn: (input: Record<string, unknown>) =>\n pswQuery(\n `mutation PswCreateMilestone($input: PswCreateMilestoneInput!) { pswCreateMilestone(input: $input) { ${MILESTONE_F} } }`,\n { input }\n ),\n onSuccess: (_d, input) =>\n qc.invalidateQueries({\n queryKey: [QK, 'engagement', (input as { engagementId: string }).engagementId],\n }),\n });\n}\nexport function useCompleteMilestone() {\n const qc = useQueryClient();\n return useMutation({\n mutationFn: (vars: { id: string; engagementId: string }) =>\n pswQuery(\n `mutation PswCompleteMilestone($id: ID!) { pswCompleteMilestone(id: $id) { ${MILESTONE_F} } }`,\n { id: vars.id }\n ),\n onSuccess: (_d, v) => qc.invalidateQueries({ queryKey: [QK, 'engagement', v.engagementId] }),\n });\n}\n\n// ============================================================================\n// Matters\n// ============================================================================\n\nexport function useMatters(\n args: {\n clientId?: string;\n engagementId?: string;\n status?: PswMatterStatus;\n search?: string;\n pagination?: PswPagination;\n } = {}\n) {\n return useQuery({\n queryKey: [QK, 'matters', args],\n queryFn: async () => {\n const data = await pswQuery<{ pswListMatters: PswConnection<PswMatter> }>(\n `query PswMatters($clientId: ID, $engagementId: ID, $status: PswMatterStatus, $search: String, $pagination: PaginationInput) {\n pswListMatters(clientId: $clientId, engagementId: $engagementId, status: $status, search: $search, pagination: $pagination) {\n items { ${MATTER_F} } pageInfo { hasMore cursor } totalCount\n }\n }`,\n {\n clientId: args.clientId ?? null,\n engagementId: args.engagementId ?? null,\n status: args.status ?? null,\n search: args.search ?? null,\n pagination: args.pagination ?? { limit: 100 },\n }\n );\n return data.pswListMatters;\n },\n });\n}\nexport function useCreateMatter() {\n const qc = useQueryClient();\n return useMutation({\n mutationFn: (input: Record<string, unknown>) =>\n pswQuery(\n `mutation PswCreateMatter($input: PswCreateMatterInput!) { pswCreateMatter(input: $input) { ${MATTER_F} } }`,\n { input }\n ),\n onSuccess: () => invalidate(qc, 'matters', 'dashboard'),\n });\n}\nexport function useUpdateMatter() {\n const qc = useQueryClient();\n return useMutation({\n mutationFn: (vars: { id: string; input: Record<string, unknown> }) =>\n pswQuery(\n `mutation PswUpdateMatter($id: ID!, $input: PswUpdateMatterInput!) { pswUpdateMatter(id: $id, input: $input) { ${MATTER_F} } }`,\n vars\n ),\n onSuccess: () => invalidate(qc, 'matters'),\n });\n}\nexport function useCloseMatter() {\n const qc = useQueryClient();\n return useMutation({\n mutationFn: (id: string) =>\n pswQuery(`mutation PswCloseMatter($id: ID!) { pswCloseMatter(id: $id) { ${MATTER_F} } }`, {\n id,\n }),\n onSuccess: () => invalidate(qc, 'matters', 'dashboard'),\n });\n}\n\n// ============================================================================\n// Time entries\n// ============================================================================\n\nexport function useTimeEntries(\n args: {\n engagementId?: string;\n matterId?: string;\n status?: PswTimeEntryStatus;\n billable?: boolean;\n pagination?: PswPagination;\n } = {}\n) {\n return useQuery({\n queryKey: [QK, 'time', args],\n queryFn: async () => {\n const data = await pswQuery<{ pswListTimeEntries: PswConnection<PswTimeEntry> }>(\n `query PswTimeEntries($engagementId: ID, $matterId: ID, $status: PswTimeEntryStatus, $billable: Boolean, $pagination: PaginationInput) {\n pswListTimeEntries(engagementId: $engagementId, matterId: $matterId, status: $status, billable: $billable, pagination: $pagination) {\n items { ${TIME_F} } pageInfo { hasMore cursor } totalCount\n }\n }`,\n {\n engagementId: args.engagementId ?? null,\n matterId: args.matterId ?? null,\n status: args.status ?? null,\n billable: args.billable ?? null,\n pagination: args.pagination ?? { limit: 100 },\n }\n );\n return data.pswListTimeEntries;\n },\n });\n}\nexport function useLogTimeEntry() {\n const qc = useQueryClient();\n return useMutation({\n mutationFn: (input: Record<string, unknown>) =>\n pswQuery(\n `mutation PswLogTime($input: PswCreateTimeEntryInput!) { pswLogTimeEntry(input: $input) { ${TIME_F} } }`,\n { input }\n ),\n onSuccess: () => invalidate(qc, 'time', 'dashboard'),\n });\n}\nexport function useSubmitTimeEntry() {\n const qc = useQueryClient();\n return useMutation({\n mutationFn: (id: string) =>\n pswQuery(`mutation PswSubmitTime($id: ID!) { pswSubmitTimeEntry(id: $id) { ${TIME_F} } }`, {\n id,\n }),\n onSuccess: () => invalidate(qc, 'time'),\n });\n}\nexport function useApproveTimeEntry() {\n const qc = useQueryClient();\n return useMutation({\n mutationFn: (id: string) =>\n pswQuery(`mutation PswApproveTime($id: ID!) { pswApproveTimeEntry(id: $id) { ${TIME_F} } }`, {\n id,\n }),\n onSuccess: () => invalidate(qc, 'time'),\n });\n}\n\n// ============================================================================\n// Invoices\n// ============================================================================\n\nexport function useInvoices(\n args: { clientId?: string; status?: PswInvoiceStatus; pagination?: PswPagination } = {}\n) {\n return useQuery({\n queryKey: [QK, 'invoices', args],\n queryFn: async () => {\n const data = await pswQuery<{ pswListInvoices: PswConnection<PswInvoice> }>(\n `query PswInvoices($clientId: ID, $status: PswInvoiceStatus, $pagination: PaginationInput) {\n pswListInvoices(clientId: $clientId, status: $status, pagination: $pagination) {\n items { ${INVOICE_F} } pageInfo { hasMore cursor } totalCount\n }\n }`,\n {\n clientId: args.clientId ?? null,\n status: args.status ?? null,\n pagination: args.pagination ?? { limit: 100 },\n }\n );\n return data.pswListInvoices;\n },\n });\n}\nexport function useCreateInvoice() {\n const qc = useQueryClient();\n return useMutation({\n mutationFn: (input: Record<string, unknown>) =>\n pswQuery(\n `mutation PswCreateInvoice($input: PswCreateInvoiceInput!) { pswCreateInvoice(input: $input) { ${INVOICE_F} } }`,\n { input }\n ),\n onSuccess: () => invalidate(qc, 'invoices', 'dashboard'),\n });\n}\nexport function useMarkInvoicePaid() {\n const qc = useQueryClient();\n return useMutation({\n mutationFn: (id: string) =>\n pswQuery(`mutation PswMarkPaid($id: ID!) { pswMarkInvoicePaid(id: $id) { ${INVOICE_F} } }`, {\n id,\n }),\n onSuccess: () => invalidate(qc, 'invoices', 'dashboard'),\n });\n}\n\n// ============================================================================\n// Compliance\n// ============================================================================\n\nexport function useComplianceChecks(\n args: { status?: PswComplianceStatus; pagination?: PswPagination } = {}\n) {\n return useQuery({\n queryKey: [QK, 'compliance', args],\n queryFn: async () => {\n const data = await pswQuery<{\n pswListComplianceChecks: PswConnection<PswComplianceCheck>;\n }>(\n `query PswCompliance($status: PswComplianceStatus, $pagination: PaginationInput) {\n pswListComplianceChecks(status: $status, pagination: $pagination) {\n items { ${COMPLIANCE_F} } pageInfo { hasMore cursor } totalCount\n }\n }`,\n { status: args.status ?? null, pagination: args.pagination ?? { limit: 100 } }\n );\n return data.pswListComplianceChecks;\n },\n });\n}\nexport function useCreateComplianceCheck() {\n const qc = useQueryClient();\n return useMutation({\n mutationFn: (input: Record<string, unknown>) =>\n pswQuery(\n `mutation PswCreateCompliance($input: PswCreateComplianceCheckInput!) { pswCreateComplianceCheck(input: $input) { ${COMPLIANCE_F} } }`,\n { input }\n ),\n onSuccess: () => invalidate(qc, 'compliance', 'dashboard'),\n });\n}\nexport function useResolveComplianceCheck() {\n const qc = useQueryClient();\n return useMutation({\n mutationFn: (vars: { id: string; status: PswComplianceStatus; details?: string }) =>\n pswQuery(\n `mutation PswResolveCompliance($id: ID!, $status: PswComplianceStatus!, $details: String) { pswResolveComplianceCheck(id: $id, status: $status, details: $details) { ${COMPLIANCE_F} } }`,\n vars\n ),\n onSuccess: () => invalidate(qc, 'compliance', 'dashboard'),\n });\n}\n\n// ============================================================================\n// Conflict checks\n// ============================================================================\n\nexport function useConflictChecks(args: { clientId?: string; pagination?: PswPagination } = {}) {\n return useQuery({\n queryKey: [QK, 'conflicts', args],\n queryFn: async () => {\n const data = await pswQuery<{ pswListConflictChecks: PswConnection<PswConflictCheck> }>(\n `query PswConflicts($clientId: ID, $pagination: PaginationInput) {\n pswListConflictChecks(clientId: $clientId, pagination: $pagination) {\n items { ${CONFLICT_F} } pageInfo { hasMore cursor } totalCount\n }\n }`,\n { clientId: args.clientId ?? null, pagination: args.pagination ?? { limit: 100 } }\n );\n return data.pswListConflictChecks;\n },\n });\n}\nexport function useCreateConflictCheck() {\n const qc = useQueryClient();\n return useMutation({\n mutationFn: (input: Record<string, unknown>) =>\n pswQuery(\n `mutation PswCreateConflict($input: PswCreateConflictCheckInput!) { pswCreateConflictCheck(input: $input) { ${CONFLICT_F} } }`,\n { input }\n ),\n onSuccess: () => invalidate(qc, 'conflicts', 'dashboard'),\n });\n}\nexport function useResolveConflictCheck() {\n const qc = useQueryClient();\n return useMutation({\n mutationFn: (vars: {\n id: string;\n status: PswConflictCheckStatus;\n findings?: string;\n waiverReason?: string;\n }) =>\n pswQuery(\n `mutation PswResolveConflict($id: ID!, $status: PswConflictCheckStatus!, $findings: String, $waiverReason: String) {\n pswResolveConflictCheck(id: $id, status: $status, findings: $findings, waiverReason: $waiverReason) { ${CONFLICT_F} }\n }`,\n vars\n ),\n onSuccess: () => invalidate(qc, 'conflicts', 'dashboard'),\n });\n}\n\n// ============================================================================\n// Practice areas\n// ============================================================================\n\nexport function usePracticeAreas() {\n return useQuery({\n queryKey: [QK, 'practiceAreas'],\n queryFn: async () => {\n const data = await pswQuery<{ pswListPracticeAreas: PswConnection<PswPracticeArea> }>(\n `query PswPracticeAreas {\n pswListPracticeAreas(pagination: { limit: 100 }) {\n items { ${PRACTICE_AREA_F} } pageInfo { hasMore cursor } totalCount\n }\n }`\n );\n return data.pswListPracticeAreas;\n },\n });\n}\nexport function useCreatePracticeArea() {\n const qc = useQueryClient();\n return useMutation({\n mutationFn: (input: Record<string, unknown>) =>\n pswQuery(\n `mutation PswCreatePracticeArea($input: PswCreatePracticeAreaInput!) { pswCreatePracticeArea(input: $input) { ${PRACTICE_AREA_F} } }`,\n { input }\n ),\n onSuccess: () => invalidate(qc, 'practiceAreas'),\n });\n}\nexport function useUpdatePracticeArea() {\n const qc = useQueryClient();\n return useMutation({\n mutationFn: (vars: { id: string; input: Record<string, unknown> }) =>\n pswQuery(\n `mutation PswUpdatePracticeArea($id: ID!, $input: PswUpdatePracticeAreaInput!) { pswUpdatePracticeArea(id: $id, input: $input) { ${PRACTICE_AREA_F} } }`,\n vars\n ),\n onSuccess: () => invalidate(qc, 'practiceAreas'),\n });\n}\n\n// ============================================================================\n// Documents (metadata over wspace-files-svc)\n// ============================================================================\n\nexport function useDocuments(\n args: {\n engagementId?: string;\n matterId?: string;\n classification?: PswDocumentClassification;\n status?: PswDocumentStatus;\n pagination?: PswPagination;\n } = {}\n) {\n return useQuery({\n queryKey: [QK, 'documents', args],\n queryFn: async () => {\n const data = await pswQuery<{ pswListDocuments: PswConnection<PswDocument> }>(\n `query PswDocuments($engagementId: ID, $matterId: ID, $classification: PswDocumentClassification, $status: PswDocumentStatus, $pagination: PaginationInput) {\n pswListDocuments(engagementId: $engagementId, matterId: $matterId, classification: $classification, status: $status, pagination: $pagination) {\n items { ${DOCUMENT_F} } pageInfo { hasMore cursor } totalCount\n }\n }`,\n {\n engagementId: args.engagementId ?? null,\n matterId: args.matterId ?? null,\n classification: args.classification ?? null,\n status: args.status ?? null,\n pagination: args.pagination ?? { limit: 100 },\n }\n );\n return data.pswListDocuments;\n },\n });\n}\nexport function useCreateDocument() {\n const qc = useQueryClient();\n return useMutation({\n mutationFn: (input: Record<string, unknown>) =>\n pswQuery(\n `mutation PswCreateDocument($input: PswCreateDocumentInput!) { pswCreateDocument(input: $input) { ${DOCUMENT_F} } }`,\n { input }\n ),\n onSuccess: () => invalidate(qc, 'documents'),\n });\n}\nexport function useArchiveDocument() {\n const qc = useQueryClient();\n return useMutation({\n mutationFn: (id: string) =>\n pswQuery(\n `mutation PswArchiveDocument($id: ID!) { pswArchiveDocument(id: $id) { ${DOCUMENT_F} } }`,\n { id }\n ),\n onSuccess: () => invalidate(qc, 'documents'),\n });\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"useProServiceWorldApi.js","names":[],"sources":["../../../src/proserviceworld/hooks/useProServiceWorldApi.ts"],"sourcesContent":["/**\n * ProServiceWorld API hooks\n * @module proserviceworld/hooks\n *\n * Real data layer for the ProServiceWorld workspace subgraph (`proserviceworld`\n * Hive service / `wspace-proserviceworld-svc`). Every hook talks to the live\n * workspace GraphQL gateway via {@link graphqlFetch} with inline operations\n * whose fields mirror `.hive-schema.graphql` exactly. No mocks.\n *\n * Conventions (mirror microfe-hookmovies / microfe-collabkin):\n * - `pswQuery` wraps graphqlFetch({ gateway: 'workspace', workspaceToken: true })\n * and throws on GraphQL errors / missing data.\n * - One react-query `useQuery` per read op and `useMutation` per write op.\n * - Strict hand-written result interfaces — no `any`.\n * - Lists paginate by offset (the workspaces gateway strips the cursor arg);\n * `*Connection { items, pageInfo { hasMore cursor }, totalCount }` verbatim.\n * - After any successful mutation we clear fe-libs' short-lived graphqlFetch\n * read cache so the very next refetch is fresh (fleet stale-read fix).\n */\n\nimport { useMutation, useQuery, useQueryClient, type QueryClient } from '@tanstack/react-query';\n\nimport { graphqlFetch } from '@burdenoff/fe-libs/shared/graphql';\nimport { clearGraphqlFetchResponseCache } from '@burdenoff/fe-libs/shared/graphql/fetch';\n\n// ============================================================================\n// Low-level runner\n// ============================================================================\n\nasync function pswQuery<TData>(\n query: string,\n variables: Record<string, unknown> = {}\n): Promise<TData> {\n const response = await graphqlFetch<TData>({\n gateway: 'workspace',\n query,\n variables,\n workspaceToken: true,\n });\n if (response.errors?.length) {\n throw new Error(response.errors[0]?.message ?? 'GraphQL request failed');\n }\n if (!response.data) {\n throw new Error('GraphQL response did not include data');\n }\n if (query.trimStart().startsWith('mutation')) {\n clearGraphqlFetchResponseCache();\n }\n return response.data;\n}\n\nconst QK = 'proserviceworld' as const;\n\n/** Invalidate a set of top-level query keys after a write. */\nfunction invalidate(qc: QueryClient, ...keys: string[]): void {\n for (const key of keys) void qc.invalidateQueries({ queryKey: [QK, key] });\n}\n\n// ============================================================================\n// Shared types (mirror .hive-schema.graphql)\n// ============================================================================\n\nexport interface PswPagination {\n limit?: number;\n offset?: number;\n}\nexport interface PswPageInfo {\n hasMore: boolean;\n cursor: string | null;\n}\nexport interface PswConnection<T> {\n items: T[];\n pageInfo: PswPageInfo;\n totalCount: number;\n}\n\nexport type PswClientType = 'INDIVIDUAL' | 'ORGANIZATION';\nexport type PswClientStatus = 'PROSPECT' | 'ACTIVE' | 'INACTIVE' | 'ARCHIVED';\nexport type PswFeeArrangement = 'FIXED' | 'HOURLY' | 'RETAINER' | 'VALUE_BASED';\nexport type PswEngagementStatus =\n | 'PROPOSAL'\n | 'ACCEPTED'\n | 'IN_PROGRESS'\n | 'REVIEW'\n | 'DELIVERED'\n | 'INVOICED'\n | 'CLOSED'\n | 'CANCELLED';\nexport type PswMatterStatus = 'OPEN' | 'ON_HOLD' | 'CLOSED' | 'ARCHIVED';\nexport type PswMatterPriority = 'LOW' | 'MEDIUM' | 'HIGH' | 'CRITICAL';\nexport type PswDeliverableStatus =\n 'DRAFT' | 'INTERNAL_REVIEW' | 'CLIENT_REVIEW' | 'ACCEPTED' | 'REJECTED';\nexport type PswMilestoneStatus = 'PENDING' | 'IN_PROGRESS' | 'COMPLETED' | 'CANCELLED';\nexport type PswDocumentStatus = 'DRAFT' | 'FINAL' | 'ARCHIVED';\nexport type PswDocumentClassification = 'PUBLIC' | 'INTERNAL' | 'CONFIDENTIAL' | 'PRIVILEGED';\nexport type PswTimeEntryStatus = 'DRAFT' | 'SUBMITTED' | 'APPROVED' | 'REJECTED' | 'BILLED';\nexport type PswInvoiceStatus = 'DRAFT' | 'SENT' | 'PAID' | 'OVERDUE' | 'CANCELLED';\nexport type PswComplianceType =\n | 'ENGAGEMENT_ACCEPTANCE'\n | 'INDEPENDENCE'\n | 'LICENSING'\n | 'CONTINUING_EDUCATION'\n | 'DATA_RETENTION'\n | 'LEGAL_HOLD';\nexport type PswComplianceStatus = 'PENDING' | 'IN_REVIEW' | 'PASSED' | 'FAILED' | 'WAIVED';\nexport type PswConflictCheckStatus =\n 'PENDING' | 'CLEAR' | 'POTENTIAL_CONFLICT' | 'CONFLICT' | 'WAIVED';\nexport type PswTeamRole = 'PARTNER' | 'MANAGER' | 'ASSOCIATE' | 'SPECIALIST' | 'SUPPORT';\n\nexport interface PswClient {\n id: string;\n name: string;\n type: PswClientType;\n status: PswClientStatus;\n industry: string | null;\n contactName: string | null;\n contactEmail: string | null;\n contactPhone: string | null;\n address: string | null;\n relationshipOwnerId: string | null;\n notes: string | null;\n tags: string[];\n createdAt: string;\n updatedAt: string;\n}\nexport interface PswClientDetail extends PswClient {\n engagements: PswEngagement[];\n matters: PswMatter[];\n}\nexport interface PswEngagement {\n id: string;\n clientId: string;\n practiceAreaId: string | null;\n name: string;\n description: string | null;\n status: PswEngagementStatus;\n feeArrangement: PswFeeArrangement;\n feeAmount: number;\n currency: string;\n startDate: string | null;\n endDate: string | null;\n responsiblePartnerId: string | null;\n tags: string[];\n createdAt: string;\n updatedAt: string;\n client?: { id: string; name: string } | null;\n}\nexport interface PswDeliverable {\n id: string;\n engagementId: string;\n name: string;\n description: string | null;\n status: PswDeliverableStatus;\n version: number;\n acceptanceCriteria: string | null;\n dueDate: string | null;\n acceptedAt: string | null;\n createdAt: string;\n}\nexport interface PswMilestone {\n id: string;\n engagementId: string;\n name: string;\n description: string | null;\n status: PswMilestoneStatus;\n dueDate: string | null;\n completedAt: string | null;\n triggerAmount: number;\n triggersInvoice: boolean;\n createdAt: string;\n}\nexport interface PswEngagementDetail extends PswEngagement {\n deliverables: PswDeliverable[];\n milestones: PswMilestone[];\n}\nexport interface PswMatter {\n id: string;\n clientId: string;\n engagementId: string | null;\n practiceAreaId: string | null;\n reference: string | null;\n title: string;\n description: string | null;\n status: PswMatterStatus;\n priority: PswMatterPriority;\n isPrivileged: boolean;\n dueDate: string | null;\n closedAt: string | null;\n leadPractitionerId: string | null;\n tags: string[];\n createdAt: string;\n updatedAt: string;\n client?: { id: string; name: string } | null;\n}\nexport interface PswTimeEntry {\n id: string;\n engagementId: string | null;\n matterId: string | null;\n practitionerId: string;\n date: string;\n minutes: number;\n billable: boolean;\n rate: number;\n narrative: string | null;\n status: PswTimeEntryStatus;\n invoiceId: string | null;\n createdAt: string;\n}\nexport interface PswInvoice {\n id: string;\n clientId: string;\n engagementId: string | null;\n number: string;\n status: PswInvoiceStatus;\n currency: string;\n subtotal: number;\n taxAmount: number;\n total: number;\n issueDate: string | null;\n dueDate: string | null;\n paidAt: string | null;\n notes: string | null;\n createdAt: string;\n}\nexport interface PswComplianceCheck {\n id: string;\n type: PswComplianceType;\n status: PswComplianceStatus;\n subjectType: string;\n subjectId: string;\n title: string;\n details: string | null;\n reviewerId: string | null;\n dueDate: string | null;\n resolvedAt: string | null;\n createdAt: string;\n}\nexport interface PswConflictCheck {\n id: string;\n clientId: string;\n matterId: string | null;\n status: PswConflictCheckStatus;\n searchedParties: string[];\n findings: string | null;\n waiverReason: string | null;\n resolvedAt: string | null;\n createdAt: string;\n}\nexport interface PswPracticeArea {\n id: string;\n name: string;\n code: string | null;\n description: string | null;\n isActive: boolean;\n createdAt: string;\n}\nexport interface PswDocument {\n id: string;\n name: string;\n description: string | null;\n status: PswDocumentStatus;\n classification: PswDocumentClassification;\n version: number;\n legalHold: boolean;\n retainUntil: string | null;\n matterId: string | null;\n engagementId: string | null;\n tags: string[];\n file: { id: string } | null;\n createdAt: string;\n}\nexport interface PswStatusCount {\n status: string;\n count: number;\n}\nexport interface PswMonthlyAmount {\n month: string;\n amount: number;\n}\nexport interface PswDashboardStats {\n totalClients: number;\n activeClients: number;\n activeEngagements: number;\n openMatters: number;\n outstandingInvoiceTotal: number;\n paidInvoiceTotal: number;\n unbilledHours: number;\n billedHours: number;\n pendingComplianceChecks: number;\n openConflictChecks: number;\n engagementsByStatus: PswStatusCount[];\n invoicesByStatus: PswStatusCount[];\n mattersByStatus: PswStatusCount[];\n revenueByMonth: PswMonthlyAmount[];\n trustHeldTotal: number;\n activeTrustAccounts: number;\n}\n\n// ----------------------------------------------------------------------------\n// Trust accounting / IOLTA reconciliation (BOFF-4209)\n// ----------------------------------------------------------------------------\nexport type PswTrustAccountStatus = 'ACTIVE' | 'CLOSED';\nexport type PswTrustTransactionType = 'DEPOSIT' | 'WITHDRAWAL' | 'TRANSFER_OUT' | 'ADJUSTMENT';\nexport type PswTrustTransferStatus = 'COMPLETED' | 'REVERSED';\n\nexport interface PswTrustAccount {\n id: string;\n name: string;\n institutionName: string | null;\n accountNumberLast4: string | null;\n currency: string;\n status: PswTrustAccountStatus;\n createdAt: string;\n}\nexport interface PswTrustTransaction {\n id: string;\n trustAccountId: string;\n clientId: string;\n matterId: string | null;\n type: PswTrustTransactionType;\n amount: number;\n balanceAfter: number;\n description: string | null;\n reference: string | null;\n transferId: string | null;\n reconciled: boolean;\n reconciledAt: string | null;\n createdAt: string;\n}\nexport interface PswTrustTransfer {\n id: string;\n trustAccountId: string;\n clientId: string;\n matterId: string | null;\n invoiceId: string | null;\n amount: number;\n reason: string | null;\n status: PswTrustTransferStatus;\n transferredAt: string;\n createdAt: string;\n}\nexport interface PswTrustClientBalance {\n clientId: string;\n matterId: string | null;\n balance: number;\n}\nexport interface PswTrustReconciliationReport {\n trustAccountId: string;\n asOf: string;\n bookBalance: number;\n statementBalance: number | null;\n difference: number | null;\n inBalance: boolean;\n clientBalances: PswTrustClientBalance[];\n reconciledCount: number;\n}\n\n// ============================================================================\n// GraphQL fragments\n// ============================================================================\n\nconst CLIENT_F = `\n id name type status industry contactName contactEmail contactPhone address\n relationshipOwnerId notes tags createdAt updatedAt`;\nconst ENGAGEMENT_F = `\n id clientId practiceAreaId name description status feeArrangement feeAmount currency\n startDate endDate responsiblePartnerId tags createdAt updatedAt client { id name }`;\nconst DELIVERABLE_F = `id engagementId name description status version acceptanceCriteria dueDate acceptedAt createdAt`;\nconst MILESTONE_F = `id engagementId name description status dueDate completedAt triggerAmount triggersInvoice createdAt`;\nconst MATTER_F = `\n id clientId engagementId practiceAreaId reference title description status priority isPrivileged\n dueDate closedAt leadPractitionerId tags createdAt updatedAt client { id name }`;\nconst TIME_F = `id engagementId matterId practitionerId date minutes billable rate narrative status invoiceId createdAt`;\nconst INVOICE_F = `id clientId engagementId number status currency subtotal taxAmount total issueDate dueDate paidAt notes createdAt`;\nconst COMPLIANCE_F = `id type status subjectType subjectId title details reviewerId dueDate resolvedAt createdAt`;\nconst CONFLICT_F = `id clientId matterId status searchedParties findings waiverReason resolvedAt createdAt`;\nconst PRACTICE_AREA_F = `id name code description isActive createdAt`;\nconst DOCUMENT_F = `id name description status classification version legalHold retainUntil matterId engagementId tags file { id } createdAt`;\nconst TRUST_ACCOUNT_F = `id name institutionName accountNumberLast4 currency status createdAt`;\nconst TRUST_TXN_F = `id trustAccountId clientId matterId type amount balanceAfter description reference transferId reconciled reconciledAt createdAt`;\nconst TRUST_TRANSFER_F = `id trustAccountId clientId matterId invoiceId amount reason status transferredAt createdAt`;\n\n// ============================================================================\n// Dashboard\n// ============================================================================\n\nexport function useDashboardStats() {\n return useQuery({\n queryKey: [QK, 'dashboard'],\n queryFn: async () => {\n const data = await pswQuery<{ pswDashboardStats: PswDashboardStats }>(`\n query PswDashboard {\n pswDashboardStats {\n totalClients activeClients activeEngagements openMatters\n outstandingInvoiceTotal paidInvoiceTotal unbilledHours billedHours\n pendingComplianceChecks openConflictChecks\n engagementsByStatus { status count }\n invoicesByStatus { status count }\n mattersByStatus { status count }\n revenueByMonth { month amount }\n trustHeldTotal activeTrustAccounts\n }\n }`);\n return data.pswDashboardStats;\n },\n });\n}\n\n// ============================================================================\n// Trust accounting / IOLTA reconciliation (BOFF-4209)\n// ============================================================================\n\nexport function useTrustAccounts(\n args: { status?: PswTrustAccountStatus; pagination?: PswPagination } = {}\n) {\n return useQuery({\n queryKey: [QK, 'trustAccounts', args],\n queryFn: async () => {\n const data = await pswQuery<{ pswListTrustAccounts: PswConnection<PswTrustAccount> }>(\n `query PswTrustAccounts($status: PswTrustAccountStatus, $pagination: PaginationInput) {\n pswListTrustAccounts(status: $status, pagination: $pagination) {\n items { ${TRUST_ACCOUNT_F} } pageInfo { hasMore cursor } totalCount\n }\n }`,\n { status: args.status ?? null, pagination: args.pagination ?? { limit: 100 } }\n );\n return data.pswListTrustAccounts;\n },\n });\n}\n\nexport function useCreateTrustAccount() {\n const qc = useQueryClient();\n return useMutation({\n mutationFn: (input: Record<string, unknown>) =>\n pswQuery(\n `mutation PswCreateTrustAccount($input: PswCreateTrustAccountInput!) {\n pswCreateTrustAccount(input: $input) { ${TRUST_ACCOUNT_F} }\n }`,\n { input }\n ),\n onSuccess: () => invalidate(qc, 'trustAccounts', 'dashboard'),\n });\n}\n\nexport function useCloseTrustAccount() {\n const qc = useQueryClient();\n return useMutation({\n mutationFn: (id: string) =>\n pswQuery(\n `mutation PswCloseTrustAccount($id: ID!) { pswCloseTrustAccount(id: $id) { ${TRUST_ACCOUNT_F} } }`,\n {\n id,\n }\n ),\n onSuccess: () => invalidate(qc, 'trustAccounts', 'dashboard'),\n });\n}\n\nexport function useTrustTransactions(\n args: {\n trustAccountId?: string;\n clientId?: string;\n matterId?: string;\n pagination?: PswPagination;\n } = {}\n) {\n return useQuery({\n queryKey: [QK, 'trustTransactions', args],\n enabled: !!args.trustAccountId,\n queryFn: async () => {\n const data = await pswQuery<{ pswListTrustTransactions: PswConnection<PswTrustTransaction> }>(\n `query PswTrustTransactions($trustAccountId: ID, $clientId: ID, $matterId: ID, $pagination: PaginationInput) {\n pswListTrustTransactions(\n trustAccountId: $trustAccountId\n clientId: $clientId\n matterId: $matterId\n pagination: $pagination\n ) {\n items { ${TRUST_TXN_F} } pageInfo { hasMore cursor } totalCount\n }\n }`,\n {\n trustAccountId: args.trustAccountId ?? null,\n clientId: args.clientId ?? null,\n matterId: args.matterId ?? null,\n pagination: args.pagination ?? { limit: 100 },\n }\n );\n return data.pswListTrustTransactions;\n },\n });\n}\n\nexport function useTrustTransfers(args: { trustAccountId?: string; clientId?: string } = {}) {\n return useQuery({\n queryKey: [QK, 'trustTransfers', args],\n enabled: !!args.trustAccountId,\n queryFn: async () => {\n const data = await pswQuery<{ pswListTrustTransfers: PswConnection<PswTrustTransfer> }>(\n `query PswTrustTransfers($trustAccountId: ID, $clientId: ID) {\n pswListTrustTransfers(trustAccountId: $trustAccountId, clientId: $clientId) {\n items { ${TRUST_TRANSFER_F} } pageInfo { hasMore cursor } totalCount\n }\n }`,\n { trustAccountId: args.trustAccountId ?? null, clientId: args.clientId ?? null }\n );\n return data.pswListTrustTransfers;\n },\n });\n}\n\nexport function useTrustClientBalance(\n trustAccountId?: string,\n clientId?: string,\n matterId?: string\n) {\n return useQuery({\n queryKey: [QK, 'trustClientBalance', trustAccountId, clientId, matterId],\n enabled: !!trustAccountId && !!clientId,\n queryFn: async () => {\n const data = await pswQuery<{ pswTrustClientBalance: PswTrustClientBalance }>(\n `query PswTrustClientBalance($trustAccountId: ID!, $clientId: ID!, $matterId: ID) {\n pswTrustClientBalance(trustAccountId: $trustAccountId, clientId: $clientId, matterId: $matterId) {\n clientId matterId balance\n }\n }`,\n { trustAccountId, clientId, matterId: matterId ?? null }\n );\n return data.pswTrustClientBalance;\n },\n });\n}\n\nexport function useRecordTrustDeposit() {\n const qc = useQueryClient();\n return useMutation({\n mutationFn: (input: Record<string, unknown>) =>\n pswQuery(\n `mutation PswRecordTrustDeposit($input: PswRecordTrustDepositInput!) {\n pswRecordTrustDeposit(input: $input) { ${TRUST_TXN_F} }\n }`,\n { input }\n ),\n onSuccess: () =>\n invalidate(qc, 'trustTransactions', 'trustClientBalance', 'trustAccounts', 'dashboard'),\n });\n}\n\nexport function useRecordTrustWithdrawal() {\n const qc = useQueryClient();\n return useMutation({\n mutationFn: (input: Record<string, unknown>) =>\n pswQuery(\n `mutation PswRecordTrustWithdrawal($input: PswRecordTrustWithdrawalInput!) {\n pswRecordTrustWithdrawal(input: $input) { ${TRUST_TXN_F} }\n }`,\n { input }\n ),\n onSuccess: () =>\n invalidate(qc, 'trustTransactions', 'trustClientBalance', 'trustAccounts', 'dashboard'),\n });\n}\n\nexport function useCreateTrustTransfer() {\n const qc = useQueryClient();\n return useMutation({\n mutationFn: (input: Record<string, unknown>) =>\n pswQuery(\n `mutation PswCreateTrustTransfer($input: PswCreateTrustTransferInput!) {\n pswCreateTrustTransfer(input: $input) { ${TRUST_TRANSFER_F} }\n }`,\n { input }\n ),\n onSuccess: () =>\n invalidate(\n qc,\n 'trustTransactions',\n 'trustTransfers',\n 'trustClientBalance',\n 'trustAccounts',\n 'dashboard'\n ),\n });\n}\n\nexport function useReconcileTrustAccount() {\n const qc = useQueryClient();\n return useMutation({\n mutationFn: (input: Record<string, unknown>) =>\n pswQuery<{ pswReconcileTrustAccount: PswTrustReconciliationReport }>(\n `mutation PswReconcileTrustAccount($input: PswReconcileTrustAccountInput!) {\n pswReconcileTrustAccount(input: $input) {\n trustAccountId asOf bookBalance statementBalance difference inBalance reconciledCount\n clientBalances { clientId matterId balance }\n }\n }`,\n { input }\n ).then((d) => d.pswReconcileTrustAccount),\n onSuccess: () => invalidate(qc, 'trustTransactions', 'trustAccounts', 'dashboard'),\n });\n}\n\n// ============================================================================\n// Clients\n// ============================================================================\n\nexport function useClients(\n args: { status?: PswClientStatus; search?: string; pagination?: PswPagination } = {}\n) {\n return useQuery({\n queryKey: [QK, 'clients', args],\n queryFn: async () => {\n const data = await pswQuery<{ pswListClients: PswConnection<PswClient> }>(\n `query PswClients($status: PswClientStatus, $search: String, $pagination: PaginationInput) {\n pswListClients(status: $status, search: $search, pagination: $pagination) {\n items { ${CLIENT_F} } pageInfo { hasMore cursor } totalCount\n }\n }`,\n {\n status: args.status ?? null,\n search: args.search ?? null,\n pagination: args.pagination ?? { limit: 100 },\n }\n );\n return data.pswListClients;\n },\n });\n}\n\nexport function useClient(id: string | null) {\n return useQuery({\n queryKey: [QK, 'client', id],\n enabled: Boolean(id),\n queryFn: async () => {\n const data = await pswQuery<{ pswClient: PswClientDetail | null }>(\n `query PswClient($id: ID!) {\n pswClient(id: $id) {\n ${CLIENT_F}\n engagements { ${ENGAGEMENT_F} }\n matters { ${MATTER_F} }\n }\n }`,\n { id }\n );\n return data.pswClient;\n },\n });\n}\n\nexport function useCreateClient() {\n const qc = useQueryClient();\n return useMutation({\n mutationFn: (input: Record<string, unknown>) =>\n pswQuery<{ pswCreateClient: PswClient }>(\n `mutation PswCreateClient($input: PswCreateClientInput!) { pswCreateClient(input: $input) { ${CLIENT_F} } }`,\n { input }\n ),\n onSuccess: () => invalidate(qc, 'clients', 'dashboard'),\n });\n}\nexport function useUpdateClient() {\n const qc = useQueryClient();\n return useMutation({\n mutationFn: (vars: { id: string; input: Record<string, unknown> }) =>\n pswQuery(\n `mutation PswUpdateClient($id: ID!, $input: PswUpdateClientInput!) { pswUpdateClient(id: $id, input: $input) { ${CLIENT_F} } }`,\n vars\n ),\n onSuccess: (_d, v) => {\n invalidate(qc, 'clients', 'dashboard');\n void qc.invalidateQueries({ queryKey: [QK, 'client', v.id] });\n },\n });\n}\nexport function useArchiveClient() {\n const qc = useQueryClient();\n return useMutation({\n mutationFn: (id: string) =>\n pswQuery(`mutation PswArchiveClient($id: ID!) { pswArchiveClient(id: $id) }`, { id }),\n onSuccess: () => invalidate(qc, 'clients', 'dashboard'),\n });\n}\n\n// ============================================================================\n// Engagements\n// ============================================================================\n\nexport function useEngagements(\n args: {\n clientId?: string;\n status?: PswEngagementStatus;\n search?: string;\n pagination?: PswPagination;\n } = {}\n) {\n return useQuery({\n queryKey: [QK, 'engagements', args],\n queryFn: async () => {\n const data = await pswQuery<{ pswListEngagements: PswConnection<PswEngagement> }>(\n `query PswEngagements($clientId: ID, $status: PswEngagementStatus, $search: String, $pagination: PaginationInput) {\n pswListEngagements(clientId: $clientId, status: $status, search: $search, pagination: $pagination) {\n items { ${ENGAGEMENT_F} } pageInfo { hasMore cursor } totalCount\n }\n }`,\n {\n clientId: args.clientId ?? null,\n status: args.status ?? null,\n search: args.search ?? null,\n pagination: args.pagination ?? { limit: 100 },\n }\n );\n return data.pswListEngagements;\n },\n });\n}\n\nexport function useEngagement(id: string | null) {\n return useQuery({\n queryKey: [QK, 'engagement', id],\n enabled: Boolean(id),\n queryFn: async () => {\n const data = await pswQuery<{ pswEngagement: PswEngagementDetail | null }>(\n `query PswEngagement($id: ID!) {\n pswEngagement(id: $id) {\n ${ENGAGEMENT_F}\n deliverables { ${DELIVERABLE_F} }\n milestones { ${MILESTONE_F} }\n }\n }`,\n { id }\n );\n return data.pswEngagement;\n },\n });\n}\n\nexport function useCreateEngagement() {\n const qc = useQueryClient();\n return useMutation({\n mutationFn: (input: Record<string, unknown>) =>\n pswQuery(\n `mutation PswCreateEngagement($input: PswCreateEngagementInput!) { pswCreateEngagement(input: $input) { ${ENGAGEMENT_F} } }`,\n { input }\n ),\n onSuccess: () => invalidate(qc, 'engagements', 'dashboard'),\n });\n}\nexport function useUpdateEngagement() {\n const qc = useQueryClient();\n return useMutation({\n mutationFn: (vars: { id: string; input: Record<string, unknown> }) =>\n pswQuery(\n `mutation PswUpdateEngagement($id: ID!, $input: PswUpdateEngagementInput!) { pswUpdateEngagement(id: $id, input: $input) { ${ENGAGEMENT_F} } }`,\n vars\n ),\n onSuccess: (_d, v) => {\n invalidate(qc, 'engagements');\n void qc.invalidateQueries({ queryKey: [QK, 'engagement', v.id] });\n },\n });\n}\nexport function useTransitionEngagement() {\n const qc = useQueryClient();\n return useMutation({\n mutationFn: (vars: { id: string; status: PswEngagementStatus }) =>\n pswQuery(\n `mutation PswTransitionEngagement($id: ID!, $status: PswEngagementStatus!) { pswTransitionEngagement(id: $id, status: $status) { ${ENGAGEMENT_F} } }`,\n vars\n ),\n onSuccess: (_d, v) => {\n invalidate(qc, 'engagements', 'dashboard');\n void qc.invalidateQueries({ queryKey: [QK, 'engagement', v.id] });\n },\n });\n}\n\n// ============================================================================\n// Deliverables & Milestones (engagement delivery)\n// ============================================================================\n\nexport function useCreateDeliverable() {\n const qc = useQueryClient();\n return useMutation({\n mutationFn: (input: Record<string, unknown>) =>\n pswQuery(\n `mutation PswCreateDeliverable($input: PswCreateDeliverableInput!) { pswCreateDeliverable(input: $input) { ${DELIVERABLE_F} } }`,\n { input }\n ),\n onSuccess: (_d, input) =>\n qc.invalidateQueries({\n queryKey: [QK, 'engagement', (input as { engagementId: string }).engagementId],\n }),\n });\n}\nexport function useTransitionDeliverable() {\n const qc = useQueryClient();\n return useMutation({\n mutationFn: (vars: { id: string; status: PswDeliverableStatus; engagementId: string }) =>\n pswQuery(\n `mutation PswTransitionDeliverable($id: ID!, $status: PswDeliverableStatus!) { pswTransitionDeliverable(id: $id, status: $status) { ${DELIVERABLE_F} } }`,\n {\n id: vars.id,\n status: vars.status,\n }\n ),\n onSuccess: (_d, v) => qc.invalidateQueries({ queryKey: [QK, 'engagement', v.engagementId] }),\n });\n}\nexport function useCreateMilestone() {\n const qc = useQueryClient();\n return useMutation({\n mutationFn: (input: Record<string, unknown>) =>\n pswQuery(\n `mutation PswCreateMilestone($input: PswCreateMilestoneInput!) { pswCreateMilestone(input: $input) { ${MILESTONE_F} } }`,\n { input }\n ),\n onSuccess: (_d, input) =>\n qc.invalidateQueries({\n queryKey: [QK, 'engagement', (input as { engagementId: string }).engagementId],\n }),\n });\n}\nexport function useCompleteMilestone() {\n const qc = useQueryClient();\n return useMutation({\n mutationFn: (vars: { id: string; engagementId: string }) =>\n pswQuery(\n `mutation PswCompleteMilestone($id: ID!) { pswCompleteMilestone(id: $id) { ${MILESTONE_F} } }`,\n { id: vars.id }\n ),\n onSuccess: (_d, v) => qc.invalidateQueries({ queryKey: [QK, 'engagement', v.engagementId] }),\n });\n}\n\n// ============================================================================\n// Matters\n// ============================================================================\n\nexport function useMatters(\n args: {\n clientId?: string;\n engagementId?: string;\n status?: PswMatterStatus;\n search?: string;\n pagination?: PswPagination;\n } = {}\n) {\n return useQuery({\n queryKey: [QK, 'matters', args],\n queryFn: async () => {\n const data = await pswQuery<{ pswListMatters: PswConnection<PswMatter> }>(\n `query PswMatters($clientId: ID, $engagementId: ID, $status: PswMatterStatus, $search: String, $pagination: PaginationInput) {\n pswListMatters(clientId: $clientId, engagementId: $engagementId, status: $status, search: $search, pagination: $pagination) {\n items { ${MATTER_F} } pageInfo { hasMore cursor } totalCount\n }\n }`,\n {\n clientId: args.clientId ?? null,\n engagementId: args.engagementId ?? null,\n status: args.status ?? null,\n search: args.search ?? null,\n pagination: args.pagination ?? { limit: 100 },\n }\n );\n return data.pswListMatters;\n },\n });\n}\nexport function useCreateMatter() {\n const qc = useQueryClient();\n return useMutation({\n mutationFn: (input: Record<string, unknown>) =>\n pswQuery(\n `mutation PswCreateMatter($input: PswCreateMatterInput!) { pswCreateMatter(input: $input) { ${MATTER_F} } }`,\n { input }\n ),\n onSuccess: () => invalidate(qc, 'matters', 'dashboard'),\n });\n}\nexport function useUpdateMatter() {\n const qc = useQueryClient();\n return useMutation({\n mutationFn: (vars: { id: string; input: Record<string, unknown> }) =>\n pswQuery(\n `mutation PswUpdateMatter($id: ID!, $input: PswUpdateMatterInput!) { pswUpdateMatter(id: $id, input: $input) { ${MATTER_F} } }`,\n vars\n ),\n onSuccess: () => invalidate(qc, 'matters'),\n });\n}\nexport function useCloseMatter() {\n const qc = useQueryClient();\n return useMutation({\n mutationFn: (id: string) =>\n pswQuery(`mutation PswCloseMatter($id: ID!) { pswCloseMatter(id: $id) { ${MATTER_F} } }`, {\n id,\n }),\n onSuccess: () => invalidate(qc, 'matters', 'dashboard'),\n });\n}\n\n// ============================================================================\n// Time entries\n// ============================================================================\n\nexport function useTimeEntries(\n args: {\n engagementId?: string;\n matterId?: string;\n status?: PswTimeEntryStatus;\n billable?: boolean;\n pagination?: PswPagination;\n } = {}\n) {\n return useQuery({\n queryKey: [QK, 'time', args],\n queryFn: async () => {\n const data = await pswQuery<{ pswListTimeEntries: PswConnection<PswTimeEntry> }>(\n `query PswTimeEntries($engagementId: ID, $matterId: ID, $status: PswTimeEntryStatus, $billable: Boolean, $pagination: PaginationInput) {\n pswListTimeEntries(engagementId: $engagementId, matterId: $matterId, status: $status, billable: $billable, pagination: $pagination) {\n items { ${TIME_F} } pageInfo { hasMore cursor } totalCount\n }\n }`,\n {\n engagementId: args.engagementId ?? null,\n matterId: args.matterId ?? null,\n status: args.status ?? null,\n billable: args.billable ?? null,\n pagination: args.pagination ?? { limit: 100 },\n }\n );\n return data.pswListTimeEntries;\n },\n });\n}\nexport function useLogTimeEntry() {\n const qc = useQueryClient();\n return useMutation({\n mutationFn: (input: Record<string, unknown>) =>\n pswQuery(\n `mutation PswLogTime($input: PswCreateTimeEntryInput!) { pswLogTimeEntry(input: $input) { ${TIME_F} } }`,\n { input }\n ),\n onSuccess: () => invalidate(qc, 'time', 'dashboard'),\n });\n}\nexport function useSubmitTimeEntry() {\n const qc = useQueryClient();\n return useMutation({\n mutationFn: (id: string) =>\n pswQuery(`mutation PswSubmitTime($id: ID!) { pswSubmitTimeEntry(id: $id) { ${TIME_F} } }`, {\n id,\n }),\n onSuccess: () => invalidate(qc, 'time'),\n });\n}\nexport function useApproveTimeEntry() {\n const qc = useQueryClient();\n return useMutation({\n mutationFn: (id: string) =>\n pswQuery(`mutation PswApproveTime($id: ID!) { pswApproveTimeEntry(id: $id) { ${TIME_F} } }`, {\n id,\n }),\n onSuccess: () => invalidate(qc, 'time'),\n });\n}\n\n// ============================================================================\n// Invoices\n// ============================================================================\n\nexport function useInvoices(\n args: { clientId?: string; status?: PswInvoiceStatus; pagination?: PswPagination } = {}\n) {\n return useQuery({\n queryKey: [QK, 'invoices', args],\n queryFn: async () => {\n const data = await pswQuery<{ pswListInvoices: PswConnection<PswInvoice> }>(\n `query PswInvoices($clientId: ID, $status: PswInvoiceStatus, $pagination: PaginationInput) {\n pswListInvoices(clientId: $clientId, status: $status, pagination: $pagination) {\n items { ${INVOICE_F} } pageInfo { hasMore cursor } totalCount\n }\n }`,\n {\n clientId: args.clientId ?? null,\n status: args.status ?? null,\n pagination: args.pagination ?? { limit: 100 },\n }\n );\n return data.pswListInvoices;\n },\n });\n}\nexport function useCreateInvoice() {\n const qc = useQueryClient();\n return useMutation({\n mutationFn: (input: Record<string, unknown>) =>\n pswQuery(\n `mutation PswCreateInvoice($input: PswCreateInvoiceInput!) { pswCreateInvoice(input: $input) { ${INVOICE_F} } }`,\n { input }\n ),\n onSuccess: () => invalidate(qc, 'invoices', 'dashboard'),\n });\n}\nexport function useMarkInvoicePaid() {\n const qc = useQueryClient();\n return useMutation({\n mutationFn: (id: string) =>\n pswQuery(`mutation PswMarkPaid($id: ID!) { pswMarkInvoicePaid(id: $id) { ${INVOICE_F} } }`, {\n id,\n }),\n onSuccess: () => invalidate(qc, 'invoices', 'dashboard'),\n });\n}\n\n// ============================================================================\n// Compliance\n// ============================================================================\n\nexport function useComplianceChecks(\n args: { status?: PswComplianceStatus; pagination?: PswPagination } = {}\n) {\n return useQuery({\n queryKey: [QK, 'compliance', args],\n queryFn: async () => {\n const data = await pswQuery<{\n pswListComplianceChecks: PswConnection<PswComplianceCheck>;\n }>(\n `query PswCompliance($status: PswComplianceStatus, $pagination: PaginationInput) {\n pswListComplianceChecks(status: $status, pagination: $pagination) {\n items { ${COMPLIANCE_F} } pageInfo { hasMore cursor } totalCount\n }\n }`,\n { status: args.status ?? null, pagination: args.pagination ?? { limit: 100 } }\n );\n return data.pswListComplianceChecks;\n },\n });\n}\nexport function useCreateComplianceCheck() {\n const qc = useQueryClient();\n return useMutation({\n mutationFn: (input: Record<string, unknown>) =>\n pswQuery(\n `mutation PswCreateCompliance($input: PswCreateComplianceCheckInput!) { pswCreateComplianceCheck(input: $input) { ${COMPLIANCE_F} } }`,\n { input }\n ),\n onSuccess: () => invalidate(qc, 'compliance', 'dashboard'),\n });\n}\nexport function useResolveComplianceCheck() {\n const qc = useQueryClient();\n return useMutation({\n mutationFn: (vars: { id: string; status: PswComplianceStatus; details?: string }) =>\n pswQuery(\n `mutation PswResolveCompliance($id: ID!, $status: PswComplianceStatus!, $details: String) { pswResolveComplianceCheck(id: $id, status: $status, details: $details) { ${COMPLIANCE_F} } }`,\n vars\n ),\n onSuccess: () => invalidate(qc, 'compliance', 'dashboard'),\n });\n}\n\n// ============================================================================\n// Conflict checks\n// ============================================================================\n\nexport function useConflictChecks(args: { clientId?: string; pagination?: PswPagination } = {}) {\n return useQuery({\n queryKey: [QK, 'conflicts', args],\n queryFn: async () => {\n const data = await pswQuery<{ pswListConflictChecks: PswConnection<PswConflictCheck> }>(\n `query PswConflicts($clientId: ID, $pagination: PaginationInput) {\n pswListConflictChecks(clientId: $clientId, pagination: $pagination) {\n items { ${CONFLICT_F} } pageInfo { hasMore cursor } totalCount\n }\n }`,\n { clientId: args.clientId ?? null, pagination: args.pagination ?? { limit: 100 } }\n );\n return data.pswListConflictChecks;\n },\n });\n}\nexport function useCreateConflictCheck() {\n const qc = useQueryClient();\n return useMutation({\n mutationFn: (input: Record<string, unknown>) =>\n pswQuery(\n `mutation PswCreateConflict($input: PswCreateConflictCheckInput!) { pswCreateConflictCheck(input: $input) { ${CONFLICT_F} } }`,\n { input }\n ),\n onSuccess: () => invalidate(qc, 'conflicts', 'dashboard'),\n });\n}\nexport function useResolveConflictCheck() {\n const qc = useQueryClient();\n return useMutation({\n mutationFn: (vars: {\n id: string;\n status: PswConflictCheckStatus;\n findings?: string;\n waiverReason?: string;\n }) =>\n pswQuery(\n `mutation PswResolveConflict($id: ID!, $status: PswConflictCheckStatus!, $findings: String, $waiverReason: String) {\n pswResolveConflictCheck(id: $id, status: $status, findings: $findings, waiverReason: $waiverReason) { ${CONFLICT_F} }\n }`,\n vars\n ),\n onSuccess: () => invalidate(qc, 'conflicts', 'dashboard'),\n });\n}\n\n// ============================================================================\n// Practice areas\n// ============================================================================\n\nexport function usePracticeAreas() {\n return useQuery({\n queryKey: [QK, 'practiceAreas'],\n queryFn: async () => {\n const data = await pswQuery<{ pswListPracticeAreas: PswConnection<PswPracticeArea> }>(\n `query PswPracticeAreas {\n pswListPracticeAreas(pagination: { limit: 100 }) {\n items { ${PRACTICE_AREA_F} } pageInfo { hasMore cursor } totalCount\n }\n }`\n );\n return data.pswListPracticeAreas;\n },\n });\n}\nexport function useCreatePracticeArea() {\n const qc = useQueryClient();\n return useMutation({\n mutationFn: (input: Record<string, unknown>) =>\n pswQuery(\n `mutation PswCreatePracticeArea($input: PswCreatePracticeAreaInput!) { pswCreatePracticeArea(input: $input) { ${PRACTICE_AREA_F} } }`,\n { input }\n ),\n onSuccess: () => invalidate(qc, 'practiceAreas'),\n });\n}\nexport function useUpdatePracticeArea() {\n const qc = useQueryClient();\n return useMutation({\n mutationFn: (vars: { id: string; input: Record<string, unknown> }) =>\n pswQuery(\n `mutation PswUpdatePracticeArea($id: ID!, $input: PswUpdatePracticeAreaInput!) { pswUpdatePracticeArea(id: $id, input: $input) { ${PRACTICE_AREA_F} } }`,\n vars\n ),\n onSuccess: () => invalidate(qc, 'practiceAreas'),\n });\n}\n\n// ============================================================================\n// Documents (metadata over wspace-files-svc)\n// ============================================================================\n\nexport function useDocuments(\n args: {\n engagementId?: string;\n matterId?: string;\n classification?: PswDocumentClassification;\n status?: PswDocumentStatus;\n pagination?: PswPagination;\n } = {}\n) {\n return useQuery({\n queryKey: [QK, 'documents', args],\n queryFn: async () => {\n const data = await pswQuery<{ pswListDocuments: PswConnection<PswDocument> }>(\n `query PswDocuments($engagementId: ID, $matterId: ID, $classification: PswDocumentClassification, $status: PswDocumentStatus, $pagination: PaginationInput) {\n pswListDocuments(engagementId: $engagementId, matterId: $matterId, classification: $classification, status: $status, pagination: $pagination) {\n items { ${DOCUMENT_F} } pageInfo { hasMore cursor } totalCount\n }\n }`,\n {\n engagementId: args.engagementId ?? null,\n matterId: args.matterId ?? null,\n classification: args.classification ?? null,\n status: args.status ?? null,\n pagination: args.pagination ?? { limit: 100 },\n }\n );\n return data.pswListDocuments;\n },\n });\n}\nexport function useCreateDocument() {\n const qc = useQueryClient();\n return useMutation({\n mutationFn: (input: Record<string, unknown>) =>\n pswQuery(\n `mutation PswCreateDocument($input: PswCreateDocumentInput!) { pswCreateDocument(input: $input) { ${DOCUMENT_F} } }`,\n { input }\n ),\n onSuccess: () => invalidate(qc, 'documents'),\n });\n}\nexport function useArchiveDocument() {\n const qc = useQueryClient();\n return useMutation({\n mutationFn: (id: string) =>\n pswQuery(\n `mutation PswArchiveDocument($id: ID!) { pswArchiveDocument(id: $id) { ${DOCUMENT_F} } }`,\n { id }\n ),\n onSuccess: () => invalidate(qc, 'documents'),\n });\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"DashboardPage.d.ts","sourceRoot":"","sources":["../../../src/proserviceworld/pages/DashboardPage.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAAE,EAAa,MAAM,OAAO,CAAC;AA0C3C,eAAO,MAAM,aAAa,EAAE,EA0G3B,CAAC"}
1
+ {"version":3,"file":"DashboardPage.d.ts","sourceRoot":"","sources":["../../../src/proserviceworld/pages/DashboardPage.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAAE,EAAa,MAAM,OAAO,CAAC;AA4C3C,eAAO,MAAM,aAAa,EAAE,EAiH3B,CAAC"}
@@ -2,198 +2,210 @@ import { useDashboardStats as e } from "../hooks/useProServiceWorldApi.js";
2
2
  import { useNav as t } from "../utils/nav.js";
3
3
  import { cn as n } from "../utils/cn.js";
4
4
  import { ErrorState as r, LoadingBlock as i, MetricCard as a, PageHeader as o, SectionCard as s, StatusPill as c, fmtHours as l, fmtMoney as u } from "../components/ui.js";
5
- import { ArrowRight as d, BarChart3 as f, Briefcase as p, Clock as m, FileText as h, FolderKanban as g, GitBranch as _, Network as v, Receipt as y, Scale as b, ShieldCheck as x, Users as S } from "lucide-react";
6
- import { jsx as C, jsxs as w } from "react/jsx-runtime";
5
+ import { ArrowRight as d, BarChart3 as f, Briefcase as p, Clock as m, FileText as h, FolderKanban as g, GitBranch as _, Network as v, Receipt as y, Scale as b, ShieldCheck as x, Users as S, Wallet as C } from "lucide-react";
6
+ import { jsx as w, jsxs as T } from "react/jsx-runtime";
7
7
  //#region src/proserviceworld/pages/DashboardPage.tsx
8
- var T = [
8
+ var E = [
9
9
  {
10
10
  label: "Clients",
11
11
  to: "clients",
12
- icon: /* @__PURE__ */ C(S, { className: "h-4 w-4" })
12
+ icon: /* @__PURE__ */ w(S, { className: "h-4 w-4" })
13
13
  },
14
14
  {
15
15
  label: "Engagements",
16
16
  to: "engagements",
17
- icon: /* @__PURE__ */ C(p, { className: "h-4 w-4" })
17
+ icon: /* @__PURE__ */ w(p, { className: "h-4 w-4" })
18
18
  },
19
19
  {
20
20
  label: "Matters",
21
21
  to: "matters",
22
- icon: /* @__PURE__ */ C(g, { className: "h-4 w-4" })
22
+ icon: /* @__PURE__ */ w(g, { className: "h-4 w-4" })
23
23
  },
24
24
  {
25
25
  label: "Time",
26
26
  to: "time",
27
- icon: /* @__PURE__ */ C(m, { className: "h-4 w-4" })
27
+ icon: /* @__PURE__ */ w(m, { className: "h-4 w-4" })
28
28
  },
29
29
  {
30
30
  label: "Invoices",
31
31
  to: "invoices",
32
- icon: /* @__PURE__ */ C(y, { className: "h-4 w-4" })
32
+ icon: /* @__PURE__ */ w(y, { className: "h-4 w-4" })
33
+ },
34
+ {
35
+ label: "Trust accounting",
36
+ to: "trust",
37
+ icon: /* @__PURE__ */ w(C, { className: "h-4 w-4" })
33
38
  },
34
39
  {
35
40
  label: "Compliance",
36
41
  to: "compliance",
37
- icon: /* @__PURE__ */ C(x, { className: "h-4 w-4" })
42
+ icon: /* @__PURE__ */ w(x, { className: "h-4 w-4" })
38
43
  },
39
44
  {
40
45
  label: "Conflict checks",
41
46
  to: "conflicts",
42
- icon: /* @__PURE__ */ C(b, { className: "h-4 w-4" })
47
+ icon: /* @__PURE__ */ w(b, { className: "h-4 w-4" })
43
48
  },
44
49
  {
45
50
  label: "Documents",
46
51
  to: "documents",
47
- icon: /* @__PURE__ */ C(h, { className: "h-4 w-4" })
52
+ icon: /* @__PURE__ */ w(h, { className: "h-4 w-4" })
48
53
  },
49
54
  {
50
55
  label: "Practice areas",
51
56
  to: "practice-areas",
52
- icon: /* @__PURE__ */ C(v, { className: "h-4 w-4" })
57
+ icon: /* @__PURE__ */ w(v, { className: "h-4 w-4" })
53
58
  },
54
59
  {
55
60
  label: "Analytics",
56
61
  to: "analytics",
57
- icon: /* @__PURE__ */ C(f, { className: "h-4 w-4" })
62
+ icon: /* @__PURE__ */ w(f, { className: "h-4 w-4" })
58
63
  }
59
- ], E = () => {
64
+ ], D = () => {
60
65
  let c = t(), { data: f, isLoading: h, error: v, refetch: b } = e();
61
- return h ? /* @__PURE__ */ C(i, { label: "Loading practice overview…" }) : v ? /* @__PURE__ */ C(r, {
66
+ return h ? /* @__PURE__ */ w(i, { label: "Loading practice overview…" }) : v ? /* @__PURE__ */ w(r, {
62
67
  error: v,
63
68
  onRetry: () => void b()
64
- }) : f ? /* @__PURE__ */ w("div", {
69
+ }) : f ? /* @__PURE__ */ T("div", {
65
70
  className: "space-y-6",
66
71
  children: [
67
- /* @__PURE__ */ C(o, {
72
+ /* @__PURE__ */ w(o, {
68
73
  title: "Practice overview",
69
74
  subtitle: "One governed view of clients, engagements, matters, time and billing across your firm."
70
75
  }),
71
- /* @__PURE__ */ w("div", {
76
+ /* @__PURE__ */ T("div", {
72
77
  className: "grid grid-cols-2 gap-3 md:grid-cols-3 lg:grid-cols-4",
73
78
  children: [
74
- /* @__PURE__ */ C(a, {
79
+ /* @__PURE__ */ w(a, {
75
80
  label: "Active clients",
76
81
  value: f.activeClients,
77
82
  hint: `${f.totalClients} total`,
78
- icon: /* @__PURE__ */ C(S, { className: "h-4 w-4" }),
83
+ icon: /* @__PURE__ */ w(S, { className: "h-4 w-4" }),
79
84
  tone: "success"
80
85
  }),
81
- /* @__PURE__ */ C(a, {
86
+ /* @__PURE__ */ w(a, {
82
87
  label: "Active engagements",
83
88
  value: f.activeEngagements,
84
- icon: /* @__PURE__ */ C(p, { className: "h-4 w-4" }),
89
+ icon: /* @__PURE__ */ w(p, { className: "h-4 w-4" }),
85
90
  tone: "accent"
86
91
  }),
87
- /* @__PURE__ */ C(a, {
92
+ /* @__PURE__ */ w(a, {
88
93
  label: "Open matters",
89
94
  value: f.openMatters,
90
- icon: /* @__PURE__ */ C(g, { className: "h-4 w-4" }),
95
+ icon: /* @__PURE__ */ w(g, { className: "h-4 w-4" }),
91
96
  tone: "info"
92
97
  }),
93
- /* @__PURE__ */ C(a, {
98
+ /* @__PURE__ */ w(a, {
94
99
  label: "Unbilled hours",
95
100
  value: l(f.unbilledHours),
96
101
  hint: `${l(f.billedHours)} billed`,
97
- icon: /* @__PURE__ */ C(m, { className: "h-4 w-4" }),
102
+ icon: /* @__PURE__ */ w(m, { className: "h-4 w-4" }),
98
103
  tone: "warning"
99
104
  }),
100
- /* @__PURE__ */ C(a, {
105
+ /* @__PURE__ */ w(a, {
101
106
  label: "Outstanding",
102
107
  value: u(f.outstandingInvoiceTotal),
103
108
  hint: "Sent + overdue",
104
- icon: /* @__PURE__ */ C(y, { className: "h-4 w-4" }),
109
+ icon: /* @__PURE__ */ w(y, { className: "h-4 w-4" }),
105
110
  tone: "warning"
106
111
  }),
107
- /* @__PURE__ */ C(a, {
112
+ /* @__PURE__ */ w(a, {
108
113
  label: "Collected",
109
114
  value: u(f.paidInvoiceTotal),
110
- icon: /* @__PURE__ */ C(y, { className: "h-4 w-4" }),
115
+ icon: /* @__PURE__ */ w(y, { className: "h-4 w-4" }),
111
116
  tone: "success"
112
117
  }),
113
- /* @__PURE__ */ C(a, {
118
+ /* @__PURE__ */ w(a, {
119
+ label: "Trust held",
120
+ value: u(f.trustHeldTotal),
121
+ hint: `${f.activeTrustAccounts} active account${f.activeTrustAccounts === 1 ? "" : "s"}`,
122
+ icon: /* @__PURE__ */ w(C, { className: "h-4 w-4" }),
123
+ tone: "info"
124
+ }),
125
+ /* @__PURE__ */ w(a, {
114
126
  label: "Compliance due",
115
127
  value: f.pendingComplianceChecks,
116
- icon: /* @__PURE__ */ C(x, { className: "h-4 w-4" }),
128
+ icon: /* @__PURE__ */ w(x, { className: "h-4 w-4" }),
117
129
  tone: f.pendingComplianceChecks ? "warning" : "success"
118
130
  }),
119
- /* @__PURE__ */ C(a, {
131
+ /* @__PURE__ */ w(a, {
120
132
  label: "Open conflicts",
121
133
  value: f.openConflictChecks,
122
- icon: /* @__PURE__ */ C(_, { className: "h-4 w-4" }),
134
+ icon: /* @__PURE__ */ w(_, { className: "h-4 w-4" }),
123
135
  tone: f.openConflictChecks ? "danger" : "success"
124
136
  })
125
137
  ]
126
138
  }),
127
- /* @__PURE__ */ w("div", {
139
+ /* @__PURE__ */ T("div", {
128
140
  className: "grid grid-cols-1 gap-4 lg:grid-cols-3",
129
141
  children: [
130
- /* @__PURE__ */ C(s, {
142
+ /* @__PURE__ */ w(s, {
131
143
  title: "Engagements by status",
132
- children: /* @__PURE__ */ C(D, { items: f.engagementsByStatus })
144
+ children: /* @__PURE__ */ w(O, { items: f.engagementsByStatus })
133
145
  }),
134
- /* @__PURE__ */ C(s, {
146
+ /* @__PURE__ */ w(s, {
135
147
  title: "Matters by status",
136
- children: /* @__PURE__ */ C(D, { items: f.mattersByStatus })
148
+ children: /* @__PURE__ */ w(O, { items: f.mattersByStatus })
137
149
  }),
138
- /* @__PURE__ */ C(s, {
150
+ /* @__PURE__ */ w(s, {
139
151
  title: "Revenue",
140
152
  description: "Invoiced totals, recent months.",
141
- children: /* @__PURE__ */ C(O, { data: f.revenueByMonth })
153
+ children: /* @__PURE__ */ w(k, { data: f.revenueByMonth })
142
154
  })
143
155
  ]
144
156
  }),
145
- /* @__PURE__ */ C(s, {
157
+ /* @__PURE__ */ w(s, {
146
158
  title: "Jump to",
147
- children: /* @__PURE__ */ C("div", {
159
+ children: /* @__PURE__ */ w("div", {
148
160
  className: "grid grid-cols-1 gap-2.5 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-5",
149
- children: T.map((e) => /* @__PURE__ */ w("button", {
161
+ children: E.map((e) => /* @__PURE__ */ T("button", {
150
162
  type: "button",
151
163
  onClick: () => c(e.to),
152
164
  className: n("group flex items-center gap-3 rounded-xl border border-border-seam bg-bg-canvas px-3.5 py-3 text-left", "transition hover:-translate-y-0.5 hover:border-accent hover:bg-bg-surface hover:shadow-sm"),
153
165
  children: [
154
- /* @__PURE__ */ C("span", {
166
+ /* @__PURE__ */ w("span", {
155
167
  className: "flex h-9 w-9 shrink-0 items-center justify-center rounded-lg bg-bg-sunken text-accent transition group-hover:bg-accent/15",
156
168
  children: e.icon
157
169
  }),
158
- /* @__PURE__ */ C("span", {
170
+ /* @__PURE__ */ w("span", {
159
171
  className: "flex-1 truncate text-sm font-medium text-text-primary",
160
172
  children: e.label
161
173
  }),
162
- /* @__PURE__ */ C(d, { className: "h-4 w-4 shrink-0 text-text-tertiary transition group-hover:translate-x-0.5 group-hover:text-accent" })
174
+ /* @__PURE__ */ w(d, { className: "h-4 w-4 shrink-0 text-text-tertiary transition group-hover:translate-x-0.5 group-hover:text-accent" })
163
175
  ]
164
176
  }, e.to))
165
177
  })
166
178
  })
167
179
  ]
168
180
  }) : null;
169
- }, D = ({ items: e }) => {
170
- if (!e.length) return /* @__PURE__ */ C("p", {
181
+ }, O = ({ items: e }) => {
182
+ if (!e.length) return /* @__PURE__ */ w("p", {
171
183
  className: "text-sm text-text-tertiary",
172
184
  children: "No records yet."
173
185
  });
174
186
  let t = Math.max(...e.map((e) => e.count), 1), r = e.reduce((e, t) => e + t.count, 0) || 1;
175
- return /* @__PURE__ */ C("ul", {
187
+ return /* @__PURE__ */ w("ul", {
176
188
  className: "space-y-3.5",
177
- children: e.map((e) => /* @__PURE__ */ w("li", {
189
+ children: e.map((e) => /* @__PURE__ */ T("li", {
178
190
  className: "grid grid-cols-[7.5rem_minmax(0,1fr)_auto] items-center gap-3",
179
191
  children: [
180
- /* @__PURE__ */ C(c, {
192
+ /* @__PURE__ */ w(c, {
181
193
  status: e.status,
182
194
  className: "justify-self-start"
183
195
  }),
184
- /* @__PURE__ */ C("div", {
196
+ /* @__PURE__ */ w("div", {
185
197
  className: "h-2.5 overflow-hidden rounded-full bg-bg-sunken",
186
- children: /* @__PURE__ */ C("div", {
187
- className: n("h-full rounded-full bg-gradient-to-r transition-all duration-500", j(e.status)),
198
+ children: /* @__PURE__ */ w("div", {
199
+ className: n("h-full rounded-full bg-gradient-to-r transition-all duration-500", M(e.status)),
188
200
  style: { width: `${Math.max(e.count / t * 100, 4)}%` }
189
201
  })
190
202
  }),
191
- /* @__PURE__ */ w("span", {
203
+ /* @__PURE__ */ T("span", {
192
204
  className: "flex items-baseline justify-end gap-1.5 tabular-nums",
193
- children: [/* @__PURE__ */ C("span", {
205
+ children: [/* @__PURE__ */ w("span", {
194
206
  className: "text-sm font-semibold text-text-primary",
195
207
  children: e.count
196
- }), /* @__PURE__ */ w("span", {
208
+ }), /* @__PURE__ */ T("span", {
197
209
  className: "text-xs text-text-tertiary",
198
210
  children: [Math.round(e.count / r * 100), "%"]
199
211
  })]
@@ -201,59 +213,59 @@ var T = [
201
213
  ]
202
214
  }, e.status))
203
215
  });
204
- }, O = ({ data: e }) => {
205
- if (!e.length) return /* @__PURE__ */ C("p", {
216
+ }, k = ({ data: e }) => {
217
+ if (!e.length) return /* @__PURE__ */ w("p", {
206
218
  className: "text-sm text-text-tertiary",
207
219
  children: "No invoiced revenue yet."
208
220
  });
209
- let t = M(Math.max(...e.map((e) => e.amount), 1)), r = [
221
+ let t = N(Math.max(...e.map((e) => e.amount), 1)), r = [
210
222
  1,
211
223
  .75,
212
224
  .5,
213
225
  .25,
214
226
  0
215
227
  ].map((e) => t * e);
216
- return /* @__PURE__ */ C("div", {
228
+ return /* @__PURE__ */ w("div", {
217
229
  className: "overflow-x-auto",
218
- children: /* @__PURE__ */ w("div", {
230
+ children: /* @__PURE__ */ T("div", {
219
231
  className: "min-w-[260px]",
220
- children: [/* @__PURE__ */ w("div", {
232
+ children: [/* @__PURE__ */ T("div", {
221
233
  className: "relative h-44",
222
- children: [r.map((e, t) => /* @__PURE__ */ w("div", {
234
+ children: [r.map((e, t) => /* @__PURE__ */ T("div", {
223
235
  className: "absolute inset-x-0 flex items-center gap-2",
224
236
  style: { top: `${t / (r.length - 1) * 100}%` },
225
- children: [/* @__PURE__ */ C("span", {
237
+ children: [/* @__PURE__ */ w("span", {
226
238
  className: "w-11 shrink-0 text-right text-[10px] leading-none tabular-nums text-text-tertiary",
227
- children: N(e)
228
- }), /* @__PURE__ */ C("span", { className: n("h-px flex-1", t === r.length - 1 ? "bg-border-seam" : "bg-border-seam/50") })]
229
- }, e)), /* @__PURE__ */ C("div", {
239
+ children: P(e)
240
+ }), /* @__PURE__ */ w("span", { className: n("h-px flex-1", t === r.length - 1 ? "bg-border-seam" : "bg-border-seam/50") })]
241
+ }, e)), /* @__PURE__ */ w("div", {
230
242
  className: "absolute inset-0 flex items-end gap-1.5 pl-[3.25rem]",
231
- children: e.map((e) => /* @__PURE__ */ C("div", {
243
+ children: e.map((e) => /* @__PURE__ */ w("div", {
232
244
  className: "group flex h-full flex-1 flex-col items-center justify-end",
233
- children: /* @__PURE__ */ C("div", {
245
+ children: /* @__PURE__ */ w("div", {
234
246
  className: "w-full max-w-[2rem] rounded-t-md bg-gradient-to-t from-accent/55 to-accent shadow-sm transition-all duration-200 group-hover:-translate-y-0.5 group-hover:shadow",
235
247
  style: { height: `${Math.max(e.amount / t * 100, 1.5)}%` },
236
248
  title: u(e.amount)
237
249
  })
238
250
  }, e.month))
239
251
  })]
240
- }), /* @__PURE__ */ C("div", {
252
+ }), /* @__PURE__ */ w("div", {
241
253
  className: "mt-2 flex gap-1.5 pl-[3.25rem]",
242
- children: e.map((e) => /* @__PURE__ */ C("span", {
254
+ children: e.map((e) => /* @__PURE__ */ w("span", {
243
255
  className: "flex-1 text-center text-[10px] text-text-tertiary",
244
- children: P(e.month)
256
+ children: F(e.month)
245
257
  }, e.month))
246
258
  })]
247
259
  })
248
260
  });
249
- }, k = {
261
+ }, A = {
250
262
  success: "from-status-success-text/55 to-status-success-text",
251
263
  warning: "from-status-warning-text/55 to-status-warning-text",
252
264
  danger: "from-status-error-text/55 to-status-error-text",
253
265
  info: "from-text-link/55 to-text-link",
254
266
  accent: "from-accent/55 to-accent",
255
267
  neutral: "from-text-tertiary/30 to-text-tertiary/70"
256
- }, A = {
268
+ }, j = {
257
269
  ACTIVE: "success",
258
270
  DELIVERED: "success",
259
271
  INVOICED: "success",
@@ -293,24 +305,24 @@ var T = [
293
305
  DRAFT: "neutral",
294
306
  WAIVED: "neutral"
295
307
  };
296
- function j(e) {
297
- return k[A[e] ?? "accent"];
298
- }
299
308
  function M(e) {
309
+ return A[j[e] ?? "accent"];
310
+ }
311
+ function N(e) {
300
312
  if (e <= 0) return 1;
301
313
  let t = 10 ** Math.floor(Math.log10(e)), n = e / t;
302
314
  return (n <= 1 ? 1 : n <= 2 ? 2 : n <= 2.5 ? 2.5 : n <= 5 ? 5 : 10) * t;
303
315
  }
304
- function N(e) {
316
+ function P(e) {
305
317
  return e >= 1e6 ? `$${(e / 1e6).toFixed(e % 1e6 == 0 ? 0 : 1)}M` : e >= 1e3 ? `$${Math.round(e / 1e3)}k` : `$${Math.round(e)}`;
306
318
  }
307
- function P(e) {
319
+ function F(e) {
308
320
  let [t, n] = e.split("-").map(Number);
309
321
  if (!t || !n) return e;
310
322
  let r = new Date(t, n - 1, 1);
311
323
  return Number.isNaN(r.getTime()) ? e : r.toLocaleDateString(void 0, { month: "short" });
312
324
  }
313
325
  //#endregion
314
- export { E as DashboardPage };
326
+ export { D as DashboardPage };
315
327
 
316
328
  //# sourceMappingURL=DashboardPage.js.map