@contractspec/example.crm-pipeline 3.7.6 → 3.7.10

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/.turbo/turbo-build.log +45 -42
  2. package/AGENTS.md +51 -33
  3. package/CHANGELOG.md +36 -0
  4. package/README.md +67 -148
  5. package/dist/browser/docs/crm-pipeline.docblock.js +1 -1
  6. package/dist/browser/docs/index.js +1 -1
  7. package/dist/browser/events/contact.event.js +1 -1
  8. package/dist/browser/events/deal.event.js +1 -1
  9. package/dist/browser/events/index.js +3 -3
  10. package/dist/browser/events/task.event.js +1 -1
  11. package/dist/browser/handlers/crm.handlers.js +13 -2
  12. package/dist/browser/handlers/index.js +13 -2
  13. package/dist/browser/index.js +680 -447
  14. package/dist/browser/ui/CrmDashboard.js +574 -352
  15. package/dist/browser/ui/CrmDealCard.js +5 -5
  16. package/dist/browser/ui/CrmPipelineBoard.js +13 -13
  17. package/dist/browser/ui/hooks/index.js +21 -10
  18. package/dist/browser/ui/hooks/useDealList.js +20 -9
  19. package/dist/browser/ui/hooks/useDealMutations.js +1 -1
  20. package/dist/browser/ui/index.js +683 -450
  21. package/dist/browser/ui/modals/CreateDealModal.js +12 -12
  22. package/dist/browser/ui/modals/DealActionsModal.js +21 -21
  23. package/dist/browser/ui/modals/index.js +33 -33
  24. package/dist/browser/ui/renderers/index.js +140 -118
  25. package/dist/browser/ui/renderers/pipeline.markdown.js +13 -2
  26. package/dist/browser/ui/renderers/pipeline.renderer.js +108 -97
  27. package/dist/browser/ui/tables/DealListTab.js +390 -0
  28. package/dist/deal/index.d.ts +2 -2
  29. package/dist/docs/crm-pipeline.docblock.js +1 -1
  30. package/dist/docs/index.js +1 -1
  31. package/dist/events/contact.event.js +1 -1
  32. package/dist/events/deal.event.js +1 -1
  33. package/dist/events/index.js +3 -3
  34. package/dist/events/task.event.js +1 -1
  35. package/dist/handlers/crm.handlers.d.ts +2 -0
  36. package/dist/handlers/crm.handlers.js +13 -2
  37. package/dist/handlers/index.d.ts +2 -2
  38. package/dist/handlers/index.js +13 -2
  39. package/dist/index.d.ts +3 -3
  40. package/dist/index.js +680 -447
  41. package/dist/node/docs/crm-pipeline.docblock.js +1 -1
  42. package/dist/node/docs/index.js +1 -1
  43. package/dist/node/events/contact.event.js +1 -1
  44. package/dist/node/events/deal.event.js +1 -1
  45. package/dist/node/events/index.js +3 -3
  46. package/dist/node/events/task.event.js +1 -1
  47. package/dist/node/handlers/crm.handlers.js +13 -2
  48. package/dist/node/handlers/index.js +13 -2
  49. package/dist/node/index.js +680 -447
  50. package/dist/node/ui/CrmDashboard.js +574 -352
  51. package/dist/node/ui/CrmDealCard.js +5 -5
  52. package/dist/node/ui/CrmPipelineBoard.js +13 -13
  53. package/dist/node/ui/hooks/index.js +21 -10
  54. package/dist/node/ui/hooks/useDealList.js +20 -9
  55. package/dist/node/ui/hooks/useDealMutations.js +1 -1
  56. package/dist/node/ui/index.js +683 -450
  57. package/dist/node/ui/modals/CreateDealModal.js +12 -12
  58. package/dist/node/ui/modals/DealActionsModal.js +21 -21
  59. package/dist/node/ui/modals/index.js +33 -33
  60. package/dist/node/ui/renderers/index.js +140 -118
  61. package/dist/node/ui/renderers/pipeline.markdown.js +13 -2
  62. package/dist/node/ui/renderers/pipeline.renderer.js +108 -97
  63. package/dist/node/ui/tables/DealListTab.js +390 -0
  64. package/dist/operations/index.d.ts +1 -1
  65. package/dist/ui/CrmDashboard.js +574 -352
  66. package/dist/ui/CrmDealCard.js +5 -5
  67. package/dist/ui/CrmPipelineBoard.js +13 -13
  68. package/dist/ui/hooks/index.d.ts +2 -2
  69. package/dist/ui/hooks/index.js +21 -10
  70. package/dist/ui/hooks/useDealList.d.ts +8 -2
  71. package/dist/ui/hooks/useDealList.js +20 -9
  72. package/dist/ui/hooks/useDealMutations.d.ts +9 -0
  73. package/dist/ui/hooks/useDealMutations.js +1 -1
  74. package/dist/ui/index.d.ts +3 -3
  75. package/dist/ui/index.js +683 -450
  76. package/dist/ui/modals/CreateDealModal.js +12 -12
  77. package/dist/ui/modals/DealActionsModal.js +21 -21
  78. package/dist/ui/modals/index.js +33 -33
  79. package/dist/ui/renderers/index.d.ts +1 -1
  80. package/dist/ui/renderers/index.js +140 -118
  81. package/dist/ui/renderers/pipeline.markdown.js +13 -2
  82. package/dist/ui/renderers/pipeline.renderer.d.ts +1 -1
  83. package/dist/ui/renderers/pipeline.renderer.js +108 -97
  84. package/dist/ui/tables/DealListTab.d.ts +20 -0
  85. package/dist/ui/tables/DealListTab.js +391 -0
  86. package/dist/ui/tables/DealListTab.smoke.test.d.ts +1 -0
  87. package/package.json +29 -14
  88. package/src/crm-pipeline.feature.ts +86 -86
  89. package/src/deal/deal.enum.ts +8 -8
  90. package/src/deal/deal.operation.ts +255 -255
  91. package/src/deal/deal.schema.ts +92 -92
  92. package/src/deal/deal.test-spec.ts +48 -48
  93. package/src/deal/index.ts +17 -19
  94. package/src/docs/crm-pipeline.docblock.ts +44 -44
  95. package/src/entities/company.entity.ts +52 -52
  96. package/src/entities/contact.entity.ts +67 -67
  97. package/src/entities/deal.entity.ts +134 -134
  98. package/src/entities/index.ts +27 -27
  99. package/src/entities/task.entity.ts +105 -105
  100. package/src/events/contact.event.ts +22 -22
  101. package/src/events/deal.event.ts +77 -77
  102. package/src/events/task.event.ts +19 -19
  103. package/src/example.ts +32 -32
  104. package/src/handlers/crm.handlers.ts +375 -357
  105. package/src/handlers/deal.handlers.ts +179 -179
  106. package/src/handlers/index.ts +18 -19
  107. package/src/handlers/mock-data.ts +167 -167
  108. package/src/index.ts +11 -11
  109. package/src/operations/index.ts +16 -16
  110. package/src/presentations/dashboard.presentation.ts +45 -45
  111. package/src/presentations/pipeline.presentation.ts +90 -90
  112. package/src/seeders/index.ts +26 -26
  113. package/src/shared/overlay-types.ts +23 -23
  114. package/src/ui/CrmDashboard.tsx +210 -279
  115. package/src/ui/CrmDealCard.tsx +64 -64
  116. package/src/ui/CrmPipelineBoard.tsx +105 -105
  117. package/src/ui/hooks/index.ts +3 -3
  118. package/src/ui/hooks/useDealList.ts +113 -85
  119. package/src/ui/hooks/useDealMutations.ts +151 -150
  120. package/src/ui/index.ts +5 -10
  121. package/src/ui/modals/CreateDealModal.tsx +217 -217
  122. package/src/ui/modals/DealActionsModal.tsx +390 -390
  123. package/src/ui/overlays/demo-overlays.ts +43 -43
  124. package/src/ui/renderers/index.ts +4 -3
  125. package/src/ui/renderers/pipeline.markdown.ts +165 -165
  126. package/src/ui/renderers/pipeline.renderer.tsx +17 -16
  127. package/src/ui/tables/DealListTab.smoke.test.tsx +149 -0
  128. package/src/ui/tables/DealListTab.tsx +276 -0
  129. package/tsconfig.json +7 -8
  130. package/tsdown.config.js +7 -3
