@contractspec/example.crm-pipeline 3.7.7 → 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/CHANGELOG.md +36 -0
- package/README.md +2 -1
- package/dist/browser/docs/crm-pipeline.docblock.js +1 -1
- package/dist/browser/docs/index.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 +392 -159
- package/dist/browser/ui/CrmDashboard.js +366 -144
- package/dist/browser/ui/hooks/index.js +19 -8
- package/dist/browser/ui/hooks/useDealList.js +19 -8
- package/dist/browser/ui/index.js +391 -158
- package/dist/browser/ui/renderers/index.js +32 -10
- package/dist/browser/ui/renderers/pipeline.markdown.js +13 -2
- package/dist/browser/ui/renderers/pipeline.renderer.js +19 -8
- package/dist/browser/ui/tables/DealListTab.js +390 -0
- package/dist/docs/crm-pipeline.docblock.js +1 -1
- package/dist/docs/index.js +1 -1
- package/dist/handlers/crm.handlers.d.ts +2 -0
- package/dist/handlers/crm.handlers.js +13 -2
- package/dist/handlers/index.js +13 -2
- package/dist/index.js +392 -159
- package/dist/node/docs/crm-pipeline.docblock.js +1 -1
- package/dist/node/docs/index.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 +392 -159
- package/dist/node/ui/CrmDashboard.js +366 -144
- package/dist/node/ui/hooks/index.js +19 -8
- package/dist/node/ui/hooks/useDealList.js +19 -8
- package/dist/node/ui/index.js +391 -158
- package/dist/node/ui/renderers/index.js +32 -10
- package/dist/node/ui/renderers/pipeline.markdown.js +13 -2
- package/dist/node/ui/renderers/pipeline.renderer.js +19 -8
- package/dist/node/ui/tables/DealListTab.js +390 -0
- package/dist/ui/CrmDashboard.js +366 -144
- package/dist/ui/hooks/index.js +19 -8
- package/dist/ui/hooks/useDealList.d.ts +8 -2
- package/dist/ui/hooks/useDealList.js +19 -8
- package/dist/ui/index.js +391 -158
- package/dist/ui/renderers/index.js +32 -10
- package/dist/ui/renderers/pipeline.markdown.js +13 -2
- package/dist/ui/renderers/pipeline.renderer.js +19 -8
- 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 +27 -12
- package/src/docs/crm-pipeline.docblock.ts +1 -1
- package/src/handlers/crm.handlers.ts +18 -1
- package/src/ui/CrmDashboard.tsx +2 -71
- package/src/ui/hooks/useDealList.ts +36 -8
- package/src/ui/tables/DealListTab.smoke.test.tsx +149 -0
- package/src/ui/tables/DealListTab.tsx +276 -0
package/dist/node/ui/index.js
CHANGED
|
@@ -22,6 +22,13 @@ function rowToDeal(row) {
|
|
|
22
22
|
updatedAt: new Date(row.updatedAt)
|
|
23
23
|
};
|
|
24
24
|
}
|
|
25
|
+
var DEAL_SORT_COLUMNS = {
|
|
26
|
+
name: "name",
|
|
27
|
+
value: "value",
|
|
28
|
+
status: "status",
|
|
29
|
+
expectedCloseDate: "expectedCloseDate",
|
|
30
|
+
updatedAt: "updatedAt"
|
|
31
|
+
};
|
|
25
32
|
function createCrmHandlers(db) {
|
|
26
33
|
async function listDeals(input) {
|
|
27
34
|
const {
|
|
@@ -32,7 +39,9 @@ function createCrmHandlers(db) {
|
|
|
32
39
|
ownerId,
|
|
33
40
|
search,
|
|
34
41
|
limit = 20,
|
|
35
|
-
offset = 0
|
|
42
|
+
offset = 0,
|
|
43
|
+
sortBy = "value",
|
|
44
|
+
sortDirection = "desc"
|
|
36
45
|
} = input;
|
|
37
46
|
let whereClause = "WHERE projectId = ?";
|
|
38
47
|
const params = [projectId];
|
|
@@ -60,7 +69,9 @@ function createCrmHandlers(db) {
|
|
|
60
69
|
const total = countResult[0]?.count ?? 0;
|
|
61
70
|
const valueResult = (await db.query(`SELECT COALESCE(SUM(value), 0) as total FROM crm_deal ${whereClause}`, params)).rows;
|
|
62
71
|
const totalValue = valueResult[0]?.total ?? 0;
|
|
63
|
-
const
|
|
72
|
+
const orderByColumn = DEAL_SORT_COLUMNS[sortBy] ?? DEAL_SORT_COLUMNS.value;
|
|
73
|
+
const orderByDirection = sortDirection === "asc" ? "ASC" : "DESC";
|
|
74
|
+
const dealRows = (await db.query(`SELECT * FROM crm_deal ${whereClause} ORDER BY ${orderByColumn} ${orderByDirection} LIMIT ? OFFSET ?`, [...params, limit, offset])).rows;
|
|
64
75
|
return {
|
|
65
76
|
deals: dealRows.map(rowToDeal),
|
|
66
77
|
total,
|
|
@@ -610,8 +621,13 @@ function useDealList(options = {}) {
|
|
|
610
621
|
const [stages, setStages] = useState2([]);
|
|
611
622
|
const [loading, setLoading] = useState2(true);
|
|
612
623
|
const [error, setError] = useState2(null);
|
|
613
|
-
const [
|
|
624
|
+
const [internalPage, setInternalPage] = useState2(0);
|
|
614
625
|
const pipelineId = options.pipelineId ?? "pipeline-1";
|
|
626
|
+
const pageIndex = options.pageIndex ?? internalPage;
|
|
627
|
+
const pageSize = options.pageSize ?? options.limit ?? 50;
|
|
628
|
+
const [sort] = options.sorting ?? [];
|
|
629
|
+
const sortBy = sort?.id;
|
|
630
|
+
const sortDirection = sort ? sort.desc ? "desc" : "asc" : undefined;
|
|
615
631
|
const fetchData = useCallback(async () => {
|
|
616
632
|
setLoading(true);
|
|
617
633
|
setError(null);
|
|
@@ -623,8 +639,10 @@ function useDealList(options = {}) {
|
|
|
623
639
|
stageId: options.stageId,
|
|
624
640
|
status: options.status === "all" ? undefined : options.status,
|
|
625
641
|
search: options.search,
|
|
626
|
-
limit:
|
|
627
|
-
offset:
|
|
642
|
+
limit: pageSize,
|
|
643
|
+
offset: pageIndex * pageSize,
|
|
644
|
+
sortBy: sortBy === "name" || sortBy === "value" || sortBy === "status" || sortBy === "expectedCloseDate" || sortBy === "updatedAt" ? sortBy : undefined,
|
|
645
|
+
sortDirection
|
|
628
646
|
}),
|
|
629
647
|
crm2.getDealsByStage({ projectId, pipelineId }),
|
|
630
648
|
crm2.getPipelineStages({ pipelineId })
|
|
@@ -644,8 +662,10 @@ function useDealList(options = {}) {
|
|
|
644
662
|
options.stageId,
|
|
645
663
|
options.status,
|
|
646
664
|
options.search,
|
|
647
|
-
|
|
648
|
-
|
|
665
|
+
pageIndex,
|
|
666
|
+
pageSize,
|
|
667
|
+
sortBy,
|
|
668
|
+
sortDirection
|
|
649
669
|
]);
|
|
650
670
|
useEffect(() => {
|
|
651
671
|
fetchData();
|
|
@@ -673,10 +693,12 @@ function useDealList(options = {}) {
|
|
|
673
693
|
loading,
|
|
674
694
|
error,
|
|
675
695
|
stats,
|
|
676
|
-
page,
|
|
696
|
+
page: pageIndex + 1,
|
|
697
|
+
pageIndex,
|
|
698
|
+
pageSize,
|
|
677
699
|
refetch: fetchData,
|
|
678
|
-
nextPage: () =>
|
|
679
|
-
prevPage: () =>
|
|
700
|
+
nextPage: options.pageIndex === undefined ? () => setInternalPage((page) => page + 1) : undefined,
|
|
701
|
+
prevPage: options.pageIndex === undefined ? () => pageIndex > 0 && setInternalPage((page) => page - 1) : undefined
|
|
680
702
|
};
|
|
681
703
|
}
|
|
682
704
|
|
|
@@ -1413,11 +1435,305 @@ function DealActionsModal({
|
|
|
1413
1435
|
}, undefined, true, undefined, this);
|
|
1414
1436
|
}
|
|
1415
1437
|
|
|
1416
|
-
// src/ui/
|
|
1438
|
+
// src/ui/tables/DealListTab.tsx
|
|
1417
1439
|
import {
|
|
1418
1440
|
Button as Button3,
|
|
1441
|
+
DataTable,
|
|
1442
|
+
LoaderBlock
|
|
1443
|
+
} from "@contractspec/lib.design-system";
|
|
1444
|
+
import { useContractTable } from "@contractspec/lib.presentation-runtime-react";
|
|
1445
|
+
import { Badge } from "@contractspec/lib.ui-kit-web/ui/badge";
|
|
1446
|
+
import { HStack, VStack } from "@contractspec/lib.ui-kit-web/ui/stack";
|
|
1447
|
+
import { Text } from "@contractspec/lib.ui-kit-web/ui/text";
|
|
1448
|
+
import * as React from "react";
|
|
1449
|
+
import { jsxDEV as jsxDEV5 } from "react/jsx-dev-runtime";
|
|
1450
|
+
"use client";
|
|
1451
|
+
function formatCurrency4(value, currency = "USD") {
|
|
1452
|
+
return new Intl.NumberFormat("en-US", {
|
|
1453
|
+
style: "currency",
|
|
1454
|
+
currency,
|
|
1455
|
+
minimumFractionDigits: 0,
|
|
1456
|
+
maximumFractionDigits: 0
|
|
1457
|
+
}).format(value);
|
|
1458
|
+
}
|
|
1459
|
+
function statusVariant(status) {
|
|
1460
|
+
switch (status) {
|
|
1461
|
+
case "WON":
|
|
1462
|
+
return "default";
|
|
1463
|
+
case "LOST":
|
|
1464
|
+
return "destructive";
|
|
1465
|
+
case "STALE":
|
|
1466
|
+
return "outline";
|
|
1467
|
+
default:
|
|
1468
|
+
return "secondary";
|
|
1469
|
+
}
|
|
1470
|
+
}
|
|
1471
|
+
function DealListDataTable({
|
|
1472
|
+
deals,
|
|
1473
|
+
totalItems,
|
|
1474
|
+
pageIndex,
|
|
1475
|
+
pageSize,
|
|
1476
|
+
sorting,
|
|
1477
|
+
loading,
|
|
1478
|
+
onSortingChange,
|
|
1479
|
+
onPaginationChange,
|
|
1480
|
+
onDealClick
|
|
1481
|
+
}) {
|
|
1482
|
+
const controller = useContractTable({
|
|
1483
|
+
data: deals,
|
|
1484
|
+
columns: [
|
|
1485
|
+
{
|
|
1486
|
+
id: "deal",
|
|
1487
|
+
header: "Deal",
|
|
1488
|
+
label: "Deal",
|
|
1489
|
+
accessor: (deal) => deal.name,
|
|
1490
|
+
cell: ({ item }) => /* @__PURE__ */ jsxDEV5(VStack, {
|
|
1491
|
+
gap: "xs",
|
|
1492
|
+
children: [
|
|
1493
|
+
/* @__PURE__ */ jsxDEV5(Text, {
|
|
1494
|
+
className: "font-medium text-sm",
|
|
1495
|
+
children: item.name
|
|
1496
|
+
}, undefined, false, undefined, this),
|
|
1497
|
+
/* @__PURE__ */ jsxDEV5(Text, {
|
|
1498
|
+
className: "text-muted-foreground text-xs",
|
|
1499
|
+
children: item.companyId ?? "Unassigned company"
|
|
1500
|
+
}, undefined, false, undefined, this)
|
|
1501
|
+
]
|
|
1502
|
+
}, undefined, true, undefined, this),
|
|
1503
|
+
size: 240,
|
|
1504
|
+
minSize: 180,
|
|
1505
|
+
canSort: true,
|
|
1506
|
+
canPin: true,
|
|
1507
|
+
canResize: true
|
|
1508
|
+
},
|
|
1509
|
+
{
|
|
1510
|
+
id: "value",
|
|
1511
|
+
header: "Value",
|
|
1512
|
+
label: "Value",
|
|
1513
|
+
accessorKey: "value",
|
|
1514
|
+
cell: ({ item }) => formatCurrency4(item.value, item.currency),
|
|
1515
|
+
align: "right",
|
|
1516
|
+
size: 140,
|
|
1517
|
+
canSort: true,
|
|
1518
|
+
canResize: true
|
|
1519
|
+
},
|
|
1520
|
+
{
|
|
1521
|
+
id: "status",
|
|
1522
|
+
header: "Status",
|
|
1523
|
+
label: "Status",
|
|
1524
|
+
accessorKey: "status",
|
|
1525
|
+
cell: ({ value }) => /* @__PURE__ */ jsxDEV5(Badge, {
|
|
1526
|
+
variant: statusVariant(value),
|
|
1527
|
+
children: String(value)
|
|
1528
|
+
}, undefined, false, undefined, this),
|
|
1529
|
+
size: 130,
|
|
1530
|
+
canSort: true,
|
|
1531
|
+
canHide: true,
|
|
1532
|
+
canPin: true,
|
|
1533
|
+
canResize: true
|
|
1534
|
+
},
|
|
1535
|
+
{
|
|
1536
|
+
id: "expectedCloseDate",
|
|
1537
|
+
header: "Expected Close",
|
|
1538
|
+
label: "Expected Close",
|
|
1539
|
+
accessor: (deal) => deal.expectedCloseDate?.toISOString() ?? "",
|
|
1540
|
+
cell: ({ item }) => item.expectedCloseDate?.toLocaleDateString() ?? "Not scheduled",
|
|
1541
|
+
size: 170,
|
|
1542
|
+
canSort: true,
|
|
1543
|
+
canHide: true,
|
|
1544
|
+
canResize: true
|
|
1545
|
+
},
|
|
1546
|
+
{
|
|
1547
|
+
id: "updatedAt",
|
|
1548
|
+
header: "Updated",
|
|
1549
|
+
label: "Updated",
|
|
1550
|
+
accessor: (deal) => deal.updatedAt.toISOString(),
|
|
1551
|
+
cell: ({ item }) => item.updatedAt.toLocaleDateString(),
|
|
1552
|
+
size: 140,
|
|
1553
|
+
canSort: true,
|
|
1554
|
+
canHide: true,
|
|
1555
|
+
canResize: true
|
|
1556
|
+
},
|
|
1557
|
+
{
|
|
1558
|
+
id: "actions",
|
|
1559
|
+
header: "Actions",
|
|
1560
|
+
label: "Actions",
|
|
1561
|
+
accessor: (deal) => deal.id,
|
|
1562
|
+
cell: ({ item }) => /* @__PURE__ */ jsxDEV5(Button3, {
|
|
1563
|
+
variant: "ghost",
|
|
1564
|
+
size: "sm",
|
|
1565
|
+
onPress: () => onDealClick?.(item.id),
|
|
1566
|
+
children: "Actions"
|
|
1567
|
+
}, undefined, false, undefined, this),
|
|
1568
|
+
size: 120,
|
|
1569
|
+
canSort: false,
|
|
1570
|
+
canHide: false,
|
|
1571
|
+
canPin: false,
|
|
1572
|
+
canResize: false
|
|
1573
|
+
}
|
|
1574
|
+
],
|
|
1575
|
+
executionMode: "server",
|
|
1576
|
+
selectionMode: "multiple",
|
|
1577
|
+
totalItems,
|
|
1578
|
+
state: {
|
|
1579
|
+
sorting,
|
|
1580
|
+
pagination: {
|
|
1581
|
+
pageIndex,
|
|
1582
|
+
pageSize
|
|
1583
|
+
}
|
|
1584
|
+
},
|
|
1585
|
+
onSortingChange,
|
|
1586
|
+
onPaginationChange,
|
|
1587
|
+
initialState: {
|
|
1588
|
+
columnVisibility: { updatedAt: false },
|
|
1589
|
+
columnPinning: { left: ["deal", "status"], right: [] }
|
|
1590
|
+
},
|
|
1591
|
+
renderExpandedContent: (deal) => /* @__PURE__ */ jsxDEV5(VStack, {
|
|
1592
|
+
gap: "sm",
|
|
1593
|
+
className: "py-2",
|
|
1594
|
+
children: [
|
|
1595
|
+
/* @__PURE__ */ jsxDEV5(HStack, {
|
|
1596
|
+
justify: "between",
|
|
1597
|
+
children: [
|
|
1598
|
+
/* @__PURE__ */ jsxDEV5(Text, {
|
|
1599
|
+
className: "font-medium text-sm",
|
|
1600
|
+
children: "Owner"
|
|
1601
|
+
}, undefined, false, undefined, this),
|
|
1602
|
+
/* @__PURE__ */ jsxDEV5(Text, {
|
|
1603
|
+
className: "text-muted-foreground text-sm",
|
|
1604
|
+
children: deal.ownerId
|
|
1605
|
+
}, undefined, false, undefined, this)
|
|
1606
|
+
]
|
|
1607
|
+
}, undefined, true, undefined, this),
|
|
1608
|
+
/* @__PURE__ */ jsxDEV5(HStack, {
|
|
1609
|
+
justify: "between",
|
|
1610
|
+
children: [
|
|
1611
|
+
/* @__PURE__ */ jsxDEV5(Text, {
|
|
1612
|
+
className: "font-medium text-sm",
|
|
1613
|
+
children: "Contact"
|
|
1614
|
+
}, undefined, false, undefined, this),
|
|
1615
|
+
/* @__PURE__ */ jsxDEV5(Text, {
|
|
1616
|
+
className: "text-muted-foreground text-sm",
|
|
1617
|
+
children: deal.contactId ?? "No linked contact"
|
|
1618
|
+
}, undefined, false, undefined, this)
|
|
1619
|
+
]
|
|
1620
|
+
}, undefined, true, undefined, this),
|
|
1621
|
+
deal.wonSource ? /* @__PURE__ */ jsxDEV5(HStack, {
|
|
1622
|
+
justify: "between",
|
|
1623
|
+
children: [
|
|
1624
|
+
/* @__PURE__ */ jsxDEV5(Text, {
|
|
1625
|
+
className: "font-medium text-sm",
|
|
1626
|
+
children: "Won Source"
|
|
1627
|
+
}, undefined, false, undefined, this),
|
|
1628
|
+
/* @__PURE__ */ jsxDEV5(Text, {
|
|
1629
|
+
className: "text-muted-foreground text-sm",
|
|
1630
|
+
children: deal.wonSource
|
|
1631
|
+
}, undefined, false, undefined, this)
|
|
1632
|
+
]
|
|
1633
|
+
}, undefined, true, undefined, this) : null,
|
|
1634
|
+
deal.lostReason ? /* @__PURE__ */ jsxDEV5(HStack, {
|
|
1635
|
+
justify: "between",
|
|
1636
|
+
children: [
|
|
1637
|
+
/* @__PURE__ */ jsxDEV5(Text, {
|
|
1638
|
+
className: "font-medium text-sm",
|
|
1639
|
+
children: "Lost Reason"
|
|
1640
|
+
}, undefined, false, undefined, this),
|
|
1641
|
+
/* @__PURE__ */ jsxDEV5(Text, {
|
|
1642
|
+
className: "text-muted-foreground text-sm",
|
|
1643
|
+
children: deal.lostReason
|
|
1644
|
+
}, undefined, false, undefined, this)
|
|
1645
|
+
]
|
|
1646
|
+
}, undefined, true, undefined, this) : null,
|
|
1647
|
+
deal.notes ? /* @__PURE__ */ jsxDEV5(VStack, {
|
|
1648
|
+
gap: "xs",
|
|
1649
|
+
children: [
|
|
1650
|
+
/* @__PURE__ */ jsxDEV5(Text, {
|
|
1651
|
+
className: "font-medium text-sm",
|
|
1652
|
+
children: "Notes"
|
|
1653
|
+
}, undefined, false, undefined, this),
|
|
1654
|
+
/* @__PURE__ */ jsxDEV5(Text, {
|
|
1655
|
+
className: "text-muted-foreground text-sm",
|
|
1656
|
+
children: deal.notes
|
|
1657
|
+
}, undefined, false, undefined, this)
|
|
1658
|
+
]
|
|
1659
|
+
}, undefined, true, undefined, this) : null
|
|
1660
|
+
]
|
|
1661
|
+
}, undefined, true, undefined, this),
|
|
1662
|
+
getCanExpand: () => true
|
|
1663
|
+
});
|
|
1664
|
+
return /* @__PURE__ */ jsxDEV5(DataTable, {
|
|
1665
|
+
controller,
|
|
1666
|
+
title: "All Deals",
|
|
1667
|
+
description: "Server-mode table using the shared ContractSpec controller.",
|
|
1668
|
+
loading,
|
|
1669
|
+
toolbar: /* @__PURE__ */ jsxDEV5(HStack, {
|
|
1670
|
+
gap: "sm",
|
|
1671
|
+
className: "flex-wrap",
|
|
1672
|
+
children: [
|
|
1673
|
+
/* @__PURE__ */ jsxDEV5(Text, {
|
|
1674
|
+
className: "text-muted-foreground text-sm",
|
|
1675
|
+
children: [
|
|
1676
|
+
"Selected ",
|
|
1677
|
+
controller.selectedRowIds.length
|
|
1678
|
+
]
|
|
1679
|
+
}, undefined, true, undefined, this),
|
|
1680
|
+
/* @__PURE__ */ jsxDEV5(Text, {
|
|
1681
|
+
className: "text-muted-foreground text-sm",
|
|
1682
|
+
children: [
|
|
1683
|
+
totalItems,
|
|
1684
|
+
" total deals"
|
|
1685
|
+
]
|
|
1686
|
+
}, undefined, true, undefined, this)
|
|
1687
|
+
]
|
|
1688
|
+
}, undefined, true, undefined, this),
|
|
1689
|
+
footer: `Page ${controller.pageIndex + 1} of ${controller.pageCount}`,
|
|
1690
|
+
emptyState: /* @__PURE__ */ jsxDEV5("div", {
|
|
1691
|
+
className: "rounded-md border border-dashed p-8 text-center text-muted-foreground text-sm",
|
|
1692
|
+
children: "No deals found"
|
|
1693
|
+
}, undefined, false, undefined, this)
|
|
1694
|
+
}, undefined, false, undefined, this);
|
|
1695
|
+
}
|
|
1696
|
+
function DealListTab({
|
|
1697
|
+
onDealClick
|
|
1698
|
+
}) {
|
|
1699
|
+
const [sorting, setSorting] = React.useState([
|
|
1700
|
+
{ id: "value", desc: true }
|
|
1701
|
+
]);
|
|
1702
|
+
const [pagination, setPagination] = React.useState({
|
|
1703
|
+
pageIndex: 0,
|
|
1704
|
+
pageSize: 3
|
|
1705
|
+
});
|
|
1706
|
+
const { data, loading } = useDealList({
|
|
1707
|
+
pageIndex: pagination.pageIndex,
|
|
1708
|
+
pageSize: pagination.pageSize,
|
|
1709
|
+
sorting
|
|
1710
|
+
});
|
|
1711
|
+
if (loading && !data) {
|
|
1712
|
+
return /* @__PURE__ */ jsxDEV5(LoaderBlock, {
|
|
1713
|
+
label: "Loading deals..."
|
|
1714
|
+
}, undefined, false, undefined, this);
|
|
1715
|
+
}
|
|
1716
|
+
return /* @__PURE__ */ jsxDEV5(DealListDataTable, {
|
|
1717
|
+
deals: data?.deals ?? [],
|
|
1718
|
+
totalItems: data?.total ?? 0,
|
|
1719
|
+
pageIndex: pagination.pageIndex,
|
|
1720
|
+
pageSize: pagination.pageSize,
|
|
1721
|
+
sorting,
|
|
1722
|
+
loading,
|
|
1723
|
+
onSortingChange: (nextSorting) => {
|
|
1724
|
+
setSorting(nextSorting);
|
|
1725
|
+
setPagination((current) => ({ ...current, pageIndex: 0 }));
|
|
1726
|
+
},
|
|
1727
|
+
onPaginationChange: setPagination,
|
|
1728
|
+
onDealClick
|
|
1729
|
+
}, undefined, false, undefined, this);
|
|
1730
|
+
}
|
|
1731
|
+
|
|
1732
|
+
// src/ui/CrmDashboard.tsx
|
|
1733
|
+
import {
|
|
1734
|
+
Button as Button4,
|
|
1419
1735
|
ErrorState,
|
|
1420
|
-
LoaderBlock,
|
|
1736
|
+
LoaderBlock as LoaderBlock2,
|
|
1421
1737
|
StatCard,
|
|
1422
1738
|
StatCardGroup
|
|
1423
1739
|
} from "@contractspec/lib.design-system";
|
|
@@ -1427,10 +1743,10 @@ import {
|
|
|
1427
1743
|
TabsList,
|
|
1428
1744
|
TabsTrigger
|
|
1429
1745
|
} from "@contractspec/lib.ui-kit-web/ui/tabs";
|
|
1430
|
-
import { useCallback as useCallback3, useState as
|
|
1431
|
-
import { jsxDEV as
|
|
1746
|
+
import { useCallback as useCallback3, useState as useState7 } from "react";
|
|
1747
|
+
import { jsxDEV as jsxDEV6 } from "react/jsx-dev-runtime";
|
|
1432
1748
|
"use client";
|
|
1433
|
-
function
|
|
1749
|
+
function formatCurrency5(value, currency = "USD") {
|
|
1434
1750
|
return new Intl.NumberFormat("en-US", {
|
|
1435
1751
|
style: "currency",
|
|
1436
1752
|
currency,
|
|
@@ -1439,9 +1755,9 @@ function formatCurrency4(value, currency = "USD") {
|
|
|
1439
1755
|
}).format(value);
|
|
1440
1756
|
}
|
|
1441
1757
|
function CrmDashboard() {
|
|
1442
|
-
const [isCreateModalOpen, setIsCreateModalOpen] =
|
|
1443
|
-
const [selectedDeal, setSelectedDeal] =
|
|
1444
|
-
const [isDealActionsOpen, setIsDealActionsOpen] =
|
|
1758
|
+
const [isCreateModalOpen, setIsCreateModalOpen] = useState7(false);
|
|
1759
|
+
const [selectedDeal, setSelectedDeal] = useState7(null);
|
|
1760
|
+
const [isDealActionsOpen, setIsDealActionsOpen] = useState7(false);
|
|
1445
1761
|
const { data, dealsByStage, stages, loading, error, stats, refetch } = useDealList();
|
|
1446
1762
|
const mutations = useDealMutations({
|
|
1447
1763
|
onSuccess: () => {
|
|
@@ -1459,32 +1775,32 @@ function CrmDashboard() {
|
|
|
1459
1775
|
await mutations.moveDeal({ dealId, stageId: toStageId });
|
|
1460
1776
|
}, [mutations]);
|
|
1461
1777
|
if (loading && !data) {
|
|
1462
|
-
return /* @__PURE__ */
|
|
1778
|
+
return /* @__PURE__ */ jsxDEV6(LoaderBlock2, {
|
|
1463
1779
|
label: "Loading CRM..."
|
|
1464
1780
|
}, undefined, false, undefined, this);
|
|
1465
1781
|
}
|
|
1466
1782
|
if (error) {
|
|
1467
|
-
return /* @__PURE__ */
|
|
1783
|
+
return /* @__PURE__ */ jsxDEV6(ErrorState, {
|
|
1468
1784
|
title: "Failed to load CRM",
|
|
1469
1785
|
description: error.message,
|
|
1470
1786
|
onRetry: refetch,
|
|
1471
1787
|
retryLabel: "Retry"
|
|
1472
1788
|
}, undefined, false, undefined, this);
|
|
1473
1789
|
}
|
|
1474
|
-
return /* @__PURE__ */
|
|
1790
|
+
return /* @__PURE__ */ jsxDEV6("div", {
|
|
1475
1791
|
className: "space-y-6",
|
|
1476
1792
|
children: [
|
|
1477
|
-
/* @__PURE__ */
|
|
1793
|
+
/* @__PURE__ */ jsxDEV6("div", {
|
|
1478
1794
|
className: "flex items-center justify-between",
|
|
1479
1795
|
children: [
|
|
1480
|
-
/* @__PURE__ */
|
|
1796
|
+
/* @__PURE__ */ jsxDEV6("h2", {
|
|
1481
1797
|
className: "font-bold text-2xl",
|
|
1482
1798
|
children: "CRM Pipeline"
|
|
1483
1799
|
}, undefined, false, undefined, this),
|
|
1484
|
-
/* @__PURE__ */
|
|
1800
|
+
/* @__PURE__ */ jsxDEV6(Button4, {
|
|
1485
1801
|
onClick: () => setIsCreateModalOpen(true),
|
|
1486
1802
|
children: [
|
|
1487
|
-
/* @__PURE__ */
|
|
1803
|
+
/* @__PURE__ */ jsxDEV6("span", {
|
|
1488
1804
|
className: "mr-2",
|
|
1489
1805
|
children: "+"
|
|
1490
1806
|
}, undefined, false, undefined, this),
|
|
@@ -1493,60 +1809,60 @@ function CrmDashboard() {
|
|
|
1493
1809
|
}, undefined, true, undefined, this)
|
|
1494
1810
|
]
|
|
1495
1811
|
}, undefined, true, undefined, this),
|
|
1496
|
-
stats && /* @__PURE__ */
|
|
1812
|
+
stats && /* @__PURE__ */ jsxDEV6(StatCardGroup, {
|
|
1497
1813
|
children: [
|
|
1498
|
-
/* @__PURE__ */
|
|
1814
|
+
/* @__PURE__ */ jsxDEV6(StatCard, {
|
|
1499
1815
|
label: "Total Pipeline",
|
|
1500
|
-
value:
|
|
1816
|
+
value: formatCurrency5(stats.totalValue),
|
|
1501
1817
|
hint: `${stats.total} deals`
|
|
1502
1818
|
}, undefined, false, undefined, this),
|
|
1503
|
-
/* @__PURE__ */
|
|
1819
|
+
/* @__PURE__ */ jsxDEV6(StatCard, {
|
|
1504
1820
|
label: "Open Deals",
|
|
1505
|
-
value:
|
|
1821
|
+
value: formatCurrency5(stats.openValue),
|
|
1506
1822
|
hint: `${stats.openCount} active`
|
|
1507
1823
|
}, undefined, false, undefined, this),
|
|
1508
|
-
/* @__PURE__ */
|
|
1824
|
+
/* @__PURE__ */ jsxDEV6(StatCard, {
|
|
1509
1825
|
label: "Won",
|
|
1510
|
-
value:
|
|
1826
|
+
value: formatCurrency5(stats.wonValue),
|
|
1511
1827
|
hint: `${stats.wonCount} closed`
|
|
1512
1828
|
}, undefined, false, undefined, this),
|
|
1513
|
-
/* @__PURE__ */
|
|
1829
|
+
/* @__PURE__ */ jsxDEV6(StatCard, {
|
|
1514
1830
|
label: "Lost",
|
|
1515
1831
|
value: stats.lostCount,
|
|
1516
1832
|
hint: "deals lost"
|
|
1517
1833
|
}, undefined, false, undefined, this)
|
|
1518
1834
|
]
|
|
1519
1835
|
}, undefined, true, undefined, this),
|
|
1520
|
-
/* @__PURE__ */
|
|
1836
|
+
/* @__PURE__ */ jsxDEV6(Tabs, {
|
|
1521
1837
|
defaultValue: "pipeline",
|
|
1522
1838
|
className: "w-full",
|
|
1523
1839
|
children: [
|
|
1524
|
-
/* @__PURE__ */
|
|
1840
|
+
/* @__PURE__ */ jsxDEV6(TabsList, {
|
|
1525
1841
|
children: [
|
|
1526
|
-
/* @__PURE__ */
|
|
1842
|
+
/* @__PURE__ */ jsxDEV6(TabsTrigger, {
|
|
1527
1843
|
value: "pipeline",
|
|
1528
1844
|
children: [
|
|
1529
|
-
/* @__PURE__ */
|
|
1845
|
+
/* @__PURE__ */ jsxDEV6("span", {
|
|
1530
1846
|
className: "mr-2",
|
|
1531
1847
|
children: "\uD83D\uDCCA"
|
|
1532
1848
|
}, undefined, false, undefined, this),
|
|
1533
1849
|
"Pipeline"
|
|
1534
1850
|
]
|
|
1535
1851
|
}, undefined, true, undefined, this),
|
|
1536
|
-
/* @__PURE__ */
|
|
1852
|
+
/* @__PURE__ */ jsxDEV6(TabsTrigger, {
|
|
1537
1853
|
value: "list",
|
|
1538
1854
|
children: [
|
|
1539
|
-
/* @__PURE__ */
|
|
1855
|
+
/* @__PURE__ */ jsxDEV6("span", {
|
|
1540
1856
|
className: "mr-2",
|
|
1541
1857
|
children: "\uD83D\uDCCB"
|
|
1542
1858
|
}, undefined, false, undefined, this),
|
|
1543
1859
|
"All Deals"
|
|
1544
1860
|
]
|
|
1545
1861
|
}, undefined, true, undefined, this),
|
|
1546
|
-
/* @__PURE__ */
|
|
1862
|
+
/* @__PURE__ */ jsxDEV6(TabsTrigger, {
|
|
1547
1863
|
value: "metrics",
|
|
1548
1864
|
children: [
|
|
1549
|
-
/* @__PURE__ */
|
|
1865
|
+
/* @__PURE__ */ jsxDEV6("span", {
|
|
1550
1866
|
className: "mr-2",
|
|
1551
1867
|
children: "\uD83D\uDCC8"
|
|
1552
1868
|
}, undefined, false, undefined, this),
|
|
@@ -1555,34 +1871,33 @@ function CrmDashboard() {
|
|
|
1555
1871
|
}, undefined, true, undefined, this)
|
|
1556
1872
|
]
|
|
1557
1873
|
}, undefined, true, undefined, this),
|
|
1558
|
-
/* @__PURE__ */
|
|
1874
|
+
/* @__PURE__ */ jsxDEV6(TabsContent, {
|
|
1559
1875
|
value: "pipeline",
|
|
1560
1876
|
className: "min-h-[400px]",
|
|
1561
|
-
children: /* @__PURE__ */
|
|
1877
|
+
children: /* @__PURE__ */ jsxDEV6(CrmPipelineBoard, {
|
|
1562
1878
|
dealsByStage,
|
|
1563
1879
|
stages,
|
|
1564
1880
|
onDealClick: handleDealClick,
|
|
1565
1881
|
onDealMove: handleDealMove
|
|
1566
1882
|
}, undefined, false, undefined, this)
|
|
1567
1883
|
}, undefined, false, undefined, this),
|
|
1568
|
-
/* @__PURE__ */
|
|
1884
|
+
/* @__PURE__ */ jsxDEV6(TabsContent, {
|
|
1569
1885
|
value: "list",
|
|
1570
1886
|
className: "min-h-[400px]",
|
|
1571
|
-
children: /* @__PURE__ */
|
|
1572
|
-
data,
|
|
1887
|
+
children: /* @__PURE__ */ jsxDEV6(DealListTab, {
|
|
1573
1888
|
onDealClick: handleDealClick
|
|
1574
1889
|
}, undefined, false, undefined, this)
|
|
1575
1890
|
}, undefined, false, undefined, this),
|
|
1576
|
-
/* @__PURE__ */
|
|
1891
|
+
/* @__PURE__ */ jsxDEV6(TabsContent, {
|
|
1577
1892
|
value: "metrics",
|
|
1578
1893
|
className: "min-h-[400px]",
|
|
1579
|
-
children: /* @__PURE__ */
|
|
1894
|
+
children: /* @__PURE__ */ jsxDEV6(MetricsTab, {
|
|
1580
1895
|
stats
|
|
1581
1896
|
}, undefined, false, undefined, this)
|
|
1582
1897
|
}, undefined, false, undefined, this)
|
|
1583
1898
|
]
|
|
1584
1899
|
}, undefined, true, undefined, this),
|
|
1585
|
-
/* @__PURE__ */
|
|
1900
|
+
/* @__PURE__ */ jsxDEV6(CreateDealModal, {
|
|
1586
1901
|
isOpen: isCreateModalOpen,
|
|
1587
1902
|
onClose: () => setIsCreateModalOpen(false),
|
|
1588
1903
|
onSubmit: async (input) => {
|
|
@@ -1591,7 +1906,7 @@ function CrmDashboard() {
|
|
|
1591
1906
|
stages,
|
|
1592
1907
|
isLoading: mutations.createState.loading
|
|
1593
1908
|
}, undefined, false, undefined, this),
|
|
1594
|
-
/* @__PURE__ */
|
|
1909
|
+
/* @__PURE__ */ jsxDEV6(DealActionsModal, {
|
|
1595
1910
|
isOpen: isDealActionsOpen,
|
|
1596
1911
|
deal: selectedDeal,
|
|
1597
1912
|
stages,
|
|
@@ -1614,112 +1929,30 @@ function CrmDashboard() {
|
|
|
1614
1929
|
]
|
|
1615
1930
|
}, undefined, true, undefined, this);
|
|
1616
1931
|
}
|
|
1617
|
-
function DealListTab({ data, onDealClick }) {
|
|
1618
|
-
if (!data?.deals.length) {
|
|
1619
|
-
return /* @__PURE__ */ jsxDEV5("div", {
|
|
1620
|
-
className: "flex h-64 items-center justify-center text-muted-foreground",
|
|
1621
|
-
children: "No deals found"
|
|
1622
|
-
}, undefined, false, undefined, this);
|
|
1623
|
-
}
|
|
1624
|
-
return /* @__PURE__ */ jsxDEV5("div", {
|
|
1625
|
-
className: "rounded-lg border border-border",
|
|
1626
|
-
children: /* @__PURE__ */ jsxDEV5("table", {
|
|
1627
|
-
className: "w-full",
|
|
1628
|
-
children: [
|
|
1629
|
-
/* @__PURE__ */ jsxDEV5("thead", {
|
|
1630
|
-
className: "border-border border-b bg-muted/30",
|
|
1631
|
-
children: /* @__PURE__ */ jsxDEV5("tr", {
|
|
1632
|
-
children: [
|
|
1633
|
-
/* @__PURE__ */ jsxDEV5("th", {
|
|
1634
|
-
className: "px-4 py-3 text-left font-medium text-sm",
|
|
1635
|
-
children: "Deal"
|
|
1636
|
-
}, undefined, false, undefined, this),
|
|
1637
|
-
/* @__PURE__ */ jsxDEV5("th", {
|
|
1638
|
-
className: "px-4 py-3 text-left font-medium text-sm",
|
|
1639
|
-
children: "Value"
|
|
1640
|
-
}, undefined, false, undefined, this),
|
|
1641
|
-
/* @__PURE__ */ jsxDEV5("th", {
|
|
1642
|
-
className: "px-4 py-3 text-left font-medium text-sm",
|
|
1643
|
-
children: "Status"
|
|
1644
|
-
}, undefined, false, undefined, this),
|
|
1645
|
-
/* @__PURE__ */ jsxDEV5("th", {
|
|
1646
|
-
className: "px-4 py-3 text-left font-medium text-sm",
|
|
1647
|
-
children: "Expected Close"
|
|
1648
|
-
}, undefined, false, undefined, this),
|
|
1649
|
-
/* @__PURE__ */ jsxDEV5("th", {
|
|
1650
|
-
className: "px-4 py-3 text-left font-medium text-sm",
|
|
1651
|
-
children: "Actions"
|
|
1652
|
-
}, undefined, false, undefined, this)
|
|
1653
|
-
]
|
|
1654
|
-
}, undefined, true, undefined, this)
|
|
1655
|
-
}, undefined, false, undefined, this),
|
|
1656
|
-
/* @__PURE__ */ jsxDEV5("tbody", {
|
|
1657
|
-
className: "divide-y divide-border",
|
|
1658
|
-
children: data.deals.map((deal) => /* @__PURE__ */ jsxDEV5("tr", {
|
|
1659
|
-
className: "hover:bg-muted/50",
|
|
1660
|
-
children: [
|
|
1661
|
-
/* @__PURE__ */ jsxDEV5("td", {
|
|
1662
|
-
className: "px-4 py-3",
|
|
1663
|
-
children: /* @__PURE__ */ jsxDEV5("div", {
|
|
1664
|
-
className: "font-medium",
|
|
1665
|
-
children: deal.name
|
|
1666
|
-
}, undefined, false, undefined, this)
|
|
1667
|
-
}, undefined, false, undefined, this),
|
|
1668
|
-
/* @__PURE__ */ jsxDEV5("td", {
|
|
1669
|
-
className: "px-4 py-3 font-mono",
|
|
1670
|
-
children: formatCurrency4(deal.value, deal.currency)
|
|
1671
|
-
}, undefined, false, undefined, this),
|
|
1672
|
-
/* @__PURE__ */ jsxDEV5("td", {
|
|
1673
|
-
className: "px-4 py-3",
|
|
1674
|
-
children: /* @__PURE__ */ jsxDEV5("span", {
|
|
1675
|
-
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"}`,
|
|
1676
|
-
children: deal.status
|
|
1677
|
-
}, undefined, false, undefined, this)
|
|
1678
|
-
}, undefined, false, undefined, this),
|
|
1679
|
-
/* @__PURE__ */ jsxDEV5("td", {
|
|
1680
|
-
className: "px-4 py-3 text-muted-foreground",
|
|
1681
|
-
children: deal.expectedCloseDate?.toLocaleDateString() ?? "-"
|
|
1682
|
-
}, undefined, false, undefined, this),
|
|
1683
|
-
/* @__PURE__ */ jsxDEV5("td", {
|
|
1684
|
-
className: "px-4 py-3",
|
|
1685
|
-
children: /* @__PURE__ */ jsxDEV5(Button3, {
|
|
1686
|
-
variant: "ghost",
|
|
1687
|
-
size: "sm",
|
|
1688
|
-
onPress: () => onDealClick?.(deal.id),
|
|
1689
|
-
children: "Actions"
|
|
1690
|
-
}, undefined, false, undefined, this)
|
|
1691
|
-
}, undefined, false, undefined, this)
|
|
1692
|
-
]
|
|
1693
|
-
}, deal.id, true, undefined, this))
|
|
1694
|
-
}, undefined, false, undefined, this)
|
|
1695
|
-
]
|
|
1696
|
-
}, undefined, true, undefined, this)
|
|
1697
|
-
}, undefined, false, undefined, this);
|
|
1698
|
-
}
|
|
1699
1932
|
function MetricsTab({
|
|
1700
1933
|
stats
|
|
1701
1934
|
}) {
|
|
1702
1935
|
if (!stats)
|
|
1703
1936
|
return null;
|
|
1704
|
-
return /* @__PURE__ */
|
|
1937
|
+
return /* @__PURE__ */ jsxDEV6("div", {
|
|
1705
1938
|
className: "space-y-6",
|
|
1706
|
-
children: /* @__PURE__ */
|
|
1939
|
+
children: /* @__PURE__ */ jsxDEV6("div", {
|
|
1707
1940
|
className: "rounded-xl border border-border bg-card p-6",
|
|
1708
1941
|
children: [
|
|
1709
|
-
/* @__PURE__ */
|
|
1942
|
+
/* @__PURE__ */ jsxDEV6("h3", {
|
|
1710
1943
|
className: "mb-4 font-semibold text-lg",
|
|
1711
1944
|
children: "Pipeline Overview"
|
|
1712
1945
|
}, undefined, false, undefined, this),
|
|
1713
|
-
/* @__PURE__ */
|
|
1946
|
+
/* @__PURE__ */ jsxDEV6("dl", {
|
|
1714
1947
|
className: "grid gap-4 sm:grid-cols-3",
|
|
1715
1948
|
children: [
|
|
1716
|
-
/* @__PURE__ */
|
|
1949
|
+
/* @__PURE__ */ jsxDEV6("div", {
|
|
1717
1950
|
children: [
|
|
1718
|
-
/* @__PURE__ */
|
|
1951
|
+
/* @__PURE__ */ jsxDEV6("dt", {
|
|
1719
1952
|
className: "text-muted-foreground text-sm",
|
|
1720
1953
|
children: "Win Rate"
|
|
1721
1954
|
}, undefined, false, undefined, this),
|
|
1722
|
-
/* @__PURE__ */
|
|
1955
|
+
/* @__PURE__ */ jsxDEV6("dd", {
|
|
1723
1956
|
className: "font-semibold text-2xl",
|
|
1724
1957
|
children: [
|
|
1725
1958
|
stats.total > 0 ? (stats.wonCount / stats.total * 100).toFixed(0) : 0,
|
|
@@ -1728,25 +1961,25 @@ function MetricsTab({
|
|
|
1728
1961
|
}, undefined, true, undefined, this)
|
|
1729
1962
|
]
|
|
1730
1963
|
}, undefined, true, undefined, this),
|
|
1731
|
-
/* @__PURE__ */
|
|
1964
|
+
/* @__PURE__ */ jsxDEV6("div", {
|
|
1732
1965
|
children: [
|
|
1733
|
-
/* @__PURE__ */
|
|
1966
|
+
/* @__PURE__ */ jsxDEV6("dt", {
|
|
1734
1967
|
className: "text-muted-foreground text-sm",
|
|
1735
1968
|
children: "Avg Deal Size"
|
|
1736
1969
|
}, undefined, false, undefined, this),
|
|
1737
|
-
/* @__PURE__ */
|
|
1970
|
+
/* @__PURE__ */ jsxDEV6("dd", {
|
|
1738
1971
|
className: "font-semibold text-2xl",
|
|
1739
|
-
children:
|
|
1972
|
+
children: formatCurrency5(stats.total > 0 ? stats.totalValue / stats.total : 0)
|
|
1740
1973
|
}, undefined, false, undefined, this)
|
|
1741
1974
|
]
|
|
1742
1975
|
}, undefined, true, undefined, this),
|
|
1743
|
-
/* @__PURE__ */
|
|
1976
|
+
/* @__PURE__ */ jsxDEV6("div", {
|
|
1744
1977
|
children: [
|
|
1745
|
-
/* @__PURE__ */
|
|
1978
|
+
/* @__PURE__ */ jsxDEV6("dt", {
|
|
1746
1979
|
className: "text-muted-foreground text-sm",
|
|
1747
1980
|
children: "Conversion"
|
|
1748
1981
|
}, undefined, false, undefined, this),
|
|
1749
|
-
/* @__PURE__ */
|
|
1982
|
+
/* @__PURE__ */ jsxDEV6("dd", {
|
|
1750
1983
|
className: "font-semibold text-2xl",
|
|
1751
1984
|
children: [
|
|
1752
1985
|
stats.wonCount,
|
|
@@ -1816,7 +2049,7 @@ var crmOverlays = [
|
|
|
1816
2049
|
crmSalesRepOverlay
|
|
1817
2050
|
];
|
|
1818
2051
|
// src/ui/renderers/pipeline.markdown.ts
|
|
1819
|
-
function
|
|
2052
|
+
function formatCurrency6(value, currency = "USD") {
|
|
1820
2053
|
return new Intl.NumberFormat("en-US", {
|
|
1821
2054
|
style: "currency",
|
|
1822
2055
|
currency,
|
|
@@ -1843,7 +2076,7 @@ var crmPipelineMarkdownRenderer = {
|
|
|
1843
2076
|
const lines = [
|
|
1844
2077
|
"# CRM Pipeline",
|
|
1845
2078
|
"",
|
|
1846
|
-
`**Total Value**: ${
|
|
2079
|
+
`**Total Value**: ${formatCurrency6(dealsResult.totalValue)}`,
|
|
1847
2080
|
`**Total Deals**: ${dealsResult.total}`,
|
|
1848
2081
|
""
|
|
1849
2082
|
];
|
|
@@ -1851,13 +2084,13 @@ var crmPipelineMarkdownRenderer = {
|
|
|
1851
2084
|
const stageDeals = dealsByStage[stage.id] ?? [];
|
|
1852
2085
|
const stageValue = stageDeals.reduce((sum, d) => sum + d.value, 0);
|
|
1853
2086
|
lines.push(`## ${stage.name}`);
|
|
1854
|
-
lines.push(`_${stageDeals.length} deals · ${
|
|
2087
|
+
lines.push(`_${stageDeals.length} deals · ${formatCurrency6(stageValue)}_`);
|
|
1855
2088
|
lines.push("");
|
|
1856
2089
|
if (stageDeals.length === 0) {
|
|
1857
2090
|
lines.push("_No deals_");
|
|
1858
2091
|
} else {
|
|
1859
2092
|
for (const deal of stageDeals) {
|
|
1860
|
-
lines.push(`- **${deal.name}** - ${
|
|
2093
|
+
lines.push(`- **${deal.name}** - ${formatCurrency6(deal.value, deal.currency)}`);
|
|
1861
2094
|
}
|
|
1862
2095
|
}
|
|
1863
2096
|
lines.push("");
|
|
@@ -1897,9 +2130,9 @@ var crmDashboardMarkdownRenderer = {
|
|
|
1897
2130
|
"| Metric | Value |",
|
|
1898
2131
|
"|--------|-------|",
|
|
1899
2132
|
`| Total Deals | ${dealsResult.total} |`,
|
|
1900
|
-
`| Pipeline Value | ${
|
|
1901
|
-
`| Open Deals | ${openDeals.length} (${
|
|
1902
|
-
`| Won Deals | ${wonDeals.length} (${
|
|
2133
|
+
`| Pipeline Value | ${formatCurrency6(dealsResult.totalValue)} |`,
|
|
2134
|
+
`| Open Deals | ${openDeals.length} (${formatCurrency6(openValue)}) |`,
|
|
2135
|
+
`| Won Deals | ${wonDeals.length} (${formatCurrency6(wonValue)}) |`,
|
|
1903
2136
|
`| Lost Deals | ${lostDeals.length} |`,
|
|
1904
2137
|
"",
|
|
1905
2138
|
"## Pipeline Stages",
|
|
@@ -1910,7 +2143,7 @@ var crmDashboardMarkdownRenderer = {
|
|
|
1910
2143
|
for (const stage of stageList.sort((a, b) => a.position - b.position)) {
|
|
1911
2144
|
const stageDeals = openDeals.filter((d) => d.stageId === stage.id);
|
|
1912
2145
|
const stageValue = stageDeals.reduce((sum, d) => sum + d.value, 0);
|
|
1913
|
-
lines.push(`| ${stage.name} | ${stageDeals.length} | ${
|
|
2146
|
+
lines.push(`| ${stage.name} | ${stageDeals.length} | ${formatCurrency6(stageValue)} |`);
|
|
1914
2147
|
}
|
|
1915
2148
|
lines.push("");
|
|
1916
2149
|
lines.push("## Recent Deals");
|
|
@@ -1923,7 +2156,7 @@ var crmDashboardMarkdownRenderer = {
|
|
|
1923
2156
|
lines.push("|------|-------|-------|--------|");
|
|
1924
2157
|
for (const deal of recentDeals) {
|
|
1925
2158
|
const stage = stageList.find((s) => s.id === deal.stageId);
|
|
1926
|
-
lines.push(`| ${deal.name} | ${
|
|
2159
|
+
lines.push(`| ${deal.name} | ${formatCurrency6(deal.value, deal.currency)} | ${stage?.name ?? "-"} | ${deal.status} |`);
|
|
1927
2160
|
}
|
|
1928
2161
|
}
|
|
1929
2162
|
return {
|
|
@@ -1935,10 +2168,10 @@ var crmDashboardMarkdownRenderer = {
|
|
|
1935
2168
|
};
|
|
1936
2169
|
|
|
1937
2170
|
// src/ui/renderers/pipeline.renderer.tsx
|
|
1938
|
-
import { jsxDEV as
|
|
2171
|
+
import { jsxDEV as jsxDEV7 } from "react/jsx-dev-runtime";
|
|
1939
2172
|
function CrmPipelineBoardWrapper() {
|
|
1940
2173
|
const { dealsByStage, stages } = useDealList();
|
|
1941
|
-
return /* @__PURE__ */
|
|
2174
|
+
return /* @__PURE__ */ jsxDEV7(CrmPipelineBoard, {
|
|
1942
2175
|
dealsByStage,
|
|
1943
2176
|
stages
|
|
1944
2177
|
}, undefined, false, undefined, this);
|
|
@@ -1952,7 +2185,7 @@ var crmPipelineReactRenderer = {
|
|
|
1952
2185
|
if (desc.source.componentKey !== "CrmPipelineView") {
|
|
1953
2186
|
throw new Error(`Unknown component: ${desc.source.componentKey}`);
|
|
1954
2187
|
}
|
|
1955
|
-
return /* @__PURE__ */
|
|
2188
|
+
return /* @__PURE__ */ jsxDEV7(CrmPipelineBoardWrapper, {}, undefined, false, undefined, this);
|
|
1956
2189
|
}
|
|
1957
2190
|
};
|
|
1958
2191
|
export {
|