@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.
- package/.turbo/turbo-build.log +45 -42
- package/AGENTS.md +51 -33
- package/CHANGELOG.md +36 -0
- package/README.md +67 -148
- package/dist/browser/docs/crm-pipeline.docblock.js +1 -1
- package/dist/browser/docs/index.js +1 -1
- 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/handlers/crm.handlers.js +13 -2
- package/dist/browser/handlers/index.js +13 -2
- package/dist/browser/index.js +680 -447
- package/dist/browser/ui/CrmDashboard.js +574 -352
- package/dist/browser/ui/CrmDealCard.js +5 -5
- package/dist/browser/ui/CrmPipelineBoard.js +13 -13
- package/dist/browser/ui/hooks/index.js +21 -10
- package/dist/browser/ui/hooks/useDealList.js +20 -9
- package/dist/browser/ui/hooks/useDealMutations.js +1 -1
- package/dist/browser/ui/index.js +683 -450
- 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 +140 -118
- package/dist/browser/ui/renderers/pipeline.markdown.js +13 -2
- package/dist/browser/ui/renderers/pipeline.renderer.js +108 -97
- package/dist/browser/ui/tables/DealListTab.js +390 -0
- package/dist/deal/index.d.ts +2 -2
- package/dist/docs/crm-pipeline.docblock.js +1 -1
- package/dist/docs/index.js +1 -1
- 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/crm.handlers.d.ts +2 -0
- package/dist/handlers/crm.handlers.js +13 -2
- package/dist/handlers/index.d.ts +2 -2
- package/dist/handlers/index.js +13 -2
- package/dist/index.d.ts +3 -3
- package/dist/index.js +680 -447
- package/dist/node/docs/crm-pipeline.docblock.js +1 -1
- package/dist/node/docs/index.js +1 -1
- 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/handlers/crm.handlers.js +13 -2
- package/dist/node/handlers/index.js +13 -2
- package/dist/node/index.js +680 -447
- package/dist/node/ui/CrmDashboard.js +574 -352
- package/dist/node/ui/CrmDealCard.js +5 -5
- package/dist/node/ui/CrmPipelineBoard.js +13 -13
- package/dist/node/ui/hooks/index.js +21 -10
- package/dist/node/ui/hooks/useDealList.js +20 -9
- package/dist/node/ui/hooks/useDealMutations.js +1 -1
- package/dist/node/ui/index.js +683 -450
- 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 +140 -118
- package/dist/node/ui/renderers/pipeline.markdown.js +13 -2
- package/dist/node/ui/renderers/pipeline.renderer.js +108 -97
- package/dist/node/ui/tables/DealListTab.js +390 -0
- package/dist/operations/index.d.ts +1 -1
- package/dist/ui/CrmDashboard.js +574 -352
- 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 +21 -10
- package/dist/ui/hooks/useDealList.d.ts +8 -2
- package/dist/ui/hooks/useDealList.js +20 -9
- 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 +683 -450
- 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 +140 -118
- package/dist/ui/renderers/pipeline.markdown.js +13 -2
- package/dist/ui/renderers/pipeline.renderer.d.ts +1 -1
- package/dist/ui/renderers/pipeline.renderer.js +108 -97
- package/dist/ui/tables/DealListTab.d.ts +20 -0
- package/dist/ui/tables/DealListTab.js +391 -0
- package/dist/ui/tables/DealListTab.smoke.test.d.ts +1 -0
- package/package.json +29 -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 +44 -44
- 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 +375 -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 +210 -279
- 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 +113 -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/src/ui/tables/DealListTab.smoke.test.tsx +149 -0
- package/src/ui/tables/DealListTab.tsx +276 -0
- package/tsconfig.json +7 -8
- package/tsdown.config.js +7 -3
|
@@ -1,86 +1,4 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
// src/ui/hooks/useDealList.ts
|
|
3
|
-
import { useCallback, useEffect, useMemo, useState } from "react";
|
|
4
|
-
import { useTemplateRuntime } from "@contractspec/lib.example-shared-ui";
|
|
5
|
-
"use client";
|
|
6
|
-
function useDealList(options = {}) {
|
|
7
|
-
const { handlers, projectId } = useTemplateRuntime();
|
|
8
|
-
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);
|
|
15
|
-
const pipelineId = options.pipelineId ?? "pipeline-1";
|
|
16
|
-
const fetchData = useCallback(async () => {
|
|
17
|
-
setLoading(true);
|
|
18
|
-
setError(null);
|
|
19
|
-
try {
|
|
20
|
-
const [dealsResult, stageDealsResult, stagesResult] = await Promise.all([
|
|
21
|
-
crm.listDeals({
|
|
22
|
-
projectId,
|
|
23
|
-
pipelineId,
|
|
24
|
-
stageId: options.stageId,
|
|
25
|
-
status: options.status === "all" ? undefined : options.status,
|
|
26
|
-
search: options.search,
|
|
27
|
-
limit: options.limit ?? 50,
|
|
28
|
-
offset: (page - 1) * (options.limit ?? 50)
|
|
29
|
-
}),
|
|
30
|
-
crm.getDealsByStage({ projectId, pipelineId }),
|
|
31
|
-
crm.getPipelineStages({ pipelineId })
|
|
32
|
-
]);
|
|
33
|
-
setData(dealsResult);
|
|
34
|
-
setDealsByStage(stageDealsResult);
|
|
35
|
-
setStages(stagesResult);
|
|
36
|
-
} catch (err) {
|
|
37
|
-
setError(err instanceof Error ? err : new Error("Unknown error"));
|
|
38
|
-
} finally {
|
|
39
|
-
setLoading(false);
|
|
40
|
-
}
|
|
41
|
-
}, [
|
|
42
|
-
crm,
|
|
43
|
-
projectId,
|
|
44
|
-
pipelineId,
|
|
45
|
-
options.stageId,
|
|
46
|
-
options.status,
|
|
47
|
-
options.search,
|
|
48
|
-
options.limit,
|
|
49
|
-
page
|
|
50
|
-
]);
|
|
51
|
-
useEffect(() => {
|
|
52
|
-
fetchData();
|
|
53
|
-
}, [fetchData]);
|
|
54
|
-
const stats = useMemo(() => {
|
|
55
|
-
if (!data)
|
|
56
|
-
return null;
|
|
57
|
-
const open = data.deals.filter((d) => d.status === "OPEN");
|
|
58
|
-
const won = data.deals.filter((d) => d.status === "WON");
|
|
59
|
-
const lost = data.deals.filter((d) => d.status === "LOST");
|
|
60
|
-
return {
|
|
61
|
-
total: data.total,
|
|
62
|
-
totalValue: data.totalValue,
|
|
63
|
-
openCount: open.length,
|
|
64
|
-
openValue: open.reduce((sum, d) => sum + d.value, 0),
|
|
65
|
-
wonCount: won.length,
|
|
66
|
-
wonValue: won.reduce((sum, d) => sum + d.value, 0),
|
|
67
|
-
lostCount: lost.length
|
|
68
|
-
};
|
|
69
|
-
}, [data]);
|
|
70
|
-
return {
|
|
71
|
-
data,
|
|
72
|
-
dealsByStage,
|
|
73
|
-
stages,
|
|
74
|
-
loading,
|
|
75
|
-
error,
|
|
76
|
-
stats,
|
|
77
|
-
page,
|
|
78
|
-
refetch: fetchData,
|
|
79
|
-
nextPage: () => setPage((p) => p + 1),
|
|
80
|
-
prevPage: () => page > 1 && setPage((p) => p - 1)
|
|
81
|
-
};
|
|
82
|
-
}
|
|
83
|
-
|
|
84
2
|
// src/ui/CrmDealCard.tsx
|
|
85
3
|
import { jsxDEV } from "react/jsx-dev-runtime";
|
|
86
4
|
"use client";
|
|
@@ -96,7 +14,7 @@ function CrmDealCard({ deal, onClick }) {
|
|
|
96
14
|
const daysUntilClose = deal.expectedCloseDate ? Math.ceil((deal.expectedCloseDate.getTime() - Date.now()) / (1000 * 60 * 60 * 24)) : null;
|
|
97
15
|
return /* @__PURE__ */ jsxDEV("div", {
|
|
98
16
|
onClick,
|
|
99
|
-
className: "
|
|
17
|
+
className: "cursor-pointer rounded-lg border border-border bg-card p-3 shadow-sm transition-shadow hover:shadow-md",
|
|
100
18
|
role: "button",
|
|
101
19
|
tabIndex: 0,
|
|
102
20
|
onKeyDown: (e) => {
|
|
@@ -105,22 +23,22 @@ function CrmDealCard({ deal, onClick }) {
|
|
|
105
23
|
},
|
|
106
24
|
children: [
|
|
107
25
|
/* @__PURE__ */ jsxDEV("h4", {
|
|
108
|
-
className: "leading-snug
|
|
26
|
+
className: "font-medium leading-snug",
|
|
109
27
|
children: deal.name
|
|
110
28
|
}, undefined, false, undefined, this),
|
|
111
29
|
/* @__PURE__ */ jsxDEV("div", {
|
|
112
|
-
className: "
|
|
30
|
+
className: "mt-2 font-semibold text-lg text-primary",
|
|
113
31
|
children: formatCurrency(deal.value, deal.currency)
|
|
114
32
|
}, undefined, false, undefined, this),
|
|
115
33
|
/* @__PURE__ */ jsxDEV("div", {
|
|
116
|
-
className: "
|
|
34
|
+
className: "mt-3 flex items-center justify-between text-muted-foreground text-xs",
|
|
117
35
|
children: [
|
|
118
36
|
daysUntilClose !== null && /* @__PURE__ */ jsxDEV("span", {
|
|
119
37
|
className: daysUntilClose < 0 ? "text-red-500" : daysUntilClose <= 7 ? "text-yellow-600 dark:text-yellow-500" : "",
|
|
120
38
|
children: daysUntilClose < 0 ? `${Math.abs(daysUntilClose)}d overdue` : daysUntilClose === 0 ? "Due today" : `${daysUntilClose}d left`
|
|
121
39
|
}, undefined, false, undefined, this),
|
|
122
40
|
/* @__PURE__ */ jsxDEV("span", {
|
|
123
|
-
className: `rounded px-1.5 py-0.5 text-xs
|
|
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"}`,
|
|
124
42
|
children: deal.status
|
|
125
43
|
}, undefined, false, undefined, this)
|
|
126
44
|
]
|
|
@@ -130,7 +48,7 @@ function CrmDealCard({ deal, onClick }) {
|
|
|
130
48
|
}
|
|
131
49
|
|
|
132
50
|
// src/ui/CrmPipelineBoard.tsx
|
|
133
|
-
import { useState
|
|
51
|
+
import { useState } from "react";
|
|
134
52
|
import { jsxDEV as jsxDEV2 } from "react/jsx-dev-runtime";
|
|
135
53
|
"use client";
|
|
136
54
|
function formatCurrency2(value) {
|
|
@@ -146,7 +64,7 @@ function CrmPipelineBoard({
|
|
|
146
64
|
onDealClick,
|
|
147
65
|
onDealMove
|
|
148
66
|
}) {
|
|
149
|
-
const [quickMoveOpen, setQuickMoveOpen] =
|
|
67
|
+
const [quickMoveOpen, setQuickMoveOpen] = useState(null);
|
|
150
68
|
const sortedStages = [...stages].sort((a, b) => a.position - b.position);
|
|
151
69
|
const handleQuickMove = (dealId, toStageId) => {
|
|
152
70
|
onDealMove?.(dealId, toStageId);
|
|
@@ -158,10 +76,10 @@ function CrmPipelineBoard({
|
|
|
158
76
|
const deals = dealsByStage[stage.id] ?? [];
|
|
159
77
|
const stageValue = deals.reduce((sum, d) => sum + d.value, 0);
|
|
160
78
|
return /* @__PURE__ */ jsxDEV2("div", {
|
|
161
|
-
className: "
|
|
79
|
+
className: "flex w-72 flex-shrink-0 flex-col rounded-lg bg-muted/30",
|
|
162
80
|
children: [
|
|
163
81
|
/* @__PURE__ */ jsxDEV2("div", {
|
|
164
|
-
className: "
|
|
82
|
+
className: "flex items-center justify-between border-border border-b px-3 py-2",
|
|
165
83
|
children: [
|
|
166
84
|
/* @__PURE__ */ jsxDEV2("div", {
|
|
167
85
|
children: [
|
|
@@ -180,7 +98,7 @@ function CrmPipelineBoard({
|
|
|
180
98
|
]
|
|
181
99
|
}, undefined, true, undefined, this),
|
|
182
100
|
/* @__PURE__ */ jsxDEV2("span", {
|
|
183
|
-
className: "
|
|
101
|
+
className: "flex h-6 w-6 items-center justify-center rounded-full bg-muted font-medium text-xs",
|
|
184
102
|
children: deals.length
|
|
185
103
|
}, undefined, false, undefined, this)
|
|
186
104
|
]
|
|
@@ -188,7 +106,7 @@ function CrmPipelineBoard({
|
|
|
188
106
|
/* @__PURE__ */ jsxDEV2("div", {
|
|
189
107
|
className: "flex flex-1 flex-col gap-2 p-2",
|
|
190
108
|
children: deals.length === 0 ? /* @__PURE__ */ jsxDEV2("div", {
|
|
191
|
-
className: "
|
|
109
|
+
className: "flex h-24 items-center justify-center rounded-md border-2 border-muted-foreground/20 border-dashed text-muted-foreground text-xs",
|
|
192
110
|
children: "No deals"
|
|
193
111
|
}, undefined, false, undefined, this) : deals.map((deal) => /* @__PURE__ */ jsxDEV2("div", {
|
|
194
112
|
className: "group relative",
|
|
@@ -206,15 +124,15 @@ function CrmPipelineBoard({
|
|
|
206
124
|
e.stopPropagation();
|
|
207
125
|
setQuickMoveOpen(quickMoveOpen === deal.id ? null : deal.id);
|
|
208
126
|
},
|
|
209
|
-
className: "
|
|
127
|
+
className: "flex h-6 w-6 items-center justify-center rounded border border-border bg-background text-xs shadow-sm hover:bg-muted",
|
|
210
128
|
title: "Quick move",
|
|
211
129
|
children: "\u27A1\uFE0F"
|
|
212
130
|
}, undefined, false, undefined, this),
|
|
213
131
|
quickMoveOpen === deal.id && /* @__PURE__ */ jsxDEV2("div", {
|
|
214
|
-
className: "
|
|
132
|
+
className: "absolute top-7 right-0 z-20 min-w-[140px] rounded-lg border border-border bg-card py-1 shadow-lg",
|
|
215
133
|
children: [
|
|
216
134
|
/* @__PURE__ */ jsxDEV2("p", {
|
|
217
|
-
className: "
|
|
135
|
+
className: "px-3 py-1 font-medium text-muted-foreground text-xs",
|
|
218
136
|
children: "Move to:"
|
|
219
137
|
}, undefined, false, undefined, this),
|
|
220
138
|
sortedStages.filter((s) => s.id !== deal.stageId).map((s) => /* @__PURE__ */ jsxDEV2("button", {
|
|
@@ -223,7 +141,7 @@ function CrmPipelineBoard({
|
|
|
223
141
|
e.stopPropagation();
|
|
224
142
|
handleQuickMove(deal.id, s.id);
|
|
225
143
|
},
|
|
226
|
-
className: "
|
|
144
|
+
className: "w-full px-3 py-1.5 text-left text-sm hover:bg-muted",
|
|
227
145
|
children: s.name
|
|
228
146
|
}, s.id, false, undefined, this))
|
|
229
147
|
]
|
|
@@ -239,6 +157,99 @@ function CrmPipelineBoard({
|
|
|
239
157
|
}, undefined, false, undefined, this);
|
|
240
158
|
}
|
|
241
159
|
|
|
160
|
+
// src/ui/hooks/useDealList.ts
|
|
161
|
+
import { useTemplateRuntime } from "@contractspec/lib.example-shared-ui";
|
|
162
|
+
import { useCallback, useEffect, useMemo, useState as useState2 } from "react";
|
|
163
|
+
"use client";
|
|
164
|
+
function useDealList(options = {}) {
|
|
165
|
+
const { handlers, projectId } = useTemplateRuntime();
|
|
166
|
+
const { crm } = handlers;
|
|
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);
|
|
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;
|
|
179
|
+
const fetchData = useCallback(async () => {
|
|
180
|
+
setLoading(true);
|
|
181
|
+
setError(null);
|
|
182
|
+
try {
|
|
183
|
+
const [dealsResult, stageDealsResult, stagesResult] = await Promise.all([
|
|
184
|
+
crm.listDeals({
|
|
185
|
+
projectId,
|
|
186
|
+
pipelineId,
|
|
187
|
+
stageId: options.stageId,
|
|
188
|
+
status: options.status === "all" ? undefined : options.status,
|
|
189
|
+
search: options.search,
|
|
190
|
+
limit: pageSize,
|
|
191
|
+
offset: pageIndex * pageSize,
|
|
192
|
+
sortBy: sortBy === "name" || sortBy === "value" || sortBy === "status" || sortBy === "expectedCloseDate" || sortBy === "updatedAt" ? sortBy : undefined,
|
|
193
|
+
sortDirection
|
|
194
|
+
}),
|
|
195
|
+
crm.getDealsByStage({ projectId, pipelineId }),
|
|
196
|
+
crm.getPipelineStages({ pipelineId })
|
|
197
|
+
]);
|
|
198
|
+
setData(dealsResult);
|
|
199
|
+
setDealsByStage(stageDealsResult);
|
|
200
|
+
setStages(stagesResult);
|
|
201
|
+
} catch (err) {
|
|
202
|
+
setError(err instanceof Error ? err : new Error("Unknown error"));
|
|
203
|
+
} finally {
|
|
204
|
+
setLoading(false);
|
|
205
|
+
}
|
|
206
|
+
}, [
|
|
207
|
+
crm,
|
|
208
|
+
projectId,
|
|
209
|
+
pipelineId,
|
|
210
|
+
options.stageId,
|
|
211
|
+
options.status,
|
|
212
|
+
options.search,
|
|
213
|
+
pageIndex,
|
|
214
|
+
pageSize,
|
|
215
|
+
sortBy,
|
|
216
|
+
sortDirection
|
|
217
|
+
]);
|
|
218
|
+
useEffect(() => {
|
|
219
|
+
fetchData();
|
|
220
|
+
}, [fetchData]);
|
|
221
|
+
const stats = useMemo(() => {
|
|
222
|
+
if (!data)
|
|
223
|
+
return null;
|
|
224
|
+
const open = data.deals.filter((d) => d.status === "OPEN");
|
|
225
|
+
const won = data.deals.filter((d) => d.status === "WON");
|
|
226
|
+
const lost = data.deals.filter((d) => d.status === "LOST");
|
|
227
|
+
return {
|
|
228
|
+
total: data.total,
|
|
229
|
+
totalValue: data.totalValue,
|
|
230
|
+
openCount: open.length,
|
|
231
|
+
openValue: open.reduce((sum, d) => sum + d.value, 0),
|
|
232
|
+
wonCount: won.length,
|
|
233
|
+
wonValue: won.reduce((sum, d) => sum + d.value, 0),
|
|
234
|
+
lostCount: lost.length
|
|
235
|
+
};
|
|
236
|
+
}, [data]);
|
|
237
|
+
return {
|
|
238
|
+
data,
|
|
239
|
+
dealsByStage,
|
|
240
|
+
stages,
|
|
241
|
+
loading,
|
|
242
|
+
error,
|
|
243
|
+
stats,
|
|
244
|
+
page: pageIndex + 1,
|
|
245
|
+
pageIndex,
|
|
246
|
+
pageSize,
|
|
247
|
+
refetch: fetchData,
|
|
248
|
+
nextPage: options.pageIndex === undefined ? () => setInternalPage((page) => page + 1) : undefined,
|
|
249
|
+
prevPage: options.pageIndex === undefined ? () => pageIndex > 0 && setInternalPage((page) => page - 1) : undefined
|
|
250
|
+
};
|
|
251
|
+
}
|
|
252
|
+
|
|
242
253
|
// src/ui/renderers/pipeline.renderer.tsx
|
|
243
254
|
import { jsxDEV as jsxDEV3 } from "react/jsx-dev-runtime";
|
|
244
255
|
function CrmPipelineBoardWrapper() {
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { ContractTableSort } from '@contractspec/lib.presentation-runtime-core';
|
|
2
|
+
import { type Deal } from '../hooks/useDealList';
|
|
3
|
+
export interface DealListDataTableProps {
|
|
4
|
+
deals: Deal[];
|
|
5
|
+
totalItems: number;
|
|
6
|
+
pageIndex: number;
|
|
7
|
+
pageSize: number;
|
|
8
|
+
sorting: ContractTableSort[];
|
|
9
|
+
loading?: boolean;
|
|
10
|
+
onSortingChange: (sorting: ContractTableSort[]) => void;
|
|
11
|
+
onPaginationChange: (pagination: {
|
|
12
|
+
pageIndex: number;
|
|
13
|
+
pageSize: number;
|
|
14
|
+
}) => void;
|
|
15
|
+
onDealClick?: (dealId: string) => void;
|
|
16
|
+
}
|
|
17
|
+
export declare function DealListDataTable({ deals, totalItems, pageIndex, pageSize, sorting, loading, onSortingChange, onPaginationChange, onDealClick, }: DealListDataTableProps): import("react/jsx-runtime").JSX.Element;
|
|
18
|
+
export declare function DealListTab({ onDealClick, }: {
|
|
19
|
+
onDealClick?: (dealId: string) => void;
|
|
20
|
+
}): import("react/jsx-runtime").JSX.Element;
|