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