@elevasis/ui 2.30.0 → 2.32.0

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.
Files changed (130) hide show
  1. package/dist/api/index.js +2 -2
  2. package/dist/app/index.css +38 -0
  3. package/dist/app/index.d.ts +190 -9
  4. package/dist/app/index.js +7 -6
  5. package/dist/charts/index.js +4 -5
  6. package/dist/{chunk-HXZQWMKE.js → chunk-2RJMVWFJ.js} +1 -6
  7. package/dist/{chunk-4VQ2PXMI.js → chunk-3FV6HBXS.js} +4 -4
  8. package/dist/{chunk-CW3UNAF2.js → chunk-4DYOXEH6.js} +410 -5
  9. package/dist/{chunk-JKTPRYGV.js → chunk-4MFNGNHF.js} +123 -192
  10. package/dist/{chunk-HYLERWRO.js → chunk-4QK76KIF.js} +7 -7
  11. package/dist/chunk-5FJJ72HU.js +13 -0
  12. package/dist/chunk-5J4PDX26.js +112 -0
  13. package/dist/{chunk-4SY6BTVZ.js → chunk-6DWD423K.js} +12 -9
  14. package/dist/{chunk-3GV5NHSS.js → chunk-7KZINJLP.js} +78 -232
  15. package/dist/{chunk-6WXDE5LZ.js → chunk-EPTHX4VZ.js} +1 -1
  16. package/dist/{chunk-6EFVZV6X.js → chunk-GCOQ3TBG.js} +243 -254
  17. package/dist/{chunk-LRZFLK2F.js → chunk-IQHU7O5Y.js} +4 -4
  18. package/dist/{chunk-X2SUMO3P.js → chunk-IZWTVFJ2.js} +16 -3
  19. package/dist/{chunk-IKQ42WHU.js → chunk-JFL3GRD4.js} +1 -1
  20. package/dist/{chunk-4FZYEEPK.js → chunk-LLRXA7D7.js} +5 -6
  21. package/dist/chunk-MOY4VOHF.js +347 -0
  22. package/dist/{chunk-XQQEKWTL.js → chunk-N55DVMAG.js} +6 -2
  23. package/dist/{chunk-7E3FUTND.js → chunk-ND5TDV2J.js} +1 -1
  24. package/dist/{chunk-WF227UBV.js → chunk-QQHOKTJA.js} +4 -4
  25. package/dist/{chunk-A7B7HLDF.js → chunk-QTI3KC7D.js} +5884 -515
  26. package/dist/chunk-QXCDKE2O.js +486 -0
  27. package/dist/chunk-R2XR4FCV.js +48 -0
  28. package/dist/chunk-R66W5UDG.js +26 -0
  29. package/dist/{chunk-T5Z7G2J2.js → chunk-RQA2EVN3.js} +6 -16
  30. package/dist/{chunk-SKXXT3E2.js → chunk-RQTWIXJ5.js} +4 -4
  31. package/dist/chunk-T35FWDAB.js +4342 -0
  32. package/dist/{chunk-DWK2QIAK.js → chunk-TYRUKGGD.js} +1 -1
  33. package/dist/{chunk-CN2HC4D4.js → chunk-UFTM5SZZ.js} +2 -2
  34. package/dist/{chunk-JCGD4GM6.js → chunk-UROTM5OR.js} +14 -1
  35. package/dist/{chunk-6YT4IKJ7.js → chunk-VNAZTCHA.js} +15 -0
  36. package/dist/{chunk-KVJ3LFH2.js → chunk-VNFR57DF.js} +4 -24
  37. package/dist/{chunk-SBCIB5TZ.js → chunk-VRNMNB3O.js} +6 -7
  38. package/dist/chunk-WQPX44YM.js +1626 -0
  39. package/dist/{chunk-T2PAD63Y.js → chunk-XZGSCABI.js} +1 -1
  40. package/dist/chunk-YLQEVSOR.js +299 -0
  41. package/dist/{chunk-P5WYW2GI.js → chunk-ZQOKIGZP.js} +152 -306
  42. package/dist/components/index.css +38 -0
  43. package/dist/components/index.d.ts +334 -38
  44. package/dist/components/index.js +42 -42
  45. package/dist/components/navigation/index.css +38 -0
  46. package/dist/components/navigation/index.js +3 -2
  47. package/dist/execution/index.d.ts +9 -3
  48. package/dist/features/auth/index.css +38 -0
  49. package/dist/features/auth/index.d.ts +212 -14
  50. package/dist/features/auth/index.js +41 -9
  51. package/dist/features/clients/index.css +649 -0
  52. package/dist/features/clients/index.d.ts +86 -0
  53. package/dist/features/clients/index.js +720 -0
  54. package/dist/features/crm/index.css +38 -0
  55. package/dist/features/crm/index.d.ts +228 -20
  56. package/dist/features/crm/index.js +20 -17
  57. package/dist/features/dashboard/index.css +38 -0
  58. package/dist/features/dashboard/index.d.ts +78 -3
  59. package/dist/features/dashboard/index.js +16 -16
  60. package/dist/features/delivery/index.css +38 -0
  61. package/dist/features/delivery/index.d.ts +201 -18
  62. package/dist/features/delivery/index.js +20 -18
  63. package/dist/features/knowledge/index.css +38 -0
  64. package/dist/features/knowledge/index.d.ts +20 -18
  65. package/dist/features/knowledge/index.js +116 -578
  66. package/dist/features/lead-gen/index.css +38 -0
  67. package/dist/features/lead-gen/index.d.ts +59 -51
  68. package/dist/features/lead-gen/index.js +20 -18
  69. package/dist/features/monitoring/index.css +38 -0
  70. package/dist/features/monitoring/index.d.ts +20 -18
  71. package/dist/features/monitoring/index.js +19 -18
  72. package/dist/features/monitoring/requests/index.css +38 -0
  73. package/dist/features/monitoring/requests/index.d.ts +21 -19
  74. package/dist/features/monitoring/requests/index.js +17 -15
  75. package/dist/features/operations/index.css +38 -0
  76. package/dist/features/operations/index.d.ts +945 -45
  77. package/dist/features/operations/index.js +24 -26
  78. package/dist/features/seo/index.d.ts +20 -18
  79. package/dist/features/seo/index.js +1 -1
  80. package/dist/features/settings/index.css +38 -0
  81. package/dist/features/settings/index.d.ts +201 -18
  82. package/dist/features/settings/index.js +18 -16
  83. package/dist/hooks/delivery/index.css +38 -0
  84. package/dist/hooks/delivery/index.d.ts +200 -0
  85. package/dist/hooks/delivery/index.js +2 -2
  86. package/dist/hooks/index.css +38 -0
  87. package/dist/hooks/index.d.ts +825 -47
  88. package/dist/hooks/index.js +14 -13
  89. package/dist/hooks/operations/command-view/utils/transformCommandViewData.d.ts +194 -3
  90. package/dist/hooks/published.css +38 -0
  91. package/dist/hooks/published.d.ts +825 -47
  92. package/dist/hooks/published.js +14 -13
  93. package/dist/index.css +38 -0
  94. package/dist/index.d.ts +1506 -1212
  95. package/dist/index.js +15 -14
  96. package/dist/initialization/index.d.ts +181 -0
  97. package/dist/knowledge/index.d.ts +813 -1068
  98. package/dist/knowledge/index.js +7370 -2869
  99. package/dist/{chunk-CLUP5H3C.js → knowledge-search-index-5KYPO746.js} +441 -963
  100. package/dist/layout/index.d.ts +6 -0
  101. package/dist/layout/index.js +4 -5
  102. package/dist/organization/index.css +38 -0
  103. package/dist/profile/index.d.ts +181 -0
  104. package/dist/provider/index.css +38 -0
  105. package/dist/provider/index.d.ts +909 -1156
  106. package/dist/provider/index.js +11 -10
  107. package/dist/provider/published.css +38 -0
  108. package/dist/provider/published.d.ts +906 -1153
  109. package/dist/provider/published.js +7 -6
  110. package/dist/supabase/index.d.ts +349 -0
  111. package/dist/test-utils/index.d.ts +16 -9
  112. package/dist/test-utils/index.js +39 -32
  113. package/dist/test-utils/setup.js +1 -1
  114. package/dist/theme/index.js +3 -3
  115. package/dist/theme/presets/index.js +1 -1
  116. package/dist/types/index.d.ts +378 -5
  117. package/dist/utils/index.d.ts +78 -3
  118. package/dist/utils/index.js +1 -1
  119. package/dist/vite/index.js +2 -2
  120. package/dist/vite-plugin-knowledge/index.js +1 -1
  121. package/package.json +47 -37
  122. package/src/provider/README.md +5 -5
  123. package/dist/chunk-2DIYILF7.js +0 -413
  124. package/dist/chunk-3MDNBHVB.js +0 -3868
  125. package/dist/chunk-6IXOKUBC.js +0 -347
  126. package/dist/chunk-AKOD52HS.js +0 -739
  127. package/dist/chunk-ECNNI3NT.js +0 -6
  128. package/dist/chunk-JDNEWB5F.js +0 -10
  129. package/dist/chunk-NITGGYH2.js +0 -476
  130. package/dist/chunk-OAVTMITG.js +0 -13
