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