@contractspec/example.crm-pipeline 3.7.6 → 3.7.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-build.log +8 -8
- package/AGENTS.md +51 -33
- package/README.md +66 -148
- package/dist/browser/events/contact.event.js +1 -1
- package/dist/browser/events/deal.event.js +1 -1
- package/dist/browser/events/index.js +3 -3
- package/dist/browser/events/task.event.js +1 -1
- package/dist/browser/index.js +293 -293
- package/dist/browser/ui/CrmDashboard.js +221 -221
- package/dist/browser/ui/CrmDealCard.js +5 -5
- package/dist/browser/ui/CrmPipelineBoard.js +13 -13
- package/dist/browser/ui/hooks/index.js +2 -2
- package/dist/browser/ui/hooks/useDealList.js +1 -1
- package/dist/browser/ui/hooks/useDealMutations.js +1 -1
- package/dist/browser/ui/index.js +290 -290
- package/dist/browser/ui/modals/CreateDealModal.js +12 -12
- package/dist/browser/ui/modals/DealActionsModal.js +21 -21
- package/dist/browser/ui/modals/index.js +33 -33
- package/dist/browser/ui/renderers/index.js +116 -116
- package/dist/browser/ui/renderers/pipeline.renderer.js +97 -97
- package/dist/deal/index.d.ts +2 -2
- package/dist/events/contact.event.js +1 -1
- package/dist/events/deal.event.js +1 -1
- package/dist/events/index.js +3 -3
- package/dist/events/task.event.js +1 -1
- package/dist/handlers/index.d.ts +2 -2
- package/dist/index.d.ts +3 -3
- package/dist/index.js +293 -293
- package/dist/node/events/contact.event.js +1 -1
- package/dist/node/events/deal.event.js +1 -1
- package/dist/node/events/index.js +3 -3
- package/dist/node/events/task.event.js +1 -1
- package/dist/node/index.js +293 -293
- package/dist/node/ui/CrmDashboard.js +221 -221
- package/dist/node/ui/CrmDealCard.js +5 -5
- package/dist/node/ui/CrmPipelineBoard.js +13 -13
- package/dist/node/ui/hooks/index.js +2 -2
- package/dist/node/ui/hooks/useDealList.js +1 -1
- package/dist/node/ui/hooks/useDealMutations.js +1 -1
- package/dist/node/ui/index.js +290 -290
- package/dist/node/ui/modals/CreateDealModal.js +12 -12
- package/dist/node/ui/modals/DealActionsModal.js +21 -21
- package/dist/node/ui/modals/index.js +33 -33
- package/dist/node/ui/renderers/index.js +116 -116
- package/dist/node/ui/renderers/pipeline.renderer.js +97 -97
- package/dist/operations/index.d.ts +1 -1
- package/dist/ui/CrmDashboard.js +221 -221
- package/dist/ui/CrmDealCard.js +5 -5
- package/dist/ui/CrmPipelineBoard.js +13 -13
- package/dist/ui/hooks/index.d.ts +2 -2
- package/dist/ui/hooks/index.js +2 -2
- package/dist/ui/hooks/useDealList.js +1 -1
- package/dist/ui/hooks/useDealMutations.d.ts +9 -0
- package/dist/ui/hooks/useDealMutations.js +1 -1
- package/dist/ui/index.d.ts +3 -3
- package/dist/ui/index.js +290 -290
- package/dist/ui/modals/CreateDealModal.js +12 -12
- package/dist/ui/modals/DealActionsModal.js +21 -21
- package/dist/ui/modals/index.js +33 -33
- package/dist/ui/renderers/index.d.ts +1 -1
- package/dist/ui/renderers/index.js +116 -116
- package/dist/ui/renderers/pipeline.renderer.d.ts +1 -1
- package/dist/ui/renderers/pipeline.renderer.js +97 -97
- package/package.json +10 -10
- package/src/crm-pipeline.feature.ts +86 -86
- package/src/deal/deal.enum.ts +8 -8
- package/src/deal/deal.operation.ts +255 -255
- package/src/deal/deal.schema.ts +92 -92
- package/src/deal/deal.test-spec.ts +48 -48
- package/src/deal/index.ts +17 -19
- package/src/docs/crm-pipeline.docblock.ts +43 -43
- package/src/entities/company.entity.ts +52 -52
- package/src/entities/contact.entity.ts +67 -67
- package/src/entities/deal.entity.ts +134 -134
- package/src/entities/index.ts +27 -27
- package/src/entities/task.entity.ts +105 -105
- package/src/events/contact.event.ts +22 -22
- package/src/events/deal.event.ts +77 -77
- package/src/events/task.event.ts +19 -19
- package/src/example.ts +32 -32
- package/src/handlers/crm.handlers.ts +358 -357
- package/src/handlers/deal.handlers.ts +179 -179
- package/src/handlers/index.ts +18 -19
- package/src/handlers/mock-data.ts +167 -167
- package/src/index.ts +11 -11
- package/src/operations/index.ts +16 -16
- package/src/presentations/dashboard.presentation.ts +45 -45
- package/src/presentations/pipeline.presentation.ts +90 -90
- package/src/seeders/index.ts +26 -26
- package/src/shared/overlay-types.ts +23 -23
- package/src/ui/CrmDashboard.tsx +256 -256
- package/src/ui/CrmDealCard.tsx +64 -64
- package/src/ui/CrmPipelineBoard.tsx +105 -105
- package/src/ui/hooks/index.ts +3 -3
- package/src/ui/hooks/useDealList.ts +85 -85
- package/src/ui/hooks/useDealMutations.ts +151 -150
- package/src/ui/index.ts +5 -10
- package/src/ui/modals/CreateDealModal.tsx +217 -217
- package/src/ui/modals/DealActionsModal.tsx +390 -390
- package/src/ui/overlays/demo-overlays.ts +43 -43
- package/src/ui/renderers/index.ts +4 -3
- package/src/ui/renderers/pipeline.markdown.ts +165 -165
- package/src/ui/renderers/pipeline.renderer.tsx +17 -16
- package/tsconfig.json +7 -8
- package/tsdown.config.js +7 -3
package/dist/node/index.js
CHANGED
|
@@ -909,8 +909,8 @@ var crmPipelineSchemaContribution = {
|
|
|
909
909
|
};
|
|
910
910
|
|
|
911
911
|
// src/events/contact.event.ts
|
|
912
|
-
import { ScalarTypeEnum as ScalarTypeEnum2, defineSchemaModel as defineSchemaModel2 } from "@contractspec/lib.schema";
|
|
913
912
|
import { defineEvent } from "@contractspec/lib.contracts-spec";
|
|
913
|
+
import { defineSchemaModel as defineSchemaModel2, ScalarTypeEnum as ScalarTypeEnum2 } from "@contractspec/lib.schema";
|
|
914
914
|
var ContactCreatedPayload = defineSchemaModel2({
|
|
915
915
|
name: "ContactCreatedPayload",
|
|
916
916
|
description: "Payload when a contact is created",
|
|
@@ -938,8 +938,8 @@ var ContactCreatedEvent = defineEvent({
|
|
|
938
938
|
});
|
|
939
939
|
|
|
940
940
|
// src/events/deal.event.ts
|
|
941
|
-
import { ScalarTypeEnum as ScalarTypeEnum3, defineSchemaModel as defineSchemaModel3 } from "@contractspec/lib.schema";
|
|
942
941
|
import { defineEvent as defineEvent2 } from "@contractspec/lib.contracts-spec";
|
|
942
|
+
import { defineSchemaModel as defineSchemaModel3, ScalarTypeEnum as ScalarTypeEnum3 } from "@contractspec/lib.schema";
|
|
943
943
|
var DealCreatedPayload = defineSchemaModel3({
|
|
944
944
|
name: "DealCreatedPayload",
|
|
945
945
|
description: "Payload when a deal is created",
|
|
@@ -1034,8 +1034,8 @@ var DealLostEvent = defineEvent2({
|
|
|
1034
1034
|
});
|
|
1035
1035
|
|
|
1036
1036
|
// src/events/task.event.ts
|
|
1037
|
-
import { ScalarTypeEnum as ScalarTypeEnum4, defineSchemaModel as defineSchemaModel4 } from "@contractspec/lib.schema";
|
|
1038
1037
|
import { defineEvent as defineEvent3 } from "@contractspec/lib.contracts-spec";
|
|
1038
|
+
import { defineSchemaModel as defineSchemaModel4, ScalarTypeEnum as ScalarTypeEnum4 } from "@contractspec/lib.schema";
|
|
1039
1039
|
var TaskCompletedPayload = defineSchemaModel4({
|
|
1040
1040
|
name: "TaskCompletedPayload",
|
|
1041
1041
|
description: "Payload when a task is completed",
|
|
@@ -1689,19 +1689,177 @@ var DealCardPresentation = definePresentation2({
|
|
|
1689
1689
|
flags: ["crm.deals.enabled"]
|
|
1690
1690
|
}
|
|
1691
1691
|
});
|
|
1692
|
+
// src/ui/CrmDealCard.tsx
|
|
1693
|
+
import { jsxDEV } from "react/jsx-dev-runtime";
|
|
1694
|
+
"use client";
|
|
1695
|
+
function formatCurrency(value, currency) {
|
|
1696
|
+
return new Intl.NumberFormat("en-US", {
|
|
1697
|
+
style: "currency",
|
|
1698
|
+
currency,
|
|
1699
|
+
minimumFractionDigits: 0,
|
|
1700
|
+
maximumFractionDigits: 0
|
|
1701
|
+
}).format(value);
|
|
1702
|
+
}
|
|
1703
|
+
function CrmDealCard({ deal: deal3, onClick }) {
|
|
1704
|
+
const daysUntilClose = deal3.expectedCloseDate ? Math.ceil((deal3.expectedCloseDate.getTime() - Date.now()) / (1000 * 60 * 60 * 24)) : null;
|
|
1705
|
+
return /* @__PURE__ */ jsxDEV("div", {
|
|
1706
|
+
onClick,
|
|
1707
|
+
className: "cursor-pointer rounded-lg border border-border bg-card p-3 shadow-sm transition-shadow hover:shadow-md",
|
|
1708
|
+
role: "button",
|
|
1709
|
+
tabIndex: 0,
|
|
1710
|
+
onKeyDown: (e) => {
|
|
1711
|
+
if (e.key === "Enter" || e.key === " ")
|
|
1712
|
+
onClick?.();
|
|
1713
|
+
},
|
|
1714
|
+
children: [
|
|
1715
|
+
/* @__PURE__ */ jsxDEV("h4", {
|
|
1716
|
+
className: "font-medium leading-snug",
|
|
1717
|
+
children: deal3.name
|
|
1718
|
+
}, undefined, false, undefined, this),
|
|
1719
|
+
/* @__PURE__ */ jsxDEV("div", {
|
|
1720
|
+
className: "mt-2 font-semibold text-lg text-primary",
|
|
1721
|
+
children: formatCurrency(deal3.value, deal3.currency)
|
|
1722
|
+
}, undefined, false, undefined, this),
|
|
1723
|
+
/* @__PURE__ */ jsxDEV("div", {
|
|
1724
|
+
className: "mt-3 flex items-center justify-between text-muted-foreground text-xs",
|
|
1725
|
+
children: [
|
|
1726
|
+
daysUntilClose !== null && /* @__PURE__ */ jsxDEV("span", {
|
|
1727
|
+
className: daysUntilClose < 0 ? "text-red-500" : daysUntilClose <= 7 ? "text-yellow-600 dark:text-yellow-500" : "",
|
|
1728
|
+
children: daysUntilClose < 0 ? `${Math.abs(daysUntilClose)}d overdue` : daysUntilClose === 0 ? "Due today" : `${daysUntilClose}d left`
|
|
1729
|
+
}, undefined, false, undefined, this),
|
|
1730
|
+
/* @__PURE__ */ jsxDEV("span", {
|
|
1731
|
+
className: `rounded px-1.5 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"}`,
|
|
1732
|
+
children: deal3.status
|
|
1733
|
+
}, undefined, false, undefined, this)
|
|
1734
|
+
]
|
|
1735
|
+
}, undefined, true, undefined, this)
|
|
1736
|
+
]
|
|
1737
|
+
}, undefined, true, undefined, this);
|
|
1738
|
+
}
|
|
1739
|
+
|
|
1740
|
+
// src/ui/CrmPipelineBoard.tsx
|
|
1741
|
+
import { useState } from "react";
|
|
1742
|
+
import { jsxDEV as jsxDEV2 } from "react/jsx-dev-runtime";
|
|
1743
|
+
"use client";
|
|
1744
|
+
function formatCurrency2(value) {
|
|
1745
|
+
if (value >= 1e6)
|
|
1746
|
+
return `$${(value / 1e6).toFixed(1)}M`;
|
|
1747
|
+
if (value >= 1000)
|
|
1748
|
+
return `$${(value / 1000).toFixed(0)}K`;
|
|
1749
|
+
return `$${value}`;
|
|
1750
|
+
}
|
|
1751
|
+
function CrmPipelineBoard({
|
|
1752
|
+
dealsByStage,
|
|
1753
|
+
stages,
|
|
1754
|
+
onDealClick,
|
|
1755
|
+
onDealMove
|
|
1756
|
+
}) {
|
|
1757
|
+
const [quickMoveOpen, setQuickMoveOpen] = useState(null);
|
|
1758
|
+
const sortedStages = [...stages].sort((a, b) => a.position - b.position);
|
|
1759
|
+
const handleQuickMove = (dealId, toStageId) => {
|
|
1760
|
+
onDealMove?.(dealId, toStageId);
|
|
1761
|
+
setQuickMoveOpen(null);
|
|
1762
|
+
};
|
|
1763
|
+
return /* @__PURE__ */ jsxDEV2("div", {
|
|
1764
|
+
className: "flex gap-4 overflow-x-auto pb-4",
|
|
1765
|
+
children: sortedStages.map((stage) => {
|
|
1766
|
+
const deals = dealsByStage[stage.id] ?? [];
|
|
1767
|
+
const stageValue = deals.reduce((sum, d) => sum + d.value, 0);
|
|
1768
|
+
return /* @__PURE__ */ jsxDEV2("div", {
|
|
1769
|
+
className: "flex w-72 flex-shrink-0 flex-col rounded-lg bg-muted/30",
|
|
1770
|
+
children: [
|
|
1771
|
+
/* @__PURE__ */ jsxDEV2("div", {
|
|
1772
|
+
className: "flex items-center justify-between border-border border-b px-3 py-2",
|
|
1773
|
+
children: [
|
|
1774
|
+
/* @__PURE__ */ jsxDEV2("div", {
|
|
1775
|
+
children: [
|
|
1776
|
+
/* @__PURE__ */ jsxDEV2("h3", {
|
|
1777
|
+
className: "font-medium",
|
|
1778
|
+
children: stage.name
|
|
1779
|
+
}, undefined, false, undefined, this),
|
|
1780
|
+
/* @__PURE__ */ jsxDEV2("p", {
|
|
1781
|
+
className: "text-muted-foreground text-xs",
|
|
1782
|
+
children: [
|
|
1783
|
+
deals.length,
|
|
1784
|
+
" deals · ",
|
|
1785
|
+
formatCurrency2(stageValue)
|
|
1786
|
+
]
|
|
1787
|
+
}, undefined, true, undefined, this)
|
|
1788
|
+
]
|
|
1789
|
+
}, undefined, true, undefined, this),
|
|
1790
|
+
/* @__PURE__ */ jsxDEV2("span", {
|
|
1791
|
+
className: "flex h-6 w-6 items-center justify-center rounded-full bg-muted font-medium text-xs",
|
|
1792
|
+
children: deals.length
|
|
1793
|
+
}, undefined, false, undefined, this)
|
|
1794
|
+
]
|
|
1795
|
+
}, undefined, true, undefined, this),
|
|
1796
|
+
/* @__PURE__ */ jsxDEV2("div", {
|
|
1797
|
+
className: "flex flex-1 flex-col gap-2 p-2",
|
|
1798
|
+
children: deals.length === 0 ? /* @__PURE__ */ jsxDEV2("div", {
|
|
1799
|
+
className: "flex h-24 items-center justify-center rounded-md border-2 border-muted-foreground/20 border-dashed text-muted-foreground text-xs",
|
|
1800
|
+
children: "No deals"
|
|
1801
|
+
}, undefined, false, undefined, this) : deals.map((deal3) => /* @__PURE__ */ jsxDEV2("div", {
|
|
1802
|
+
className: "group relative",
|
|
1803
|
+
children: [
|
|
1804
|
+
/* @__PURE__ */ jsxDEV2(CrmDealCard, {
|
|
1805
|
+
deal: deal3,
|
|
1806
|
+
onClick: () => onDealClick?.(deal3.id)
|
|
1807
|
+
}, undefined, false, undefined, this),
|
|
1808
|
+
deal3.status === "OPEN" && onDealMove && /* @__PURE__ */ jsxDEV2("div", {
|
|
1809
|
+
className: "absolute top-1 right-1 opacity-0 transition-opacity group-hover:opacity-100",
|
|
1810
|
+
children: [
|
|
1811
|
+
/* @__PURE__ */ jsxDEV2("button", {
|
|
1812
|
+
type: "button",
|
|
1813
|
+
onClick: (e) => {
|
|
1814
|
+
e.stopPropagation();
|
|
1815
|
+
setQuickMoveOpen(quickMoveOpen === deal3.id ? null : deal3.id);
|
|
1816
|
+
},
|
|
1817
|
+
className: "flex h-6 w-6 items-center justify-center rounded border border-border bg-background text-xs shadow-sm hover:bg-muted",
|
|
1818
|
+
title: "Quick move",
|
|
1819
|
+
children: "➡️"
|
|
1820
|
+
}, undefined, false, undefined, this),
|
|
1821
|
+
quickMoveOpen === deal3.id && /* @__PURE__ */ jsxDEV2("div", {
|
|
1822
|
+
className: "absolute top-7 right-0 z-20 min-w-[140px] rounded-lg border border-border bg-card py-1 shadow-lg",
|
|
1823
|
+
children: [
|
|
1824
|
+
/* @__PURE__ */ jsxDEV2("p", {
|
|
1825
|
+
className: "px-3 py-1 font-medium text-muted-foreground text-xs",
|
|
1826
|
+
children: "Move to:"
|
|
1827
|
+
}, undefined, false, undefined, this),
|
|
1828
|
+
sortedStages.filter((s) => s.id !== deal3.stageId).map((s) => /* @__PURE__ */ jsxDEV2("button", {
|
|
1829
|
+
type: "button",
|
|
1830
|
+
onClick: (e) => {
|
|
1831
|
+
e.stopPropagation();
|
|
1832
|
+
handleQuickMove(deal3.id, s.id);
|
|
1833
|
+
},
|
|
1834
|
+
className: "w-full px-3 py-1.5 text-left text-sm hover:bg-muted",
|
|
1835
|
+
children: s.name
|
|
1836
|
+
}, s.id, false, undefined, this))
|
|
1837
|
+
]
|
|
1838
|
+
}, undefined, true, undefined, this)
|
|
1839
|
+
]
|
|
1840
|
+
}, undefined, true, undefined, this)
|
|
1841
|
+
]
|
|
1842
|
+
}, deal3.id, true, undefined, this))
|
|
1843
|
+
}, undefined, false, undefined, this)
|
|
1844
|
+
]
|
|
1845
|
+
}, stage.id, true, undefined, this);
|
|
1846
|
+
})
|
|
1847
|
+
}, undefined, false, undefined, this);
|
|
1848
|
+
}
|
|
1849
|
+
|
|
1692
1850
|
// src/ui/hooks/useDealList.ts
|
|
1693
|
-
import { useCallback, useEffect, useMemo, useState } from "react";
|
|
1694
1851
|
import { useTemplateRuntime } from "@contractspec/lib.example-shared-ui";
|
|
1852
|
+
import { useCallback, useEffect, useMemo, useState as useState2 } from "react";
|
|
1695
1853
|
"use client";
|
|
1696
1854
|
function useDealList(options = {}) {
|
|
1697
1855
|
const { handlers, projectId } = useTemplateRuntime();
|
|
1698
1856
|
const { crm: crm2 } = handlers;
|
|
1699
|
-
const [data, setData] =
|
|
1700
|
-
const [dealsByStage, setDealsByStage] =
|
|
1701
|
-
const [stages, setStages] =
|
|
1702
|
-
const [loading, setLoading] =
|
|
1703
|
-
const [error, setError] =
|
|
1704
|
-
const [page, setPage] =
|
|
1857
|
+
const [data, setData] = useState2(null);
|
|
1858
|
+
const [dealsByStage, setDealsByStage] = useState2({});
|
|
1859
|
+
const [stages, setStages] = useState2([]);
|
|
1860
|
+
const [loading, setLoading] = useState2(true);
|
|
1861
|
+
const [error, setError] = useState2(null);
|
|
1862
|
+
const [page, setPage] = useState2(1);
|
|
1705
1863
|
const pipelineId = options.pipelineId ?? "pipeline-1";
|
|
1706
1864
|
const fetchData = useCallback(async () => {
|
|
1707
1865
|
setLoading(true);
|
|
@@ -1772,27 +1930,27 @@ function useDealList(options = {}) {
|
|
|
1772
1930
|
}
|
|
1773
1931
|
|
|
1774
1932
|
// src/ui/hooks/useDealMutations.ts
|
|
1775
|
-
import { useCallback as useCallback2, useState as useState2 } from "react";
|
|
1776
1933
|
import { useTemplateRuntime as useTemplateRuntime2 } from "@contractspec/lib.example-shared-ui";
|
|
1934
|
+
import { useCallback as useCallback2, useState as useState3 } from "react";
|
|
1777
1935
|
function useDealMutations(options = {}) {
|
|
1778
1936
|
const { handlers, projectId } = useTemplateRuntime2();
|
|
1779
1937
|
const { crm: crm2 } = handlers;
|
|
1780
|
-
const [createState, setCreateState] =
|
|
1938
|
+
const [createState, setCreateState] = useState3({
|
|
1781
1939
|
loading: false,
|
|
1782
1940
|
error: null,
|
|
1783
1941
|
data: null
|
|
1784
1942
|
});
|
|
1785
|
-
const [moveState, setMoveState] =
|
|
1943
|
+
const [moveState, setMoveState] = useState3({
|
|
1786
1944
|
loading: false,
|
|
1787
1945
|
error: null,
|
|
1788
1946
|
data: null
|
|
1789
1947
|
});
|
|
1790
|
-
const [winState, setWinState] =
|
|
1948
|
+
const [winState, setWinState] = useState3({
|
|
1791
1949
|
loading: false,
|
|
1792
1950
|
error: null,
|
|
1793
1951
|
data: null
|
|
1794
1952
|
});
|
|
1795
|
-
const [loseState, setLoseState] =
|
|
1953
|
+
const [loseState, setLoseState] = useState3({
|
|
1796
1954
|
loading: false,
|
|
1797
1955
|
error: null,
|
|
1798
1956
|
data: null
|
|
@@ -1869,167 +2027,9 @@ function useDealMutations(options = {}) {
|
|
|
1869
2027
|
};
|
|
1870
2028
|
}
|
|
1871
2029
|
|
|
1872
|
-
// src/ui/CrmDealCard.tsx
|
|
1873
|
-
import { jsxDEV } from "react/jsx-dev-runtime";
|
|
1874
|
-
"use client";
|
|
1875
|
-
function formatCurrency(value, currency) {
|
|
1876
|
-
return new Intl.NumberFormat("en-US", {
|
|
1877
|
-
style: "currency",
|
|
1878
|
-
currency,
|
|
1879
|
-
minimumFractionDigits: 0,
|
|
1880
|
-
maximumFractionDigits: 0
|
|
1881
|
-
}).format(value);
|
|
1882
|
-
}
|
|
1883
|
-
function CrmDealCard({ deal: deal3, onClick }) {
|
|
1884
|
-
const daysUntilClose = deal3.expectedCloseDate ? Math.ceil((deal3.expectedCloseDate.getTime() - Date.now()) / (1000 * 60 * 60 * 24)) : null;
|
|
1885
|
-
return /* @__PURE__ */ jsxDEV("div", {
|
|
1886
|
-
onClick,
|
|
1887
|
-
className: "border-border bg-card cursor-pointer rounded-lg border p-3 shadow-sm transition-shadow hover:shadow-md",
|
|
1888
|
-
role: "button",
|
|
1889
|
-
tabIndex: 0,
|
|
1890
|
-
onKeyDown: (e) => {
|
|
1891
|
-
if (e.key === "Enter" || e.key === " ")
|
|
1892
|
-
onClick?.();
|
|
1893
|
-
},
|
|
1894
|
-
children: [
|
|
1895
|
-
/* @__PURE__ */ jsxDEV("h4", {
|
|
1896
|
-
className: "leading-snug font-medium",
|
|
1897
|
-
children: deal3.name
|
|
1898
|
-
}, undefined, false, undefined, this),
|
|
1899
|
-
/* @__PURE__ */ jsxDEV("div", {
|
|
1900
|
-
className: "text-primary mt-2 text-lg font-semibold",
|
|
1901
|
-
children: formatCurrency(deal3.value, deal3.currency)
|
|
1902
|
-
}, undefined, false, undefined, this),
|
|
1903
|
-
/* @__PURE__ */ jsxDEV("div", {
|
|
1904
|
-
className: "text-muted-foreground mt-3 flex items-center justify-between text-xs",
|
|
1905
|
-
children: [
|
|
1906
|
-
daysUntilClose !== null && /* @__PURE__ */ jsxDEV("span", {
|
|
1907
|
-
className: daysUntilClose < 0 ? "text-red-500" : daysUntilClose <= 7 ? "text-yellow-600 dark:text-yellow-500" : "",
|
|
1908
|
-
children: daysUntilClose < 0 ? `${Math.abs(daysUntilClose)}d overdue` : daysUntilClose === 0 ? "Due today" : `${daysUntilClose}d left`
|
|
1909
|
-
}, undefined, false, undefined, this),
|
|
1910
|
-
/* @__PURE__ */ jsxDEV("span", {
|
|
1911
|
-
className: `rounded px-1.5 py-0.5 text-xs font-medium ${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"}`,
|
|
1912
|
-
children: deal3.status
|
|
1913
|
-
}, undefined, false, undefined, this)
|
|
1914
|
-
]
|
|
1915
|
-
}, undefined, true, undefined, this)
|
|
1916
|
-
]
|
|
1917
|
-
}, undefined, true, undefined, this);
|
|
1918
|
-
}
|
|
1919
|
-
|
|
1920
|
-
// src/ui/CrmPipelineBoard.tsx
|
|
1921
|
-
import { useState as useState3 } from "react";
|
|
1922
|
-
import { jsxDEV as jsxDEV2 } from "react/jsx-dev-runtime";
|
|
1923
|
-
"use client";
|
|
1924
|
-
function formatCurrency2(value) {
|
|
1925
|
-
if (value >= 1e6)
|
|
1926
|
-
return `$${(value / 1e6).toFixed(1)}M`;
|
|
1927
|
-
if (value >= 1000)
|
|
1928
|
-
return `$${(value / 1000).toFixed(0)}K`;
|
|
1929
|
-
return `$${value}`;
|
|
1930
|
-
}
|
|
1931
|
-
function CrmPipelineBoard({
|
|
1932
|
-
dealsByStage,
|
|
1933
|
-
stages,
|
|
1934
|
-
onDealClick,
|
|
1935
|
-
onDealMove
|
|
1936
|
-
}) {
|
|
1937
|
-
const [quickMoveOpen, setQuickMoveOpen] = useState3(null);
|
|
1938
|
-
const sortedStages = [...stages].sort((a, b) => a.position - b.position);
|
|
1939
|
-
const handleQuickMove = (dealId, toStageId) => {
|
|
1940
|
-
onDealMove?.(dealId, toStageId);
|
|
1941
|
-
setQuickMoveOpen(null);
|
|
1942
|
-
};
|
|
1943
|
-
return /* @__PURE__ */ jsxDEV2("div", {
|
|
1944
|
-
className: "flex gap-4 overflow-x-auto pb-4",
|
|
1945
|
-
children: sortedStages.map((stage) => {
|
|
1946
|
-
const deals = dealsByStage[stage.id] ?? [];
|
|
1947
|
-
const stageValue = deals.reduce((sum, d) => sum + d.value, 0);
|
|
1948
|
-
return /* @__PURE__ */ jsxDEV2("div", {
|
|
1949
|
-
className: "bg-muted/30 flex w-72 flex-shrink-0 flex-col rounded-lg",
|
|
1950
|
-
children: [
|
|
1951
|
-
/* @__PURE__ */ jsxDEV2("div", {
|
|
1952
|
-
className: "border-border flex items-center justify-between border-b px-3 py-2",
|
|
1953
|
-
children: [
|
|
1954
|
-
/* @__PURE__ */ jsxDEV2("div", {
|
|
1955
|
-
children: [
|
|
1956
|
-
/* @__PURE__ */ jsxDEV2("h3", {
|
|
1957
|
-
className: "font-medium",
|
|
1958
|
-
children: stage.name
|
|
1959
|
-
}, undefined, false, undefined, this),
|
|
1960
|
-
/* @__PURE__ */ jsxDEV2("p", {
|
|
1961
|
-
className: "text-muted-foreground text-xs",
|
|
1962
|
-
children: [
|
|
1963
|
-
deals.length,
|
|
1964
|
-
" deals · ",
|
|
1965
|
-
formatCurrency2(stageValue)
|
|
1966
|
-
]
|
|
1967
|
-
}, undefined, true, undefined, this)
|
|
1968
|
-
]
|
|
1969
|
-
}, undefined, true, undefined, this),
|
|
1970
|
-
/* @__PURE__ */ jsxDEV2("span", {
|
|
1971
|
-
className: "bg-muted flex h-6 w-6 items-center justify-center rounded-full text-xs font-medium",
|
|
1972
|
-
children: deals.length
|
|
1973
|
-
}, undefined, false, undefined, this)
|
|
1974
|
-
]
|
|
1975
|
-
}, undefined, true, undefined, this),
|
|
1976
|
-
/* @__PURE__ */ jsxDEV2("div", {
|
|
1977
|
-
className: "flex flex-1 flex-col gap-2 p-2",
|
|
1978
|
-
children: deals.length === 0 ? /* @__PURE__ */ jsxDEV2("div", {
|
|
1979
|
-
className: "border-muted-foreground/20 text-muted-foreground flex h-24 items-center justify-center rounded-md border-2 border-dashed text-xs",
|
|
1980
|
-
children: "No deals"
|
|
1981
|
-
}, undefined, false, undefined, this) : deals.map((deal3) => /* @__PURE__ */ jsxDEV2("div", {
|
|
1982
|
-
className: "group relative",
|
|
1983
|
-
children: [
|
|
1984
|
-
/* @__PURE__ */ jsxDEV2(CrmDealCard, {
|
|
1985
|
-
deal: deal3,
|
|
1986
|
-
onClick: () => onDealClick?.(deal3.id)
|
|
1987
|
-
}, undefined, false, undefined, this),
|
|
1988
|
-
deal3.status === "OPEN" && onDealMove && /* @__PURE__ */ jsxDEV2("div", {
|
|
1989
|
-
className: "absolute top-1 right-1 opacity-0 transition-opacity group-hover:opacity-100",
|
|
1990
|
-
children: [
|
|
1991
|
-
/* @__PURE__ */ jsxDEV2("button", {
|
|
1992
|
-
type: "button",
|
|
1993
|
-
onClick: (e) => {
|
|
1994
|
-
e.stopPropagation();
|
|
1995
|
-
setQuickMoveOpen(quickMoveOpen === deal3.id ? null : deal3.id);
|
|
1996
|
-
},
|
|
1997
|
-
className: "bg-background border-border hover:bg-muted flex h-6 w-6 items-center justify-center rounded border text-xs shadow-sm",
|
|
1998
|
-
title: "Quick move",
|
|
1999
|
-
children: "➡️"
|
|
2000
|
-
}, undefined, false, undefined, this),
|
|
2001
|
-
quickMoveOpen === deal3.id && /* @__PURE__ */ jsxDEV2("div", {
|
|
2002
|
-
className: "bg-card border-border absolute top-7 right-0 z-20 min-w-[140px] rounded-lg border py-1 shadow-lg",
|
|
2003
|
-
children: [
|
|
2004
|
-
/* @__PURE__ */ jsxDEV2("p", {
|
|
2005
|
-
className: "text-muted-foreground px-3 py-1 text-xs font-medium",
|
|
2006
|
-
children: "Move to:"
|
|
2007
|
-
}, undefined, false, undefined, this),
|
|
2008
|
-
sortedStages.filter((s) => s.id !== deal3.stageId).map((s) => /* @__PURE__ */ jsxDEV2("button", {
|
|
2009
|
-
type: "button",
|
|
2010
|
-
onClick: (e) => {
|
|
2011
|
-
e.stopPropagation();
|
|
2012
|
-
handleQuickMove(deal3.id, s.id);
|
|
2013
|
-
},
|
|
2014
|
-
className: "hover:bg-muted w-full px-3 py-1.5 text-left text-sm",
|
|
2015
|
-
children: s.name
|
|
2016
|
-
}, s.id, false, undefined, this))
|
|
2017
|
-
]
|
|
2018
|
-
}, undefined, true, undefined, this)
|
|
2019
|
-
]
|
|
2020
|
-
}, undefined, true, undefined, this)
|
|
2021
|
-
]
|
|
2022
|
-
}, deal3.id, true, undefined, this))
|
|
2023
|
-
}, undefined, false, undefined, this)
|
|
2024
|
-
]
|
|
2025
|
-
}, stage.id, true, undefined, this);
|
|
2026
|
-
})
|
|
2027
|
-
}, undefined, false, undefined, this);
|
|
2028
|
-
}
|
|
2029
|
-
|
|
2030
2030
|
// src/ui/modals/CreateDealModal.tsx
|
|
2031
|
-
import { useState as useState4 } from "react";
|
|
2032
2031
|
import { Button, Input } from "@contractspec/lib.design-system";
|
|
2032
|
+
import { useState as useState4 } from "react";
|
|
2033
2033
|
import { jsxDEV as jsxDEV3 } from "react/jsx-dev-runtime";
|
|
2034
2034
|
"use client";
|
|
2035
2035
|
var CURRENCIES = ["USD", "EUR", "GBP", "CAD"];
|
|
@@ -2088,7 +2088,7 @@ function CreateDealModal({
|
|
|
2088
2088
|
className: "fixed inset-0 z-50 flex items-center justify-center",
|
|
2089
2089
|
children: [
|
|
2090
2090
|
/* @__PURE__ */ jsxDEV3("div", {
|
|
2091
|
-
className: "bg-background/80
|
|
2091
|
+
className: "absolute inset-0 bg-background/80 backdrop-blur-sm",
|
|
2092
2092
|
onClick: onClose,
|
|
2093
2093
|
role: "button",
|
|
2094
2094
|
tabIndex: 0,
|
|
@@ -2099,10 +2099,10 @@ function CreateDealModal({
|
|
|
2099
2099
|
"aria-label": "Close modal"
|
|
2100
2100
|
}, undefined, false, undefined, this),
|
|
2101
2101
|
/* @__PURE__ */ jsxDEV3("div", {
|
|
2102
|
-
className: "
|
|
2102
|
+
className: "relative z-10 w-full max-w-md rounded-xl border border-border bg-card p-6 shadow-xl",
|
|
2103
2103
|
children: [
|
|
2104
2104
|
/* @__PURE__ */ jsxDEV3("h2", {
|
|
2105
|
-
className: "mb-4 text-xl
|
|
2105
|
+
className: "mb-4 font-semibold text-xl",
|
|
2106
2106
|
children: "Create New Deal"
|
|
2107
2107
|
}, undefined, false, undefined, this),
|
|
2108
2108
|
/* @__PURE__ */ jsxDEV3("form", {
|
|
@@ -2113,7 +2113,7 @@ function CreateDealModal({
|
|
|
2113
2113
|
children: [
|
|
2114
2114
|
/* @__PURE__ */ jsxDEV3("label", {
|
|
2115
2115
|
htmlFor: "deal-name",
|
|
2116
|
-
className: "
|
|
2116
|
+
className: "mb-1 block font-medium text-muted-foreground text-sm",
|
|
2117
2117
|
children: "Deal Name *"
|
|
2118
2118
|
}, undefined, false, undefined, this),
|
|
2119
2119
|
/* @__PURE__ */ jsxDEV3(Input, {
|
|
@@ -2133,7 +2133,7 @@ function CreateDealModal({
|
|
|
2133
2133
|
children: [
|
|
2134
2134
|
/* @__PURE__ */ jsxDEV3("label", {
|
|
2135
2135
|
htmlFor: "deal-value",
|
|
2136
|
-
className: "
|
|
2136
|
+
className: "mb-1 block font-medium text-muted-foreground text-sm",
|
|
2137
2137
|
children: "Value *"
|
|
2138
2138
|
}, undefined, false, undefined, this),
|
|
2139
2139
|
/* @__PURE__ */ jsxDEV3(Input, {
|
|
@@ -2153,7 +2153,7 @@ function CreateDealModal({
|
|
|
2153
2153
|
children: [
|
|
2154
2154
|
/* @__PURE__ */ jsxDEV3("label", {
|
|
2155
2155
|
htmlFor: "deal-currency",
|
|
2156
|
-
className: "
|
|
2156
|
+
className: "mb-1 block font-medium text-muted-foreground text-sm",
|
|
2157
2157
|
children: "Currency"
|
|
2158
2158
|
}, undefined, false, undefined, this),
|
|
2159
2159
|
/* @__PURE__ */ jsxDEV3("select", {
|
|
@@ -2161,7 +2161,7 @@ function CreateDealModal({
|
|
|
2161
2161
|
value: currency,
|
|
2162
2162
|
onChange: (e) => setCurrency(e.target.value),
|
|
2163
2163
|
disabled: isLoading,
|
|
2164
|
-
className: "
|
|
2164
|
+
className: "h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-ring disabled:opacity-50",
|
|
2165
2165
|
children: CURRENCIES.map((c) => /* @__PURE__ */ jsxDEV3("option", {
|
|
2166
2166
|
value: c,
|
|
2167
2167
|
children: c
|
|
@@ -2175,7 +2175,7 @@ function CreateDealModal({
|
|
|
2175
2175
|
children: [
|
|
2176
2176
|
/* @__PURE__ */ jsxDEV3("label", {
|
|
2177
2177
|
htmlFor: "deal-stage",
|
|
2178
|
-
className: "
|
|
2178
|
+
className: "mb-1 block font-medium text-muted-foreground text-sm",
|
|
2179
2179
|
children: "Pipeline Stage *"
|
|
2180
2180
|
}, undefined, false, undefined, this),
|
|
2181
2181
|
/* @__PURE__ */ jsxDEV3("select", {
|
|
@@ -2183,7 +2183,7 @@ function CreateDealModal({
|
|
|
2183
2183
|
value: stageId,
|
|
2184
2184
|
onChange: (e) => setStageId(e.target.value),
|
|
2185
2185
|
disabled: isLoading,
|
|
2186
|
-
className: "
|
|
2186
|
+
className: "h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-ring disabled:opacity-50",
|
|
2187
2187
|
children: stages.map((stage) => /* @__PURE__ */ jsxDEV3("option", {
|
|
2188
2188
|
value: stage.id,
|
|
2189
2189
|
children: stage.name
|
|
@@ -2195,7 +2195,7 @@ function CreateDealModal({
|
|
|
2195
2195
|
children: [
|
|
2196
2196
|
/* @__PURE__ */ jsxDEV3("label", {
|
|
2197
2197
|
htmlFor: "deal-close-date",
|
|
2198
|
-
className: "
|
|
2198
|
+
className: "mb-1 block font-medium text-muted-foreground text-sm",
|
|
2199
2199
|
children: "Expected Close Date"
|
|
2200
2200
|
}, undefined, false, undefined, this),
|
|
2201
2201
|
/* @__PURE__ */ jsxDEV3(Input, {
|
|
@@ -2208,7 +2208,7 @@ function CreateDealModal({
|
|
|
2208
2208
|
]
|
|
2209
2209
|
}, undefined, true, undefined, this),
|
|
2210
2210
|
error && /* @__PURE__ */ jsxDEV3("div", {
|
|
2211
|
-
className: "bg-destructive/10
|
|
2211
|
+
className: "rounded-md bg-destructive/10 p-3 text-destructive text-sm",
|
|
2212
2212
|
children: error
|
|
2213
2213
|
}, undefined, false, undefined, this),
|
|
2214
2214
|
/* @__PURE__ */ jsxDEV3("div", {
|
|
@@ -2237,8 +2237,8 @@ function CreateDealModal({
|
|
|
2237
2237
|
}
|
|
2238
2238
|
|
|
2239
2239
|
// src/ui/modals/DealActionsModal.tsx
|
|
2240
|
-
import { useState as useState5 } from "react";
|
|
2241
2240
|
import { Button as Button2 } from "@contractspec/lib.design-system";
|
|
2241
|
+
import { useState as useState5 } from "react";
|
|
2242
2242
|
import { jsxDEV as jsxDEV4, Fragment } from "react/jsx-dev-runtime";
|
|
2243
2243
|
"use client";
|
|
2244
2244
|
function formatCurrency3(value, currency) {
|
|
@@ -2339,7 +2339,7 @@ function DealActionsModal({
|
|
|
2339
2339
|
className: "fixed inset-0 z-50 flex items-center justify-center",
|
|
2340
2340
|
children: [
|
|
2341
2341
|
/* @__PURE__ */ jsxDEV4("div", {
|
|
2342
|
-
className: "bg-background/80
|
|
2342
|
+
className: "absolute inset-0 bg-background/80 backdrop-blur-sm",
|
|
2343
2343
|
onClick: handleClose,
|
|
2344
2344
|
role: "button",
|
|
2345
2345
|
tabIndex: 0,
|
|
@@ -2350,21 +2350,21 @@ function DealActionsModal({
|
|
|
2350
2350
|
"aria-label": "Close modal"
|
|
2351
2351
|
}, undefined, false, undefined, this),
|
|
2352
2352
|
/* @__PURE__ */ jsxDEV4("div", {
|
|
2353
|
-
className: "
|
|
2353
|
+
className: "relative z-10 w-full max-w-md rounded-xl border border-border bg-card p-6 shadow-xl",
|
|
2354
2354
|
children: [
|
|
2355
2355
|
/* @__PURE__ */ jsxDEV4("div", {
|
|
2356
|
-
className: "
|
|
2356
|
+
className: "mb-4 border-border border-b pb-4",
|
|
2357
2357
|
children: [
|
|
2358
2358
|
/* @__PURE__ */ jsxDEV4("h2", {
|
|
2359
|
-
className: "text-xl
|
|
2359
|
+
className: "font-semibold text-xl",
|
|
2360
2360
|
children: deal3.name
|
|
2361
2361
|
}, undefined, false, undefined, this),
|
|
2362
2362
|
/* @__PURE__ */ jsxDEV4("p", {
|
|
2363
|
-
className: "
|
|
2363
|
+
className: "font-medium text-lg text-primary",
|
|
2364
2364
|
children: formatCurrency3(deal3.value, deal3.currency)
|
|
2365
2365
|
}, undefined, false, undefined, this),
|
|
2366
2366
|
/* @__PURE__ */ jsxDEV4("span", {
|
|
2367
|
-
className: `mt-2 inline-flex rounded-full px-2 py-0.5 text-xs
|
|
2367
|
+
className: `mt-2 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"}`,
|
|
2368
2368
|
children: deal3.status
|
|
2369
2369
|
}, undefined, false, undefined, this)
|
|
2370
2370
|
]
|
|
@@ -2416,7 +2416,7 @@ function DealActionsModal({
|
|
|
2416
2416
|
]
|
|
2417
2417
|
}, undefined, true, undefined, this),
|
|
2418
2418
|
deal3.status !== "OPEN" && /* @__PURE__ */ jsxDEV4("p", {
|
|
2419
|
-
className: "
|
|
2419
|
+
className: "py-4 text-center text-muted-foreground",
|
|
2420
2420
|
children: [
|
|
2421
2421
|
"This deal is already ",
|
|
2422
2422
|
deal3.status.toLowerCase(),
|
|
@@ -2441,14 +2441,14 @@ function DealActionsModal({
|
|
|
2441
2441
|
children: [
|
|
2442
2442
|
/* @__PURE__ */ jsxDEV4("label", {
|
|
2443
2443
|
htmlFor: "won-source",
|
|
2444
|
-
className: "
|
|
2444
|
+
className: "mb-1 block font-medium text-muted-foreground text-sm",
|
|
2445
2445
|
children: "How did you win this deal?"
|
|
2446
2446
|
}, undefined, false, undefined, this),
|
|
2447
2447
|
/* @__PURE__ */ jsxDEV4("select", {
|
|
2448
2448
|
id: "won-source",
|
|
2449
2449
|
value: wonSource,
|
|
2450
2450
|
onChange: (e) => setWonSource(e.target.value),
|
|
2451
|
-
className: "
|
|
2451
|
+
className: "h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-ring",
|
|
2452
2452
|
children: [
|
|
2453
2453
|
/* @__PURE__ */ jsxDEV4("option", {
|
|
2454
2454
|
value: "",
|
|
@@ -2482,7 +2482,7 @@ function DealActionsModal({
|
|
|
2482
2482
|
children: [
|
|
2483
2483
|
/* @__PURE__ */ jsxDEV4("label", {
|
|
2484
2484
|
htmlFor: "win-notes",
|
|
2485
|
-
className: "
|
|
2485
|
+
className: "mb-1 block font-medium text-muted-foreground text-sm",
|
|
2486
2486
|
children: "Notes (optional)"
|
|
2487
2487
|
}, undefined, false, undefined, this),
|
|
2488
2488
|
/* @__PURE__ */ jsxDEV4("textarea", {
|
|
@@ -2491,12 +2491,12 @@ function DealActionsModal({
|
|
|
2491
2491
|
onChange: (e) => setNotes(e.target.value),
|
|
2492
2492
|
placeholder: "Any additional notes about the win...",
|
|
2493
2493
|
rows: 3,
|
|
2494
|
-
className: "
|
|
2494
|
+
className: "w-full rounded-md border border-input bg-background px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-ring"
|
|
2495
2495
|
}, undefined, false, undefined, this)
|
|
2496
2496
|
]
|
|
2497
2497
|
}, undefined, true, undefined, this),
|
|
2498
2498
|
error && /* @__PURE__ */ jsxDEV4("div", {
|
|
2499
|
-
className: "bg-destructive/10
|
|
2499
|
+
className: "rounded-md bg-destructive/10 p-3 text-destructive text-sm",
|
|
2500
2500
|
children: error
|
|
2501
2501
|
}, undefined, false, undefined, this),
|
|
2502
2502
|
/* @__PURE__ */ jsxDEV4("div", {
|
|
@@ -2524,14 +2524,14 @@ function DealActionsModal({
|
|
|
2524
2524
|
children: [
|
|
2525
2525
|
/* @__PURE__ */ jsxDEV4("label", {
|
|
2526
2526
|
htmlFor: "lost-reason",
|
|
2527
|
-
className: "
|
|
2527
|
+
className: "mb-1 block font-medium text-muted-foreground text-sm",
|
|
2528
2528
|
children: "Why was this deal lost? *"
|
|
2529
2529
|
}, undefined, false, undefined, this),
|
|
2530
2530
|
/* @__PURE__ */ jsxDEV4("select", {
|
|
2531
2531
|
id: "lost-reason",
|
|
2532
2532
|
value: lostReason,
|
|
2533
2533
|
onChange: (e) => setLostReason(e.target.value),
|
|
2534
|
-
className: "
|
|
2534
|
+
className: "h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-ring",
|
|
2535
2535
|
children: [
|
|
2536
2536
|
/* @__PURE__ */ jsxDEV4("option", {
|
|
2537
2537
|
value: "",
|
|
@@ -2573,7 +2573,7 @@ function DealActionsModal({
|
|
|
2573
2573
|
children: [
|
|
2574
2574
|
/* @__PURE__ */ jsxDEV4("label", {
|
|
2575
2575
|
htmlFor: "lose-notes",
|
|
2576
|
-
className: "
|
|
2576
|
+
className: "mb-1 block font-medium text-muted-foreground text-sm",
|
|
2577
2577
|
children: "Notes (optional)"
|
|
2578
2578
|
}, undefined, false, undefined, this),
|
|
2579
2579
|
/* @__PURE__ */ jsxDEV4("textarea", {
|
|
@@ -2582,12 +2582,12 @@ function DealActionsModal({
|
|
|
2582
2582
|
onChange: (e) => setNotes(e.target.value),
|
|
2583
2583
|
placeholder: "Any additional details...",
|
|
2584
2584
|
rows: 3,
|
|
2585
|
-
className: "
|
|
2585
|
+
className: "w-full rounded-md border border-input bg-background px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-ring"
|
|
2586
2586
|
}, undefined, false, undefined, this)
|
|
2587
2587
|
]
|
|
2588
2588
|
}, undefined, true, undefined, this),
|
|
2589
2589
|
error && /* @__PURE__ */ jsxDEV4("div", {
|
|
2590
|
-
className: "bg-destructive/10
|
|
2590
|
+
className: "rounded-md bg-destructive/10 p-3 text-destructive text-sm",
|
|
2591
2591
|
children: error
|
|
2592
2592
|
}, undefined, false, undefined, this),
|
|
2593
2593
|
/* @__PURE__ */ jsxDEV4("div", {
|
|
@@ -2616,14 +2616,14 @@ function DealActionsModal({
|
|
|
2616
2616
|
children: [
|
|
2617
2617
|
/* @__PURE__ */ jsxDEV4("label", {
|
|
2618
2618
|
htmlFor: "move-stage",
|
|
2619
|
-
className: "
|
|
2619
|
+
className: "mb-1 block font-medium text-muted-foreground text-sm",
|
|
2620
2620
|
children: "Move to Stage"
|
|
2621
2621
|
}, undefined, false, undefined, this),
|
|
2622
2622
|
/* @__PURE__ */ jsxDEV4("select", {
|
|
2623
2623
|
id: "move-stage",
|
|
2624
2624
|
value: selectedStageId,
|
|
2625
2625
|
onChange: (e) => setSelectedStageId(e.target.value),
|
|
2626
|
-
className: "
|
|
2626
|
+
className: "h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-ring",
|
|
2627
2627
|
children: stages.map((stage) => /* @__PURE__ */ jsxDEV4("option", {
|
|
2628
2628
|
value: stage.id,
|
|
2629
2629
|
children: [
|
|
@@ -2635,7 +2635,7 @@ function DealActionsModal({
|
|
|
2635
2635
|
]
|
|
2636
2636
|
}, undefined, true, undefined, this),
|
|
2637
2637
|
error && /* @__PURE__ */ jsxDEV4("div", {
|
|
2638
|
-
className: "bg-destructive/10
|
|
2638
|
+
className: "rounded-md bg-destructive/10 p-3 text-destructive text-sm",
|
|
2639
2639
|
children: error
|
|
2640
2640
|
}, undefined, false, undefined, this),
|
|
2641
2641
|
/* @__PURE__ */ jsxDEV4("div", {
|
|
@@ -2663,7 +2663,6 @@ function DealActionsModal({
|
|
|
2663
2663
|
}
|
|
2664
2664
|
|
|
2665
2665
|
// src/ui/CrmDashboard.tsx
|
|
2666
|
-
import { useCallback as useCallback3, useState as useState6 } from "react";
|
|
2667
2666
|
import {
|
|
2668
2667
|
Button as Button3,
|
|
2669
2668
|
ErrorState,
|
|
@@ -2677,6 +2676,7 @@ import {
|
|
|
2677
2676
|
TabsList,
|
|
2678
2677
|
TabsTrigger
|
|
2679
2678
|
} from "@contractspec/lib.ui-kit-web/ui/tabs";
|
|
2679
|
+
import { useCallback as useCallback3, useState as useState6 } from "react";
|
|
2680
2680
|
import { jsxDEV as jsxDEV5 } from "react/jsx-dev-runtime";
|
|
2681
2681
|
"use client";
|
|
2682
2682
|
function formatCurrency4(value, currency = "USD") {
|
|
@@ -2727,7 +2727,7 @@ function CrmDashboard() {
|
|
|
2727
2727
|
className: "flex items-center justify-between",
|
|
2728
2728
|
children: [
|
|
2729
2729
|
/* @__PURE__ */ jsxDEV5("h2", {
|
|
2730
|
-
className: "text-2xl
|
|
2730
|
+
className: "font-bold text-2xl",
|
|
2731
2731
|
children: "CRM Pipeline"
|
|
2732
2732
|
}, undefined, false, undefined, this),
|
|
2733
2733
|
/* @__PURE__ */ jsxDEV5(Button3, {
|
|
@@ -2866,44 +2866,44 @@ function CrmDashboard() {
|
|
|
2866
2866
|
function DealListTab({ data, onDealClick }) {
|
|
2867
2867
|
if (!data?.deals.length) {
|
|
2868
2868
|
return /* @__PURE__ */ jsxDEV5("div", {
|
|
2869
|
-
className: "
|
|
2869
|
+
className: "flex h-64 items-center justify-center text-muted-foreground",
|
|
2870
2870
|
children: "No deals found"
|
|
2871
2871
|
}, undefined, false, undefined, this);
|
|
2872
2872
|
}
|
|
2873
2873
|
return /* @__PURE__ */ jsxDEV5("div", {
|
|
2874
|
-
className: "
|
|
2874
|
+
className: "rounded-lg border border-border",
|
|
2875
2875
|
children: /* @__PURE__ */ jsxDEV5("table", {
|
|
2876
2876
|
className: "w-full",
|
|
2877
2877
|
children: [
|
|
2878
2878
|
/* @__PURE__ */ jsxDEV5("thead", {
|
|
2879
|
-
className: "border-border bg-muted/30
|
|
2879
|
+
className: "border-border border-b bg-muted/30",
|
|
2880
2880
|
children: /* @__PURE__ */ jsxDEV5("tr", {
|
|
2881
2881
|
children: [
|
|
2882
2882
|
/* @__PURE__ */ jsxDEV5("th", {
|
|
2883
|
-
className: "px-4 py-3 text-left text-sm
|
|
2883
|
+
className: "px-4 py-3 text-left font-medium text-sm",
|
|
2884
2884
|
children: "Deal"
|
|
2885
2885
|
}, undefined, false, undefined, this),
|
|
2886
2886
|
/* @__PURE__ */ jsxDEV5("th", {
|
|
2887
|
-
className: "px-4 py-3 text-left text-sm
|
|
2887
|
+
className: "px-4 py-3 text-left font-medium text-sm",
|
|
2888
2888
|
children: "Value"
|
|
2889
2889
|
}, undefined, false, undefined, this),
|
|
2890
2890
|
/* @__PURE__ */ jsxDEV5("th", {
|
|
2891
|
-
className: "px-4 py-3 text-left text-sm
|
|
2891
|
+
className: "px-4 py-3 text-left font-medium text-sm",
|
|
2892
2892
|
children: "Status"
|
|
2893
2893
|
}, undefined, false, undefined, this),
|
|
2894
2894
|
/* @__PURE__ */ jsxDEV5("th", {
|
|
2895
|
-
className: "px-4 py-3 text-left text-sm
|
|
2895
|
+
className: "px-4 py-3 text-left font-medium text-sm",
|
|
2896
2896
|
children: "Expected Close"
|
|
2897
2897
|
}, undefined, false, undefined, this),
|
|
2898
2898
|
/* @__PURE__ */ jsxDEV5("th", {
|
|
2899
|
-
className: "px-4 py-3 text-left text-sm
|
|
2899
|
+
className: "px-4 py-3 text-left font-medium text-sm",
|
|
2900
2900
|
children: "Actions"
|
|
2901
2901
|
}, undefined, false, undefined, this)
|
|
2902
2902
|
]
|
|
2903
2903
|
}, undefined, true, undefined, this)
|
|
2904
2904
|
}, undefined, false, undefined, this),
|
|
2905
2905
|
/* @__PURE__ */ jsxDEV5("tbody", {
|
|
2906
|
-
className: "divide-
|
|
2906
|
+
className: "divide-y divide-border",
|
|
2907
2907
|
children: data.deals.map((deal3) => /* @__PURE__ */ jsxDEV5("tr", {
|
|
2908
2908
|
className: "hover:bg-muted/50",
|
|
2909
2909
|
children: [
|
|
@@ -2921,12 +2921,12 @@ function DealListTab({ data, onDealClick }) {
|
|
|
2921
2921
|
/* @__PURE__ */ jsxDEV5("td", {
|
|
2922
2922
|
className: "px-4 py-3",
|
|
2923
2923
|
children: /* @__PURE__ */ jsxDEV5("span", {
|
|
2924
|
-
className: `inline-flex rounded-full px-2 py-0.5 text-xs
|
|
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
2925
|
children: deal3.status
|
|
2926
2926
|
}, undefined, false, undefined, this)
|
|
2927
2927
|
}, undefined, false, undefined, this),
|
|
2928
2928
|
/* @__PURE__ */ jsxDEV5("td", {
|
|
2929
|
-
className: "
|
|
2929
|
+
className: "px-4 py-3 text-muted-foreground",
|
|
2930
2930
|
children: deal3.expectedCloseDate?.toLocaleDateString() ?? "-"
|
|
2931
2931
|
}, undefined, false, undefined, this),
|
|
2932
2932
|
/* @__PURE__ */ jsxDEV5("td", {
|
|
@@ -2953,10 +2953,10 @@ function MetricsTab({
|
|
|
2953
2953
|
return /* @__PURE__ */ jsxDEV5("div", {
|
|
2954
2954
|
className: "space-y-6",
|
|
2955
2955
|
children: /* @__PURE__ */ jsxDEV5("div", {
|
|
2956
|
-
className: "border-border bg-card
|
|
2956
|
+
className: "rounded-xl border border-border bg-card p-6",
|
|
2957
2957
|
children: [
|
|
2958
2958
|
/* @__PURE__ */ jsxDEV5("h3", {
|
|
2959
|
-
className: "mb-4 text-lg
|
|
2959
|
+
className: "mb-4 font-semibold text-lg",
|
|
2960
2960
|
children: "Pipeline Overview"
|
|
2961
2961
|
}, undefined, false, undefined, this),
|
|
2962
2962
|
/* @__PURE__ */ jsxDEV5("dl", {
|
|
@@ -2969,7 +2969,7 @@ function MetricsTab({
|
|
|
2969
2969
|
children: "Win Rate"
|
|
2970
2970
|
}, undefined, false, undefined, this),
|
|
2971
2971
|
/* @__PURE__ */ jsxDEV5("dd", {
|
|
2972
|
-
className: "text-2xl
|
|
2972
|
+
className: "font-semibold text-2xl",
|
|
2973
2973
|
children: [
|
|
2974
2974
|
stats.total > 0 ? (stats.wonCount / stats.total * 100).toFixed(0) : 0,
|
|
2975
2975
|
"%"
|
|
@@ -2984,7 +2984,7 @@ function MetricsTab({
|
|
|
2984
2984
|
children: "Avg Deal Size"
|
|
2985
2985
|
}, undefined, false, undefined, this),
|
|
2986
2986
|
/* @__PURE__ */ jsxDEV5("dd", {
|
|
2987
|
-
className: "text-2xl
|
|
2987
|
+
className: "font-semibold text-2xl",
|
|
2988
2988
|
children: formatCurrency4(stats.total > 0 ? stats.totalValue / stats.total : 0)
|
|
2989
2989
|
}, undefined, false, undefined, this)
|
|
2990
2990
|
]
|
|
@@ -2996,7 +2996,7 @@ function MetricsTab({
|
|
|
2996
2996
|
children: "Conversion"
|
|
2997
2997
|
}, undefined, false, undefined, this),
|
|
2998
2998
|
/* @__PURE__ */ jsxDEV5("dd", {
|
|
2999
|
-
className: "text-2xl
|
|
2999
|
+
className: "font-semibold text-2xl",
|
|
3000
3000
|
children: [
|
|
3001
3001
|
stats.wonCount,
|
|
3002
3002
|
" / ",
|
|
@@ -3011,31 +3011,59 @@ function MetricsTab({
|
|
|
3011
3011
|
}, undefined, true, undefined, this)
|
|
3012
3012
|
}, undefined, false, undefined, this);
|
|
3013
3013
|
}
|
|
3014
|
+
|
|
3014
3015
|
// src/ui/hooks/index.ts
|
|
3015
3016
|
"use client";
|
|
3016
|
-
|
|
3017
|
-
|
|
3018
|
-
|
|
3019
|
-
|
|
3020
|
-
|
|
3021
|
-
|
|
3022
|
-
|
|
3023
|
-
|
|
3024
|
-
},
|
|
3025
|
-
|
|
3026
|
-
|
|
3027
|
-
|
|
3028
|
-
|
|
3029
|
-
|
|
3030
|
-
|
|
3031
|
-
|
|
3032
|
-
|
|
3033
|
-
|
|
3017
|
+
// src/ui/overlays/demo-overlays.ts
|
|
3018
|
+
var crmDemoOverlay = {
|
|
3019
|
+
overlayId: "crm-pipeline.demo-user",
|
|
3020
|
+
version: "1.0.0",
|
|
3021
|
+
description: "Demo mode with sample data",
|
|
3022
|
+
appliesTo: {
|
|
3023
|
+
feature: "crm-pipeline",
|
|
3024
|
+
role: "demo"
|
|
3025
|
+
},
|
|
3026
|
+
modifications: [
|
|
3027
|
+
{
|
|
3028
|
+
type: "hideField",
|
|
3029
|
+
field: "importButton",
|
|
3030
|
+
reason: "Not available in demo"
|
|
3031
|
+
},
|
|
3032
|
+
{
|
|
3033
|
+
type: "hideField",
|
|
3034
|
+
field: "exportButton",
|
|
3035
|
+
reason: "Not available in demo"
|
|
3036
|
+
},
|
|
3037
|
+
{
|
|
3038
|
+
type: "addBadge",
|
|
3039
|
+
position: "header",
|
|
3040
|
+
label: "Demo Mode",
|
|
3041
|
+
variant: "warning"
|
|
3034
3042
|
}
|
|
3035
|
-
|
|
3036
|
-
}
|
|
3043
|
+
]
|
|
3037
3044
|
};
|
|
3038
|
-
|
|
3045
|
+
var crmSalesRepOverlay = {
|
|
3046
|
+
overlayId: "crm-pipeline.sales-rep",
|
|
3047
|
+
version: "1.0.0",
|
|
3048
|
+
description: "Sales rep focused view",
|
|
3049
|
+
appliesTo: {
|
|
3050
|
+
feature: "crm-pipeline",
|
|
3051
|
+
role: "sales-rep"
|
|
3052
|
+
},
|
|
3053
|
+
modifications: [
|
|
3054
|
+
{
|
|
3055
|
+
type: "hideField",
|
|
3056
|
+
field: "teamMetrics",
|
|
3057
|
+
reason: "Team metrics for managers only"
|
|
3058
|
+
},
|
|
3059
|
+
{ type: "hideField", field: "pipelineSettings", reason: "Admin only" },
|
|
3060
|
+
{ type: "renameLabel", field: "deals", newLabel: "My Deals" }
|
|
3061
|
+
]
|
|
3062
|
+
};
|
|
3063
|
+
var crmOverlays = [
|
|
3064
|
+
crmDemoOverlay,
|
|
3065
|
+
crmSalesRepOverlay
|
|
3066
|
+
];
|
|
3039
3067
|
// src/ui/renderers/pipeline.markdown.ts
|
|
3040
3068
|
function formatCurrency5(value, currency = "USD") {
|
|
3041
3069
|
return new Intl.NumberFormat("en-US", {
|
|
@@ -3154,56 +3182,28 @@ var crmDashboardMarkdownRenderer = {
|
|
|
3154
3182
|
};
|
|
3155
3183
|
}
|
|
3156
3184
|
};
|
|
3157
|
-
|
|
3158
|
-
|
|
3159
|
-
|
|
3160
|
-
|
|
3161
|
-
|
|
3162
|
-
|
|
3163
|
-
|
|
3164
|
-
|
|
3165
|
-
},
|
|
3166
|
-
|
|
3167
|
-
|
|
3168
|
-
|
|
3169
|
-
|
|
3170
|
-
|
|
3171
|
-
|
|
3172
|
-
{
|
|
3173
|
-
type: "hideField",
|
|
3174
|
-
field: "exportButton",
|
|
3175
|
-
reason: "Not available in demo"
|
|
3176
|
-
},
|
|
3177
|
-
{
|
|
3178
|
-
type: "addBadge",
|
|
3179
|
-
position: "header",
|
|
3180
|
-
label: "Demo Mode",
|
|
3181
|
-
variant: "warning"
|
|
3185
|
+
|
|
3186
|
+
// src/ui/renderers/pipeline.renderer.tsx
|
|
3187
|
+
import { jsxDEV as jsxDEV6 } from "react/jsx-dev-runtime";
|
|
3188
|
+
function CrmPipelineBoardWrapper() {
|
|
3189
|
+
const { dealsByStage, stages } = useDealList();
|
|
3190
|
+
return /* @__PURE__ */ jsxDEV6(CrmPipelineBoard, {
|
|
3191
|
+
dealsByStage,
|
|
3192
|
+
stages
|
|
3193
|
+
}, undefined, false, undefined, this);
|
|
3194
|
+
}
|
|
3195
|
+
var crmPipelineReactRenderer = {
|
|
3196
|
+
target: "react",
|
|
3197
|
+
render: async (desc, _ctx) => {
|
|
3198
|
+
if (desc.source.type !== "component") {
|
|
3199
|
+
throw new Error("Invalid source type");
|
|
3182
3200
|
}
|
|
3183
|
-
|
|
3184
|
-
};
|
|
3185
|
-
|
|
3186
|
-
|
|
3187
|
-
|
|
3188
|
-
description: "Sales rep focused view",
|
|
3189
|
-
appliesTo: {
|
|
3190
|
-
feature: "crm-pipeline",
|
|
3191
|
-
role: "sales-rep"
|
|
3192
|
-
},
|
|
3193
|
-
modifications: [
|
|
3194
|
-
{
|
|
3195
|
-
type: "hideField",
|
|
3196
|
-
field: "teamMetrics",
|
|
3197
|
-
reason: "Team metrics for managers only"
|
|
3198
|
-
},
|
|
3199
|
-
{ type: "hideField", field: "pipelineSettings", reason: "Admin only" },
|
|
3200
|
-
{ type: "renameLabel", field: "deals", newLabel: "My Deals" }
|
|
3201
|
-
]
|
|
3201
|
+
if (desc.source.componentKey !== "CrmPipelineView") {
|
|
3202
|
+
throw new Error(`Unknown component: ${desc.source.componentKey}`);
|
|
3203
|
+
}
|
|
3204
|
+
return /* @__PURE__ */ jsxDEV6(CrmPipelineBoardWrapper, {}, undefined, false, undefined, this);
|
|
3205
|
+
}
|
|
3202
3206
|
};
|
|
3203
|
-
var crmOverlays = [
|
|
3204
|
-
crmDemoOverlay,
|
|
3205
|
-
crmSalesRepOverlay
|
|
3206
|
-
];
|
|
3207
3207
|
// src/index.ts
|
|
3208
3208
|
import { identityRbacSchemaContribution } from "@contractspec/lib.identity-rbac";
|
|
3209
3209
|
import { auditTrailSchemaContribution } from "@contractspec/module.audit-trail";
|