@@ -0,0 +1,720 @@
1
+ import '../../chunk-R2XR4FCV.js';
2
+ import { PageContainer } from '../../chunk-BZZCNLT6.js';
3
+ import '../../chunk-TUMSNGTX.js';
4
+ import { FilterBar } from '../../chunk-PDHTXPSF.js';
5
+ import { CustomModal } from '../../chunk-R66W5UDG.js';
6
+ import '../../chunk-7M2VOCYN.js';
7
+ import { useClientStatus, useCreateClient, useUpdateClient, useDeleteClient, usePaginationState, useClients, useClient } from '../../chunk-GCOQ3TBG.js';
8
+ import '../../chunk-VNAZTCHA.js';
9
+ import { showApiErrorNotification } from '../../chunk-XZGSCABI.js';
10
+ import '../../chunk-BRXELOHC.js';
11
+ import '../../chunk-3ZMAGTWF.js';
12
+ import '../../chunk-5FJJ72HU.js';
13
+ import '../../chunk-RQTWIXJ5.js';
14
+ import '../../chunk-RQA2EVN3.js';
15
+ import '../../chunk-3FV6HBXS.js';
16
+ import '../../chunk-WLOQ4IBG.js';
17
+ import '../../chunk-6DWD423K.js';
18
+ import { StatCard, CardHeader, EmptyState, PageTitleCaption, CenteredErrorState } from '../../chunk-EPTHX4VZ.js';
19
+ import '../../chunk-3KMDHCAR.js';
20
+ import '../../chunk-YLQEVSOR.js';
21
+ import '../../chunk-SZHARWKU.js';
22
+ import '../../chunk-QXCDKE2O.js';
23
+ import { SubshellContentContainer } from '../../chunk-TKAYX2SP.js';
24
+ import '../../chunk-NYBEU5TE.js';
25
+ import '../../chunk-T35FWDAB.js';
26
+ import '../../chunk-ND5TDV2J.js';
27
+ import '../../chunk-2IFYDILW.js';
28
+ import '../../chunk-Q7DJKLEN.js';
29
+ import '../../chunk-JA5ECJJB.js';
30
+ import '../../chunk-HUJCU55S.js';
31
+ import '../../chunk-E565XMTQ.js';
32
+ import '../../chunk-JBWJ6WHZ.js';
33
+ import '../../chunk-DT3QYZVU.js';
34
+ import '../../chunk-RNP5R5I3.js';
35
+ import { UuidSchema, PAGE_SIZE_DEFAULT, formatTimeAgo } from '../../chunk-2RJMVWFJ.js';
36
+ import '../../chunk-KRWALB24.js';
37
+ import '../../chunk-VKIZUUPM.js';
38
+ import '../../chunk-533DUEQY.js';
39
+ import '../../chunk-DD3CCMCZ.js';
40
+ import '../../chunk-2Q2JQSQO.js';
41
+ import '../../chunk-KJ3QUBNU.js';
42
+ import '../../chunk-BRJ3QZ4E.js';
43
+ import '../../chunk-I2KLQ2HA.js';
44
+ import { Badge, SimpleGrid, Paper, Stack, Table, Title, TextInput, Select, Group, Button, Text, Alert, Center, Loader, Pagination } from '@mantine/core';
45
+ import { jsx, jsxs } from 'react/jsx-runtime';
46
+ import { IconUsers, IconCircleCheck, IconRocket, IconBriefcase, IconAlertTriangle, IconPlus, IconSearch, IconInbox, IconCash, IconUser, IconBuilding, IconArrowLeft, IconEdit, IconRefresh, IconTrash } from '@tabler/icons-react';
47
+ import { z } from 'zod';
48
+ import { useForm } from '@mantine/form';
49
+ import { zod4Resolver } from 'mantine-form-zod-resolver';
50
+ import { useEffect, useState } from 'react';
51
+ import { useDisclosure, useDebouncedValue } from '@mantine/hooks';
52
+ import { useNavigate } from '@tanstack/react-router';
53
+
54
+ // src/features/clients/_shared.ts
55
+ var CLIENT_STATUS_COLORS = {
56
+ active: "green",
57
+ onboarding: "blue",
58
+ paused: "yellow",
59
+ completed: "gray",
60
+ churned: "red"
61
+ };
62
+ function formatClientStatusLabel(status) {
63
+ return status.charAt(0).toUpperCase() + status.slice(1);
64
+ }
65
+ function ClientStatusBadge({ status }) {
66
+ return /* @__PURE__ */ jsx(Badge, { variant: "light", color: CLIENT_STATUS_COLORS[status] ?? "gray", size: "sm", children: formatClientStatusLabel(status) });
67
+ }
68
+ var ClientStatusSchema = z.enum(["active", "onboarding", "paused", "completed", "churned"]);
69
+ z.object({
70
+ clientId: UuidSchema
71
+ }).strict();
72
+ z.object({
73
+ status: ClientStatusSchema.optional(),
74
+ search: z.string().trim().min(1).max(255).optional(),
75
+ limit: z.coerce.number().int().min(1).max(100).default(50),
76
+ offset: z.coerce.number().int().min(0).default(0)
77
+ }).strict();
78
+ z.object({
79
+ id: z.string(),
80
+ name: z.string(),
81
+ status: ClientStatusSchema
82
+ });
83
+ var ClientResponseSchema = z.object({
84
+ id: z.string(),
85
+ organizationId: z.string(),
86
+ name: z.string(),
87
+ status: ClientStatusSchema,
88
+ sourceDealId: z.string().nullable(),
89
+ primaryCompanyId: z.string().nullable(),
90
+ primaryContactId: z.string().nullable(),
91
+ convertedAt: z.string().nullable(),
92
+ metadata: z.record(z.string(), z.unknown()),
93
+ createdAt: z.string(),
94
+ updatedAt: z.string()
95
+ });
96
+ var ClientDealRefSchema = z.object({
97
+ id: z.string(),
98
+ contactEmail: z.string(),
99
+ stageKey: z.string().nullable(),
100
+ stateKey: z.string().nullable(),
101
+ updatedAt: z.string()
102
+ });
103
+ var ClientProjectRefSchema = z.object({
104
+ id: z.string(),
105
+ name: z.string(),
106
+ kind: z.string(),
107
+ status: z.string(),
108
+ updatedAt: z.string()
109
+ });
110
+ var ClientCompanyRefSchema = z.object({
111
+ id: z.string(),
112
+ name: z.string(),
113
+ domain: z.string().nullable(),
114
+ status: z.string()
115
+ });
116
+ var ClientContactRefSchema = z.object({
117
+ id: z.string(),
118
+ email: z.string(),
119
+ firstName: z.string().nullable(),
120
+ lastName: z.string().nullable(),
121
+ title: z.string().nullable(),
122
+ companyId: z.string().nullable(),
123
+ status: z.string()
124
+ });
125
+ var ClientLineageSchema = z.object({
126
+ deals: z.array(ClientDealRefSchema),
127
+ projects: z.array(ClientProjectRefSchema),
128
+ companies: z.array(ClientCompanyRefSchema),
129
+ contacts: z.array(ClientContactRefSchema)
130
+ });
131
+ ClientResponseSchema.extend({
132
+ lineage: ClientLineageSchema
133
+ });
134
+ z.object({
135
+ data: z.array(ClientResponseSchema),
136
+ total: z.number().int().min(0),
137
+ limit: z.number().int().min(1),
138
+ offset: z.number().int().min(0)
139
+ });
140
+ z.object({
141
+ totalClients: z.number().int().min(0),
142
+ byStatus: z.record(ClientStatusSchema, z.number().int().min(0)),
143
+ linkedDeals: z.number().int().min(0),
144
+ linkedProjects: z.number().int().min(0),
145
+ linkedCompanies: z.number().int().min(0),
146
+ linkedContacts: z.number().int().min(0)
147
+ });
148
+ var CreateClientRequestSchema = z.object({
149
+ name: z.string().trim().min(1).max(255),
150
+ status: ClientStatusSchema.optional(),
151
+ sourceDealId: UuidSchema.nullable().optional(),
152
+ primaryCompanyId: UuidSchema.nullable().optional(),
153
+ primaryContactId: UuidSchema.nullable().optional(),
154
+ metadata: z.record(z.string(), z.unknown()).nullable().optional()
155
+ }).strict();
156
+ z.object({
157
+ name: z.string().trim().min(1).max(255).optional(),
158
+ status: ClientStatusSchema.optional(),
159
+ sourceDealId: UuidSchema.nullable().optional(),
160
+ primaryCompanyId: UuidSchema.nullable().optional(),
161
+ primaryContactId: UuidSchema.nullable().optional(),
162
+ metadata: z.record(z.string(), z.unknown()).nullable().optional()
163
+ }).strict().refine((data) => Object.keys(data).length > 0, {
164
+ message: "At least one field must be provided"
165
+ });
166
+ function ClientsMetricsStrip() {
167
+ const { data, isLoading } = useClientStatus();
168
+ return /* @__PURE__ */ jsxs(SimpleGrid, { cols: { base: 2, sm: 4 }, children: [
169
+ /* @__PURE__ */ jsx(
170
+ StatCard,
171
+ {
172
+ variant: "hero",
173
+ icon: IconUsers,
174
+ value: String(data?.totalClients ?? 0),
175
+ label: "Total Clients",
176
+ isLoading
177
+ }
178
+ ),
179
+ /* @__PURE__ */ jsx(
180
+ StatCard,
181
+ {
182
+ variant: "hero",
183
+ icon: IconCircleCheck,
184
+ value: String(data?.byStatus?.active ?? 0),
185
+ label: "Active",
186
+ isLoading
187
+ }
188
+ ),
189
+ /* @__PURE__ */ jsx(
190
+ StatCard,
191
+ {
192
+ variant: "hero",
193
+ icon: IconRocket,
194
+ value: String(data?.byStatus?.onboarding ?? 0),
195
+ label: "Onboarding",
196
+ isLoading
197
+ }
198
+ ),
199
+ /* @__PURE__ */ jsx(
200
+ StatCard,
201
+ {
202
+ variant: "hero",
203
+ icon: IconBriefcase,
204
+ value: String(data?.linkedProjects ?? 0),
205
+ label: "Linked Projects",
206
+ isLoading
207
+ }
208
+ )
209
+ ] });
210
+ }
211
+ function ClientLineageSection({
212
+ title,
213
+ icon,
214
+ rows,
215
+ columns,
216
+ emptyText,
217
+ emptyIcon,
218
+ rowKey,
219
+ onRowClick
220
+ }) {
221
+ return /* @__PURE__ */ jsx(Paper, { withBorder: true, children: /* @__PURE__ */ jsxs(Stack, { gap: "md", children: [
222
+ /* @__PURE__ */ jsx(CardHeader, { icon, title, mb: 0 }),
223
+ rows.length === 0 ? /* @__PURE__ */ jsx(EmptyState, { icon: emptyIcon, title: emptyText }) : /* @__PURE__ */ jsxs(Table, { children: [
224
+ /* @__PURE__ */ jsx(Table.Thead, { children: /* @__PURE__ */ jsx(Table.Tr, { children: columns.map((c) => /* @__PURE__ */ jsx(Table.Th, { children: c.header }, c.header)) }) }),
225
+ /* @__PURE__ */ jsx(Table.Tbody, { children: rows.map((row) => /* @__PURE__ */ jsx(
226
+ Table.Tr,
227
+ {
228
+ style: onRowClick ? { cursor: "pointer" } : void 0,
229
+ onClick: onRowClick ? () => onRowClick(row) : void 0,
230
+ children: columns.map((c) => /* @__PURE__ */ jsx(Table.Td, { children: c.render(row) }, c.header))
231
+ },
232
+ rowKey(row)
233
+ )) })
234
+ ] })
235
+ ] }) });
236
+ }
237
+ var STATUS_OPTIONS = [
238
+ { value: "active", label: "Active" },
239
+ { value: "onboarding", label: "Onboarding" },
240
+ { value: "paused", label: "Paused" },
241
+ { value: "completed", label: "Completed" },
242
+ { value: "churned", label: "Churned" }
243
+ ];
244
+ function CreateClientModal({ opened, onClose }) {
245
+ const createClient = useCreateClient();
246
+ const form = useForm({
247
+ initialValues: {
248
+ name: "",
249
+ status: void 0
250
+ },
251
+ validate: zod4Resolver(CreateClientRequestSchema)
252
+ });
253
+ const handleSubmit = async (values) => {
254
+ try {
255
+ await createClient.mutateAsync(values);
256
+ form.reset();
257
+ onClose();
258
+ } catch (error) {
259
+ showApiErrorNotification(error);
260
+ }
261
+ };
262
+ const handleClose = () => {
263
+ if (!createClient.isPending) {
264
+ form.reset();
265
+ onClose();
266
+ }
267
+ };
268
+ return /* @__PURE__ */ jsx(CustomModal, { opened, onClose: handleClose, size: "md", loading: createClient.isPending, children: /* @__PURE__ */ jsx("form", { onSubmit: form.onSubmit(handleSubmit), children: /* @__PURE__ */ jsxs(Stack, { p: "md", children: [
269
+ /* @__PURE__ */ jsx(Title, { order: 3, children: "New Client" }),
270
+ /* @__PURE__ */ jsx(
271
+ TextInput,
272
+ {
273
+ label: "Name",
274
+ placeholder: "Enter client name",
275
+ required: true,
276
+ ...form.getInputProps("name"),
277
+ disabled: createClient.isPending
278
+ }
279
+ ),
280
+ /* @__PURE__ */ jsx(
281
+ Select,
282
+ {
283
+ label: "Status",
284
+ placeholder: "Select status (optional)",
285
+ data: STATUS_OPTIONS,
286
+ clearable: true,
287
+ ...form.getInputProps("status"),
288
+ disabled: createClient.isPending
289
+ }
290
+ ),
291
+ /* @__PURE__ */ jsxs(Group, { justify: "space-between", mt: "xs", children: [
292
+ /* @__PURE__ */ jsx(Button, { variant: "light", onClick: handleClose, disabled: createClient.isPending, children: "Cancel" }),
293
+ /* @__PURE__ */ jsx(Button, { type: "submit", loading: createClient.isPending, children: "Create Client" })
294
+ ] })
295
+ ] }) }) });
296
+ }
297
+ var EditNameSchema = z.object({ name: z.string().trim().min(1).max(255) });
298
+ function EditClientNameModal({ opened, onClose, clientId, currentName }) {
299
+ const updateClient = useUpdateClient();
300
+ const form = useForm({
301
+ initialValues: { name: currentName },
302
+ validate: zod4Resolver(EditNameSchema)
303
+ });
304
+ useEffect(() => {
305
+ if (opened) {
306
+ form.setValues({ name: currentName });
307
+ }
308
+ }, [opened, currentName]);
309
+ const handleSubmit = async (values) => {
310
+ try {
311
+ await updateClient.mutateAsync({ clientId, updates: { name: values.name } });
312
+ onClose();
313
+ } catch (error) {
314
+ showApiErrorNotification(error);
315
+ }
316
+ };
317
+ const handleClose = () => {
318
+ if (!updateClient.isPending) {
319
+ form.reset();
320
+ onClose();
321
+ }
322
+ };
323
+ return /* @__PURE__ */ jsx(CustomModal, { opened, onClose: handleClose, size: "sm", loading: updateClient.isPending, children: /* @__PURE__ */ jsx("form", { onSubmit: form.onSubmit(handleSubmit), children: /* @__PURE__ */ jsxs(Stack, { p: "md", children: [
324
+ /* @__PURE__ */ jsx(Title, { order: 4, children: "Edit Client Name" }),
325
+ /* @__PURE__ */ jsx(
326
+ TextInput,
327
+ {
328
+ label: "Name",
329
+ placeholder: "Enter client name",
330
+ required: true,
331
+ ...form.getInputProps("name"),
332
+ disabled: updateClient.isPending
333
+ }
334
+ ),
335
+ /* @__PURE__ */ jsxs(Group, { justify: "space-between", mt: "xs", children: [
336
+ /* @__PURE__ */ jsx(Button, { variant: "light", onClick: handleClose, disabled: updateClient.isPending, children: "Cancel" }),
337
+ /* @__PURE__ */ jsx(Button, { type: "submit", loading: updateClient.isPending, children: "Save" })
338
+ ] })
339
+ ] }) }) });
340
+ }
341
+ var STATUS_OPTIONS2 = [
342
+ { value: "active", label: "Active" },
343
+ { value: "onboarding", label: "Onboarding" },
344
+ { value: "paused", label: "Paused" },
345
+ { value: "completed", label: "Completed" },
346
+ { value: "churned", label: "Churned" }
347
+ ];
348
+ function UpdateClientStatusModal({ opened, onClose, clientId, currentStatus }) {
349
+ const updateClient = useUpdateClient();
350
+ const form = useForm({
351
+ initialValues: { status: currentStatus }
352
+ });
353
+ useEffect(() => {
354
+ if (opened) {
355
+ form.setValues({ status: currentStatus });
356
+ }
357
+ }, [opened, currentStatus]);
358
+ const handleSubmit = async (values) => {
359
+ try {
360
+ await updateClient.mutateAsync({ clientId, updates: { status: values.status } });
361
+ onClose();
362
+ } catch (error) {
363
+ showApiErrorNotification(error);
364
+ }
365
+ };
366
+ const handleClose = () => {
367
+ if (!updateClient.isPending) {
368
+ onClose();
369
+ }
370
+ };
371
+ return /* @__PURE__ */ jsx(CustomModal, { opened, onClose: handleClose, size: "sm", loading: updateClient.isPending, children: /* @__PURE__ */ jsx("form", { onSubmit: form.onSubmit(handleSubmit), children: /* @__PURE__ */ jsxs(Stack, { p: "md", children: [
372
+ /* @__PURE__ */ jsx(Title, { order: 4, children: "Change Status" }),
373
+ /* @__PURE__ */ jsxs(Text, { size: "sm", c: "dimmed", children: [
374
+ "Current status: ",
375
+ formatClientStatusLabel(currentStatus)
376
+ ] }),
377
+ /* @__PURE__ */ jsx(
378
+ Select,
379
+ {
380
+ label: "New Status",
381
+ data: STATUS_OPTIONS2,
382
+ ...form.getInputProps("status"),
383
+ disabled: updateClient.isPending
384
+ }
385
+ ),
386
+ /* @__PURE__ */ jsxs(Group, { justify: "space-between", mt: "xs", children: [
387
+ /* @__PURE__ */ jsx(Button, { variant: "light", onClick: handleClose, disabled: updateClient.isPending, children: "Cancel" }),
388
+ /* @__PURE__ */ jsx(Button, { type: "submit", loading: updateClient.isPending, children: "Update Status" })
389
+ ] })
390
+ ] }) }) });
391
+ }
392
+ function DeleteClientConfirm({ opened, onClose, clientId, clientName, onDeleted }) {
393
+ const deleteClient = useDeleteClient();
394
+ const [inlineError, setInlineError] = useState(null);
395
+ const handleConfirm = async () => {
396
+ setInlineError(null);
397
+ try {
398
+ await deleteClient.mutateAsync(clientId);
399
+ onClose();
400
+ onDeleted?.();
401
+ } catch (error) {
402
+ const message = error instanceof Error ? error.message : "Failed to delete client";
403
+ setInlineError(message);
404
+ }
405
+ };
406
+ const handleClose = () => {
407
+ if (!deleteClient.isPending) {
408
+ setInlineError(null);
409
+ onClose();
410
+ }
411
+ };
412
+ return /* @__PURE__ */ jsx(CustomModal, { opened, onClose: handleClose, size: "sm", loading: deleteClient.isPending, children: /* @__PURE__ */ jsxs(Stack, { p: "md", children: [
413
+ /* @__PURE__ */ jsx(Title, { order: 4, children: "Delete Client" }),
414
+ /* @__PURE__ */ jsxs(Text, { size: "sm", children: [
415
+ "Are you sure you want to delete ",
416
+ /* @__PURE__ */ jsx("strong", { children: clientName }),
417
+ "? This action cannot be undone."
418
+ ] }),
419
+ inlineError && /* @__PURE__ */ jsx(Alert, { icon: /* @__PURE__ */ jsx(IconAlertTriangle, { size: 16 }), color: "red", title: "Cannot delete client", children: inlineError }),
420
+ /* @__PURE__ */ jsxs(Group, { justify: "space-between", mt: "xs", children: [
421
+ /* @__PURE__ */ jsx(Button, { variant: "light", onClick: handleClose, disabled: deleteClient.isPending, children: "Cancel" }),
422
+ /* @__PURE__ */ jsx(Button, { color: "red", onClick: handleConfirm, loading: deleteClient.isPending, children: "Delete" })
423
+ ] })
424
+ ] }) });
425
+ }
426
+ var STATUS_OPTIONS3 = [
427
+ { value: "active", label: "Active" },
428
+ { value: "onboarding", label: "Onboarding" },
429
+ { value: "paused", label: "Paused" },
430
+ { value: "completed", label: "Completed" },
431
+ { value: "churned", label: "Churned" }
432
+ ];
433
+ function ClientsListPage({ onClientClick } = {}) {
434
+ const [statusFilter, setStatusFilter] = useState(null);
435
+ const [searchQuery, setSearchQuery] = useState("");
436
+ const [createOpened, { open: openCreate, close: closeCreate }] = useDisclosure(false);
437
+ const [debouncedSearch] = useDebouncedValue(searchQuery, 300);
438
+ const pagination = usePaginationState(PAGE_SIZE_DEFAULT, [statusFilter, debouncedSearch]);
439
+ const { data, isLoading, error } = useClients({
440
+ status: statusFilter ?? void 0,
441
+ search: debouncedSearch.trim() || void 0,
442
+ limit: PAGE_SIZE_DEFAULT,
443
+ offset: pagination.offset
444
+ });
445
+ const rows = data?.data ?? [];
446
+ const total = data?.total ?? 0;
447
+ return /* @__PURE__ */ jsxs(SubshellContentContainer, { children: [
448
+ /* @__PURE__ */ jsx(PageContainer, { children: /* @__PURE__ */ jsxs(Stack, { children: [
449
+ /* @__PURE__ */ jsx(
450
+ PageTitleCaption,
451
+ {
452
+ title: "Clients",
453
+ caption: "Closed-won deals and ongoing engagements",
454
+ rightSection: /* @__PURE__ */ jsx(Button, { variant: "filled", size: "sm", leftSection: /* @__PURE__ */ jsx(IconPlus, { size: 16 }), onClick: openCreate, children: "New Client" })
455
+ }
456
+ ),
457
+ /* @__PURE__ */ jsx(ClientsMetricsStrip, {}),
458
+ /* @__PURE__ */ jsx(Paper, { withBorder: true, children: /* @__PURE__ */ jsxs(Stack, { children: [
459
+ /* @__PURE__ */ jsxs(FilterBar, { children: [
460
+ /* @__PURE__ */ jsx(
461
+ Select,
462
+ {
463
+ placeholder: "All Statuses",
464
+ data: STATUS_OPTIONS3,
465
+ value: statusFilter,
466
+ onChange: (v) => setStatusFilter(v),
467
+ clearable: true,
468
+ size: "sm",
469
+ style: { minWidth: 180 }
470
+ }
471
+ ),
472
+ /* @__PURE__ */ jsx(
473
+ TextInput,
474
+ {
475
+ placeholder: "Search clients...",
476
+ leftSection: /* @__PURE__ */ jsx(IconSearch, { size: 16 }),
477
+ value: searchQuery,
478
+ onChange: (e) => setSearchQuery(e.currentTarget.value),
479
+ size: "sm",
480
+ style: { minWidth: 250 }
481
+ }
482
+ )
483
+ ] }),
484
+ isLoading ? /* @__PURE__ */ jsx(Center, { p: "xl", children: /* @__PURE__ */ jsx(Loader, {}) }) : error ? /* @__PURE__ */ jsx(CenteredErrorState, { error, title: "Failed to load clients" }) : !rows.length ? /* @__PURE__ */ jsx(
485
+ EmptyState,
486
+ {
487
+ icon: IconUsers,
488
+ title: "No clients found",
489
+ description: "Clients are created when a deal is closed-won."
490
+ }
491
+ ) : /* @__PURE__ */ jsxs(Table, { children: [
492
+ /* @__PURE__ */ jsx(Table.Thead, { children: /* @__PURE__ */ jsxs(Table.Tr, { children: [
493
+ /* @__PURE__ */ jsx(Table.Th, { children: "Name" }),
494
+ /* @__PURE__ */ jsx(Table.Th, { children: "Status" }),
495
+ /* @__PURE__ */ jsx(Table.Th, { children: "Converted" }),
496
+ /* @__PURE__ */ jsx(Table.Th, { children: "Updated" })
497
+ ] }) }),
498
+ /* @__PURE__ */ jsx(Table.Tbody, { children: rows.map((client) => {
499
+ const rowProps = onClientClick ? {
500
+ style: { cursor: "pointer" },
501
+ onClick: () => onClientClick(client.id)
502
+ } : void 0;
503
+ return /* @__PURE__ */ jsxs(Table.Tr, { ...rowProps, children: [
504
+ /* @__PURE__ */ jsx(Table.Td, { children: /* @__PURE__ */ jsx(Text, { fw: 500, children: client.name }) }),
505
+ /* @__PURE__ */ jsx(Table.Td, { children: /* @__PURE__ */ jsx(ClientStatusBadge, { status: client.status }) }),
506
+ /* @__PURE__ */ jsx(Table.Td, { children: /* @__PURE__ */ jsx(Text, { size: "sm", c: "dimmed", children: formatTimeAgo(client.convertedAt) }) }),
507
+ /* @__PURE__ */ jsx(Table.Td, { children: /* @__PURE__ */ jsx(Text, { size: "sm", c: "dimmed", children: formatTimeAgo(client.updatedAt) }) })
508
+ ] }, client.id);
509
+ }) })
510
+ ] }),
511
+ total > PAGE_SIZE_DEFAULT && /* @__PURE__ */ jsx(Group, { justify: "center", children: /* @__PURE__ */ jsx(
512
+ Pagination,
513
+ {
514
+ value: pagination.page,
515
+ onChange: pagination.setPage,
516
+ total: pagination.totalPages(total),
517
+ size: "sm"
518
+ }
519
+ ) })
520
+ ] }) })
521
+ ] }) }),
522
+ /* @__PURE__ */ jsx(CreateClientModal, { opened: createOpened, onClose: closeCreate })
523
+ ] });
524
+ }
525
+ function DetailRow({ label, value }) {
526
+ return /* @__PURE__ */ jsxs(Group, { gap: "xs", align: "flex-start", wrap: "nowrap", children: [
527
+ /* @__PURE__ */ jsx(Text, { size: "sm", fw: 500, style: { width: 140, flexShrink: 0 }, children: label }),
528
+ /* @__PURE__ */ jsx(Text, { size: "sm", style: { minWidth: 0, wordBreak: "break-word", color: "var(--color-text-subtle)" }, children: value ?? "N/A" })
529
+ ] });
530
+ }
531
+ function ClientDetailPage({ clientId }) {
532
+ const navigate = useNavigate();
533
+ const { data: client, isLoading, error } = useClient(clientId);
534
+ const [editNameOpened, { open: openEditName, close: closeEditName }] = useDisclosure(false);
535
+ const [updateStatusOpened, { open: openUpdateStatus, close: closeUpdateStatus }] = useDisclosure(false);
536
+ const [deleteOpened, { open: openDelete, close: closeDelete }] = useDisclosure(false);
537
+ const backButton = /* @__PURE__ */ jsx(
538
+ Button,
539
+ {
540
+ variant: "light",
541
+ size: "sm",
542
+ leftSection: /* @__PURE__ */ jsx(IconArrowLeft, { size: 16 }),
543
+ onClick: () => navigate({ to: "/clients" }),
544
+ children: "Clients"
545
+ }
546
+ );
547
+ const headerActions = /* @__PURE__ */ jsxs(Group, { gap: "xs", children: [
548
+ /* @__PURE__ */ jsx(Button, { variant: "light", size: "sm", leftSection: /* @__PURE__ */ jsx(IconEdit, { size: 16 }), onClick: openEditName, children: "Edit name" }),
549
+ /* @__PURE__ */ jsx(Button, { variant: "light", size: "sm", leftSection: /* @__PURE__ */ jsx(IconRefresh, { size: 16 }), onClick: openUpdateStatus, children: "Change status" }),
550
+ /* @__PURE__ */ jsx(Button, { variant: "light", size: "sm", color: "red", leftSection: /* @__PURE__ */ jsx(IconTrash, { size: 16 }), onClick: openDelete, children: "Delete" }),
551
+ backButton
552
+ ] });
553
+ if (isLoading) {
554
+ return /* @__PURE__ */ jsx(SubshellContentContainer, { children: /* @__PURE__ */ jsx(PageContainer, { children: /* @__PURE__ */ jsxs(Stack, { gap: "md", children: [
555
+ /* @__PURE__ */ jsx(PageTitleCaption, { title: "Client Detail", caption: "Loading client details...", rightSection: backButton }),
556
+ /* @__PURE__ */ jsx(Paper, { withBorder: true, children: /* @__PURE__ */ jsx(Center, { p: "xl", children: /* @__PURE__ */ jsx(Loader, {}) }) })
557
+ ] }) }) });
558
+ }
559
+ if (error) {
560
+ return /* @__PURE__ */ jsx(SubshellContentContainer, { children: /* @__PURE__ */ jsx(PageContainer, { children: /* @__PURE__ */ jsxs(Stack, { gap: "md", children: [
561
+ /* @__PURE__ */ jsx(PageTitleCaption, { title: "Client Detail", caption: "Unable to load client details", rightSection: backButton }),
562
+ /* @__PURE__ */ jsx(Paper, { withBorder: true, children: /* @__PURE__ */ jsx(CenteredErrorState, { error, title: "Failed to load client" }) })
563
+ ] }) }) });
564
+ }
565
+ if (!client) {
566
+ return /* @__PURE__ */ jsx(SubshellContentContainer, { children: /* @__PURE__ */ jsx(PageContainer, { children: /* @__PURE__ */ jsxs(Stack, { gap: "md", children: [
567
+ /* @__PURE__ */ jsx(PageTitleCaption, { title: "Client Detail", caption: "Client not found", rightSection: backButton }),
568
+ /* @__PURE__ */ jsx(Paper, { withBorder: true, children: /* @__PURE__ */ jsx(
569
+ EmptyState,
570
+ {
571
+ icon: IconInbox,
572
+ title: "Client not found",
573
+ description: "The selected client no longer exists."
574
+ }
575
+ ) })
576
+ ] }) }) });
577
+ }
578
+ const caption = client.convertedAt ? `Converted ${formatTimeAgo(client.convertedAt)}` : "Not yet converted";
579
+ return /* @__PURE__ */ jsxs(SubshellContentContainer, { children: [
580
+ /* @__PURE__ */ jsx(PageContainer, { children: /* @__PURE__ */ jsxs(Stack, { gap: "md", children: [
581
+ /* @__PURE__ */ jsx(PageTitleCaption, { title: client.name, caption, rightSection: headerActions }),
582
+ /* @__PURE__ */ jsx(Paper, { withBorder: true, children: /* @__PURE__ */ jsxs(Stack, { gap: "md", children: [
583
+ /* @__PURE__ */ jsx(CardHeader, { icon: /* @__PURE__ */ jsx(IconUsers, { size: 18 }), title: "Client", mb: 0 }),
584
+ /* @__PURE__ */ jsxs(SimpleGrid, { cols: { base: 1, sm: 2 }, spacing: "sm", children: [
585
+ /* @__PURE__ */ jsx(DetailRow, { label: "Status", value: /* @__PURE__ */ jsx(ClientStatusBadge, { status: client.status }) }),
586
+ /* @__PURE__ */ jsx(
587
+ DetailRow,
588
+ {
589
+ label: "Converted",
590
+ value: client.convertedAt ? new Date(client.convertedAt).toLocaleDateString() : "N/A"
591
+ }
592
+ ),
593
+ /* @__PURE__ */ jsx(
594
+ DetailRow,
595
+ {
596
+ label: "Source Deal",
597
+ value: client.sourceDealId ? /* @__PURE__ */ jsx(
598
+ Text,
599
+ {
600
+ size: "sm",
601
+ style: { cursor: "pointer", color: "var(--color-primary)" },
602
+ onClick: () => navigate({ to: "/crm/deals/$dealId", params: { dealId: client.sourceDealId } }),
603
+ children: client.sourceDealId
604
+ }
605
+ ) : "N/A"
606
+ }
607
+ ),
608
+ /* @__PURE__ */ jsx(DetailRow, { label: "Primary Company", value: client.primaryCompanyId ?? "N/A" }),
609
+ /* @__PURE__ */ jsx(DetailRow, { label: "Primary Contact", value: client.primaryContactId ?? "N/A" }),
610
+ /* @__PURE__ */ jsx(DetailRow, { label: "Created", value: new Date(client.createdAt).toLocaleDateString() }),
611
+ /* @__PURE__ */ jsx(DetailRow, { label: "Updated", value: formatTimeAgo(client.updatedAt) })
612
+ ] })
613
+ ] }) }),
614
+ /* @__PURE__ */ jsx(
615
+ ClientLineageSection,
616
+ {
617
+ title: "Projects",
618
+ icon: /* @__PURE__ */ jsx(IconBriefcase, { size: 18 }),
619
+ rows: client.lineage.projects,
620
+ emptyText: "No projects yet",
621
+ emptyIcon: IconBriefcase,
622
+ rowKey: (row) => row.id,
623
+ onRowClick: (row) => navigate({ to: "/projects/$projectId", params: { projectId: row.id } }),
624
+ columns: [
625
+ { header: "Name", render: (row) => row.name },
626
+ { header: "Kind", render: (row) => row.kind },
627
+ { header: "Status", render: (row) => row.status },
628
+ { header: "Updated", render: (row) => formatTimeAgo(row.updatedAt) }
629
+ ]
630
+ }
631
+ ),
632
+ /* @__PURE__ */ jsx(
633
+ ClientLineageSection,
634
+ {
635
+ title: "Deals",
636
+ icon: /* @__PURE__ */ jsx(IconCash, { size: 18 }),
637
+ rows: client.lineage.deals,
638
+ emptyText: "No linked deals",
639
+ emptyIcon: IconCash,
640
+ rowKey: (row) => row.id,
641
+ onRowClick: (row) => navigate({ to: "/crm/deals/$dealId", params: { dealId: row.id } }),
642
+ columns: [
643
+ { header: "Contact Email", render: (row) => row.contactEmail },
644
+ { header: "Stage", render: (row) => row.stageKey ?? "\u2014" },
645
+ { header: "State", render: (row) => row.stateKey ?? "\u2014" },
646
+ { header: "Updated", render: (row) => formatTimeAgo(row.updatedAt) }
647
+ ]
648
+ }
649
+ ),
650
+ /* @__PURE__ */ jsx(
651
+ ClientLineageSection,
652
+ {
653
+ title: "Contacts",
654
+ icon: /* @__PURE__ */ jsx(IconUser, { size: 18 }),
655
+ rows: client.lineage.contacts,
656
+ emptyText: "No contacts",
657
+ emptyIcon: IconUser,
658
+ rowKey: (row) => row.id,
659
+ onRowClick: (row) => navigate({ to: "/crm/contacts/$contactId", params: { contactId: row.id } }),
660
+ columns: [
661
+ {
662
+ header: "Name",
663
+ render: (row) => [row.firstName, row.lastName].filter(Boolean).join(" ") || "\u2014"
664
+ },
665
+ { header: "Email", render: (row) => row.email },
666
+ { header: "Title", render: (row) => row.title ?? "\u2014" },
667
+ { header: "Status", render: (row) => row.status }
668
+ ]
669
+ }
670
+ ),
671
+ /* @__PURE__ */ jsx(
672
+ ClientLineageSection,
673
+ {
674
+ title: "Companies",
675
+ icon: /* @__PURE__ */ jsx(IconBuilding, { size: 18 }),
676
+ rows: client.lineage.companies,
677
+ emptyText: "No companies",
678
+ emptyIcon: IconBuilding,
679
+ rowKey: (row) => row.id,
680
+ onRowClick: (row) => navigate({ to: "/crm/companies/$companyId", params: { companyId: row.id } }),
681
+ columns: [
682
+ { header: "Name", render: (row) => row.name },
683
+ { header: "Domain", render: (row) => row.domain ?? "\u2014" },
684
+ { header: "Status", render: (row) => row.status }
685
+ ]
686
+ }
687
+ )
688
+ ] }) }),
689
+ /* @__PURE__ */ jsx(
690
+ EditClientNameModal,
691
+ {
692
+ opened: editNameOpened,
693
+ onClose: closeEditName,
694
+ clientId,
695
+ currentName: client.name
696
+ }
697
+ ),
698
+ /* @__PURE__ */ jsx(
699
+ UpdateClientStatusModal,
700
+ {
701
+ opened: updateStatusOpened,
702
+ onClose: closeUpdateStatus,
703
+ clientId,
704
+ currentStatus: client.status
705
+ }
706
+ ),
707
+ /* @__PURE__ */ jsx(
708
+ DeleteClientConfirm,
709
+ {
710
+ opened: deleteOpened,
711
+ onClose: closeDelete,
712
+ clientId,
713
+ clientName: client.name,
714
+ onDeleted: () => navigate({ to: "/clients" })
715
+ }
716
+ )
717
+ ] });
718
+ }
719
+
720
+ export { CLIENT_STATUS_COLORS, ClientDetailPage, ClientLineageSection, ClientStatusBadge, ClientsListPage, ClientsMetricsStrip, CreateClientModal, DeleteClientConfirm, EditClientNameModal, UpdateClientStatusModal, formatClientStatusLabel };