@burdenoff/microfe-proserviceworld 2026.719.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.
- package/dist/proserviceworld/ProServiceWorldRoot.d.ts.map +1 -1
- package/dist/proserviceworld/ProServiceWorldRoot.js +18 -12
- package/dist/proserviceworld/ProServiceWorldRoot.js.map +1 -1
- package/dist/proserviceworld/ProServiceWorldRoutes.d.ts.map +1 -1
- package/dist/proserviceworld/ProServiceWorldRoutes.js +34 -27
- package/dist/proserviceworld/ProServiceWorldRoutes.js.map +1 -1
- package/dist/proserviceworld/hooks/useProServiceWorldApi.d.ts +77 -0
- package/dist/proserviceworld/hooks/useProServiceWorldApi.d.ts.map +1 -1
- package/dist/proserviceworld/hooks/useProServiceWorldApi.js +243 -141
- package/dist/proserviceworld/hooks/useProServiceWorldApi.js.map +1 -1
- package/dist/proserviceworld/pages/DashboardPage.d.ts.map +1 -1
- package/dist/proserviceworld/pages/DashboardPage.js +94 -82
- package/dist/proserviceworld/pages/DashboardPage.js.map +1 -1
- package/dist/proserviceworld/pages/TrustPage.d.ts +14 -0
- package/dist/proserviceworld/pages/TrustPage.d.ts.map +1 -0
- package/dist/proserviceworld/pages/TrustPage.js +603 -0
- package/dist/proserviceworld/pages/TrustPage.js.map +1 -0
- package/package.json +19 -11
|
@@ -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;
|
|
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
|
|
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
|
|
8
|
+
var E = [
|
|
9
9
|
{
|
|
10
10
|
label: "Clients",
|
|
11
11
|
to: "clients",
|
|
12
|
-
icon: /* @__PURE__ */
|
|
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__ */
|
|
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__ */
|
|
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__ */
|
|
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__ */
|
|
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__ */
|
|
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__ */
|
|
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__ */
|
|
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__ */
|
|
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__ */
|
|
62
|
+
icon: /* @__PURE__ */ w(f, { className: "h-4 w-4" })
|
|
58
63
|
}
|
|
59
|
-
],
|
|
64
|
+
], D = () => {
|
|
60
65
|
let c = t(), { data: f, isLoading: h, error: v, refetch: b } = e();
|
|
61
|
-
return h ? /* @__PURE__ */
|
|
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__ */
|
|
69
|
+
}) : f ? /* @__PURE__ */ T("div", {
|
|
65
70
|
className: "space-y-6",
|
|
66
71
|
children: [
|
|
67
|
-
/* @__PURE__ */
|
|
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__ */
|
|
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__ */
|
|
79
|
+
/* @__PURE__ */ w(a, {
|
|
75
80
|
label: "Active clients",
|
|
76
81
|
value: f.activeClients,
|
|
77
82
|
hint: `${f.totalClients} total`,
|
|
78
|
-
icon: /* @__PURE__ */
|
|
83
|
+
icon: /* @__PURE__ */ w(S, { className: "h-4 w-4" }),
|
|
79
84
|
tone: "success"
|
|
80
85
|
}),
|
|
81
|
-
/* @__PURE__ */
|
|
86
|
+
/* @__PURE__ */ w(a, {
|
|
82
87
|
label: "Active engagements",
|
|
83
88
|
value: f.activeEngagements,
|
|
84
|
-
icon: /* @__PURE__ */
|
|
89
|
+
icon: /* @__PURE__ */ w(p, { className: "h-4 w-4" }),
|
|
85
90
|
tone: "accent"
|
|
86
91
|
}),
|
|
87
|
-
/* @__PURE__ */
|
|
92
|
+
/* @__PURE__ */ w(a, {
|
|
88
93
|
label: "Open matters",
|
|
89
94
|
value: f.openMatters,
|
|
90
|
-
icon: /* @__PURE__ */
|
|
95
|
+
icon: /* @__PURE__ */ w(g, { className: "h-4 w-4" }),
|
|
91
96
|
tone: "info"
|
|
92
97
|
}),
|
|
93
|
-
/* @__PURE__ */
|
|
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__ */
|
|
102
|
+
icon: /* @__PURE__ */ w(m, { className: "h-4 w-4" }),
|
|
98
103
|
tone: "warning"
|
|
99
104
|
}),
|
|
100
|
-
/* @__PURE__ */
|
|
105
|
+
/* @__PURE__ */ w(a, {
|
|
101
106
|
label: "Outstanding",
|
|
102
107
|
value: u(f.outstandingInvoiceTotal),
|
|
103
108
|
hint: "Sent + overdue",
|
|
104
|
-
icon: /* @__PURE__ */
|
|
109
|
+
icon: /* @__PURE__ */ w(y, { className: "h-4 w-4" }),
|
|
105
110
|
tone: "warning"
|
|
106
111
|
}),
|
|
107
|
-
/* @__PURE__ */
|
|
112
|
+
/* @__PURE__ */ w(a, {
|
|
108
113
|
label: "Collected",
|
|
109
114
|
value: u(f.paidInvoiceTotal),
|
|
110
|
-
icon: /* @__PURE__ */
|
|
115
|
+
icon: /* @__PURE__ */ w(y, { className: "h-4 w-4" }),
|
|
111
116
|
tone: "success"
|
|
112
117
|
}),
|
|
113
|
-
/* @__PURE__ */
|
|
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__ */
|
|
128
|
+
icon: /* @__PURE__ */ w(x, { className: "h-4 w-4" }),
|
|
117
129
|
tone: f.pendingComplianceChecks ? "warning" : "success"
|
|
118
130
|
}),
|
|
119
|
-
/* @__PURE__ */
|
|
131
|
+
/* @__PURE__ */ w(a, {
|
|
120
132
|
label: "Open conflicts",
|
|
121
133
|
value: f.openConflictChecks,
|
|
122
|
-
icon: /* @__PURE__ */
|
|
134
|
+
icon: /* @__PURE__ */ w(_, { className: "h-4 w-4" }),
|
|
123
135
|
tone: f.openConflictChecks ? "danger" : "success"
|
|
124
136
|
})
|
|
125
137
|
]
|
|
126
138
|
}),
|
|
127
|
-
/* @__PURE__ */
|
|
139
|
+
/* @__PURE__ */ T("div", {
|
|
128
140
|
className: "grid grid-cols-1 gap-4 lg:grid-cols-3",
|
|
129
141
|
children: [
|
|
130
|
-
/* @__PURE__ */
|
|
142
|
+
/* @__PURE__ */ w(s, {
|
|
131
143
|
title: "Engagements by status",
|
|
132
|
-
children: /* @__PURE__ */
|
|
144
|
+
children: /* @__PURE__ */ w(O, { items: f.engagementsByStatus })
|
|
133
145
|
}),
|
|
134
|
-
/* @__PURE__ */
|
|
146
|
+
/* @__PURE__ */ w(s, {
|
|
135
147
|
title: "Matters by status",
|
|
136
|
-
children: /* @__PURE__ */
|
|
148
|
+
children: /* @__PURE__ */ w(O, { items: f.mattersByStatus })
|
|
137
149
|
}),
|
|
138
|
-
/* @__PURE__ */
|
|
150
|
+
/* @__PURE__ */ w(s, {
|
|
139
151
|
title: "Revenue",
|
|
140
152
|
description: "Invoiced totals, recent months.",
|
|
141
|
-
children: /* @__PURE__ */
|
|
153
|
+
children: /* @__PURE__ */ w(k, { data: f.revenueByMonth })
|
|
142
154
|
})
|
|
143
155
|
]
|
|
144
156
|
}),
|
|
145
|
-
/* @__PURE__ */
|
|
157
|
+
/* @__PURE__ */ w(s, {
|
|
146
158
|
title: "Jump to",
|
|
147
|
-
children: /* @__PURE__ */
|
|
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:
|
|
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__ */
|
|
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__ */
|
|
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__ */
|
|
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
|
-
},
|
|
170
|
-
if (!e.length) return /* @__PURE__ */
|
|
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__ */
|
|
187
|
+
return /* @__PURE__ */ w("ul", {
|
|
176
188
|
className: "space-y-3.5",
|
|
177
|
-
children: e.map((e) => /* @__PURE__ */
|
|
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__ */
|
|
192
|
+
/* @__PURE__ */ w(c, {
|
|
181
193
|
status: e.status,
|
|
182
194
|
className: "justify-self-start"
|
|
183
195
|
}),
|
|
184
|
-
/* @__PURE__ */
|
|
196
|
+
/* @__PURE__ */ w("div", {
|
|
185
197
|
className: "h-2.5 overflow-hidden rounded-full bg-bg-sunken",
|
|
186
|
-
children: /* @__PURE__ */
|
|
187
|
-
className: n("h-full rounded-full bg-gradient-to-r transition-all duration-500",
|
|
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__ */
|
|
203
|
+
/* @__PURE__ */ T("span", {
|
|
192
204
|
className: "flex items-baseline justify-end gap-1.5 tabular-nums",
|
|
193
|
-
children: [/* @__PURE__ */
|
|
205
|
+
children: [/* @__PURE__ */ w("span", {
|
|
194
206
|
className: "text-sm font-semibold text-text-primary",
|
|
195
207
|
children: e.count
|
|
196
|
-
}), /* @__PURE__ */
|
|
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
|
-
},
|
|
205
|
-
if (!e.length) return /* @__PURE__ */
|
|
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 =
|
|
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__ */
|
|
228
|
+
return /* @__PURE__ */ w("div", {
|
|
217
229
|
className: "overflow-x-auto",
|
|
218
|
-
children: /* @__PURE__ */
|
|
230
|
+
children: /* @__PURE__ */ T("div", {
|
|
219
231
|
className: "min-w-[260px]",
|
|
220
|
-
children: [/* @__PURE__ */
|
|
232
|
+
children: [/* @__PURE__ */ T("div", {
|
|
221
233
|
className: "relative h-44",
|
|
222
|
-
children: [r.map((e, t) => /* @__PURE__ */
|
|
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__ */
|
|
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:
|
|
228
|
-
}), /* @__PURE__ */
|
|
229
|
-
}, e)), /* @__PURE__ */
|
|
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__ */
|
|
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__ */
|
|
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__ */
|
|
252
|
+
}), /* @__PURE__ */ w("div", {
|
|
241
253
|
className: "mt-2 flex gap-1.5 pl-[3.25rem]",
|
|
242
|
-
children: e.map((e) => /* @__PURE__ */
|
|
254
|
+
children: e.map((e) => /* @__PURE__ */ w("span", {
|
|
243
255
|
className: "flex-1 text-center text-[10px] text-text-tertiary",
|
|
244
|
-
children:
|
|
256
|
+
children: F(e.month)
|
|
245
257
|
}, e.month))
|
|
246
258
|
})]
|
|
247
259
|
})
|
|
248
260
|
});
|
|
249
|
-
},
|
|
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
|
-
},
|
|
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
|
|
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
|
|
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 {
|
|
326
|
+
export { D as DashboardPage };
|
|
315
327
|
|
|
316
328
|
//# sourceMappingURL=DashboardPage.js.map
|