@@ -1,17 +1,180 @@
1
+ // src/ui/CrmDealCard.tsx
2
+ import { jsxDEV } from "react/jsx-dev-runtime";
3
+ "use client";
4
+ function formatCurrency(value, currency) {
5
+ return new Intl.NumberFormat("en-US", {
6
+ style: "currency",
7
+ currency,
8
+ minimumFractionDigits: 0,
9
+ maximumFractionDigits: 0
10
+ }).format(value);
11
+ }
12
+ function CrmDealCard({ deal, onClick }) {
13
+ const daysUntilClose = deal.expectedCloseDate ? Math.ceil((deal.expectedCloseDate.getTime() - Date.now()) / (1000 * 60 * 60 * 24)) : null;
14
+ return /* @__PURE__ */ jsxDEV("div", {
15
+ onClick,
16
+ className: "cursor-pointer rounded-lg border border-border bg-card p-3 shadow-sm transition-shadow hover:shadow-md",
17
+ role: "button",
18
+ tabIndex: 0,
19
+ onKeyDown: (e) => {
20
+ if (e.key === "Enter" || e.key === " ")
21
+ onClick?.();
22
+ },
23
+ children: [
24
+ /* @__PURE__ */ jsxDEV("h4", {
25
+ className: "font-medium leading-snug",
26
+ children: deal.name
27
+ }, undefined, false, undefined, this),
28
+ /* @__PURE__ */ jsxDEV("div", {
29
+ className: "mt-2 font-semibold text-lg text-primary",
30
+ children: formatCurrency(deal.value, deal.currency)
31
+ }, undefined, false, undefined, this),
32
+ /* @__PURE__ */ jsxDEV("div", {
33
+ className: "mt-3 flex items-center justify-between text-muted-foreground text-xs",
34
+ children: [
35
+ daysUntilClose !== null && /* @__PURE__ */ jsxDEV("span", {
36
+ className: daysUntilClose < 0 ? "text-red-500" : daysUntilClose <= 7 ? "text-yellow-600 dark:text-yellow-500" : "",
37
+ children: daysUntilClose < 0 ? `${Math.abs(daysUntilClose)}d overdue` : daysUntilClose === 0 ? "Due today" : `${daysUntilClose}d left`
38
+ }, undefined, false, undefined, this),
39
+ /* @__PURE__ */ jsxDEV("span", {
40
+ className: `rounded px-1.5 py-0.5 font-medium text-xs ${deal.status === "WON" ? "bg-green-100 text-green-700 dark:bg-green-900/30 dark:text-green-400" : deal.status === "LOST" ? "bg-red-100 text-red-700 dark:bg-red-900/30 dark:text-red-400" : "bg-blue-100 text-blue-700 dark:bg-blue-900/30 dark:text-blue-400"}`,
41
+ children: deal.status
42
+ }, undefined, false, undefined, this)
43
+ ]
44
+ }, undefined, true, undefined, this)
45
+ ]
46
+ }, undefined, true, undefined, this);
47
+ }
48
+
49
+ // src/ui/CrmPipelineBoard.tsx
50
+ import { useState } from "react";
51
+ import { jsxDEV as jsxDEV2 } from "react/jsx-dev-runtime";
52
+ "use client";
53
+ function formatCurrency2(value) {
54
+ if (value >= 1e6)
55
+ return `$${(value / 1e6).toFixed(1)}M`;
56
+ if (value >= 1000)
57
+ return `$${(value / 1000).toFixed(0)}K`;
58
+ return `$${value}`;
59
+ }
60
+ function CrmPipelineBoard({
61
+ dealsByStage,
62
+ stages,
63
+ onDealClick,
64
+ onDealMove
65
+ }) {
66
+ const [quickMoveOpen, setQuickMoveOpen] = useState(null);
67
+ const sortedStages = [...stages].sort((a, b) => a.position - b.position);
68
+ const handleQuickMove = (dealId, toStageId) => {
69
+ onDealMove?.(dealId, toStageId);
70
+ setQuickMoveOpen(null);
71
+ };
72
+ return /* @__PURE__ */ jsxDEV2("div", {
73
+ className: "flex gap-4 overflow-x-auto pb-4",
74
+ children: sortedStages.map((stage) => {
75
+ const deals = dealsByStage[stage.id] ?? [];
76
+ const stageValue = deals.reduce((sum, d) => sum + d.value, 0);
77
+ return /* @__PURE__ */ jsxDEV2("div", {
78
+ className: "flex w-72 flex-shrink-0 flex-col rounded-lg bg-muted/30",
79
+ children: [
80
+ /* @__PURE__ */ jsxDEV2("div", {
81
+ className: "flex items-center justify-between border-border border-b px-3 py-2",
82
+ children: [
83
+ /* @__PURE__ */ jsxDEV2("div", {
84
+ children: [
85
+ /* @__PURE__ */ jsxDEV2("h3", {
86
+ className: "font-medium",
87
+ children: stage.name
88
+ }, undefined, false, undefined, this),
89
+ /* @__PURE__ */ jsxDEV2("p", {
90
+ className: "text-muted-foreground text-xs",
91
+ children: [
92
+ deals.length,
93
+ " deals · ",
94
+ formatCurrency2(stageValue)
95
+ ]
96
+ }, undefined, true, undefined, this)
97
+ ]
98
+ }, undefined, true, undefined, this),
99
+ /* @__PURE__ */ jsxDEV2("span", {
100
+ className: "flex h-6 w-6 items-center justify-center rounded-full bg-muted font-medium text-xs",
101
+ children: deals.length
102
+ }, undefined, false, undefined, this)
103
+ ]
104
+ }, undefined, true, undefined, this),
105
+ /* @__PURE__ */ jsxDEV2("div", {
106
+ className: "flex flex-1 flex-col gap-2 p-2",
107
+ children: deals.length === 0 ? /* @__PURE__ */ jsxDEV2("div", {
108
+ className: "flex h-24 items-center justify-center rounded-md border-2 border-muted-foreground/20 border-dashed text-muted-foreground text-xs",
109
+ children: "No deals"
110
+ }, undefined, false, undefined, this) : deals.map((deal) => /* @__PURE__ */ jsxDEV2("div", {
111
+ className: "group relative",
112
+ children: [
113
+ /* @__PURE__ */ jsxDEV2(CrmDealCard, {
114
+ deal,
115
+ onClick: () => onDealClick?.(deal.id)
116
+ }, undefined, false, undefined, this),
117
+ deal.status === "OPEN" && onDealMove && /* @__PURE__ */ jsxDEV2("div", {
118
+ className: "absolute top-1 right-1 opacity-0 transition-opacity group-hover:opacity-100",
119
+ children: [
120
+ /* @__PURE__ */ jsxDEV2("button", {
121
+ type: "button",
122
+ onClick: (e) => {
123
+ e.stopPropagation();
124
+ setQuickMoveOpen(quickMoveOpen === deal.id ? null : deal.id);
125
+ },
126
+ className: "flex h-6 w-6 items-center justify-center rounded border border-border bg-background text-xs shadow-sm hover:bg-muted",
127
+ title: "Quick move",
128
+ children: "➡️"
129
+ }, undefined, false, undefined, this),
130
+ quickMoveOpen === deal.id && /* @__PURE__ */ jsxDEV2("div", {
131
+ className: "absolute top-7 right-0 z-20 min-w-[140px] rounded-lg border border-border bg-card py-1 shadow-lg",
132
+ children: [
133
+ /* @__PURE__ */ jsxDEV2("p", {
134
+ className: "px-3 py-1 font-medium text-muted-foreground text-xs",
135
+ children: "Move to:"
136
+ }, undefined, false, undefined, this),
137
+ sortedStages.filter((s) => s.id !== deal.stageId).map((s) => /* @__PURE__ */ jsxDEV2("button", {
138
+ type: "button",
139
+ onClick: (e) => {
140
+ e.stopPropagation();
141
+ handleQuickMove(deal.id, s.id);
142
+ },
143
+ className: "w-full px-3 py-1.5 text-left text-sm hover:bg-muted",
144
+ children: s.name
145
+ }, s.id, false, undefined, this))
146
+ ]
147
+ }, undefined, true, undefined, this)
148
+ ]
149
+ }, undefined, true, undefined, this)
150
+ ]
151
+ }, deal.id, true, undefined, this))
152
+ }, undefined, false, undefined, this)
153
+ ]
154
+ }, stage.id, true, undefined, this);
155
+ })
156
+ }, undefined, false, undefined, this);
157
+ }
158
+
1
159
  // src/ui/hooks/useDealList.ts
2
- import { useCallback, useEffect, useMemo, useState } from "react";
3
160
  import { useTemplateRuntime } from "@contractspec/lib.example-shared-ui";
161
+ import { useCallback, useEffect, useMemo, useState as useState2 } from "react";
4
162
  "use client";
