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