@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/browser/index.js
CHANGED
|
@@ -550,7 +550,7 @@ var crmPipelineDocBlocks = [
|
|
|
550
550
|
- deal.created, stage.moved, task.completed, contact.updated.
|
|
551
551
|
|
|
552
552
|
## Presentations
|
|
553
|
-
- Pipelines/kanban, deal detail, contact/company profiles, task lists.
|
|
553
|
+
- Pipelines/kanban, deal detail, contact/company profiles, task lists, and a server-mode shared table for the deal list.
|
|
554
554
|
|
|
555
555
|
## Notes
|
|
556
556
|
- Stage definitions should be declarative; enforce via spec and regeneration.
|
|
@@ -1119,6 +1119,13 @@ function rowToDeal(row) {
|
|
|
1119
1119
|
updatedAt: new Date(row.updatedAt)
|
|
1120
1120
|
};
|
|
1121
1121
|
}
|
|
1122
|
+
var DEAL_SORT_COLUMNS = {
|
|
1123
|
+
name: "name",
|
|
1124
|
+
value: "value",
|
|
1125
|
+
status: "status",
|
|
1126
|
+
expectedCloseDate: "expectedCloseDate",
|
|
1127
|
+
updatedAt: "updatedAt"
|
|
1128
|
+
};
|
|
1122
1129
|
function createCrmHandlers(db) {
|
|
1123
1130
|
async function listDeals(input) {
|
|
1124
1131
|
const {
|
|
@@ -1129,7 +1136,9 @@ function createCrmHandlers(db) {
|
|
|
1129
1136
|
ownerId,
|
|
1130
1137
|
search,
|
|
1131
1138
|
limit = 20,
|
|
1132
|
-
offset = 0
|
|
1139
|
+
offset = 0,
|
|
1140
|
+
sortBy = "value",
|
|
1141
|
+
sortDirection = "desc"
|
|
1133
1142
|
} = input;
|
|
1134
1143
|
let whereClause = "WHERE projectId = ?";
|
|
1135
1144
|
const params = [projectId];
|
|
@@ -1157,7 +1166,9 @@ function createCrmHandlers(db) {
|
|
|
1157
1166
|
const total = countResult[0]?.count ?? 0;
|
|
1158
1167
|
const valueResult = (await db.query(`SELECT COALESCE(SUM(value), 0) as total FROM crm_deal ${whereClause}`, params)).rows;
|
|
1159
1168
|
const totalValue = valueResult[0]?.total ?? 0;
|
|
1160
|
-
const
|
|
1169
|
+
const orderByColumn = DEAL_SORT_COLUMNS[sortBy] ?? DEAL_SORT_COLUMNS.value;
|
|
1170
|
+
const orderByDirection = sortDirection === "asc" ? "ASC" : "DESC";
|
|
1171
|
+
const dealRows = (await db.query(`SELECT * FROM crm_deal ${whereClause} ORDER BY ${orderByColumn} ${orderByDirection} LIMIT ? OFFSET ?`, [...params, limit, offset])).rows;
|
|
1161
1172
|
return {
|
|
1162
1173
|
deals: dealRows.map(rowToDeal),
|
|
1163
1174
|
total,
|
|
@@ -1859,8 +1870,13 @@ function useDealList(options = {}) {
|
|
|
1859
1870
|
const [stages, setStages] = useState2([]);
|
|
1860
1871
|
const [loading, setLoading] = useState2(true);
|
|
1861
1872
|
const [error, setError] = useState2(null);
|
|
1862
|
-
const [
|
|
1873
|
+
const [internalPage, setInternalPage] = useState2(0);
|
|
1863
1874
|
const pipelineId = options.pipelineId ?? "pipeline-1";
|
|
1875
|
+
const pageIndex = options.pageIndex ?? internalPage;
|
|
1876
|
+
const pageSize = options.pageSize ?? options.limit ?? 50;
|
|
1877
|
+
const [sort] = options.sorting ?? [];
|
|
1878
|
+
const sortBy = sort?.id;
|
|
1879
|
+
const sortDirection = sort ? sort.desc ? "desc" : "asc" : undefined;
|
|
1864
1880
|
const fetchData = useCallback(async () => {
|
|
1865
1881
|
setLoading(true);
|
|
1866
1882
|
setError(null);
|
|
@@ -1872,8 +1888,10 @@ function useDealList(options = {}) {
|
|
|
1872
1888
|
stageId: options.stageId,
|
|
1873
1889
|
status: options.status === "all" ? undefined : options.status,
|
|
1874
1890
|
search: options.search,
|
|
1875
|
-
limit:
|
|
1876
|
-
offset:
|
|
1891
|
+
limit: pageSize,
|
|
1892
|
+
offset: pageIndex * pageSize,
|
|
1893
|
+
sortBy: sortBy === "name" || sortBy === "value" || sortBy === "status" || sortBy === "expectedCloseDate" || sortBy === "updatedAt" ? sortBy : undefined,
|
|
1894
|
+
sortDirection
|
|
1877
1895
|
}),
|
|
1878
1896
|
crm2.getDealsByStage({ projectId, pipelineId }),
|
|
1879
1897
|
crm2.getPipelineStages({ pipelineId })
|
|
@@ -1893,8 +1911,10 @@ function useDealList(options = {}) {
|
|
|
1893
1911
|
options.stageId,
|
|
1894
1912
|
options.status,
|
|
1895
1913
|
options.search,
|
|
1896
|
-
|
|
1897
|
-
|
|
1914
|
+
pageIndex,
|
|
1915
|
+
pageSize,
|
|
1916
|
+
sortBy,
|
|
1917
|
+
sortDirection
|
|
1898
1918
|
]);
|
|
1899
1919
|
useEffect(() => {
|
|
1900
1920
|
fetchData();
|
|
@@ -1922,10 +1942,12 @@ function useDealList(options = {}) {
|
|
|
1922
1942
|
loading,
|
|
1923
1943
|
error,
|
|
1924
1944
|
stats,
|
|
1925
|
-
page,
|
|
1945
|
+
page: pageIndex + 1,
|
|
1946
|
+
pageIndex,
|
|
1947
|
+
pageSize,
|
|
1926
1948
|
refetch: fetchData,
|
|
1927
|
-
nextPage: () =>
|
|
1928
|
-
prevPage: () =>
|
|
1949
|
+
nextPage: options.pageIndex === undefined ? () => setInternalPage((page) => page + 1) : undefined,
|
|
1950
|
+
prevPage: options.pageIndex === undefined ? () => pageIndex > 0 && setInternalPage((page) => page - 1) : undefined
|
|
1929
1951
|
};
|
|
1930
1952
|
}
|
|
1931
1953
|
|
|
@@ -2662,11 +2684,305 @@ function DealActionsModal({
|
|
|
2662
2684
|
}, undefined, true, undefined, this);
|
|
2663
2685
|
}
|
|
2664
2686
|
|
|
2665
|
-
// src/ui/
|
|
2687
|
+
// src/ui/tables/DealListTab.tsx
|
|
2666
2688
|
import {
|
|
2667
2689
|
Button as Button3,
|
|
2690
|
+
DataTable,
|
|
2691
|
+
LoaderBlock
|
|
2692
|
+
} from "@contractspec/lib.design-system";
|
|
2693
|
+
import { useContractTable } from "@contractspec/lib.presentation-runtime-react";
|
|
2694
|
+
import { Badge } from "@contractspec/lib.ui-kit-web/ui/badge";
|
|
2695
|
+
import { HStack, VStack } from "@contractspec/lib.ui-kit-web/ui/stack";
|
|
2696
|
+
import { Text } from "@contractspec/lib.ui-kit-web/ui/text";
|
|
2697
|
+
import * as React from "react";
|
|
2698
|
+
import { jsxDEV as jsxDEV5 } from "react/jsx-dev-runtime";
|
|
2699
|
+
"use client";
|
|
2700
|
+
function formatCurrency4(value, currency = "USD") {
|
|
2701
|
+
return new Intl.NumberFormat("en-US", {
|
|
2702
|
+
style: "currency",
|
|
2703
|
+
currency,
|
|
2704
|
+
minimumFractionDigits: 0,
|
|
2705
|
+
maximumFractionDigits: 0
|
|
2706
|
+
}).format(value);
|
|
2707
|
+
}
|
|
2708
|
+
function statusVariant(status) {
|
|
2709
|
+
switch (status) {
|
|
2710
|
+
case "WON":
|
|
2711
|
+
return "default";
|
|
2712
|
+
case "LOST":
|
|
2713
|
+
return "destructive";
|
|
2714
|
+
case "STALE":
|
|
2715
|
+
return "outline";
|
|
2716
|
+
default:
|
|
2717
|
+
return "secondary";
|
|
2718
|
+
}
|
|
2719
|
+
}
|
|
2720
|
+
function DealListDataTable({
|
|
2721
|
+
deals,
|
|
2722
|
+
totalItems,
|
|
2723
|
+
pageIndex,
|
|
2724
|
+
pageSize,
|
|
2725
|
+
sorting,
|
|
2726
|
+
loading,
|
|
2727
|
+
onSortingChange,
|
|
2728
|
+
onPaginationChange,
|
|
2729
|
+
onDealClick
|
|
2730
|
+
}) {
|
|
2731
|
+
const controller = useContractTable({
|
|
2732
|
+
data: deals,
|
|
2733
|
+
columns: [
|
|
2734
|
+
{
|
|
2735
|
+
id: "deal",
|
|
2736
|
+
header: "Deal",
|
|
2737
|
+
label: "Deal",
|
|
2738
|
+
accessor: (deal3) => deal3.name,
|
|
2739
|
+
cell: ({ item }) => /* @__PURE__ */ jsxDEV5(VStack, {
|
|
2740
|
+
gap: "xs",
|
|
2741
|
+
children: [
|
|
2742
|
+
/* @__PURE__ */ jsxDEV5(Text, {
|
|
2743
|
+
className: "font-medium text-sm",
|
|
2744
|
+
children: item.name
|
|
2745
|
+
}, undefined, false, undefined, this),
|
|
2746
|
+
/* @__PURE__ */ jsxDEV5(Text, {
|
|
2747
|
+
className: "text-muted-foreground text-xs",
|
|
2748
|
+
children: item.companyId ?? "Unassigned company"
|
|
2749
|
+
}, undefined, false, undefined, this)
|
|
2750
|
+
]
|
|
2751
|
+
}, undefined, true, undefined, this),
|
|
2752
|
+
size: 240,
|
|
2753
|
+
minSize: 180,
|
|
2754
|
+
canSort: true,
|
|
2755
|
+
canPin: true,
|
|
2756
|
+
canResize: true
|
|
2757
|
+
},
|
|
2758
|
+
{
|
|
2759
|
+
id: "value",
|
|
2760
|
+
header: "Value",
|
|
2761
|
+
label: "Value",
|
|
2762
|
+
accessorKey: "value",
|
|
2763
|
+
cell: ({ item }) => formatCurrency4(item.value, item.currency),
|
|
2764
|
+
align: "right",
|
|
2765
|
+
size: 140,
|
|
2766
|
+
canSort: true,
|
|
2767
|
+
canResize: true
|
|
2768
|
+
},
|
|
2769
|
+
{
|
|
2770
|
+
id: "status",
|
|
2771
|
+
header: "Status",
|
|
2772
|
+
label: "Status",
|
|
2773
|
+
accessorKey: "status",
|
|
2774
|
+
cell: ({ value }) => /* @__PURE__ */ jsxDEV5(Badge, {
|
|
2775
|
+
variant: statusVariant(value),
|
|
2776
|
+
children: String(value)
|
|
2777
|
+
}, undefined, false, undefined, this),
|
|
2778
|
+
size: 130,
|
|
2779
|
+
canSort: true,
|
|
2780
|
+
canHide: true,
|
|
2781
|
+
canPin: true,
|
|
2782
|
+
canResize: true
|
|
2783
|
+
},
|
|
2784
|
+
{
|
|
2785
|
+
id: "expectedCloseDate",
|
|
2786
|
+
header: "Expected Close",
|
|
2787
|
+
label: "Expected Close",
|
|
2788
|
+
accessor: (deal3) => deal3.expectedCloseDate?.toISOString() ?? "",
|
|
2789
|
+
cell: ({ item }) => item.expectedCloseDate?.toLocaleDateString() ?? "Not scheduled",
|
|
2790
|
+
size: 170,
|
|
2791
|
+
canSort: true,
|
|
2792
|
+
canHide: true,
|
|
2793
|
+
canResize: true
|
|
2794
|
+
},
|
|
2795
|
+
{
|
|
2796
|
+
id: "updatedAt",
|
|
2797
|
+
header: "Updated",
|
|
2798
|
+
label: "Updated",
|
|
2799
|
+
accessor: (deal3) => deal3.updatedAt.toISOString(),
|
|
2800
|
+
cell: ({ item }) => item.updatedAt.toLocaleDateString(),
|
|
2801
|
+
size: 140,
|
|
2802
|
+
canSort: true,
|
|
2803
|
+
canHide: true,
|
|
2804
|
+
canResize: true
|
|
2805
|
+
},
|
|
2806
|
+
{
|
|
2807
|
+
id: "actions",
|
|
2808
|
+
header: "Actions",
|
|
2809
|
+
label: "Actions",
|
|
2810
|
+
accessor: (deal3) => deal3.id,
|
|
2811
|
+
cell: ({ item }) => /* @__PURE__ */ jsxDEV5(Button3, {
|
|
2812
|
+
variant: "ghost",
|
|
2813
|
+
size: "sm",
|
|
2814
|
+
onPress: () => onDealClick?.(item.id),
|
|
2815
|
+
children: "Actions"
|
|
2816
|
+
}, undefined, false, undefined, this),
|
|
2817
|
+
size: 120,
|
|
2818
|
+
canSort: false,
|
|
2819
|
+
canHide: false,
|
|
2820
|
+
canPin: false,
|
|
2821
|
+
canResize: false
|
|
2822
|
+
}
|
|
2823
|
+
],
|
|
2824
|
+
executionMode: "server",
|
|
2825
|
+
selectionMode: "multiple",
|
|
2826
|
+
totalItems,
|
|
2827
|
+
state: {
|
|
2828
|
+
sorting,
|
|
2829
|
+
pagination: {
|
|
2830
|
+
pageIndex,
|
|
2831
|
+
pageSize
|
|
2832
|
+
}
|
|
2833
|
+
},
|
|
2834
|
+
onSortingChange,
|
|
2835
|
+
onPaginationChange,
|
|
2836
|
+
initialState: {
|
|
2837
|
+
columnVisibility: { updatedAt: false },
|
|
2838
|
+
columnPinning: { left: ["deal", "status"], right: [] }
|
|
2839
|
+
},
|
|
2840
|
+
renderExpandedContent: (deal3) => /* @__PURE__ */ jsxDEV5(VStack, {
|
|
2841
|
+
gap: "sm",
|
|
2842
|
+
className: "py-2",
|
|
2843
|
+
children: [
|
|
2844
|
+
/* @__PURE__ */ jsxDEV5(HStack, {
|
|
2845
|
+
justify: "between",
|
|
2846
|
+
children: [
|
|
2847
|
+
/* @__PURE__ */ jsxDEV5(Text, {
|
|
2848
|
+
className: "font-medium text-sm",
|
|
2849
|
+
children: "Owner"
|
|
2850
|
+
}, undefined, false, undefined, this),
|
|
2851
|
+
/* @__PURE__ */ jsxDEV5(Text, {
|
|
2852
|
+
className: "text-muted-foreground text-sm",
|
|
2853
|
+
children: deal3.ownerId
|
|
2854
|
+
}, undefined, false, undefined, this)
|
|
2855
|
+
]
|
|
2856
|
+
}, undefined, true, undefined, this),
|
|
2857
|
+
/* @__PURE__ */ jsxDEV5(HStack, {
|
|
2858
|
+
justify: "between",
|
|
2859
|
+
children: [
|
|
2860
|
+
/* @__PURE__ */ jsxDEV5(Text, {
|
|
2861
|
+
className: "font-medium text-sm",
|
|
2862
|
+
children: "Contact"
|
|
2863
|
+
}, undefined, false, undefined, this),
|
|
2864
|
+
/* @__PURE__ */ jsxDEV5(Text, {
|
|
2865
|
+
className: "text-muted-foreground text-sm",
|
|
2866
|
+
children: deal3.contactId ?? "No linked contact"
|
|
2867
|
+
}, undefined, false, undefined, this)
|
|
2868
|
+
]
|
|
2869
|
+
}, undefined, true, undefined, this),
|
|
2870
|
+
deal3.wonSource ? /* @__PURE__ */ jsxDEV5(HStack, {
|
|
2871
|
+
justify: "between",
|
|
2872
|
+
children: [
|
|
2873
|
+
/* @__PURE__ */ jsxDEV5(Text, {
|
|
2874
|
+
className: "font-medium text-sm",
|
|
2875
|
+
children: "Won Source"
|
|
2876
|
+
}, undefined, false, undefined, this),
|
|
2877
|
+
/* @__PURE__ */ jsxDEV5(Text, {
|
|
2878
|
+
className: "text-muted-foreground text-sm",
|
|
2879
|
+
children: deal3.wonSource
|
|
2880
|
+
}, undefined, false, undefined, this)
|
|
2881
|
+
]
|
|
2882
|
+
}, undefined, true, undefined, this) : null,
|
|
2883
|
+
deal3.lostReason ? /* @__PURE__ */ jsxDEV5(HStack, {
|
|
2884
|
+
justify: "between",
|
|
2885
|
+
children: [
|
|
2886
|
+
/* @__PURE__ */ jsxDEV5(Text, {
|
|
2887
|
+
className: "font-medium text-sm",
|
|
2888
|
+
children: "Lost Reason"
|
|
2889
|
+
}, undefined, false, undefined, this),
|
|
2890
|
+
/* @__PURE__ */ jsxDEV5(Text, {
|
|
2891
|
+
className: "text-muted-foreground text-sm",
|
|
2892
|
+
children: deal3.lostReason
|
|
2893
|
+
}, undefined, false, undefined, this)
|
|
2894
|
+
]
|
|
2895
|
+
}, undefined, true, undefined, this) : null,
|
|
2896
|
+
deal3.notes ? /* @__PURE__ */ jsxDEV5(VStack, {
|
|
2897
|
+
gap: "xs",
|
|
2898
|
+
children: [
|
|
2899
|
+
/* @__PURE__ */ jsxDEV5(Text, {
|
|
2900
|
+
className: "font-medium text-sm",
|
|
2901
|
+
children: "Notes"
|
|
2902
|
+
}, undefined, false, undefined, this),
|
|
2903
|
+
/* @__PURE__ */ jsxDEV5(Text, {
|
|
2904
|
+
className: "text-muted-foreground text-sm",
|
|
2905
|
+
children: deal3.notes
|
|
2906
|
+
}, undefined, false, undefined, this)
|
|
2907
|
+
]
|
|
2908
|
+
}, undefined, true, undefined, this) : null
|
|
2909
|
+
]
|
|
2910
|
+
}, undefined, true, undefined, this),
|
|
2911
|
+
getCanExpand: () => true
|
|
2912
|
+
});
|
|
2913
|
+
return /* @__PURE__ */ jsxDEV5(DataTable, {
|
|
2914
|
+
controller,
|
|
2915
|
+
title: "All Deals",
|
|
2916
|
+
description: "Server-mode table using the shared ContractSpec controller.",
|
|
2917
|
+
loading,
|
|
2918
|
+
toolbar: /* @__PURE__ */ jsxDEV5(HStack, {
|
|
2919
|
+
gap: "sm",
|
|
2920
|
+
className: "flex-wrap",
|
|
2921
|
+
children: [
|
|
2922
|
+
/* @__PURE__ */ jsxDEV5(Text, {
|
|
2923
|
+
className: "text-muted-foreground text-sm",
|
|
2924
|
+
children: [
|
|
2925
|
+
"Selected ",
|
|
2926
|
+
controller.selectedRowIds.length
|
|
2927
|
+
]
|
|
2928
|
+
}, undefined, true, undefined, this),
|
|
2929
|
+
/* @__PURE__ */ jsxDEV5(Text, {
|
|
2930
|
+
className: "text-muted-foreground text-sm",
|
|
2931
|
+
children: [
|
|
2932
|
+
totalItems,
|
|
2933
|
+
" total deals"
|
|
2934
|
+
]
|
|
2935
|
+
}, undefined, true, undefined, this)
|
|
2936
|
+
]
|
|
2937
|
+
}, undefined, true, undefined, this),
|
|
2938
|
+
footer: `Page ${controller.pageIndex + 1} of ${controller.pageCount}`,
|
|
2939
|
+
emptyState: /* @__PURE__ */ jsxDEV5("div", {
|
|
2940
|
+
className: "rounded-md border border-dashed p-8 text-center text-muted-foreground text-sm",
|
|
2941
|
+
children: "No deals found"
|
|
2942
|
+
}, undefined, false, undefined, this)
|
|
2943
|
+
}, undefined, false, undefined, this);
|
|
2944
|
+
}
|
|
2945
|
+
function DealListTab({
|
|
2946
|
+
onDealClick
|
|
2947
|
+
}) {
|
|
2948
|
+
const [sorting, setSorting] = React.useState([
|
|
2949
|
+
{ id: "value", desc: true }
|
|
2950
|
+
]);
|
|
2951
|
+
const [pagination, setPagination] = React.useState({
|
|
2952
|
+
pageIndex: 0,
|
|
2953
|
+
pageSize: 3
|
|
2954
|
+
});
|
|
2955
|
+
const { data, loading } = useDealList({
|
|
2956
|
+
pageIndex: pagination.pageIndex,
|
|
2957
|
+
pageSize: pagination.pageSize,
|
|
2958
|
+
sorting
|
|
2959
|
+
});
|
|
2960
|
+
if (loading && !data) {
|
|
2961
|
+
return /* @__PURE__ */ jsxDEV5(LoaderBlock, {
|
|
2962
|
+
label: "Loading deals..."
|
|
2963
|
+
}, undefined, false, undefined, this);
|
|
2964
|
+
}
|
|
2965
|
+
return /* @__PURE__ */ jsxDEV5(DealListDataTable, {
|
|
2966
|
+
deals: data?.deals ?? [],
|
|
2967
|
+
totalItems: data?.total ?? 0,
|
|
2968
|
+
pageIndex: pagination.pageIndex,
|
|
2969
|
+
pageSize: pagination.pageSize,
|
|
2970
|
+
sorting,
|
|
2971
|
+
loading,
|
|
2972
|
+
onSortingChange: (nextSorting) => {
|
|
2973
|
+
setSorting(nextSorting);
|
|
2974
|
+
setPagination((current) => ({ ...current, pageIndex: 0 }));
|
|
2975
|
+
},
|
|
2976
|
+
onPaginationChange: setPagination,
|
|
2977
|
+
onDealClick
|
|
2978
|
+
}, undefined, false, undefined, this);
|
|
2979
|
+
}
|
|
2980
|
+
|
|
2981
|
+
// src/ui/CrmDashboard.tsx
|
|
2982
|
+
import {
|
|
2983
|
+
Button as Button4,
|
|
2668
2984
|
ErrorState,
|
|
2669
|
-
LoaderBlock,
|
|
2985
|
+
LoaderBlock as LoaderBlock2,
|
|
2670
2986
|
StatCard,
|
|
2671
2987
|
StatCardGroup
|
|
2672
2988
|
} from "@contractspec/lib.design-system";
|
|
@@ -2676,10 +2992,10 @@ import {
|
|
|
2676
2992
|
TabsList,
|
|
2677
2993
|
TabsTrigger
|
|
2678
2994
|
} from "@contractspec/lib.ui-kit-web/ui/tabs";
|
|
2679
|
-
import { useCallback as useCallback3, useState as
|
|
2680
|
-
import { jsxDEV as
|
|
2995
|
+
import { useCallback as useCallback3, useState as useState7 } from "react";
|
|
2996
|
+
import { jsxDEV as jsxDEV6 } from "react/jsx-dev-runtime";
|
|
2681
2997
|
"use client";
|
|
2682
|
-
function
|
|
2998
|
+
function formatCurrency5(value, currency = "USD") {
|
|
2683
2999
|
return new Intl.NumberFormat("en-US", {
|
|
2684
3000
|
style: "currency",
|
|
2685
3001
|
currency,
|
|
@@ -2688,9 +3004,9 @@ function formatCurrency4(value, currency = "USD") {
|
|
|
2688
3004
|
}).format(value);
|
|
2689
3005
|
}
|
|
2690
3006
|
function CrmDashboard() {
|
|
2691
|
-
const [isCreateModalOpen, setIsCreateModalOpen] =
|
|
2692
|
-
const [selectedDeal, setSelectedDeal] =
|
|
2693
|
-
const [isDealActionsOpen, setIsDealActionsOpen] =
|
|
3007
|
+
const [isCreateModalOpen, setIsCreateModalOpen] = useState7(false);
|
|
3008
|
+
const [selectedDeal, setSelectedDeal] = useState7(null);
|
|
3009
|
+
const [isDealActionsOpen, setIsDealActionsOpen] = useState7(false);
|
|
2694
3010
|
const { data, dealsByStage, stages, loading, error, stats, refetch } = useDealList();
|
|
2695
3011
|
const mutations = useDealMutations({
|
|
2696
3012
|
onSuccess: () => {
|
|
@@ -2708,32 +3024,32 @@ function CrmDashboard() {
|
|
|
2708
3024
|
await mutations.moveDeal({ dealId, stageId: toStageId });
|
|
2709
3025
|
}, [mutations]);
|
|
2710
3026
|
if (loading && !data) {
|
|
2711
|
-
return /* @__PURE__ */
|
|
3027
|
+
return /* @__PURE__ */ jsxDEV6(LoaderBlock2, {
|
|
2712
3028
|
label: "Loading CRM..."
|
|
2713
3029
|
}, undefined, false, undefined, this);
|
|
2714
3030
|
}
|
|
2715
3031
|
if (error) {
|
|
2716
|
-
return /* @__PURE__ */
|
|
3032
|
+
return /* @__PURE__ */ jsxDEV6(ErrorState, {
|
|
2717
3033
|
title: "Failed to load CRM",
|
|
2718
3034
|
description: error.message,
|
|
2719
3035
|
onRetry: refetch,
|
|
2720
3036
|
retryLabel: "Retry"
|
|
2721
3037
|
}, undefined, false, undefined, this);
|
|
2722
3038
|
}
|
|
2723
|
-
return /* @__PURE__ */
|
|
3039
|
+
return /* @__PURE__ */ jsxDEV6("div", {
|
|
2724
3040
|
className: "space-y-6",
|
|
2725
3041
|
children: [
|
|
2726
|
-
/* @__PURE__ */
|
|
3042
|
+
/* @__PURE__ */ jsxDEV6("div", {
|
|
2727
3043
|
className: "flex items-center justify-between",
|
|
2728
3044
|
children: [
|
|
2729
|
-
/* @__PURE__ */
|
|
3045
|
+
/* @__PURE__ */ jsxDEV6("h2", {
|
|
2730
3046
|
className: "font-bold text-2xl",
|
|
2731
3047
|
children: "CRM Pipeline"
|
|
2732
3048
|
}, undefined, false, undefined, this),
|
|
2733
|
-
/* @__PURE__ */
|
|
3049
|
+
/* @__PURE__ */ jsxDEV6(Button4, {
|
|
2734
3050
|
onClick: () => setIsCreateModalOpen(true),
|
|
2735
3051
|
children: [
|
|
2736
|
-
/* @__PURE__ */
|
|
3052
|
+
/* @__PURE__ */ jsxDEV6("span", {
|
|
2737
3053
|
className: "mr-2",
|
|
2738
3054
|
children: "+"
|
|
2739
3055
|
}, undefined, false, undefined, this),
|
|
@@ -2742,60 +3058,60 @@ function CrmDashboard() {
|
|
|
2742
3058
|
}, undefined, true, undefined, this)
|
|
2743
3059
|
]
|
|
2744
3060
|
}, undefined, true, undefined, this),
|
|
2745
|
-
stats && /* @__PURE__ */
|
|
3061
|
+
stats && /* @__PURE__ */ jsxDEV6(StatCardGroup, {
|
|
2746
3062
|
children: [
|
|
2747
|
-
/* @__PURE__ */
|
|
3063
|
+
/* @__PURE__ */ jsxDEV6(StatCard, {
|
|
2748
3064
|
label: "Total Pipeline",
|
|
2749
|
-
value:
|
|
3065
|
+
value: formatCurrency5(stats.totalValue),
|
|
2750
3066
|
hint: `${stats.total} deals`
|
|
2751
3067
|
}, undefined, false, undefined, this),
|
|
2752
|
-
/* @__PURE__ */
|
|
3068
|
+
/* @__PURE__ */ jsxDEV6(StatCard, {
|
|
2753
3069
|
label: "Open Deals",
|
|
2754
|
-
value:
|
|
3070
|
+
value: formatCurrency5(stats.openValue),
|
|
2755
3071
|
hint: `${stats.openCount} active`
|
|
2756
3072
|
}, undefined, false, undefined, this),
|
|
2757
|
-
/* @__PURE__ */
|
|
3073
|
+
/* @__PURE__ */ jsxDEV6(StatCard, {
|
|
2758
3074
|
label: "Won",
|
|
2759
|
-
value:
|
|
3075
|
+
value: formatCurrency5(stats.wonValue),
|
|
2760
3076
|
hint: `${stats.wonCount} closed`
|
|
2761
3077
|
}, undefined, false, undefined, this),
|
|
2762
|
-
/* @__PURE__ */
|
|
3078
|
+
/* @__PURE__ */ jsxDEV6(StatCard, {
|
|
2763
3079
|
label: "Lost",
|
|
2764
3080
|
value: stats.lostCount,
|
|
2765
3081
|
hint: "deals lost"
|
|
2766
3082
|
}, undefined, false, undefined, this)
|
|
2767
3083
|
]
|
|
2768
3084
|
}, undefined, true, undefined, this),
|
|
2769
|
-
/* @__PURE__ */
|
|
3085
|
+
/* @__PURE__ */ jsxDEV6(Tabs, {
|
|
2770
3086
|
defaultValue: "pipeline",
|
|
2771
3087
|
className: "w-full",
|
|
2772
3088
|
children: [
|
|
2773
|
-
/* @__PURE__ */
|
|
3089
|
+
/* @__PURE__ */ jsxDEV6(TabsList, {
|
|
2774
3090
|
children: [
|
|
2775
|
-
/* @__PURE__ */
|
|
3091
|
+
/* @__PURE__ */ jsxDEV6(TabsTrigger, {
|
|
2776
3092
|
value: "pipeline",
|
|
2777
3093
|
children: [
|
|
2778
|
-
/* @__PURE__ */
|
|
3094
|
+
/* @__PURE__ */ jsxDEV6("span", {
|
|
2779
3095
|
className: "mr-2",
|
|
2780
3096
|
children: "\uD83D\uDCCA"
|
|
2781
3097
|
}, undefined, false, undefined, this),
|
|
2782
3098
|
"Pipeline"
|
|
2783
3099
|
]
|
|
2784
3100
|
}, undefined, true, undefined, this),
|
|
2785
|
-
/* @__PURE__ */
|
|
3101
|
+
/* @__PURE__ */ jsxDEV6(TabsTrigger, {
|
|
2786
3102
|
value: "list",
|
|
2787
3103
|
children: [
|
|
2788
|
-
/* @__PURE__ */
|
|
3104
|
+
/* @__PURE__ */ jsxDEV6("span", {
|
|
2789
3105
|
className: "mr-2",
|
|
2790
3106
|
children: "\uD83D\uDCCB"
|
|
2791
3107
|
}, undefined, false, undefined, this),
|
|
2792
3108
|
"All Deals"
|
|
2793
3109
|
]
|
|
2794
3110
|
}, undefined, true, undefined, this),
|
|
2795
|
-
/* @__PURE__ */
|
|
3111
|
+
/* @__PURE__ */ jsxDEV6(TabsTrigger, {
|
|
2796
3112
|
value: "metrics",
|
|
2797
3113
|
children: [
|
|
2798
|
-
/* @__PURE__ */
|
|
3114
|
+
/* @__PURE__ */ jsxDEV6("span", {
|
|
2799
3115
|
className: "mr-2",
|
|
2800
3116
|
children: "\uD83D\uDCC8"
|
|
2801
3117
|
}, undefined, false, undefined, this),
|
|
@@ -2804,34 +3120,33 @@ function CrmDashboard() {
|
|
|
2804
3120
|
}, undefined, true, undefined, this)
|
|
2805
3121
|
]
|
|
2806
3122
|
}, undefined, true, undefined, this),
|
|
2807
|
-
/* @__PURE__ */
|
|
3123
|
+
/* @__PURE__ */ jsxDEV6(TabsContent, {
|
|
2808
3124
|
value: "pipeline",
|
|
2809
3125
|
className: "min-h-[400px]",
|
|
2810
|
-
children: /* @__PURE__ */
|
|
3126
|
+
children: /* @__PURE__ */ jsxDEV6(CrmPipelineBoard, {
|
|
2811
3127
|
dealsByStage,
|
|
2812
3128
|
stages,
|
|
2813
3129
|
onDealClick: handleDealClick,
|
|
2814
3130
|
onDealMove: handleDealMove
|
|
2815
3131
|
}, undefined, false, undefined, this)
|
|
2816
3132
|
}, undefined, false, undefined, this),
|
|
2817
|
-
/* @__PURE__ */
|
|
3133
|
+
/* @__PURE__ */ jsxDEV6(TabsContent, {
|
|
2818
3134
|
value: "list",
|
|
2819
3135
|
className: "min-h-[400px]",
|
|
2820
|
-
children: /* @__PURE__ */
|
|
2821
|
-
data,
|
|
3136
|
+
children: /* @__PURE__ */ jsxDEV6(DealListTab, {
|
|
2822
3137
|
onDealClick: handleDealClick
|
|
2823
3138
|
}, undefined, false, undefined, this)
|
|
2824
3139
|
}, undefined, false, undefined, this),
|
|
2825
|
-
/* @__PURE__ */
|
|
3140
|
+
/* @__PURE__ */ jsxDEV6(TabsContent, {
|
|
2826
3141
|
value: "metrics",
|
|
2827
3142
|
className: "min-h-[400px]",
|
|
2828
|
-
children: /* @__PURE__ */
|
|
3143
|
+
children: /* @__PURE__ */ jsxDEV6(MetricsTab, {
|
|
2829
3144
|
stats
|
|
2830
3145
|
}, undefined, false, undefined, this)
|
|
2831
3146
|
}, undefined, false, undefined, this)
|
|
2832
3147
|
]
|
|
2833
3148
|
}, undefined, true, undefined, this),
|
|
2834
|
-
/* @__PURE__ */
|
|
3149
|
+
/* @__PURE__ */ jsxDEV6(CreateDealModal, {
|
|
2835
3150
|
isOpen: isCreateModalOpen,
|
|
2836
3151
|
onClose: () => setIsCreateModalOpen(false),
|
|
2837
3152
|
onSubmit: async (input) => {
|
|
@@ -2840,7 +3155,7 @@ function CrmDashboard() {
|
|
|
2840
3155
|
stages,
|
|
2841
3156
|
isLoading: mutations.createState.loading
|
|
2842
3157
|
}, undefined, false, undefined, this),
|
|
2843
|
-
/* @__PURE__ */
|
|
3158
|
+
/* @__PURE__ */ jsxDEV6(DealActionsModal, {
|
|
2844
3159
|
isOpen: isDealActionsOpen,
|
|
2845
3160
|
deal: selectedDeal,
|
|
2846
3161
|
stages,
|
|
@@ -2863,112 +3178,30 @@ function CrmDashboard() {
|
|
|
2863
3178
|
]
|
|
2864
3179
|
}, undefined, true, undefined, this);
|
|
2865
3180
|
}
|
|
2866
|
-
function DealListTab({ data, onDealClick }) {
|
|
2867
|
-
if (!data?.deals.length) {
|
|
2868
|
-
return /* @__PURE__ */ jsxDEV5("div", {
|
|
2869
|
-
className: "flex h-64 items-center justify-center text-muted-foreground",
|
|
2870
|
-
children: "No deals found"
|
|
2871
|
-
}, undefined, false, undefined, this);
|
|
2872
|
-
}
|
|
2873
|
-
return /* @__PURE__ */ jsxDEV5("div", {
|
|
2874
|
-
className: "rounded-lg border border-border",
|
|
2875
|
-
children: /* @__PURE__ */ jsxDEV5("table", {
|
|
2876
|
-
className: "w-full",
|
|
2877
|
-
children: [
|
|
2878
|
-
/* @__PURE__ */ jsxDEV5("thead", {
|
|
2879
|
-
className: "border-border border-b bg-muted/30",
|
|
2880
|
-
children: /* @__PURE__ */ jsxDEV5("tr", {
|
|
2881
|
-
children: [
|
|
2882
|
-
/* @__PURE__ */ jsxDEV5("th", {
|
|
2883
|
-
className: "px-4 py-3 text-left font-medium text-sm",
|
|
2884
|
-
children: "Deal"
|
|
2885
|
-
}, undefined, false, undefined, this),
|
|
2886
|
-
/* @__PURE__ */ jsxDEV5("th", {
|
|
2887
|
-
className: "px-4 py-3 text-left font-medium text-sm",
|
|
2888
|
-
children: "Value"
|
|
2889
|
-
}, undefined, false, undefined, this),
|
|
2890
|
-
/* @__PURE__ */ jsxDEV5("th", {
|
|
2891
|
-
className: "px-4 py-3 text-left font-medium text-sm",
|
|
2892
|
-
children: "Status"
|
|
2893
|
-
}, undefined, false, undefined, this),
|
|
2894
|
-
/* @__PURE__ */ jsxDEV5("th", {
|
|
2895
|
-
className: "px-4 py-3 text-left font-medium text-sm",
|
|
2896
|
-
children: "Expected Close"
|
|
2897
|
-
}, undefined, false, undefined, this),
|
|
2898
|
-
/* @__PURE__ */ jsxDEV5("th", {
|
|
2899
|
-
className: "px-4 py-3 text-left font-medium text-sm",
|
|
2900
|
-
children: "Actions"
|
|
2901
|
-
}, undefined, false, undefined, this)
|
|
2902
|
-
]
|
|
2903
|
-
}, undefined, true, undefined, this)
|
|
2904
|
-
}, undefined, false, undefined, this),
|
|
2905
|
-
/* @__PURE__ */ jsxDEV5("tbody", {
|
|
2906
|
-
className: "divide-y divide-border",
|
|
2907
|
-
children: data.deals.map((deal3) => /* @__PURE__ */ jsxDEV5("tr", {
|
|
2908
|
-
className: "hover:bg-muted/50",
|
|
2909
|
-
children: [
|
|
2910
|
-
/* @__PURE__ */ jsxDEV5("td", {
|
|
2911
|
-
className: "px-4 py-3",
|
|
2912
|
-
children: /* @__PURE__ */ jsxDEV5("div", {
|
|
2913
|
-
className: "font-medium",
|
|
2914
|
-
children: deal3.name
|
|
2915
|
-
}, undefined, false, undefined, this)
|
|
2916
|
-
}, undefined, false, undefined, this),
|
|
2917
|
-
/* @__PURE__ */ jsxDEV5("td", {
|
|
2918
|
-
className: "px-4 py-3 font-mono",
|
|
2919
|
-
children: formatCurrency4(deal3.value, deal3.currency)
|
|
2920
|
-
}, undefined, false, undefined, this),
|
|
2921
|
-
/* @__PURE__ */ jsxDEV5("td", {
|
|
2922
|
-
className: "px-4 py-3",
|
|
2923
|
-
children: /* @__PURE__ */ jsxDEV5("span", {
|
|
2924
|
-
className: `inline-flex rounded-full px-2 py-0.5 font-medium text-xs ${deal3.status === "WON" ? "bg-green-100 text-green-700 dark:bg-green-900/30 dark:text-green-400" : deal3.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"}`,
|
|
2925
|
-
children: deal3.status
|
|
2926
|
-
}, undefined, false, undefined, this)
|
|
2927
|
-
}, undefined, false, undefined, this),
|
|
2928
|
-
/* @__PURE__ */ jsxDEV5("td", {
|
|
2929
|
-
className: "px-4 py-3 text-muted-foreground",
|
|
2930
|
-
children: deal3.expectedCloseDate?.toLocaleDateString() ?? "-"
|
|
2931
|
-
}, undefined, false, undefined, this),
|
|
2932
|
-
/* @__PURE__ */ jsxDEV5("td", {
|
|
2933
|
-
className: "px-4 py-3",
|
|
2934
|
-
children: /* @__PURE__ */ jsxDEV5(Button3, {
|
|
2935
|
-
variant: "ghost",
|
|
2936
|
-
size: "sm",
|
|
2937
|
-
onPress: () => onDealClick?.(deal3.id),
|
|
2938
|
-
children: "Actions"
|
|
2939
|
-
}, undefined, false, undefined, this)
|
|
2940
|
-
}, undefined, false, undefined, this)
|
|
2941
|
-
]
|
|
2942
|
-
}, deal3.id, true, undefined, this))
|
|
2943
|
-
}, undefined, false, undefined, this)
|
|
2944
|
-
]
|
|
2945
|
-
}, undefined, true, undefined, this)
|
|
2946
|
-
}, undefined, false, undefined, this);
|
|
2947
|
-
}
|
|
2948
3181
|
function MetricsTab({
|
|
2949
3182
|
stats
|
|
2950
3183
|
}) {
|
|
2951
3184
|
if (!stats)
|
|
2952
3185
|
return null;
|
|
2953
|
-
return /* @__PURE__ */
|
|
3186
|
+
return /* @__PURE__ */ jsxDEV6("div", {
|
|
2954
3187
|
className: "space-y-6",
|
|
2955
|
-
children: /* @__PURE__ */
|
|
3188
|
+
children: /* @__PURE__ */ jsxDEV6("div", {
|
|
2956
3189
|
className: "rounded-xl border border-border bg-card p-6",
|
|
2957
3190
|
children: [
|
|
2958
|
-
/* @__PURE__ */
|
|
3191
|
+
/* @__PURE__ */ jsxDEV6("h3", {
|
|
2959
3192
|
className: "mb-4 font-semibold text-lg",
|
|
2960
3193
|
children: "Pipeline Overview"
|
|
2961
3194
|
}, undefined, false, undefined, this),
|
|
2962
|
-
/* @__PURE__ */
|
|
3195
|
+
/* @__PURE__ */ jsxDEV6("dl", {
|
|
2963
3196
|
className: "grid gap-4 sm:grid-cols-3",
|
|
2964
3197
|
children: [
|
|
2965
|
-
/* @__PURE__ */
|
|
3198
|
+
/* @__PURE__ */ jsxDEV6("div", {
|
|
2966
3199
|
children: [
|
|
2967
|
-
/* @__PURE__ */
|
|
3200
|
+
/* @__PURE__ */ jsxDEV6("dt", {
|
|
2968
3201
|
className: "text-muted-foreground text-sm",
|
|
2969
3202
|
children: "Win Rate"
|
|
2970
3203
|
}, undefined, false, undefined, this),
|
|
2971
|
-
/* @__PURE__ */
|
|
3204
|
+
/* @__PURE__ */ jsxDEV6("dd", {
|
|
2972
3205
|
className: "font-semibold text-2xl",
|
|
2973
3206
|
children: [
|
|
2974
3207
|
stats.total > 0 ? (stats.wonCount / stats.total * 100).toFixed(0) : 0,
|
|
@@ -2977,25 +3210,25 @@ function MetricsTab({
|
|
|
2977
3210
|
}, undefined, true, undefined, this)
|
|
2978
3211
|
]
|
|
2979
3212
|
}, undefined, true, undefined, this),
|
|
2980
|
-
/* @__PURE__ */
|
|
3213
|
+
/* @__PURE__ */ jsxDEV6("div", {
|
|
2981
3214
|
children: [
|
|
2982
|
-
/* @__PURE__ */
|
|
3215
|
+
/* @__PURE__ */ jsxDEV6("dt", {
|
|
2983
3216
|
className: "text-muted-foreground text-sm",
|
|
2984
3217
|
children: "Avg Deal Size"
|
|
2985
3218
|
}, undefined, false, undefined, this),
|
|
2986
|
-
/* @__PURE__ */
|
|
3219
|
+
/* @__PURE__ */ jsxDEV6("dd", {
|
|
2987
3220
|
className: "font-semibold text-2xl",
|
|
2988
|
-
children:
|
|
3221
|
+
children: formatCurrency5(stats.total > 0 ? stats.totalValue / stats.total : 0)
|
|
2989
3222
|
}, undefined, false, undefined, this)
|
|
2990
3223
|
]
|
|
2991
3224
|
}, undefined, true, undefined, this),
|
|
2992
|
-
/* @__PURE__ */
|
|
3225
|
+
/* @__PURE__ */ jsxDEV6("div", {
|
|
2993
3226
|
children: [
|
|
2994
|
-
/* @__PURE__ */
|
|
3227
|
+
/* @__PURE__ */ jsxDEV6("dt", {
|
|
2995
3228
|
className: "text-muted-foreground text-sm",
|
|
2996
3229
|
children: "Conversion"
|
|
2997
3230
|
}, undefined, false, undefined, this),
|
|
2998
|
-
/* @__PURE__ */
|
|
3231
|
+
/* @__PURE__ */ jsxDEV6("dd", {
|
|
2999
3232
|
className: "font-semibold text-2xl",
|
|
3000
3233
|
children: [
|
|
3001
3234
|
stats.wonCount,
|
|
@@ -3065,7 +3298,7 @@ var crmOverlays = [
|
|
|
3065
3298
|
crmSalesRepOverlay
|
|
3066
3299
|
];
|
|
3067
3300
|
// src/ui/renderers/pipeline.markdown.ts
|
|
3068
|
-
function
|
|
3301
|
+
function formatCurrency6(value, currency = "USD") {
|
|
3069
3302
|
return new Intl.NumberFormat("en-US", {
|
|
3070
3303
|
style: "currency",
|
|
3071
3304
|
currency,
|
|
@@ -3092,7 +3325,7 @@ var crmPipelineMarkdownRenderer = {
|
|
|
3092
3325
|
const lines = [
|
|
3093
3326
|
"# CRM Pipeline",
|
|
3094
3327
|
"",
|
|
3095
|
-
`**Total Value**: ${
|
|
3328
|
+
`**Total Value**: ${formatCurrency6(dealsResult.totalValue)}`,
|
|
3096
3329
|
`**Total Deals**: ${dealsResult.total}`,
|
|
3097
3330
|
""
|
|
3098
3331
|
];
|
|
@@ -3100,13 +3333,13 @@ var crmPipelineMarkdownRenderer = {
|
|
|
3100
3333
|
const stageDeals = dealsByStage[stage.id] ?? [];
|
|
3101
3334
|
const stageValue = stageDeals.reduce((sum, d) => sum + d.value, 0);
|
|
3102
3335
|
lines.push(`## ${stage.name}`);
|
|
3103
|
-
lines.push(`_${stageDeals.length} deals · ${
|
|
3336
|
+
lines.push(`_${stageDeals.length} deals · ${formatCurrency6(stageValue)}_`);
|
|
3104
3337
|
lines.push("");
|
|
3105
3338
|
if (stageDeals.length === 0) {
|
|
3106
3339
|
lines.push("_No deals_");
|
|
3107
3340
|
} else {
|
|
3108
3341
|
for (const deal3 of stageDeals) {
|
|
3109
|
-
lines.push(`- **${deal3.name}** - ${
|
|
3342
|
+
lines.push(`- **${deal3.name}** - ${formatCurrency6(deal3.value, deal3.currency)}`);
|
|
3110
3343
|
}
|
|
3111
3344
|
}
|
|
3112
3345
|
lines.push("");
|
|
@@ -3146,9 +3379,9 @@ var crmDashboardMarkdownRenderer = {
|
|
|
3146
3379
|
"| Metric | Value |",
|
|
3147
3380
|
"|--------|-------|",
|
|
3148
3381
|
`| Total Deals | ${dealsResult.total} |`,
|
|
3149
|
-
`| Pipeline Value | ${
|
|
3150
|
-
`| Open Deals | ${openDeals.length} (${
|
|
3151
|
-
`| Won Deals | ${wonDeals.length} (${
|
|
3382
|
+
`| Pipeline Value | ${formatCurrency6(dealsResult.totalValue)} |`,
|
|
3383
|
+
`| Open Deals | ${openDeals.length} (${formatCurrency6(openValue)}) |`,
|
|
3384
|
+
`| Won Deals | ${wonDeals.length} (${formatCurrency6(wonValue)}) |`,
|
|
3152
3385
|
`| Lost Deals | ${lostDeals.length} |`,
|
|
3153
3386
|
"",
|
|
3154
3387
|
"## Pipeline Stages",
|
|
@@ -3159,7 +3392,7 @@ var crmDashboardMarkdownRenderer = {
|
|
|
3159
3392
|
for (const stage of stageList.sort((a, b) => a.position - b.position)) {
|
|
3160
3393
|
const stageDeals = openDeals.filter((d) => d.stageId === stage.id);
|
|
3161
3394
|
const stageValue = stageDeals.reduce((sum, d) => sum + d.value, 0);
|
|
3162
|
-
lines.push(`| ${stage.name} | ${stageDeals.length} | ${
|
|
3395
|
+
lines.push(`| ${stage.name} | ${stageDeals.length} | ${formatCurrency6(stageValue)} |`);
|
|
3163
3396
|
}
|
|
3164
3397
|
lines.push("");
|
|
3165
3398
|
lines.push("## Recent Deals");
|
|
@@ -3172,7 +3405,7 @@ var crmDashboardMarkdownRenderer = {
|
|
|
3172
3405
|
lines.push("|------|-------|-------|--------|");
|
|
3173
3406
|
for (const deal3 of recentDeals) {
|
|
3174
3407
|
const stage = stageList.find((s) => s.id === deal3.stageId);
|
|
3175
|
-
lines.push(`| ${deal3.name} | ${
|
|
3408
|
+
lines.push(`| ${deal3.name} | ${formatCurrency6(deal3.value, deal3.currency)} | ${stage?.name ?? "-"} | ${deal3.status} |`);
|
|
3176
3409
|
}
|
|
3177
3410
|
}
|
|
3178
3411
|
return {
|
|
@@ -3184,10 +3417,10 @@ var crmDashboardMarkdownRenderer = {
|
|
|
3184
3417
|
};
|
|
3185
3418
|
|
|
3186
3419
|
// src/ui/renderers/pipeline.renderer.tsx
|
|
3187
|
-
import { jsxDEV as
|
|
3420
|
+
import { jsxDEV as jsxDEV7 } from "react/jsx-dev-runtime";
|
|
3188
3421
|
function CrmPipelineBoardWrapper() {
|
|
3189
3422
|
const { dealsByStage, stages } = useDealList();
|
|
3190
|
-
return /* @__PURE__ */
|
|
3423
|
+
return /* @__PURE__ */ jsxDEV7(CrmPipelineBoard, {
|
|
3191
3424
|
dealsByStage,
|
|
3192
3425
|
stages
|
|
3193
3426
|
}, undefined, false, undefined, this);
|
|
@@ -3201,7 +3434,7 @@ var crmPipelineReactRenderer = {
|
|
|
3201
3434
|
if (desc.source.componentKey !== "CrmPipelineView") {
|
|
3202
3435
|
throw new Error(`Unknown component: ${desc.source.componentKey}`);
|
|
3203
3436
|
}
|
|
3204
|
-
return /* @__PURE__ */
|
|
3437
|
+
return /* @__PURE__ */ jsxDEV7(CrmPipelineBoardWrapper, {}, undefined, false, undefined, this);
|
|
3205
3438
|
}
|
|
3206
3439
|
};
|
|
3207
3440
|
// src/index.ts
|