5
163
  function useDealList(options = {}) {
6
164
  const { handlers, projectId } = useTemplateRuntime();
7
165
  const { crm } = handlers;
8
- const [data, setData] = useState(null);
9
- const [dealsByStage, setDealsByStage] = useState({});
10
- const [stages, setStages] = useState([]);
11
- const [loading, setLoading] = useState(true);
12
- const [error, setError] = useState(null);
13
- const [page, setPage] = useState(1);
166
+ const [data, setData] = useState2(null);
167
+ const [dealsByStage, setDealsByStage] = useState2({});
168
+ const [stages, setStages] = useState2([]);
169
+ const [loading, setLoading] = useState2(true);
170
+ const [error, setError] = useState2(null);
171
+ const [internalPage, setInternalPage] = useState2(0);
14
172
  const pipelineId = options.pipelineId ?? "pipeline-1";
173
+ const pageIndex = options.pageIndex ?? internalPage;
174
+ const pageSize = options.pageSize ?? options.limit ?? 50;
175
+ const [sort] = options.sorting ?? [];
176
+ const sortBy = sort?.id;
177
+ const sortDirection = sort ? sort.desc ? "desc" : "asc" : undefined;
15
178
  const fetchData = useCallback(async () => {
16
179
  setLoading(true);
17
180
  setError(null);
@@ -23,8 +186,10 @@ function useDealList(options = {}) {
23
186
  stageId: options.stageId,
24
187
  status: options.status === "all" ? undefined : options.status,
25
188
  search: options.search,
26
- limit: options.limit ?? 50,
27
- offset: (page - 1) * (options.limit ?? 50)
189
+ limit: pageSize,
190
+ offset: pageIndex * pageSize,
191
+ sortBy: sortBy === "name" || sortBy === "value" || sortBy === "status" || sortBy === "expectedCloseDate" || sortBy === "updatedAt" ? sortBy : undefined,
192
+ sortDirection
28
193
  }),
29
194
  crm.getDealsByStage({ projectId, pipelineId }),
30
195
  crm.getPipelineStages({ pipelineId })
@@ -44,8 +209,10 @@ function useDealList(options = {}) {
44
209
  options.stageId,
45
210
  options.status,
46
211
  options.search,
47
- options.limit,
48
- page
212
+ pageIndex,
213
+ pageSize,
214
+ sortBy,
215
+ sortDirection
49
216
  ]);
50
217
  useEffect(() => {
51
218
  fetchData();
@@ -73,35 +240,37 @@ function useDealList(options = {}) {
73
240
  loading,
74
241
  error,
75
242
  stats,
76
- page,
243
+ page: pageIndex + 1,
244
+ pageIndex,
245
+ pageSize,
77
246
  refetch: fetchData,
78
- nextPage: () => setPage((p) => p + 1),
79
- prevPage: () => page > 1 && setPage((p) => p - 1)
247
+ nextPage: options.pageIndex === undefined ? () => setInternalPage((page) => page + 1) : undefined,
248
+ prevPage: options.pageIndex === undefined ? () => pageIndex > 0 && setInternalPage((page) => page - 1) : undefined
80
249
  };
81
250
  }
82
251
 
83
252
  // src/ui/hooks/useDealMutations.ts
84
- import { useCallback as useCallback2, useState as useState2 } from "react";
85
253
  import { useTemplateRuntime as useTemplateRuntime2 } from "@contractspec/lib.example-shared-ui";
254
+ import { useCallback as useCallback2, useState as useState3 } from "react";
86
255
  function useDealMutations(options = {}) {
87
256
  const { handlers, projectId } = useTemplateRuntime2();
88
257
  const { crm } = handlers;
89
- const [createState, setCreateState] = useState2({
258
+ const [createState, setCreateState] = useState3({
90
259
  loading: false,
91
260
  error: null,
92
261
  data: null
93
262
  });
94
- const [moveState, setMoveState] = useState2({
263
+ const [moveState, setMoveState] = useState3({
95
264
  loading: false,
96
265
  error: null,
97
266
  data: null
98
267
  });
99
- const [winState, setWinState] = useState2({
268
+ const [winState, setWinState] = useState3({
100
269
  loading: false,
101
270
  error: null,
102
271
  data: null
103
272
  });
104
- const [loseState, setLoseState] = useState2({
273
+ const [loseState, setLoseState] = useState3({
105
274
  loading: false,
106
275
  error: null,
107
276
  data: null
@@ -178,167 +347,9 @@ function useDealMutations(options = {}) {
178
347
  };
179
348
  }
180
349
 
181
- // src/ui/CrmDealCard.tsx
182
- import { jsxDEV } from "react/jsx-dev-runtime";
183
- "use client";
184
- function formatCurrency(value, currency) {
185
- return new Intl.NumberFormat("en-US", {
186
- style: "currency",
187
- currency,
188
- minimumFractionDigits: 0,
189
- maximumFractionDigits: 0
190
- }).format(value);
191
- }
192
- function CrmDealCard({ deal, onClick }) {
193
- const daysUntilClose = deal.expectedCloseDate ? Math.ceil((deal.expectedCloseDate.getTime() - Date.now()) / (1000 * 60 * 60 * 24)) : null;
194
- return /* @__PURE__ */ jsxDEV("div", {
195
- onClick,
196
- className: "border-border bg-card cursor-pointer rounded-lg border p-3 shadow-sm transition-shadow hover:shadow-md",
197
- role: "button",
198
- tabIndex: 0,
199
- onKeyDown: (e) => {
200
- if (e.key === "Enter" || e.key === " ")
201
- onClick?.();
202
- },
203
- children: [
204
- /* @__PURE__ */ jsxDEV("h4", {
205
- className: "leading-snug font-medium",
206
- children: deal.name
207
- }, undefined, false, undefined, this),
208
- /* @__PURE__ */ jsxDEV("div", {
209
- className: "text-primary mt-2 text-lg font-semibold",
210
- children: formatCurrency(deal.value, deal.currency)
211
- }, undefined, false, undefined, this),
212
- /* @__PURE__ */ jsxDEV("div", {
213
- className: "text-muted-foreground mt-3 flex items-center justify-between text-xs",
214
- children: [
215
- daysUntilClose !== null && /* @__PURE__ */ jsxDEV("span", {
216
- className: daysUntilClose < 0 ? "text-red-500" : daysUntilClose <= 7 ? "text-yellow-600 dark:text-yellow-500" : "",
217
- children: daysUntilClose < 0 ? `${Math.abs(daysUntilClose)}d overdue` : daysUntilClose === 0 ? "Due today" : `${daysUntilClose}d left`
218
- }, undefined, false, undefined, this),
219
- /* @__PURE__ */ jsxDEV("span", {
220
- className: `rounded px-1.5 py-0.5 text-xs font-medium ${deal.status === "WON" ? "bg-green-100 text-green-700 dark:bg-green-900/30 dark:text-green-400" : deal.status === "LOST" ? "bg-red-100 text-red-700 dark:bg-red-900/30 dark:text-red-400" : "bg-blue-100 text-blue-700 dark:bg-blue-900/30 dark:text-blue-400"}`,
221
- children: deal.status
222
- }, undefined, false, undefined, this)
223
- ]
224
- }, undefined, true, undefined, this)
225
- ]
226
- }, undefined, true, undefined, this);
227
- }
228
-
229
- // src/ui/CrmPipelineBoard.tsx
230
- import { useState as useState3 } from "react";
231
- import { jsxDEV as jsxDEV2 } from "react/jsx-dev-runtime";
232
- "use client";
233
- function formatCurrency2(value) {
234
- if (value >= 1e6)
235
- return `$${(value / 1e6).toFixed(1)}M`;
236
- if (value >= 1000)
237
- return `$${(value / 1000).toFixed(0)}K`;
238
- return `$${value}`;
239
- }
240
- function CrmPipelineBoard({
241
- dealsByStage,
242
- stages,
243
- onDealClick,
244
- onDealMove
245
- }) {
246
- const [quickMoveOpen, setQuickMoveOpen] = useState3(null);
247
- const sortedStages = [...stages].sort((a, b) => a.position - b.position);
248
- const handleQuickMove = (dealId, toStageId) => {
249
- onDealMove?.(dealId, toStageId);
250
- setQuickMoveOpen(null);
251
- };
252
- return /* @__PURE__ */ jsxDEV2("div", {
253
- className: "flex gap-4 overflow-x-auto pb-4",
254
- children: sortedStages.map((stage) => {
255
- const deals = dealsByStage[stage.id] ?? [];
256
- const stageValue = deals.reduce((sum, d) => sum + d.value, 0);
257
- return /* @__PURE__ */ jsxDEV2("div", {
258
- className: "bg-muted/30 flex w-72 flex-shrink-0 flex-col rounded-lg",
259
- children: [
260
- /* @__PURE__ */ jsxDEV2("div", {
261
- className: "border-border flex items-center justify-between border-b px-3 py-2",
262
- children: [
263
- /* @__PURE__ */ jsxDEV2("div", {
264
- children: [
265
- /* @__PURE__ */ jsxDEV2("h3", {
266
- className: "font-medium",
267
- children: stage.name
268
- }, undefined, false, undefined, this),
269
- /* @__PURE__ */ jsxDEV2("p", {
270
- className: "text-muted-foreground text-xs",
271
- children: [
272
- deals.length,
273
- " deals · ",
274
- formatCurrency2(stageValue)
275
- ]
276
- }, undefined, true, undefined, this)
277
- ]
278
- }, undefined, true, undefined, this),
279
- /* @__PURE__ */ jsxDEV2("span", {
280
- className: "bg-muted flex h-6 w-6 items-center justify-center rounded-full text-xs font-medium",
281
- children: deals.length
282
- }, undefined, false, undefined, this)
283
- ]
284
- }, undefined, true, undefined, this),
285
- /* @__PURE__ */ jsxDEV2("div", {
286
- className: "flex flex-1 flex-col gap-2 p-2",
287
- children: deals.length === 0 ? /* @__PURE__ */ jsxDEV2("div", {
288
- className: "border-muted-foreground/20 text-muted-foreground flex h-24 items-center justify-center rounded-md border-2 border-dashed text-xs",
289
- children: "No deals"
290
- }, undefined, false, undefined, this) : deals.map((deal) => /* @__PURE__ */ jsxDEV2("div", {
291
- className: "group relative",
292
- children: [
293
- /* @__PURE__ */ jsxDEV2(CrmDealCard, {
294
- deal,
295
- onClick: () => onDealClick?.(deal.id)
296
- }, undefined, false, undefined, this),
297
- deal.status === "OPEN" && onDealMove && /* @__PURE__ */ jsxDEV2("div", {
298
- className: "absolute top-1 right-1 opacity-0 transition-opacity group-hover:opacity-100",
299
- children: [
300
- /* @__PURE__ */ jsxDEV2("button", {
301
- type: "button",
302
- onClick: (e) => {
303
- e.stopPropagation();
304
- setQuickMoveOpen(quickMoveOpen === deal.id ? null : deal.id);
305
- },
306
- className: "bg-background border-border hover:bg-muted flex h-6 w-6 items-center justify-center rounded border text-xs shadow-sm",
307
- title: "Quick move",
308
- children: "➡️"
309
- }, undefined, false, undefined, this),
310
- quickMoveOpen === deal.id && /* @__PURE__ */ jsxDEV2("div", {
311
- className: "bg-card border-border absolute top-7 right-0 z-20 min-w-[140px] rounded-lg border py-1 shadow-lg",
312
- children: [
313
- /* @__PURE__ */ jsxDEV2("p", {
314
- className: "text-muted-foreground px-3 py-1 text-xs font-medium",
315
- children: "Move to:"
316
- }, undefined, false, undefined, this),
317
- sortedStages.filter((s) => s.id !== deal.stageId).map((s) => /* @__PURE__ */ jsxDEV2("button", {
318
- type: "button",
319
- onClick: (e) => {
320
- e.stopPropagation();
321
- handleQuickMove(deal.id, s.id);
322
- },
323
- className: "hover:bg-muted w-full px-3 py-1.5 text-left text-sm",
324
- children: s.name
325
- }, s.id, false, undefined, this))
326
- ]
327
- }, undefined, true, undefined, this)
328
- ]
329
- }, undefined, true, undefined, this)
330
- ]
331
- }, deal.id, true, undefined, this))
332
- }, undefined, false, undefined, this)
333
- ]
334
- }, stage.id, true, undefined, this);
335
- })
336
- }, undefined, false, undefined, this);
337
- }
338
-
339
350
  // src/ui/modals/CreateDealModal.tsx
340
- import { useState as useState4 } from "react";
341
351
  import { Button, Input } from "@contractspec/lib.design-system";
352
+ import { useState as useState4 } from "react";
342
353
  import { jsxDEV as jsxDEV3 } from "react/jsx-dev-runtime";
343
354
  "use client";
344
355
  var CURRENCIES = ["USD", "EUR", "GBP", "CAD"];
@@ -397,7 +408,7 @@ function CreateDealModal({
397
408
  className: "fixed inset-0 z-50 flex items-center justify-center",
398
409
  children: [
399
410
  /* @__PURE__ */ jsxDEV3("div", {
400
- className: "bg-background/80 absolute inset-0 backdrop-blur-sm",
411
+ className: "absolute inset-0 bg-background/80 backdrop-blur-sm",
401
412
  onClick: onClose,
402
413
  role: "button",
403
414
  tabIndex: 0,
@@ -408,10 +419,10 @@ function CreateDealModal({
408
419
  "aria-label": "Close modal"
409
420
  }, undefined, false, undefined, this),
410
421
  /* @__PURE__ */ jsxDEV3("div", {
411
- className: "bg-card border-border relative z-10 w-full max-w-md rounded-xl border p-6 shadow-xl",
422
+ className: "relative z-10 w-full max-w-md rounded-xl border border-border bg-card p-6 shadow-xl",
412
423
  children: [
413
424
  /* @__PURE__ */ jsxDEV3("h2", {
414
- className: "mb-4 text-xl font-semibold",
425
+ className: "mb-4 font-semibold text-xl",
415
426
  children: "Create New Deal"
416
427
  }, undefined, false, undefined, this),
417
428
  /* @__PURE__ */ jsxDEV3("form", {
@@ -422,7 +433,7 @@ function CreateDealModal({
422
433
  children: [
423
434
  /* @__PURE__ */ jsxDEV3("label", {
424
435
  htmlFor: "deal-name",
425
- className: "text-muted-foreground mb-1 block text-sm font-medium",
436
+ className: "mb-1 block font-medium text-muted-foreground text-sm",
426
437
  children: "Deal Name *"
427
438
  }, undefined, false, undefined, this),
428
439
  /* @__PURE__ */ jsxDEV3(Input, {
@@ -442,7 +453,7 @@ function CreateDealModal({
442
453
  children: [
443
454
  /* @__PURE__ */ jsxDEV3("label", {
444
455
  htmlFor: "deal-value",
445
- className: "text-muted-foreground mb-1 block text-sm font-medium",
456
+ className: "mb-1 block font-medium text-muted-foreground text-sm",
446
457
  children: "Value *"
447
458
  }, undefined, false, undefined, this),
448
459
  /* @__PURE__ */ jsxDEV3(Input, {
@@ -462,7 +473,7 @@ function CreateDealModal({
462
473
  children: [
463
474
  /* @__PURE__ */ jsxDEV3("label", {
464
475
  htmlFor: "deal-currency",
465
- className: "text-muted-foreground mb-1 block text-sm font-medium",
476
+ className: "mb-1 block font-medium text-muted-foreground text-sm",
466
477
  children: "Currency"
467
478
  }, undefined, false, undefined, this),
468
479
  /* @__PURE__ */ jsxDEV3("select", {
@@ -470,7 +481,7 @@ function CreateDealModal({
470
481
  value: currency,
471
482
  onChange: (e) => setCurrency(e.target.value),
472
483
  disabled: isLoading,
473
- className: "border-input bg-background focus:ring-ring h-10 w-full rounded-md border px-3 py-2 text-sm focus:ring-2 focus:outline-none disabled:opacity-50",
484
+ className: "h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-ring disabled:opacity-50",
474
485
  children: CURRENCIES.map((c) => /* @__PURE__ */ jsxDEV3("option", {
475
486
  value: c,
476
487
  children: c
@@ -484,7 +495,7 @@ function CreateDealModal({
484
495
  children: [
485
496
  /* @__PURE__ */ jsxDEV3("label", {
486
497
  htmlFor: "deal-stage",
487
- className: "text-muted-foreground mb-1 block text-sm font-medium",
498
+ className: "mb-1 block font-medium text-muted-foreground text-sm",
488
499
  children: "Pipeline Stage *"
489
500
  }, undefined, false, undefined, this),
490
501
  /* @__PURE__ */ jsxDEV3("select", {
@@ -492,7 +503,7 @@ function CreateDealModal({
492
503
  value: stageId,
493
504
  onChange: (e) => setStageId(e.target.value),
494
505
  disabled: isLoading,
495
- className: "border-input bg-background focus:ring-ring h-10 w-full rounded-md border px-3 py-2 text-sm focus:ring-2 focus:outline-none disabled:opacity-50",
506
+ className: "h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-ring disabled:opacity-50",
496
507
  children: stages.map((stage) => /* @__PURE__ */ jsxDEV3("option", {
497
508
  value: stage.id,
498
509
  children: stage.name
@@ -504,7 +515,7 @@ function CreateDealModal({
504
515
  children: [
505
516
  /* @__PURE__ */ jsxDEV3("label", {
506
517
  htmlFor: "deal-close-date",
507
- className: "text-muted-foreground mb-1 block text-sm font-medium",
518
+ className: "mb-1 block font-medium text-muted-foreground text-sm",
508
519
  children: "Expected Close Date"
509
520
  }, undefined, false, undefined, this),
510
521
  /* @__PURE__ */ jsxDEV3(Input, {
@@ -517,7 +528,7 @@ function CreateDealModal({
517
528
  ]
518
529
  }, undefined, true, undefined, this),
519
530
  error && /* @__PURE__ */ jsxDEV3("div", {
520
- className: "bg-destructive/10 text-destructive rounded-md p-3 text-sm",
531
+ className: "rounded-md bg-destructive/10 p-3 text-destructive text-sm",
521
532
  children: error
522
533
  }, undefined, false, undefined, this),
523
534
  /* @__PURE__ */ jsxDEV3("div", {
@@ -546,8 +557,8 @@ function CreateDealModal({
546
557
  }
547
558
 
548
559
  // src/ui/modals/DealActionsModal.tsx
549
- import { useState as useState5 } from "react";
550
560
  import { Button as Button2 } from "@contractspec/lib.design-system";
561
+ import { useState as useState5 } from "react";
551
562
  import { jsxDEV as jsxDEV4, Fragment } from "react/jsx-dev-runtime";
552
563
  "use client";
553
564
  function formatCurrency3(value, currency) {
@@ -648,7 +659,7 @@ function DealActionsModal({
648
659
  className: "fixed inset-0 z-50 flex items-center justify-center",
649
660
  children: [
650
661
  /* @__PURE__ */ jsxDEV4("div", {
651
- className: "bg-background/80 absolute inset-0 backdrop-blur-sm",
662
+ className: "absolute inset-0 bg-background/80 backdrop-blur-sm",
652
663
  onClick: handleClose,
653
664
  role: "button",
654
665
  tabIndex: 0,
@@ -659,21 +670,21 @@ function DealActionsModal({
659
670
  "aria-label": "Close modal"
660
671
  }, undefined, false, undefined, this),
661
672
  /* @__PURE__ */ jsxDEV4("div", {
662
- className: "bg-card border-border relative z-10 w-full max-w-md rounded-xl border p-6 shadow-xl",
673
+ className: "relative z-10 w-full max-w-md rounded-xl border border-border bg-card p-6 shadow-xl",
663
674
  children: [
664
675
  /* @__PURE__ */ jsxDEV4("div", {
665
- className: "border-border mb-4 border-b pb-4",
676
+ className: "mb-4 border-border border-b pb-4",
666
677
  children: [
667
678
  /* @__PURE__ */ jsxDEV4("h2", {
668
- className: "text-xl font-semibold",
679
+ className: "font-semibold text-xl",
669
680
  children: deal.name
670
681
  }, undefined, false, undefined, this),
671
682
  /* @__PURE__ */ jsxDEV4("p", {
672
- className: "text-primary text-lg font-medium",
683
+ className: "font-medium text-lg text-primary",
673
684
  children: formatCurrency3(deal.value, deal.currency)
674
685
  }, undefined, false, undefined, this),
675
686
  /* @__PURE__ */ jsxDEV4("span", {
676
- className: `mt-2 inline-flex rounded-full px-2 py-0.5 text-xs font-medium ${deal.status === "WON" ? "bg-green-100 text-green-700 dark:bg-green-900/30 dark:text-green-400" : deal.status === "LOST" ? "bg-red-100 text-red-700 dark:bg-red-900/30 dark:text-red-400" : "bg-blue-100 text-blue-700 dark:bg-blue-900/30 dark:text-blue-400"}`,
687
+ className: `mt-2 inline-flex rounded-full px-2 py-0.5 font-medium text-xs ${deal.status === "WON" ? "bg-green-100 text-green-700 dark:bg-green-900/30 dark:text-green-400" : deal.status === "LOST" ? "bg-red-100 text-red-700 dark:bg-red-900/30 dark:text-red-400" : "bg-blue-100 text-blue-700 dark:bg-blue-900/30 dark:text-blue-400"}`,
677
688
  children: deal.status
678
689
  }, undefined, false, undefined, this)
679
690
  ]
@@ -725,7 +736,7 @@ function DealActionsModal({
725
736
  ]
726
737
  }, undefined, true, undefined, this),
727
738
  deal.status !== "OPEN" && /* @__PURE__ */ jsxDEV4("p", {
728
- className: "text-muted-foreground py-4 text-center",
739
+ className: "py-4 text-center text-muted-foreground",
729
740
  children: [
730
741
  "This deal is already ",
731
742
  deal.status.toLowerCase(),
@@ -750,14 +761,14 @@ function DealActionsModal({
750
761
  children: [
751
762
  /* @__PURE__ */ jsxDEV4("label", {
752
763
  htmlFor: "won-source",
753
- className: "text-muted-foreground mb-1 block text-sm font-medium",
764
+ className: "mb-1 block font-medium text-muted-foreground text-sm",
754
765
  children: "How did you win this deal?"
755
766
  }, undefined, false, undefined, this),
756
767
  /* @__PURE__ */ jsxDEV4("select", {
757
768
  id: "won-source",
758
769
  value: wonSource,
759
770
  onChange: (e) => setWonSource(e.target.value),
760
- className: "border-input bg-background focus:ring-ring h-10 w-full rounded-md border px-3 py-2 text-sm focus:ring-2 focus:outline-none",
771
+ className: "h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-ring",
761
772
  children: [
762
773
  /* @__PURE__ */ jsxDEV4("option", {
763
774
  value: "",
@@ -791,7 +802,7 @@ function DealActionsModal({
791
802
  children: [
792
803
  /* @__PURE__ */ jsxDEV4("label", {
793
804
  htmlFor: "win-notes",
794
- className: "text-muted-foreground mb-1 block text-sm font-medium",
805
+ className: "mb-1 block font-medium text-muted-foreground text-sm",
795
806
  children: "Notes (optional)"
796
807
  }, undefined, false, undefined, this),
797
808
  /* @__PURE__ */ jsxDEV4("textarea", {
@@ -800,12 +811,12 @@ function DealActionsModal({
800
811
  onChange: (e) => setNotes(e.target.value),
801
812
  placeholder: "Any additional notes about the win...",
802
813
  rows: 3,
803
- className: "border-input bg-background focus:ring-ring w-full rounded-md border px-3 py-2 text-sm focus:ring-2 focus:outline-none"
814
+ className: "w-full rounded-md border border-input bg-background px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-ring"
804
815
  }, undefined, false, undefined, this)
805
816
  ]
806
817
  }, undefined, true, undefined, this),
807
818
  error && /* @__PURE__ */ jsxDEV4("div", {
808
- className: "bg-destructive/10 text-destructive rounded-md p-3 text-sm",
819
+ className: "rounded-md bg-destructive/10 p-3 text-destructive text-sm",
809
820
  children: error
810
821
  }, undefined, false, undefined, this),
811
822
  /* @__PURE__ */ jsxDEV4("div", {
@@ -833,14 +844,14 @@ function DealActionsModal({
833
844
  children: [
834
845
  /* @__PURE__ */ jsxDEV4("label", {
835
846
  htmlFor: "lost-reason",
836
- className: "text-muted-foreground mb-1 block text-sm font-medium",
847
+ className: "mb-1 block font-medium text-muted-foreground text-sm",
837
848
  children: "Why was this deal lost? *"
838
849
  }, undefined, false, undefined, this),
839
850
  /* @__PURE__ */ jsxDEV4("select", {
840
851
  id: "lost-reason",
841
852
  value: lostReason,
842
853
  onChange: (e) => setLostReason(e.target.value),
843
- className: "border-input bg-background focus:ring-ring h-10 w-full rounded-md border px-3 py-2 text-sm focus:ring-2 focus:outline-none",
854
+ className: "h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-ring",
844
855
  children: [
845
856
  /* @__PURE__ */ jsxDEV4("option", {
846
857
  value: "",
@@ -882,7 +893,7 @@ function DealActionsModal({
882
893
  children: [
883
894
  /* @__PURE__ */ jsxDEV4("label", {
884
895
  htmlFor: "lose-notes",
885
- className: "text-muted-foreground mb-1 block text-sm font-medium",
896
+ className: "mb-1 block font-medium text-muted-foreground text-sm",
886
897
  children: "Notes (optional)"
887
898
  }, undefined, false, undefined, this),
888
899
  /* @__PURE__ */ jsxDEV4("textarea", {
@@ -891,12 +902,12 @@ function DealActionsModal({
891
902
  onChange: (e) => setNotes(e.target.value),
892
903
  placeholder: "Any additional details...",
893
904
  rows: 3,
894
- className: "border-input bg-background focus:ring-ring w-full rounded-md border px-3 py-2 text-sm focus:ring-2 focus:outline-none"
905
+ className: "w-full rounded-md border border-input bg-background px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-ring"
895
906
  }, undefined, false, undefined, this)
896
907
  ]
897
908
  }, undefined, true, undefined, this),
898
909
  error && /* @__PURE__ */ jsxDEV4("div", {
899
- className: "bg-destructive/10 text-destructive rounded-md p-3 text-sm",
910
+ className: "rounded-md bg-destructive/10 p-3 text-destructive text-sm",
900
911
  children: error
901
912
  }, undefined, false, undefined, this),
902
913
  /* @__PURE__ */ jsxDEV4("div", {
@@ -925,14 +936,14 @@ function DealActionsModal({
925
936
  children: [
926
937
  /* @__PURE__ */ jsxDEV4("label", {
927
938
  htmlFor: "move-stage",
928
- className: "text-muted-foreground mb-1 block text-sm font-medium",
939
+ className: "mb-1 block font-medium text-muted-foreground text-sm",
929
940
  children: "Move to Stage"
930
941
  }, undefined, false, undefined, this),
931
942
  /* @__PURE__ */ jsxDEV4("select", {
932
943
  id: "move-stage",
933
944
  value: selectedStageId,
934
945
  onChange: (e) => setSelectedStageId(e.target.value),
935
- className: "border-input bg-background focus:ring-ring h-10 w-full rounded-md border px-3 py-2 text-sm focus:ring-2 focus:outline-none",
946
+ className: "h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-ring",
936
947
  children: stages.map((stage) => /* @__PURE__ */ jsxDEV4("option", {
937
948
  value: stage.id,
938
949
  children: [
@@ -944,7 +955,7 @@ function DealActionsModal({
944
955
  ]
945
956
  }, undefined, true, undefined, this),
946
957
  error && /* @__PURE__ */ jsxDEV4("div", {
947
- className: "bg-destructive/10 text-destructive rounded-md p-3 text-sm",
958
+ className: "rounded-md bg-destructive/10 p-3 text-destructive text-sm",
948
959
  children: error
949
960
  }, undefined, false, undefined, this),
950
961
  /* @__PURE__ */ jsxDEV4("div", {
@@ -971,12 +982,305 @@ function DealActionsModal({
971
982
  }, undefined, true, undefined, this);
972
983
  }
973
984
 
974
- // src/ui/CrmDashboard.tsx
975
- import { useCallback as useCallback3, useState as useState6 } from "react";
985
+ // src/ui/tables/DealListTab.tsx
976
986
  import {
977
987
  Button as Button3,
988
+ DataTable,
989
+ LoaderBlock
990
+ } from "@contractspec/lib.design-system";
991
+ import { useContractTable } from "@contractspec/lib.presentation-runtime-react";
992
+ import { Badge } from "@contractspec/lib.ui-kit-web/ui/badge";
993
+ import { HStack, VStack } from "@contractspec/lib.ui-kit-web/ui/stack";
994
+ import { Text } from "@contractspec/lib.ui-kit-web/ui/text";
995
+ import * as React from "react";
996
+ import { jsxDEV as jsxDEV5 } from "react/jsx-dev-runtime";
997
+ "use client";
998
+ function formatCurrency4(value, currency = "USD") {
999
+ return new Intl.NumberFormat("en-US", {
1000
+ style: "currency",
1001
+ currency,
1002
+ minimumFractionDigits: 0,
1003
+ maximumFractionDigits: 0
1004
+ }).format(value);
1005
+ }
1006
+ function statusVariant(status) {
1007
+ switch (status) {
1008
+ case "WON":
1009
+ return "default";
1010
+ case "LOST":
1011
+ return "destructive";
1012
+ case "STALE":
1013
+ return "outline";
1014
+ default:
1015
+ return "secondary";
1016
+ }
1017
+ }
1018
+ function DealListDataTable({
1019
+ deals,
1020
+ totalItems,
1021
+ pageIndex,
1022
+ pageSize,
1023
+ sorting,
1024
+ loading,
1025
+ onSortingChange,
1026
+ onPaginationChange,
1027
+ onDealClick
1028
+ }) {
1029
+ const controller = useContractTable({
1030
+ data: deals,
1031
+ columns: [
1032
+ {
1033
+ id: "deal",
1034
+ header: "Deal",
1035
+ label: "Deal",
1036
+ accessor: (deal) => deal.name,
1037
+ cell: ({ item }) => /* @__PURE__ */ jsxDEV5(VStack, {
1038
+ gap: "xs",
1039
+ children: [
1040
+ /* @__PURE__ */ jsxDEV5(Text, {
1041
+ className: "font-medium text-sm",
1042
+ children: item.name
1043
+ }, undefined, false, undefined, this),
1044
+ /* @__PURE__ */ jsxDEV5(Text, {
1045
+ className: "text-muted-foreground text-xs",
1046
+ children: item.companyId ?? "Unassigned company"
1047
+ }, undefined, false, undefined, this)
1048
+ ]
1049
+ }, undefined, true, undefined, this),
1050
+ size: 240,
1051
+ minSize: 180,
1052
+ canSort: true,
1053
+ canPin: true,
1054
+ canResize: true
1055
+ },
1056
+ {
1057
+ id: "value",
1058
+ header: "Value",
1059
+ label: "Value",
1060
+ accessorKey: "value",
1061
+ cell: ({ item }) => formatCurrency4(item.value, item.currency),
1062
+ align: "right",
1063
+ size: 140,
1064
+ canSort: true,
1065
+ canResize: true
1066
+ },
1067
+ {
1068
+ id: "status",
1069
+ header: "Status",
1070
+ label: "Status",
1071
+ accessorKey: "status",
1072
+ cell: ({ value }) => /* @__PURE__ */ jsxDEV5(Badge, {
1073
+ variant: statusVariant(value),
1074
+ children: String(value)
1075
+ }, undefined, false, undefined, this),
1076
+ size: 130,
1077
+ canSort: true,
1078
+ canHide: true,
1079
+ canPin: true,
1080
+ canResize: true
1081
+ },
1082
+ {
1083
+ id: "expectedCloseDate",
1084
+ header: "Expected Close",
1085
+ label: "Expected Close",
1086
+ accessor: (deal) => deal.expectedCloseDate?.toISOString() ?? "",
1087
+ cell: ({ item }) => item.expectedCloseDate?.toLocaleDateString() ?? "Not scheduled",
1088
+ size: 170,
1089
+ canSort: true,
1090
+ canHide: true,
1091
+ canResize: true
1092
+ },
1093
+ {
1094
+ id: "updatedAt",
1095
+ header: "Updated",
1096
+ label: "Updated",
1097
+ accessor: (deal) => deal.updatedAt.toISOString(),
1098
+ cell: ({ item }) => item.updatedAt.toLocaleDateString(),
1099
+ size: 140,
1100
+ canSort: true,
1101
+ canHide: true,
1102
+ canResize: true
1103
+ },
1104
+ {
1105
+ id: "actions",
1106
+ header: "Actions",
1107
+ label: "Actions",
1108
+ accessor: (deal) => deal.id,
1109
+ cell: ({ item }) => /* @__PURE__ */ jsxDEV5(Button3, {
1110
+ variant: "ghost",
1111
+ size: "sm",
1112
+ onPress: () => onDealClick?.(item.id),
1113
+ children: "Actions"
1114
+ }, undefined, false, undefined, this),
1115
+ size: 120,
1116
+ canSort: false,
1117
+ canHide: false,
1118
+ canPin: false,
1119
+ canResize: false
1120
+ }
1121
+ ],
1122
+ executionMode: "server",
1123
+ selectionMode: "multiple",
1124
+ totalItems,
1125
+ state: {
1126
+ sorting,
1127
+ pagination: {
1128
+ pageIndex,
1129
+ pageSize
1130
+ }
1131
+ },
1132
+ onSortingChange,
1133
+ onPaginationChange,
1134
+ initialState: {
1135
+ columnVisibility: { updatedAt: false },
1136
+ columnPinning: { left: ["deal", "status"], right: [] }
1137
+ },
1138
+ renderExpandedContent: (deal) => /* @__PURE__ */ jsxDEV5(VStack, {
1139
+ gap: "sm",
1140
+ className: "py-2",
1141
+ children: [
1142
+ /* @__PURE__ */ jsxDEV5(HStack, {
1143
+ justify: "between",
1144
+ children: [
1145
+ /* @__PURE__ */ jsxDEV5(Text, {
1146
+ className: "font-medium text-sm",
1147
+ children: "Owner"
1148
+ }, undefined, false, undefined, this),
1149
+ /* @__PURE__ */ jsxDEV5(Text, {
1150
+ className: "text-muted-foreground text-sm",
1151
+ children: deal.ownerId
1152
+ }, undefined, false, undefined, this)
1153
+ ]
1154
+ }, undefined, true, undefined, this),
1155
+ /* @__PURE__ */ jsxDEV5(HStack, {
1156
+ justify: "between",
1157
+ children: [
1158
+ /* @__PURE__ */ jsxDEV5(Text, {
1159
+ className: "font-medium text-sm",
1160
+ children: "Contact"
1161
+ }, undefined, false, undefined, this),
1162
+ /* @__PURE__ */ jsxDEV5(Text, {
1163
+ className: "text-muted-foreground text-sm",
1164
+ children: deal.contactId ?? "No linked contact"
1165
+ }, undefined, false, undefined, this)
1166
+ ]
1167
+ }, undefined, true, undefined, this),
1168
+ deal.wonSource ? /* @__PURE__ */ jsxDEV5(HStack, {
1169
+ justify: "between",
1170
+ children: [
1171
+ /* @__PURE__ */ jsxDEV5(Text, {
1172
+ className: "font-medium text-sm",
1173
+ children: "Won Source"
1174
+ }, undefined, false, undefined, this),
1175
+ /* @__PURE__ */ jsxDEV5(Text, {
1176
+ className: "text-muted-foreground text-sm",
1177
+ children: deal.wonSource
1178
+ }, undefined, false, undefined, this)
1179
+ ]
1180
+ }, undefined, true, undefined, this) : null,
1181
+ deal.lostReason ? /* @__PURE__ */ jsxDEV5(HStack, {
1182
+ justify: "between",
1183
+ children: [
1184
+ /* @__PURE__ */ jsxDEV5(Text, {
1185
+ className: "font-medium text-sm",
1186
+ children: "Lost Reason"
1187
+ }, undefined, false, undefined, this),
1188
+ /* @__PURE__ */ jsxDEV5(Text, {
1189
+ className: "text-muted-foreground text-sm",
1190
+ children: deal.lostReason
1191
+ }, undefined, false, undefined, this)
1192
+ ]
1193
+ }, undefined, true, undefined, this) : null,
1194
+ deal.notes ? /* @__PURE__ */ jsxDEV5(VStack, {
1195
+ gap: "xs",
1196
+ children: [
1197
+ /* @__PURE__ */ jsxDEV5(Text, {
1198
+ className: "font-medium text-sm",
1199
+ children: "Notes"
1200
+ }, undefined, false, undefined, this),
1201
+ /* @__PURE__ */ jsxDEV5(Text, {
1202
+ className: "text-muted-foreground text-sm",
1203
+ children: deal.notes
1204
+ }, undefined, false, undefined, this)
1205
+ ]
1206
+ }, undefined, true, undefined, this) : null
1207
+ ]
1208
+ }, undefined, true, undefined, this),
1209
+ getCanExpand: () => true
1210
+ });
1211
+ return /* @__PURE__ */ jsxDEV5(DataTable, {
1212
+ controller,
1213
+ title: "All Deals",
1214
+ description: "Server-mode table using the shared ContractSpec controller.",
1215
+ loading,
1216
+ toolbar: /* @__PURE__ */ jsxDEV5(HStack, {
1217
+ gap: "sm",
1218
+ className: "flex-wrap",
1219
+ children: [
1220
+ /* @__PURE__ */ jsxDEV5(Text, {
1221
+ className: "text-muted-foreground text-sm",
1222
+ children: [
1223
+ "Selected ",
1224
+ controller.selectedRowIds.length
1225
+ ]
1226
+ }, undefined, true, undefined, this),
1227
+ /* @__PURE__ */ jsxDEV5(Text, {
1228
+ className: "text-muted-foreground text-sm",
1229
+ children: [
1230
+ totalItems,
1231
+ " total deals"
1232
+ ]
1233
+ }, undefined, true, undefined, this)
1234
+ ]
1235
+ }, undefined, true, undefined, this),
1236
+ footer: `Page ${controller.pageIndex + 1} of ${controller.pageCount}`,
1237
+ emptyState: /* @__PURE__ */ jsxDEV5("div", {
1238
+ className: "rounded-md border border-dashed p-8 text-center text-muted-foreground text-sm",
1239
+ children: "No deals found"
1240
+ }, undefined, false, undefined, this)
1241
+ }, undefined, false, undefined, this);
1242
+ }
1243
+ function DealListTab({
1244
+ onDealClick
1245
+ }) {
1246
+ const [sorting, setSorting] = React.useState([
1247
+ { id: "value", desc: true }
1248
+ ]);
1249
+ const [pagination, setPagination] = React.useState({
1250
+ pageIndex: 0,
1251
+ pageSize: 3
1252
+ });
1253
+ const { data, loading } = useDealList({
1254
+ pageIndex: pagination.pageIndex,
1255
+ pageSize: pagination.pageSize,
1256
+ sorting
1257
+ });
1258
+ if (loading && !data) {
1259
+ return /* @__PURE__ */ jsxDEV5(LoaderBlock, {
1260
+ label: "Loading deals..."
1261
+ }, undefined, false, undefined, this);
1262
+ }
1263
+ return /* @__PURE__ */ jsxDEV5(DealListDataTable, {
1264
+ deals: data?.deals ?? [],
1265
+ totalItems: data?.total ?? 0,
1266
+ pageIndex: pagination.pageIndex,
1267
+ pageSize: pagination.pageSize,
1268
+ sorting,
1269
+ loading,
1270
+ onSortingChange: (nextSorting) => {
1271
+ setSorting(nextSorting);
1272
+ setPagination((current) => ({ ...current, pageIndex: 0 }));
1273
+ },
1274
+ onPaginationChange: setPagination,
1275
+ onDealClick
1276
+ }, undefined, false, undefined, this);
1277
+ }
1278
+
1279
+ // src/ui/CrmDashboard.tsx
1280
+ import {
1281
+ Button as Button4,
978
1282
  ErrorState,
979
- LoaderBlock,
1283
+ LoaderBlock as LoaderBlock2,
980
1284
  StatCard,
981
1285
  StatCardGroup
982
1286
  } from "@contractspec/lib.design-system";
@@ -986,9 +1290,10 @@ import {
986
1290
  TabsList,
987
1291
  TabsTrigger
988
1292
  } from "@contractspec/lib.ui-kit-web/ui/tabs";
989
- import { jsxDEV as jsxDEV5 } from "react/jsx-dev-runtime";
1293
+ import { useCallback as useCallback3, useState as useState7 } from "react";
1294
+ import { jsxDEV as jsxDEV6 } from "react/jsx-dev-runtime";
990
1295
  "use client";
991
- function formatCurrency4(value, currency = "USD") {
1296
+ function formatCurrency5(value, currency = "USD") {
992
1297
  return new Intl.NumberFormat("en-US", {
993
1298
  style: "currency",
994
1299
  currency,
@@ -997,9 +1302,9 @@ function formatCurrency4(value, currency = "USD") {
997
1302
  }).format(value);
998
1303
  }
999
1304
  function CrmDashboard() {
1000
- const [isCreateModalOpen, setIsCreateModalOpen] = useState6(false);
1001
- const [selectedDeal, setSelectedDeal] = useState6(null);
1002
- const [isDealActionsOpen, setIsDealActionsOpen] = useState6(false);
1305
+ const [isCreateModalOpen, setIsCreateModalOpen] = useState7(false);
1306
+ const [selectedDeal, setSelectedDeal] = useState7(null);
1307
+ const [isDealActionsOpen, setIsDealActionsOpen] = useState7(false);
1003
1308
  const { data, dealsByStage, stages, loading, error, stats, refetch } = useDealList();
1004
1309
  const mutations = useDealMutations({
1005
1310
  onSuccess: () => {
@@ -1017,32 +1322,32 @@ function CrmDashboard() {
1017
1322
  await mutations.moveDeal({ dealId, stageId: toStageId });
1018
1323
  }, [mutations]);
1019
1324
  if (loading && !data) {
1020
- return /* @__PURE__ */ jsxDEV5(LoaderBlock, {
1325
+ return /* @__PURE__ */ jsxDEV6(LoaderBlock2, {
1021
1326
  label: "Loading CRM..."
1022
1327
  }, undefined, false, undefined, this);
1023
1328
  }
1024
1329
  if (error) {
1025
- return /* @__PURE__ */ jsxDEV5(ErrorState, {
1330
+ return /* @__PURE__ */ jsxDEV6(ErrorState, {
1026
1331
  title: "Failed to load CRM",
1027
1332
  description: error.message,
1028
1333
  onRetry: refetch,
1029
1334
  retryLabel: "Retry"
1030
1335
  }, undefined, false, undefined, this);
1031
1336
  }
1032
- return /* @__PURE__ */ jsxDEV5("div", {
1337
+ return /* @__PURE__ */ jsxDEV6("div", {
1033
1338
  className: "space-y-6",
1034
1339
  children: [
1035
- /* @__PURE__ */ jsxDEV5("div", {
1340
+ /* @__PURE__ */ jsxDEV6("div", {
1036
1341
  className: "flex items-center justify-between",
1037
1342
  children: [
1038
- /* @__PURE__ */ jsxDEV5("h2", {
1039
- className: "text-2xl font-bold",
1343
+ /* @__PURE__ */ jsxDEV6("h2", {
1344
+ className: "font-bold text-2xl",
1040
1345
  children: "CRM Pipeline"
1041
1346
  }, undefined, false, undefined, this),
1042
- /* @__PURE__ */ jsxDEV5(Button3, {
1347
+ /* @__PURE__ */ jsxDEV6(Button4, {
1043
1348
  onClick: () => setIsCreateModalOpen(true),
1044
1349
  children: [
1045
- /* @__PURE__ */ jsxDEV5("span", {
1350
+ /* @__PURE__ */ jsxDEV6("span", {
1046
1351
  className: "mr-2",
1047
1352
  children: "+"
1048
1353
  }, undefined, false, undefined, this),
@@ -1051,60 +1356,60 @@ function CrmDashboard() {
1051
1356
  }, undefined, true, undefined, this)
1052
1357
  ]
1053
1358
  }, undefined, true, undefined, this),
1054
- stats && /* @__PURE__ */ jsxDEV5(StatCardGroup, {
1359
+ stats && /* @__PURE__ */ jsxDEV6(StatCardGroup, {
1055
1360
  children: [
1056
- /* @__PURE__ */ jsxDEV5(StatCard, {
1361
+ /* @__PURE__ */ jsxDEV6(StatCard, {
1057
1362
  label: "Total Pipeline",
1058
- value: formatCurrency4(stats.totalValue),
1363
+ value: formatCurrency5(stats.totalValue),
1059
1364
  hint: `${stats.total} deals`
1060
1365
  }, undefined, false, undefined, this),
1061
- /* @__PURE__ */ jsxDEV5(StatCard, {
1366
+ /* @__PURE__ */ jsxDEV6(StatCard, {
1062
1367
  label: "Open Deals",
1063
- value: formatCurrency4(stats.openValue),
1368
+ value: formatCurrency5(stats.openValue),
1064
1369
  hint: `${stats.openCount} active`
1065
1370
  }, undefined, false, undefined, this),
1066
- /* @__PURE__ */ jsxDEV5(StatCard, {
1371
+ /* @__PURE__ */ jsxDEV6(StatCard, {
1067
1372
  label: "Won",
1068
- value: formatCurrency4(stats.wonValue),
1373
+ value: formatCurrency5(stats.wonValue),
1069
1374
  hint: `${stats.wonCount} closed`
1070
1375
  }, undefined, false, undefined, this),
1071
- /* @__PURE__ */ jsxDEV5(StatCard, {
1376
+ /* @__PURE__ */ jsxDEV6(StatCard, {
1072
1377
  label: "Lost",
1073
1378
  value: stats.lostCount,
1074
1379
  hint: "deals lost"
1075
1380
  }, undefined, false, undefined, this)
1076
1381
  ]
1077
1382
  }, undefined, true, undefined, this),
1078
- /* @__PURE__ */ jsxDEV5(Tabs, {
1383
+ /* @__PURE__ */ jsxDEV6(Tabs, {
1079
1384
  defaultValue: "pipeline",
1080
1385
  className: "w-full",
1081
1386
  children: [
1082
- /* @__PURE__ */ jsxDEV5(TabsList, {
1387
+ /* @__PURE__ */ jsxDEV6(TabsList, {
1083
1388
  children: [
1084
- /* @__PURE__ */ jsxDEV5(TabsTrigger, {
1389
+ /* @__PURE__ */ jsxDEV6(TabsTrigger, {
1085
1390
  value: "pipeline",
1086
1391
  children: [
1087
- /* @__PURE__ */ jsxDEV5("span", {
1392
+ /* @__PURE__ */ jsxDEV6("span", {
1088
1393
  className: "mr-2",
1089
1394
  children: "\uD83D\uDCCA"
1090
1395
  }, undefined, false, undefined, this),
1091
1396
  "Pipeline"
1092
1397
  ]
1093
1398
  }, undefined, true, undefined, this),
1094
- /* @__PURE__ */ jsxDEV5(TabsTrigger, {
1399
+ /* @__PURE__ */ jsxDEV6(TabsTrigger, {
1095
1400
  value: "list",
1096
1401
  children: [
1097
- /* @__PURE__ */ jsxDEV5("span", {
1402
+ /* @__PURE__ */ jsxDEV6("span", {
1098
1403
  className: "mr-2",
1099
1404
  children: "\uD83D\uDCCB"
1100
1405
  }, undefined, false, undefined, this),
1101
1406
  "All Deals"
1102
1407
  ]
1103
1408
  }, undefined, true, undefined, this),
1104
- /* @__PURE__ */ jsxDEV5(TabsTrigger, {
1409
+ /* @__PURE__ */ jsxDEV6(TabsTrigger, {
1105
1410
  value: "metrics",
1106
1411
  children: [
1107
- /* @__PURE__ */ jsxDEV5("span", {
1412
+ /* @__PURE__ */ jsxDEV6("span", {
1108
1413
  className: "mr-2",
1109
1414
  children: "\uD83D\uDCC8"
1110
1415
  }, undefined, false, undefined, this),
@@ -1113,34 +1418,33 @@ function CrmDashboard() {
1113
1418
  }, undefined, true, undefined, this)
1114
1419
  ]
1115
1420
  }, undefined, true, undefined, this),
1116
- /* @__PURE__ */ jsxDEV5(TabsContent, {
1421
+ /* @__PURE__ */ jsxDEV6(TabsContent, {
1117
1422
  value: "pipeline",
1118
1423
  className: "min-h-[400px]",
1119
- children: /* @__PURE__ */ jsxDEV5(CrmPipelineBoard, {
1424
+ children: /* @__PURE__ */ jsxDEV6(CrmPipelineBoard, {
1120
1425
  dealsByStage,
1121
1426
  stages,
1122
1427
  onDealClick: handleDealClick,
1123
1428
  onDealMove: handleDealMove
1124
1429
  }, undefined, false, undefined, this)
1125
1430
  }, undefined, false, undefined, this),
1126
- /* @__PURE__ */ jsxDEV5(TabsContent, {
1431
+ /* @__PURE__ */ jsxDEV6(TabsContent, {
1127
1432
  value: "list",
1128
1433
  className: "min-h-[400px]",
1129
- children: /* @__PURE__ */ jsxDEV5(DealListTab, {
1130
- data,
1434
+ children: /* @__PURE__ */ jsxDEV6(DealListTab, {
1131
1435
  onDealClick: handleDealClick
1132
1436
  }, undefined, false, undefined, this)
1133
1437
  }, undefined, false, undefined, this),
1134
- /* @__PURE__ */ jsxDEV5(TabsContent, {
1438
+ /* @__PURE__ */ jsxDEV6(TabsContent, {
1135
1439
  value: "metrics",
1136
1440
  className: "min-h-[400px]",
1137
- children: /* @__PURE__ */ jsxDEV5(MetricsTab, {
1441
+ children: /* @__PURE__ */ jsxDEV6(MetricsTab, {
1138
1442
  stats
1139
1443
  }, undefined, false, undefined, this)
1140
1444
  }, undefined, false, undefined, this)
1141
1445
  ]
1142
1446
  }, undefined, true, undefined, this),
1143
- /* @__PURE__ */ jsxDEV5(CreateDealModal, {
1447
+ /* @__PURE__ */ jsxDEV6(CreateDealModal, {
1144
1448
  isOpen: isCreateModalOpen,
1145
1449
  onClose: () => setIsCreateModalOpen(false),
1146
1450
  onSubmit: async (input) => {
@@ -1149,7 +1453,7 @@ function CrmDashboard() {
1149
1453
  stages,
1150
1454
  isLoading: mutations.createState.loading
1151
1455
  }, undefined, false, undefined, this),
1152
- /* @__PURE__ */ jsxDEV5(DealActionsModal, {
1456
+ /* @__PURE__ */ jsxDEV6(DealActionsModal, {
1153
1457
  isOpen: isDealActionsOpen,
1154
1458
  deal: selectedDeal,
1155
1459
  stages,
@@ -1172,113 +1476,31 @@ function CrmDashboard() {
1172
1476
  ]
1173
1477
  }, undefined, true, undefined, this);
1174
1478
  }
1175
- function DealListTab({ data, onDealClick }) {
1176
- if (!data?.deals.length) {
1177
- return /* @__PURE__ */ jsxDEV5("div", {
1178
- className: "text-muted-foreground flex h-64 items-center justify-center",
1179
- children: "No deals found"
1180
- }, undefined, false, undefined, this);
1181
- }
1182
- return /* @__PURE__ */ jsxDEV5("div", {
1183
- className: "border-border rounded-lg border",
1184
- children: /* @__PURE__ */ jsxDEV5("table", {
1185
- className: "w-full",
1186
- children: [
1187
- /* @__PURE__ */ jsxDEV5("thead", {
1188
- className: "border-border bg-muted/30 border-b",
1189
- children: /* @__PURE__ */ jsxDEV5("tr", {
1190
- children: [
1191
- /* @__PURE__ */ jsxDEV5("th", {
1192
- className: "px-4 py-3 text-left text-sm font-medium",
1193
- children: "Deal"
1194
- }, undefined, false, undefined, this),
1195
- /* @__PURE__ */ jsxDEV5("th", {
1196
- className: "px-4 py-3 text-left text-sm font-medium",
1197
- children: "Value"
1198
- }, undefined, false, undefined, this),
1199
- /* @__PURE__ */ jsxDEV5("th", {
1200
- className: "px-4 py-3 text-left text-sm font-medium",
1201
- children: "Status"
1202
- }, undefined, false, undefined, this),
1203
- /* @__PURE__ */ jsxDEV5("th", {
1204
- className: "px-4 py-3 text-left text-sm font-medium",
1205
- children: "Expected Close"
1206
- }, undefined, false, undefined, this),
1207
- /* @__PURE__ */ jsxDEV5("th", {
1208
- className: "px-4 py-3 text-left text-sm font-medium",
1209
- children: "Actions"
1210
- }, undefined, false, undefined, this)
1211
- ]
1212
- }, undefined, true, undefined, this)
1213
- }, undefined, false, undefined, this),
1214
- /* @__PURE__ */ jsxDEV5("tbody", {
1215
- className: "divide-border divide-y",
1216
- children: data.deals.map((deal) => /* @__PURE__ */ jsxDEV5("tr", {
1217
- className: "hover:bg-muted/50",
1218
- children: [
1219
- /* @__PURE__ */ jsxDEV5("td", {
1220
- className: "px-4 py-3",
1221
- children: /* @__PURE__ */ jsxDEV5("div", {
1222
- className: "font-medium",
1223
- children: deal.name
1224
- }, undefined, false, undefined, this)
1225
- }, undefined, false, undefined, this),
1226
- /* @__PURE__ */ jsxDEV5("td", {
1227
- className: "px-4 py-3 font-mono",
1228
- children: formatCurrency4(deal.value, deal.currency)
1229
- }, undefined, false, undefined, this),
1230
- /* @__PURE__ */ jsxDEV5("td", {
1231
- className: "px-4 py-3",
1232
- children: /* @__PURE__ */ jsxDEV5("span", {
1233
- className: `inline-flex rounded-full px-2 py-0.5 text-xs font-medium ${deal.status === "WON" ? "bg-green-100 text-green-700 dark:bg-green-900/30 dark:text-green-400" : deal.status === "LOST" ? "bg-red-100 text-red-700 dark:bg-red-900/30 dark:text-red-400" : "bg-blue-100 text-blue-700 dark:bg-blue-900/30 dark:text-blue-400"}`,
1234
- children: deal.status
1235
- }, undefined, false, undefined, this)
1236
- }, undefined, false, undefined, this),
1237
- /* @__PURE__ */ jsxDEV5("td", {
1238
- className: "text-muted-foreground px-4 py-3",
1239
- children: deal.expectedCloseDate?.toLocaleDateString() ?? "-"
1240
- }, undefined, false, undefined, this),
1241
- /* @__PURE__ */ jsxDEV5("td", {
1242
- className: "px-4 py-3",
1243
- children: /* @__PURE__ */ jsxDEV5(Button3, {
1244
- variant: "ghost",
1245
- size: "sm",
1246
- onPress: () => onDealClick?.(deal.id),
1247
- children: "Actions"
1248
- }, undefined, false, undefined, this)
1249
- }, undefined, false, undefined, this)
1250
- ]
1251
- }, deal.id, true, undefined, this))
1252
- }, undefined, false, undefined, this)
1253
- ]
1254
- }, undefined, true, undefined, this)
1255
- }, undefined, false, undefined, this);
1256
- }
1257
1479
  function MetricsTab({
1258
1480
  stats
1259
1481
  }) {
1260
1482
  if (!stats)
1261
1483
  return null;
1262
- return /* @__PURE__ */ jsxDEV5("div", {
1484
+ return /* @__PURE__ */ jsxDEV6("div", {
1263
1485
  className: "space-y-6",
1264
- children: /* @__PURE__ */ jsxDEV5("div", {
1265
- className: "border-border bg-card rounded-xl border p-6",
1486
+ children: /* @__PURE__ */ jsxDEV6("div", {
1487
+ className: "rounded-xl border border-border bg-card p-6",
1266
1488
  children: [
1267
- /* @__PURE__ */ jsxDEV5("h3", {
1268
- className: "mb-4 text-lg font-semibold",
1489
+ /* @__PURE__ */ jsxDEV6("h3", {
1490
+ className: "mb-4 font-semibold text-lg",
1269
1491
  children: "Pipeline Overview"
1270
1492
  }, undefined, false, undefined, this),
1271
- /* @__PURE__ */ jsxDEV5("dl", {
1493
+ /* @__PURE__ */ jsxDEV6("dl", {
1272
1494
  className: "grid gap-4 sm:grid-cols-3",
1273
1495
  children: [
1274
- /* @__PURE__ */ jsxDEV5("div", {
1496
+ /* @__PURE__ */ jsxDEV6("div", {
1275
1497
  children: [
1276
- /* @__PURE__ */ jsxDEV5("dt", {
1498
+ /* @__PURE__ */ jsxDEV6("dt", {
1277
1499
  className: "text-muted-foreground text-sm",
1278
1500
  children: "Win Rate"
1279
1501
  }, undefined, false, undefined, this),
1280
- /* @__PURE__ */ jsxDEV5("dd", {
1281
- className: "text-2xl font-semibold",
1502
+ /* @__PURE__ */ jsxDEV6("dd", {
1503
+ className: "font-semibold text-2xl",
1282
1504
  children: [
1283
1505
  stats.total > 0 ? (stats.wonCount / stats.total * 100).toFixed(0) : 0,
1284
1506
  "%"
@@ -1286,26 +1508,26 @@ function MetricsTab({
1286
1508
  }, undefined, true, undefined, this)
1287
1509
  ]
1288
1510
  }, undefined, true, undefined, this),
1289
- /* @__PURE__ */ jsxDEV5("div", {
1511
+ /* @__PURE__ */ jsxDEV6("div", {
1290
1512
  children: [
1291
- /* @__PURE__ */ jsxDEV5("dt", {
1513
+ /* @__PURE__ */ jsxDEV6("dt", {
1292
1514
  className: "text-muted-foreground text-sm",
1293
1515
  children: "Avg Deal Size"
1294
1516
  }, undefined, false, undefined, this),
1295
- /* @__PURE__ */ jsxDEV5("dd", {
1296
- className: "text-2xl font-semibold",
1297
- children: formatCurrency4(stats.total > 0 ? stats.totalValue / stats.total : 0)
1517
+ /* @__PURE__ */ jsxDEV6("dd", {
1518
+ className: "font-semibold text-2xl",
1519
+ children: formatCurrency5(stats.total > 0 ? stats.totalValue / stats.total : 0)
1298
1520
  }, undefined, false, undefined, this)
1299
1521
  ]
1300
1522
  }, undefined, true, undefined, this),
1301
- /* @__PURE__ */ jsxDEV5("div", {
1523
+ /* @__PURE__ */ jsxDEV6("div", {
1302
1524
  children: [
1303
- /* @__PURE__ */ jsxDEV5("dt", {
1525
+ /* @__PURE__ */ jsxDEV6("dt", {
1304
1526
  className: "text-muted-foreground text-sm",
1305
1527
  children: "Conversion"
1306
1528
  }, undefined, false, undefined, this),
1307
- /* @__PURE__ */ jsxDEV5("dd", {
1308
- className: "text-2xl font-semibold",
1529
+ /* @__PURE__ */ jsxDEV6("dd", {
1530
+ className: "font-semibold text-2xl",
1309
1531
  children: [
1310
1532
  stats.wonCount,
1311
1533
  " / ",