@contractspec/example.crm-pipeline 3.7.5 → 3.7.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-build.log +8 -8
- package/AGENTS.md +51 -33
- package/CHANGELOG.md +16 -0
- package/README.md +66 -148
- package/dist/browser/events/contact.event.js +1 -1
- package/dist/browser/events/deal.event.js +1 -1
- package/dist/browser/events/index.js +3 -3
- package/dist/browser/events/task.event.js +1 -1
- package/dist/browser/index.js +293 -293
- package/dist/browser/ui/CrmDashboard.js +221 -221
- package/dist/browser/ui/CrmDealCard.js +5 -5
- package/dist/browser/ui/CrmPipelineBoard.js +13 -13
- package/dist/browser/ui/hooks/index.js +2 -2
- package/dist/browser/ui/hooks/useDealList.js +1 -1
- package/dist/browser/ui/hooks/useDealMutations.js +1 -1
- package/dist/browser/ui/index.js +290 -290
- package/dist/browser/ui/modals/CreateDealModal.js +12 -12
- package/dist/browser/ui/modals/DealActionsModal.js +21 -21
- package/dist/browser/ui/modals/index.js +33 -33
- package/dist/browser/ui/renderers/index.js +116 -116
- package/dist/browser/ui/renderers/pipeline.renderer.js +97 -97
- package/dist/deal/index.d.ts +2 -2
- package/dist/events/contact.event.js +1 -1
- package/dist/events/deal.event.js +1 -1
- package/dist/events/index.js +3 -3
- package/dist/events/task.event.js +1 -1
- package/dist/handlers/index.d.ts +2 -2
- package/dist/index.d.ts +3 -3
- package/dist/index.js +293 -293
- package/dist/node/events/contact.event.js +1 -1
- package/dist/node/events/deal.event.js +1 -1
- package/dist/node/events/index.js +3 -3
- package/dist/node/events/task.event.js +1 -1
- package/dist/node/index.js +293 -293
- package/dist/node/ui/CrmDashboard.js +221 -221
- package/dist/node/ui/CrmDealCard.js +5 -5
- package/dist/node/ui/CrmPipelineBoard.js +13 -13
- package/dist/node/ui/hooks/index.js +2 -2
- package/dist/node/ui/hooks/useDealList.js +1 -1
- package/dist/node/ui/hooks/useDealMutations.js +1 -1
- package/dist/node/ui/index.js +290 -290
- package/dist/node/ui/modals/CreateDealModal.js +12 -12
- package/dist/node/ui/modals/DealActionsModal.js +21 -21
- package/dist/node/ui/modals/index.js +33 -33
- package/dist/node/ui/renderers/index.js +116 -116
- package/dist/node/ui/renderers/pipeline.renderer.js +97 -97
- package/dist/operations/index.d.ts +1 -1
- package/dist/ui/CrmDashboard.js +221 -221
- package/dist/ui/CrmDealCard.js +5 -5
- package/dist/ui/CrmPipelineBoard.js +13 -13
- package/dist/ui/hooks/index.d.ts +2 -2
- package/dist/ui/hooks/index.js +2 -2
- package/dist/ui/hooks/useDealList.js +1 -1
- package/dist/ui/hooks/useDealMutations.d.ts +9 -0
- package/dist/ui/hooks/useDealMutations.js +1 -1
- package/dist/ui/index.d.ts +3 -3
- package/dist/ui/index.js +290 -290
- package/dist/ui/modals/CreateDealModal.js +12 -12
- package/dist/ui/modals/DealActionsModal.js +21 -21
- package/dist/ui/modals/index.js +33 -33
- package/dist/ui/renderers/index.d.ts +1 -1
- package/dist/ui/renderers/index.js +116 -116
- package/dist/ui/renderers/pipeline.renderer.d.ts +1 -1
- package/dist/ui/renderers/pipeline.renderer.js +97 -97
- package/package.json +14 -14
- package/src/crm-pipeline.feature.ts +86 -86
- package/src/deal/deal.enum.ts +8 -8
- package/src/deal/deal.operation.ts +255 -255
- package/src/deal/deal.schema.ts +92 -92
- package/src/deal/deal.test-spec.ts +48 -48
- package/src/deal/index.ts +17 -19
- package/src/docs/crm-pipeline.docblock.ts +43 -43
- package/src/entities/company.entity.ts +52 -52
- package/src/entities/contact.entity.ts +67 -67
- package/src/entities/deal.entity.ts +134 -134
- package/src/entities/index.ts +27 -27
- package/src/entities/task.entity.ts +105 -105
- package/src/events/contact.event.ts +22 -22
- package/src/events/deal.event.ts +77 -77
- package/src/events/task.event.ts +19 -19
- package/src/example.ts +32 -32
- package/src/handlers/crm.handlers.ts +358 -357
- package/src/handlers/deal.handlers.ts +179 -179
- package/src/handlers/index.ts +18 -19
- package/src/handlers/mock-data.ts +167 -167
- package/src/index.ts +11 -11
- package/src/operations/index.ts +16 -16
- package/src/presentations/dashboard.presentation.ts +45 -45
- package/src/presentations/pipeline.presentation.ts +90 -90
- package/src/seeders/index.ts +26 -26
- package/src/shared/overlay-types.ts +23 -23
- package/src/ui/CrmDashboard.tsx +256 -256
- package/src/ui/CrmDealCard.tsx +64 -64
- package/src/ui/CrmPipelineBoard.tsx +105 -105
- package/src/ui/hooks/index.ts +3 -3
- package/src/ui/hooks/useDealList.ts +85 -85
- package/src/ui/hooks/useDealMutations.ts +151 -150
- package/src/ui/index.ts +5 -10
- package/src/ui/modals/CreateDealModal.tsx +217 -217
- package/src/ui/modals/DealActionsModal.tsx +390 -390
- package/src/ui/overlays/demo-overlays.ts +43 -43
- package/src/ui/renderers/index.ts +4 -3
- package/src/ui/renderers/pipeline.markdown.ts +165 -165
- package/src/ui/renderers/pipeline.renderer.tsx +17 -16
- package/tsconfig.json +7 -8
- package/tsdown.config.js +7 -3
|
@@ -1,16 +1,174 @@
|
|
|
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] =
|
|
9
|
-
const [dealsByStage, setDealsByStage] =
|
|
10
|
-
const [stages, setStages] =
|
|
11
|
-
const [loading, setLoading] =
|
|
12
|
-
const [error, setError] =
|
|
13
|
-
const [page, setPage] =
|
|
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 [page, setPage] = useState2(1);
|
|
14
172
|
const pipelineId = options.pipelineId ?? "pipeline-1";
|
|
15
173
|
const fetchData = useCallback(async () => {
|
|
16
174
|
setLoading(true);
|
|
@@ -81,27 +239,27 @@ function useDealList(options = {}) {
|
|
|
81
239
|
}
|
|
82
240
|
|
|
83
241
|
// src/ui/hooks/useDealMutations.ts
|
|
84
|
-
import { useCallback as useCallback2, useState as useState2 } from "react";
|
|
85
242
|
import { useTemplateRuntime as useTemplateRuntime2 } from "@contractspec/lib.example-shared-ui";
|
|
243
|
+
import { useCallback as useCallback2, useState as useState3 } from "react";
|
|
86
244
|
function useDealMutations(options = {}) {
|
|
87
245
|
const { handlers, projectId } = useTemplateRuntime2();
|
|
88
246
|
const { crm } = handlers;
|
|
89
|
-
const [createState, setCreateState] =
|
|
247
|
+
const [createState, setCreateState] = useState3({
|
|
90
248
|
loading: false,
|
|
91
249
|
error: null,
|
|
92
250
|
data: null
|
|
93
251
|
});
|
|
94
|
-
const [moveState, setMoveState] =
|
|
252
|
+
const [moveState, setMoveState] = useState3({
|
|
95
253
|
loading: false,
|
|
96
254
|
error: null,
|
|
97
255
|
data: null
|
|
98
256
|
});
|
|
99
|
-
const [winState, setWinState] =
|
|
257
|
+
const [winState, setWinState] = useState3({
|
|
100
258
|
loading: false,
|
|
101
259
|
error: null,
|
|
102
260
|
data: null
|
|
103
261
|
});
|
|
104
|
-
const [loseState, setLoseState] =
|
|
262
|
+
const [loseState, setLoseState] = useState3({
|
|
105
263
|
loading: false,
|
|
106
264
|
error: null,
|
|
107
265
|
data: null
|
|
@@ -178,167 +336,9 @@ function useDealMutations(options = {}) {
|
|
|
178
336
|
};
|
|
179
337
|
}
|
|
180
338
|
|
|
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
339
|
// src/ui/modals/CreateDealModal.tsx
|
|
340
|
-
import { useState as useState4 } from "react";
|
|
341
340
|
import { Button, Input } from "@contractspec/lib.design-system";
|
|
341
|
+
import { useState as useState4 } from "react";
|
|
342
342
|
import { jsxDEV as jsxDEV3 } from "react/jsx-dev-runtime";
|
|
343
343
|
"use client";
|
|
344
344
|
var CURRENCIES = ["USD", "EUR", "GBP", "CAD"];
|
|
@@ -397,7 +397,7 @@ function CreateDealModal({
|
|
|
397
397
|
className: "fixed inset-0 z-50 flex items-center justify-center",
|
|
398
398
|
children: [
|
|
399
399
|
/* @__PURE__ */ jsxDEV3("div", {
|
|
400
|
-
className: "bg-background/80
|
|
400
|
+
className: "absolute inset-0 bg-background/80 backdrop-blur-sm",
|
|
401
401
|
onClick: onClose,
|
|
402
402
|
role: "button",
|
|
403
403
|
tabIndex: 0,
|
|
@@ -408,10 +408,10 @@ function CreateDealModal({
|
|
|
408
408
|
"aria-label": "Close modal"
|
|
409
409
|
}, undefined, false, undefined, this),
|
|
410
410
|
/* @__PURE__ */ jsxDEV3("div", {
|
|
411
|
-
className: "
|
|
411
|
+
className: "relative z-10 w-full max-w-md rounded-xl border border-border bg-card p-6 shadow-xl",
|
|
412
412
|
children: [
|
|
413
413
|
/* @__PURE__ */ jsxDEV3("h2", {
|
|
414
|
-
className: "mb-4 text-xl
|
|
414
|
+
className: "mb-4 font-semibold text-xl",
|
|
415
415
|
children: "Create New Deal"
|
|
416
416
|
}, undefined, false, undefined, this),
|
|
417
417
|
/* @__PURE__ */ jsxDEV3("form", {
|
|
@@ -422,7 +422,7 @@ function CreateDealModal({
|
|
|
422
422
|
children: [
|
|
423
423
|
/* @__PURE__ */ jsxDEV3("label", {
|
|
424
424
|
htmlFor: "deal-name",
|
|
425
|
-
className: "
|
|
425
|
+
className: "mb-1 block font-medium text-muted-foreground text-sm",
|
|
426
426
|
children: "Deal Name *"
|
|
427
427
|
}, undefined, false, undefined, this),
|
|
428
428
|
/* @__PURE__ */ jsxDEV3(Input, {
|
|
@@ -442,7 +442,7 @@ function CreateDealModal({
|
|
|
442
442
|
children: [
|
|
443
443
|
/* @__PURE__ */ jsxDEV3("label", {
|
|
444
444
|
htmlFor: "deal-value",
|
|
445
|
-
className: "
|
|
445
|
+
className: "mb-1 block font-medium text-muted-foreground text-sm",
|
|
446
446
|
children: "Value *"
|
|
447
447
|
}, undefined, false, undefined, this),
|
|
448
448
|
/* @__PURE__ */ jsxDEV3(Input, {
|
|
@@ -462,7 +462,7 @@ function CreateDealModal({
|
|
|
462
462
|
children: [
|
|
463
463
|
/* @__PURE__ */ jsxDEV3("label", {
|
|
464
464
|
htmlFor: "deal-currency",
|
|
465
|
-
className: "
|
|
465
|
+
className: "mb-1 block font-medium text-muted-foreground text-sm",
|
|
466
466
|
children: "Currency"
|
|
467
467
|
}, undefined, false, undefined, this),
|
|
468
468
|
/* @__PURE__ */ jsxDEV3("select", {
|
|
@@ -470,7 +470,7 @@ function CreateDealModal({
|
|
|
470
470
|
value: currency,
|
|
471
471
|
onChange: (e) => setCurrency(e.target.value),
|
|
472
472
|
disabled: isLoading,
|
|
473
|
-
className: "
|
|
473
|
+
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
474
|
children: CURRENCIES.map((c) => /* @__PURE__ */ jsxDEV3("option", {
|
|
475
475
|
value: c,
|
|
476
476
|
children: c
|
|
@@ -484,7 +484,7 @@ function CreateDealModal({
|
|
|
484
484
|
children: [
|
|
485
485
|
/* @__PURE__ */ jsxDEV3("label", {
|
|
486
486
|
htmlFor: "deal-stage",
|
|
487
|
-
className: "
|
|
487
|
+
className: "mb-1 block font-medium text-muted-foreground text-sm",
|
|
488
488
|
children: "Pipeline Stage *"
|
|
489
489
|
}, undefined, false, undefined, this),
|
|
490
490
|
/* @__PURE__ */ jsxDEV3("select", {
|
|
@@ -492,7 +492,7 @@ function CreateDealModal({
|
|
|
492
492
|
value: stageId,
|
|
493
493
|
onChange: (e) => setStageId(e.target.value),
|
|
494
494
|
disabled: isLoading,
|
|
495
|
-
className: "
|
|
495
|
+
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
496
|
children: stages.map((stage) => /* @__PURE__ */ jsxDEV3("option", {
|
|
497
497
|
value: stage.id,
|
|
498
498
|
children: stage.name
|
|
@@ -504,7 +504,7 @@ function CreateDealModal({
|
|
|
504
504
|
children: [
|
|
505
505
|
/* @__PURE__ */ jsxDEV3("label", {
|
|
506
506
|
htmlFor: "deal-close-date",
|
|
507
|
-
className: "
|
|
507
|
+
className: "mb-1 block font-medium text-muted-foreground text-sm",
|
|
508
508
|
children: "Expected Close Date"
|
|
509
509
|
}, undefined, false, undefined, this),
|
|
510
510
|
/* @__PURE__ */ jsxDEV3(Input, {
|
|
@@ -517,7 +517,7 @@ function CreateDealModal({
|
|
|
517
517
|
]
|
|
518
518
|
}, undefined, true, undefined, this),
|
|
519
519
|
error && /* @__PURE__ */ jsxDEV3("div", {
|
|
520
|
-
className: "bg-destructive/10
|
|
520
|
+
className: "rounded-md bg-destructive/10 p-3 text-destructive text-sm",
|
|
521
521
|
children: error
|
|
522
522
|
}, undefined, false, undefined, this),
|
|
523
523
|
/* @__PURE__ */ jsxDEV3("div", {
|
|
@@ -546,8 +546,8 @@ function CreateDealModal({
|
|
|
546
546
|
}
|
|
547
547
|
|
|
548
548
|
// src/ui/modals/DealActionsModal.tsx
|
|
549
|
-
import { useState as useState5 } from "react";
|
|
550
549
|
import { Button as Button2 } from "@contractspec/lib.design-system";
|
|
550
|
+
import { useState as useState5 } from "react";
|
|
551
551
|
import { jsxDEV as jsxDEV4, Fragment } from "react/jsx-dev-runtime";
|
|
552
552
|
"use client";
|
|
553
553
|
function formatCurrency3(value, currency) {
|
|
@@ -648,7 +648,7 @@ function DealActionsModal({
|
|
|
648
648
|
className: "fixed inset-0 z-50 flex items-center justify-center",
|
|
649
649
|
children: [
|
|
650
650
|
/* @__PURE__ */ jsxDEV4("div", {
|
|
651
|
-
className: "bg-background/80
|
|
651
|
+
className: "absolute inset-0 bg-background/80 backdrop-blur-sm",
|
|
652
652
|
onClick: handleClose,
|
|
653
653
|
role: "button",
|
|
654
654
|
tabIndex: 0,
|
|
@@ -659,21 +659,21 @@ function DealActionsModal({
|
|
|
659
659
|
"aria-label": "Close modal"
|
|
660
660
|
}, undefined, false, undefined, this),
|
|
661
661
|
/* @__PURE__ */ jsxDEV4("div", {
|
|
662
|
-
className: "
|
|
662
|
+
className: "relative z-10 w-full max-w-md rounded-xl border border-border bg-card p-6 shadow-xl",
|
|
663
663
|
children: [
|
|
664
664
|
/* @__PURE__ */ jsxDEV4("div", {
|
|
665
|
-
className: "
|
|
665
|
+
className: "mb-4 border-border border-b pb-4",
|
|
666
666
|
children: [
|
|
667
667
|
/* @__PURE__ */ jsxDEV4("h2", {
|
|
668
|
-
className: "text-xl
|
|
668
|
+
className: "font-semibold text-xl",
|
|
669
669
|
children: deal.name
|
|
670
670
|
}, undefined, false, undefined, this),
|
|
671
671
|
/* @__PURE__ */ jsxDEV4("p", {
|
|
672
|
-
className: "
|
|
672
|
+
className: "font-medium text-lg text-primary",
|
|
673
673
|
children: formatCurrency3(deal.value, deal.currency)
|
|
674
674
|
}, undefined, false, undefined, this),
|
|
675
675
|
/* @__PURE__ */ jsxDEV4("span", {
|
|
676
|
-
className: `mt-2 inline-flex rounded-full px-2 py-0.5 text-xs
|
|
676
|
+
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
677
|
children: deal.status
|
|
678
678
|
}, undefined, false, undefined, this)
|
|
679
679
|
]
|
|
@@ -725,7 +725,7 @@ function DealActionsModal({
|
|
|
725
725
|
]
|
|
726
726
|
}, undefined, true, undefined, this),
|
|
727
727
|
deal.status !== "OPEN" && /* @__PURE__ */ jsxDEV4("p", {
|
|
728
|
-
className: "
|
|
728
|
+
className: "py-4 text-center text-muted-foreground",
|
|
729
729
|
children: [
|
|
730
730
|
"This deal is already ",
|
|
731
731
|
deal.status.toLowerCase(),
|
|
@@ -750,14 +750,14 @@ function DealActionsModal({
|
|
|
750
750
|
children: [
|
|
751
751
|
/* @__PURE__ */ jsxDEV4("label", {
|
|
752
752
|
htmlFor: "won-source",
|
|
753
|
-
className: "
|
|
753
|
+
className: "mb-1 block font-medium text-muted-foreground text-sm",
|
|
754
754
|
children: "How did you win this deal?"
|
|
755
755
|
}, undefined, false, undefined, this),
|
|
756
756
|
/* @__PURE__ */ jsxDEV4("select", {
|
|
757
757
|
id: "won-source",
|
|
758
758
|
value: wonSource,
|
|
759
759
|
onChange: (e) => setWonSource(e.target.value),
|
|
760
|
-
className: "
|
|
760
|
+
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
761
|
children: [
|
|
762
762
|
/* @__PURE__ */ jsxDEV4("option", {
|
|
763
763
|
value: "",
|
|
@@ -791,7 +791,7 @@ function DealActionsModal({
|
|
|
791
791
|
children: [
|
|
792
792
|
/* @__PURE__ */ jsxDEV4("label", {
|
|
793
793
|
htmlFor: "win-notes",
|
|
794
|
-
className: "
|
|
794
|
+
className: "mb-1 block font-medium text-muted-foreground text-sm",
|
|
795
795
|
children: "Notes (optional)"
|
|
796
796
|
}, undefined, false, undefined, this),
|
|
797
797
|
/* @__PURE__ */ jsxDEV4("textarea", {
|
|
@@ -800,12 +800,12 @@ function DealActionsModal({
|
|
|
800
800
|
onChange: (e) => setNotes(e.target.value),
|
|
801
801
|
placeholder: "Any additional notes about the win...",
|
|
802
802
|
rows: 3,
|
|
803
|
-
className: "
|
|
803
|
+
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
804
|
}, undefined, false, undefined, this)
|
|
805
805
|
]
|
|
806
806
|
}, undefined, true, undefined, this),
|
|
807
807
|
error && /* @__PURE__ */ jsxDEV4("div", {
|
|
808
|
-
className: "bg-destructive/10
|
|
808
|
+
className: "rounded-md bg-destructive/10 p-3 text-destructive text-sm",
|
|
809
809
|
children: error
|
|
810
810
|
}, undefined, false, undefined, this),
|
|
811
811
|
/* @__PURE__ */ jsxDEV4("div", {
|
|
@@ -833,14 +833,14 @@ function DealActionsModal({
|
|
|
833
833
|
children: [
|
|
834
834
|
/* @__PURE__ */ jsxDEV4("label", {
|
|
835
835
|
htmlFor: "lost-reason",
|
|
836
|
-
className: "
|
|
836
|
+
className: "mb-1 block font-medium text-muted-foreground text-sm",
|
|
837
837
|
children: "Why was this deal lost? *"
|
|
838
838
|
}, undefined, false, undefined, this),
|
|
839
839
|
/* @__PURE__ */ jsxDEV4("select", {
|
|
840
840
|
id: "lost-reason",
|
|
841
841
|
value: lostReason,
|
|
842
842
|
onChange: (e) => setLostReason(e.target.value),
|
|
843
|
-
className: "
|
|
843
|
+
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
844
|
children: [
|
|
845
845
|
/* @__PURE__ */ jsxDEV4("option", {
|
|
846
846
|
value: "",
|
|
@@ -882,7 +882,7 @@ function DealActionsModal({
|
|
|
882
882
|
children: [
|
|
883
883
|
/* @__PURE__ */ jsxDEV4("label", {
|
|
884
884
|
htmlFor: "lose-notes",
|
|
885
|
-
className: "
|
|
885
|
+
className: "mb-1 block font-medium text-muted-foreground text-sm",
|
|
886
886
|
children: "Notes (optional)"
|
|
887
887
|
}, undefined, false, undefined, this),
|
|
888
888
|
/* @__PURE__ */ jsxDEV4("textarea", {
|
|
@@ -891,12 +891,12 @@ function DealActionsModal({
|
|
|
891
891
|
onChange: (e) => setNotes(e.target.value),
|
|
892
892
|
placeholder: "Any additional details...",
|
|
893
893
|
rows: 3,
|
|
894
|
-
className: "
|
|
894
|
+
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
895
|
}, undefined, false, undefined, this)
|
|
896
896
|
]
|
|
897
897
|
}, undefined, true, undefined, this),
|
|
898
898
|
error && /* @__PURE__ */ jsxDEV4("div", {
|
|
899
|
-
className: "bg-destructive/10
|
|
899
|
+
className: "rounded-md bg-destructive/10 p-3 text-destructive text-sm",
|
|
900
900
|
children: error
|
|
901
901
|
}, undefined, false, undefined, this),
|
|
902
902
|
/* @__PURE__ */ jsxDEV4("div", {
|
|
@@ -925,14 +925,14 @@ function DealActionsModal({
|
|
|
925
925
|
children: [
|
|
926
926
|
/* @__PURE__ */ jsxDEV4("label", {
|
|
927
927
|
htmlFor: "move-stage",
|
|
928
|
-
className: "
|
|
928
|
+
className: "mb-1 block font-medium text-muted-foreground text-sm",
|
|
929
929
|
children: "Move to Stage"
|
|
930
930
|
}, undefined, false, undefined, this),
|
|
931
931
|
/* @__PURE__ */ jsxDEV4("select", {
|
|
932
932
|
id: "move-stage",
|
|
933
933
|
value: selectedStageId,
|
|
934
934
|
onChange: (e) => setSelectedStageId(e.target.value),
|
|
935
|
-
className: "
|
|
935
|
+
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
936
|
children: stages.map((stage) => /* @__PURE__ */ jsxDEV4("option", {
|
|
937
937
|
value: stage.id,
|
|
938
938
|
children: [
|
|
@@ -944,7 +944,7 @@ function DealActionsModal({
|
|
|
944
944
|
]
|
|
945
945
|
}, undefined, true, undefined, this),
|
|
946
946
|
error && /* @__PURE__ */ jsxDEV4("div", {
|
|
947
|
-
className: "bg-destructive/10
|
|
947
|
+
className: "rounded-md bg-destructive/10 p-3 text-destructive text-sm",
|
|
948
948
|
children: error
|
|
949
949
|
}, undefined, false, undefined, this),
|
|
950
950
|
/* @__PURE__ */ jsxDEV4("div", {
|
|
@@ -972,7 +972,6 @@ function DealActionsModal({
|
|
|
972
972
|
}
|
|
973
973
|
|
|
974
974
|
// src/ui/CrmDashboard.tsx
|
|
975
|
-
import { useCallback as useCallback3, useState as useState6 } from "react";
|
|
976
975
|
import {
|
|
977
976
|
Button as Button3,
|
|
978
977
|
ErrorState,
|
|
@@ -986,6 +985,7 @@ import {
|
|
|
986
985
|
TabsList,
|
|
987
986
|
TabsTrigger
|
|
988
987
|
} from "@contractspec/lib.ui-kit-web/ui/tabs";
|
|
988
|
+
import { useCallback as useCallback3, useState as useState6 } from "react";
|
|
989
989
|
import { jsxDEV as jsxDEV5 } from "react/jsx-dev-runtime";
|
|
990
990
|
"use client";
|
|
991
991
|
function formatCurrency4(value, currency = "USD") {
|
|
@@ -1036,7 +1036,7 @@ function CrmDashboard() {
|
|
|
1036
1036
|
className: "flex items-center justify-between",
|
|
1037
1037
|
children: [
|
|
1038
1038
|
/* @__PURE__ */ jsxDEV5("h2", {
|
|
1039
|
-
className: "text-2xl
|
|
1039
|
+
className: "font-bold text-2xl",
|
|
1040
1040
|
children: "CRM Pipeline"
|
|
1041
1041
|
}, undefined, false, undefined, this),
|
|
1042
1042
|
/* @__PURE__ */ jsxDEV5(Button3, {
|
|
@@ -1175,44 +1175,44 @@ function CrmDashboard() {
|
|
|
1175
1175
|
function DealListTab({ data, onDealClick }) {
|
|
1176
1176
|
if (!data?.deals.length) {
|
|
1177
1177
|
return /* @__PURE__ */ jsxDEV5("div", {
|
|
1178
|
-
className: "
|
|
1178
|
+
className: "flex h-64 items-center justify-center text-muted-foreground",
|
|
1179
1179
|
children: "No deals found"
|
|
1180
1180
|
}, undefined, false, undefined, this);
|
|
1181
1181
|
}
|
|
1182
1182
|
return /* @__PURE__ */ jsxDEV5("div", {
|
|
1183
|
-
className: "
|
|
1183
|
+
className: "rounded-lg border border-border",
|
|
1184
1184
|
children: /* @__PURE__ */ jsxDEV5("table", {
|
|
1185
1185
|
className: "w-full",
|
|
1186
1186
|
children: [
|
|
1187
1187
|
/* @__PURE__ */ jsxDEV5("thead", {
|
|
1188
|
-
className: "border-border bg-muted/30
|
|
1188
|
+
className: "border-border border-b bg-muted/30",
|
|
1189
1189
|
children: /* @__PURE__ */ jsxDEV5("tr", {
|
|
1190
1190
|
children: [
|
|
1191
1191
|
/* @__PURE__ */ jsxDEV5("th", {
|
|
1192
|
-
className: "px-4 py-3 text-left text-sm
|
|
1192
|
+
className: "px-4 py-3 text-left font-medium text-sm",
|
|
1193
1193
|
children: "Deal"
|
|
1194
1194
|
}, undefined, false, undefined, this),
|
|
1195
1195
|
/* @__PURE__ */ jsxDEV5("th", {
|
|
1196
|
-
className: "px-4 py-3 text-left text-sm
|
|
1196
|
+
className: "px-4 py-3 text-left font-medium text-sm",
|
|
1197
1197
|
children: "Value"
|
|
1198
1198
|
}, undefined, false, undefined, this),
|
|
1199
1199
|
/* @__PURE__ */ jsxDEV5("th", {
|
|
1200
|
-
className: "px-4 py-3 text-left text-sm
|
|
1200
|
+
className: "px-4 py-3 text-left font-medium text-sm",
|
|
1201
1201
|
children: "Status"
|
|
1202
1202
|
}, undefined, false, undefined, this),
|
|
1203
1203
|
/* @__PURE__ */ jsxDEV5("th", {
|
|
1204
|
-
className: "px-4 py-3 text-left text-sm
|
|
1204
|
+
className: "px-4 py-3 text-left font-medium text-sm",
|
|
1205
1205
|
children: "Expected Close"
|
|
1206
1206
|
}, undefined, false, undefined, this),
|
|
1207
1207
|
/* @__PURE__ */ jsxDEV5("th", {
|
|
1208
|
-
className: "px-4 py-3 text-left text-sm
|
|
1208
|
+
className: "px-4 py-3 text-left font-medium text-sm",
|
|
1209
1209
|
children: "Actions"
|
|
1210
1210
|
}, undefined, false, undefined, this)
|
|
1211
1211
|
]
|
|
1212
1212
|
}, undefined, true, undefined, this)
|
|
1213
1213
|
}, undefined, false, undefined, this),
|
|
1214
1214
|
/* @__PURE__ */ jsxDEV5("tbody", {
|
|
1215
|
-
className: "divide-
|
|
1215
|
+
className: "divide-y divide-border",
|
|
1216
1216
|
children: data.deals.map((deal) => /* @__PURE__ */ jsxDEV5("tr", {
|
|
1217
1217
|
className: "hover:bg-muted/50",
|
|
1218
1218
|
children: [
|
|
@@ -1230,12 +1230,12 @@ function DealListTab({ data, onDealClick }) {
|
|
|
1230
1230
|
/* @__PURE__ */ jsxDEV5("td", {
|
|
1231
1231
|
className: "px-4 py-3",
|
|
1232
1232
|
children: /* @__PURE__ */ jsxDEV5("span", {
|
|
1233
|
-
className: `inline-flex rounded-full px-2 py-0.5 text-xs
|
|
1233
|
+
className: `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"}`,
|
|
1234
1234
|
children: deal.status
|
|
1235
1235
|
}, undefined, false, undefined, this)
|
|
1236
1236
|
}, undefined, false, undefined, this),
|
|
1237
1237
|
/* @__PURE__ */ jsxDEV5("td", {
|
|
1238
|
-
className: "
|
|
1238
|
+
className: "px-4 py-3 text-muted-foreground",
|
|
1239
1239
|
children: deal.expectedCloseDate?.toLocaleDateString() ?? "-"
|
|
1240
1240
|
}, undefined, false, undefined, this),
|
|
1241
1241
|
/* @__PURE__ */ jsxDEV5("td", {
|
|
@@ -1262,10 +1262,10 @@ function MetricsTab({
|
|
|
1262
1262
|
return /* @__PURE__ */ jsxDEV5("div", {
|
|
1263
1263
|
className: "space-y-6",
|
|
1264
1264
|
children: /* @__PURE__ */ jsxDEV5("div", {
|
|
1265
|
-
className: "border-border bg-card
|
|
1265
|
+
className: "rounded-xl border border-border bg-card p-6",
|
|
1266
1266
|
children: [
|
|
1267
1267
|
/* @__PURE__ */ jsxDEV5("h3", {
|
|
1268
|
-
className: "mb-4 text-lg
|
|
1268
|
+
className: "mb-4 font-semibold text-lg",
|
|
1269
1269
|
children: "Pipeline Overview"
|
|
1270
1270
|
}, undefined, false, undefined, this),
|
|
1271
1271
|
/* @__PURE__ */ jsxDEV5("dl", {
|
|
@@ -1278,7 +1278,7 @@ function MetricsTab({
|
|
|
1278
1278
|
children: "Win Rate"
|
|
1279
1279
|
}, undefined, false, undefined, this),
|
|
1280
1280
|
/* @__PURE__ */ jsxDEV5("dd", {
|
|
1281
|
-
className: "text-2xl
|
|
1281
|
+
className: "font-semibold text-2xl",
|
|
1282
1282
|
children: [
|
|
1283
1283
|
stats.total > 0 ? (stats.wonCount / stats.total * 100).toFixed(0) : 0,
|
|
1284
1284
|
"%"
|
|
@@ -1293,7 +1293,7 @@ function MetricsTab({
|
|
|
1293
1293
|
children: "Avg Deal Size"
|
|
1294
1294
|
}, undefined, false, undefined, this),
|
|
1295
1295
|
/* @__PURE__ */ jsxDEV5("dd", {
|
|
1296
|
-
className: "text-2xl
|
|
1296
|
+
className: "font-semibold text-2xl",
|
|
1297
1297
|
children: formatCurrency4(stats.total > 0 ? stats.totalValue / stats.total : 0)
|
|
1298
1298
|
}, undefined, false, undefined, this)
|
|
1299
1299
|
]
|
|
@@ -1305,7 +1305,7 @@ function MetricsTab({
|
|
|
1305
1305
|
children: "Conversion"
|
|
1306
1306
|
}, undefined, false, undefined, this),
|
|
1307
1307
|
/* @__PURE__ */ jsxDEV5("dd", {
|
|
1308
|
-
className: "text-2xl
|
|
1308
|
+
className: "font-semibold text-2xl",
|
|
1309
1309
|
children: [
|
|
1310
1310
|
stats.wonCount,
|
|
1311
1311
|
" / ",
|