@contractspec/example.crm-pipeline 0.0.0-canary-20260113170453
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$colon$bundle.log +172 -0
- package/.turbo/turbo-build.log +173 -0
- package/CHANGELOG.md +436 -0
- package/LICENSE +21 -0
- package/README.md +139 -0
- package/dist/crm-pipeline.feature.d.ts +12 -0
- package/dist/crm-pipeline.feature.d.ts.map +1 -0
- package/dist/crm-pipeline.feature.js +166 -0
- package/dist/crm-pipeline.feature.js.map +1 -0
- package/dist/deal/deal.enum.d.ts +14 -0
- package/dist/deal/deal.enum.d.ts.map +1 -0
- package/dist/deal/deal.enum.js +25 -0
- package/dist/deal/deal.enum.js.map +1 -0
- package/dist/deal/deal.operation.d.ts +513 -0
- package/dist/deal/deal.operation.d.ts.map +1 -0
- package/dist/deal/deal.operation.js +270 -0
- package/dist/deal/deal.operation.js.map +1 -0
- package/dist/deal/deal.schema.d.ts +300 -0
- package/dist/deal/deal.schema.d.ts.map +1 -0
- package/dist/deal/deal.schema.js +286 -0
- package/dist/deal/deal.schema.js.map +1 -0
- package/dist/deal/deal.test-spec.d.ts +8 -0
- package/dist/deal/deal.test-spec.d.ts.map +1 -0
- package/dist/deal/deal.test-spec.js +65 -0
- package/dist/deal/deal.test-spec.js.map +1 -0
- package/dist/deal/index.d.ts +4 -0
- package/dist/deal/index.js +5 -0
- package/dist/docs/crm-pipeline.docblock.d.ts +1 -0
- package/dist/docs/crm-pipeline.docblock.js +100 -0
- package/dist/docs/crm-pipeline.docblock.js.map +1 -0
- package/dist/docs/index.d.ts +1 -0
- package/dist/docs/index.js +1 -0
- package/dist/entities/company.entity.d.ts +40 -0
- package/dist/entities/company.entity.d.ts.map +1 -0
- package/dist/entities/company.entity.js +63 -0
- package/dist/entities/company.entity.js.map +1 -0
- package/dist/entities/contact.entity.d.ts +44 -0
- package/dist/entities/contact.entity.d.ts.map +1 -0
- package/dist/entities/contact.entity.js +78 -0
- package/dist/entities/contact.entity.js.map +1 -0
- package/dist/entities/deal.entity.d.ts +73 -0
- package/dist/entities/deal.entity.d.ts.map +1 -0
- package/dist/entities/deal.entity.js +120 -0
- package/dist/entities/deal.entity.js.map +1 -0
- package/dist/entities/index.d.ts +15 -0
- package/dist/entities/index.d.ts.map +1 -0
- package/dist/entities/index.js +33 -0
- package/dist/entities/index.js.map +1 -0
- package/dist/entities/task.entity.d.ts +65 -0
- package/dist/entities/task.entity.d.ts.map +1 -0
- package/dist/entities/task.entity.js +129 -0
- package/dist/entities/task.entity.js.map +1 -0
- package/dist/events/contact.event.d.ts +29 -0
- package/dist/events/contact.event.d.ts.map +1 -0
- package/dist/events/contact.event.js +45 -0
- package/dist/events/contact.event.js.map +1 -0
- package/dist/events/deal.event.d.ts +111 -0
- package/dist/events/deal.event.d.ts.map +1 -0
- package/dist/events/deal.event.js +172 -0
- package/dist/events/deal.event.js.map +1 -0
- package/dist/events/index.d.ts +4 -0
- package/dist/events/index.js +5 -0
- package/dist/events/task.event.d.ts +29 -0
- package/dist/events/task.event.d.ts.map +1 -0
- package/dist/events/task.event.js +45 -0
- package/dist/events/task.event.js.map +1 -0
- package/dist/example.d.ts +7 -0
- package/dist/example.d.ts.map +1 -0
- package/dist/example.js +53 -0
- package/dist/example.js.map +1 -0
- package/dist/handlers/crm.handlers.d.ts +89 -0
- package/dist/handlers/crm.handlers.d.ts.map +1 -0
- package/dist/handlers/crm.handlers.js +172 -0
- package/dist/handlers/crm.handlers.js.map +1 -0
- package/dist/handlers/deal.handlers.d.ts +94 -0
- package/dist/handlers/deal.handlers.d.ts.map +1 -0
- package/dist/handlers/deal.handlers.js +120 -0
- package/dist/handlers/deal.handlers.js.map +1 -0
- package/dist/handlers/index.d.ts +4 -0
- package/dist/handlers/index.js +5 -0
- package/dist/handlers/mock-data.d.ts +49 -0
- package/dist/handlers/mock-data.d.ts.map +1 -0
- package/dist/handlers/mock-data.js +188 -0
- package/dist/handlers/mock-data.js.map +1 -0
- package/dist/index.d.ts +47 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +56 -0
- package/dist/index.js.map +1 -0
- package/dist/operations/index.d.ts +5 -0
- package/dist/operations/index.js +6 -0
- package/dist/presentations/dashboard.presentation.d.ts +14 -0
- package/dist/presentations/dashboard.presentation.d.ts.map +1 -0
- package/dist/presentations/dashboard.presentation.js +62 -0
- package/dist/presentations/dashboard.presentation.js.map +1 -0
- package/dist/presentations/index.d.ts +3 -0
- package/dist/presentations/index.js +4 -0
- package/dist/presentations/pipeline.presentation.d.ts +22 -0
- package/dist/presentations/pipeline.presentation.d.ts.map +1 -0
- package/dist/presentations/pipeline.presentation.js +122 -0
- package/dist/presentations/pipeline.presentation.js.map +1 -0
- package/dist/seeders/index.d.ts +10 -0
- package/dist/seeders/index.d.ts.map +1 -0
- package/dist/seeders/index.js +47 -0
- package/dist/seeders/index.js.map +1 -0
- package/dist/shared/overlay-types.d.ts +34 -0
- package/dist/shared/overlay-types.d.ts.map +1 -0
- package/dist/shared/overlay-types.js +0 -0
- package/dist/ui/CrmDashboard.d.ts +7 -0
- package/dist/ui/CrmDashboard.d.ts.map +1 -0
- package/dist/ui/CrmDashboard.js +304 -0
- package/dist/ui/CrmDashboard.js.map +1 -0
- package/dist/ui/CrmDealCard.d.ts +15 -0
- package/dist/ui/CrmDealCard.d.ts.map +1 -0
- package/dist/ui/CrmDealCard.js +49 -0
- package/dist/ui/CrmDealCard.js.map +1 -0
- package/dist/ui/CrmPipelineBoard.d.ts +23 -0
- package/dist/ui/CrmPipelineBoard.d.ts.map +1 -0
- package/dist/ui/CrmPipelineBoard.js +98 -0
- package/dist/ui/CrmPipelineBoard.js.map +1 -0
- package/dist/ui/hooks/index.d.ts +3 -0
- package/dist/ui/hooks/index.js +6 -0
- package/dist/ui/hooks/useDealList.d.ts +35 -0
- package/dist/ui/hooks/useDealList.d.ts.map +1 -0
- package/dist/ui/hooks/useDealList.js +94 -0
- package/dist/ui/hooks/useDealList.js.map +1 -0
- package/dist/ui/hooks/useDealMutations.d.ts +26 -0
- package/dist/ui/hooks/useDealMutations.d.ts.map +1 -0
- package/dist/ui/hooks/useDealMutations.js +159 -0
- package/dist/ui/hooks/useDealMutations.js.map +1 -0
- package/dist/ui/index.d.ts +14 -0
- package/dist/ui/index.js +15 -0
- package/dist/ui/modals/CreateDealModal.d.ts +33 -0
- package/dist/ui/modals/CreateDealModal.d.ts.map +1 -0
- package/dist/ui/modals/CreateDealModal.js +183 -0
- package/dist/ui/modals/CreateDealModal.js.map +1 -0
- package/dist/ui/modals/DealActionsModal.d.ts +51 -0
- package/dist/ui/modals/DealActionsModal.d.ts.map +1 -0
- package/dist/ui/modals/DealActionsModal.js +372 -0
- package/dist/ui/modals/DealActionsModal.js.map +1 -0
- package/dist/ui/modals/index.d.ts +3 -0
- package/dist/ui/modals/index.js +4 -0
- package/dist/ui/overlays/demo-overlays.d.ts +19 -0
- package/dist/ui/overlays/demo-overlays.d.ts.map +1 -0
- package/dist/ui/overlays/demo-overlays.js +68 -0
- package/dist/ui/overlays/demo-overlays.js.map +1 -0
- package/dist/ui/overlays/index.d.ts +2 -0
- package/dist/ui/overlays/index.js +3 -0
- package/dist/ui/renderers/index.d.ts +3 -0
- package/dist/ui/renderers/index.js +4 -0
- package/dist/ui/renderers/pipeline.markdown.d.ts +23 -0
- package/dist/ui/renderers/pipeline.markdown.d.ts.map +1 -0
- package/dist/ui/renderers/pipeline.markdown.js +118 -0
- package/dist/ui/renderers/pipeline.markdown.js.map +1 -0
- package/dist/ui/renderers/pipeline.renderer.d.ts +9 -0
- package/dist/ui/renderers/pipeline.renderer.d.ts.map +1 -0
- package/dist/ui/renderers/pipeline.renderer.js +28 -0
- package/dist/ui/renderers/pipeline.renderer.js.map +1 -0
- package/example.ts +1 -0
- package/package.json +127 -0
- package/src/crm-pipeline.feature.ts +100 -0
- package/src/deal/deal.enum.ts +21 -0
- package/src/deal/deal.operation.ts +291 -0
- package/src/deal/deal.schema.ts +154 -0
- package/src/deal/deal.test-spec.ts +55 -0
- package/src/deal/index.ts +26 -0
- package/src/docs/crm-pipeline.docblock.ts +98 -0
- package/src/docs/index.ts +1 -0
- package/src/entities/company.entity.ts +77 -0
- package/src/entities/contact.entity.ts +93 -0
- package/src/entities/deal.entity.ts +160 -0
- package/src/entities/index.ts +45 -0
- package/src/entities/task.entity.ts +137 -0
- package/src/events/contact.event.ts +31 -0
- package/src/events/deal.event.ts +104 -0
- package/src/events/index.ts +3 -0
- package/src/events/task.event.ts +28 -0
- package/src/example.ts +38 -0
- package/src/handlers/crm.handlers.ts +415 -0
- package/src/handlers/deal.handlers.ts +253 -0
- package/src/handlers/index.ts +30 -0
- package/src/handlers/mock-data.ts +198 -0
- package/src/index.ts +32 -0
- package/src/operations/index.ts +20 -0
- package/src/presentations/dashboard.presentation.ts +59 -0
- package/src/presentations/index.ts +2 -0
- package/src/presentations/pipeline.presentation.ts +117 -0
- package/src/seeders/index.ts +35 -0
- package/src/shared/overlay-types.ts +39 -0
- package/src/ui/CrmDashboard.tsx +311 -0
- package/src/ui/CrmDealCard.tsx +83 -0
- package/src/ui/CrmPipelineBoard.tsx +136 -0
- package/src/ui/hooks/index.ts +10 -0
- package/src/ui/hooks/useDealList.ts +113 -0
- package/src/ui/hooks/useDealMutations.ts +174 -0
- package/src/ui/index.ts +18 -0
- package/src/ui/modals/CreateDealModal.tsx +239 -0
- package/src/ui/modals/DealActionsModal.tsx +424 -0
- package/src/ui/modals/index.ts +2 -0
- package/src/ui/overlays/demo-overlays.ts +68 -0
- package/src/ui/overlays/index.ts +1 -0
- package/src/ui/renderers/index.ts +6 -0
- package/src/ui/renderers/pipeline.markdown.ts +198 -0
- package/src/ui/renderers/pipeline.renderer.tsx +35 -0
- package/tsconfig.json +10 -0
- package/tsconfig.tsbuildinfo +1 -0
- package/tsdown.config.js +7 -0
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import { mockGetPipelineStagesHandler, mockListDealsHandler } from "@contractspec/example.crm-pipeline/handlers";
|
|
2
|
+
|
|
3
|
+
//#region src/ui/renderers/pipeline.markdown.ts
|
|
4
|
+
function formatCurrency(value, currency = "USD") {
|
|
5
|
+
return new Intl.NumberFormat("en-US", {
|
|
6
|
+
style: "currency",
|
|
7
|
+
currency,
|
|
8
|
+
minimumFractionDigits: 0
|
|
9
|
+
}).format(value);
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Markdown renderer for CRM Pipeline Kanban view (crm-pipeline.deal.pipeline)
|
|
13
|
+
* Only handles PipelineKanbanView component
|
|
14
|
+
*/
|
|
15
|
+
const crmPipelineMarkdownRenderer = {
|
|
16
|
+
target: "markdown",
|
|
17
|
+
render: async (desc, _ctx) => {
|
|
18
|
+
if (desc.source.type !== "component" || desc.source.componentKey !== "PipelineKanbanView") throw new Error("crmPipelineMarkdownRenderer: not PipelineKanbanView");
|
|
19
|
+
const pipelineId = "pipeline-1";
|
|
20
|
+
const [dealsResult, stages] = await Promise.all([mockListDealsHandler({
|
|
21
|
+
pipelineId,
|
|
22
|
+
limit: 50
|
|
23
|
+
}), mockGetPipelineStagesHandler({ pipelineId })]);
|
|
24
|
+
const deals = dealsResult.deals;
|
|
25
|
+
const stageList = stages;
|
|
26
|
+
const dealsByStage = {};
|
|
27
|
+
for (const stage of stageList) dealsByStage[stage.id] = deals.filter((d) => d.stageId === stage.id && d.status === "OPEN");
|
|
28
|
+
const lines = [
|
|
29
|
+
"# CRM Pipeline",
|
|
30
|
+
"",
|
|
31
|
+
`**Total Value**: ${formatCurrency(dealsResult.totalValue)}`,
|
|
32
|
+
`**Total Deals**: ${dealsResult.total}`,
|
|
33
|
+
""
|
|
34
|
+
];
|
|
35
|
+
for (const stage of stageList.sort((a, b) => a.position - b.position)) {
|
|
36
|
+
const stageDeals = dealsByStage[stage.id] ?? [];
|
|
37
|
+
const stageValue = stageDeals.reduce((sum, d) => sum + d.value, 0);
|
|
38
|
+
lines.push(`## ${stage.name}`);
|
|
39
|
+
lines.push(`_${stageDeals.length} deals · ${formatCurrency(stageValue)}_`);
|
|
40
|
+
lines.push("");
|
|
41
|
+
if (stageDeals.length === 0) lines.push("_No deals_");
|
|
42
|
+
else for (const deal of stageDeals) lines.push(`- **${deal.name}** - ${formatCurrency(deal.value, deal.currency)}`);
|
|
43
|
+
lines.push("");
|
|
44
|
+
}
|
|
45
|
+
return {
|
|
46
|
+
mimeType: "text/markdown",
|
|
47
|
+
body: lines.join("\n")
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
};
|
|
51
|
+
/**
|
|
52
|
+
* Markdown renderer for CRM Dashboard (crm-pipeline.dashboard)
|
|
53
|
+
* Only handles CrmDashboard component
|
|
54
|
+
*/
|
|
55
|
+
const crmDashboardMarkdownRenderer = {
|
|
56
|
+
target: "markdown",
|
|
57
|
+
render: async (desc, _ctx) => {
|
|
58
|
+
if (desc.source.type !== "component" || desc.source.componentKey !== "CrmDashboard") throw new Error("crmDashboardMarkdownRenderer: not CrmDashboard");
|
|
59
|
+
const pipelineId = "pipeline-1";
|
|
60
|
+
const [dealsResult, stages] = await Promise.all([mockListDealsHandler({
|
|
61
|
+
pipelineId,
|
|
62
|
+
limit: 100
|
|
63
|
+
}), mockGetPipelineStagesHandler({ pipelineId })]);
|
|
64
|
+
const deals = dealsResult.deals;
|
|
65
|
+
const stageList = stages;
|
|
66
|
+
const openDeals = deals.filter((d) => d.status === "OPEN");
|
|
67
|
+
const wonDeals = deals.filter((d) => d.status === "WON");
|
|
68
|
+
const lostDeals = deals.filter((d) => d.status === "LOST");
|
|
69
|
+
const openValue = openDeals.reduce((sum, d) => sum + d.value, 0);
|
|
70
|
+
const wonValue = wonDeals.reduce((sum, d) => sum + d.value, 0);
|
|
71
|
+
const lines = [
|
|
72
|
+
"# CRM Dashboard",
|
|
73
|
+
"",
|
|
74
|
+
"> Sales pipeline overview and key metrics",
|
|
75
|
+
"",
|
|
76
|
+
"## Summary",
|
|
77
|
+
"",
|
|
78
|
+
"| Metric | Value |",
|
|
79
|
+
"|--------|-------|",
|
|
80
|
+
`| Total Deals | ${dealsResult.total} |`,
|
|
81
|
+
`| Pipeline Value | ${formatCurrency(dealsResult.totalValue)} |`,
|
|
82
|
+
`| Open Deals | ${openDeals.length} (${formatCurrency(openValue)}) |`,
|
|
83
|
+
`| Won Deals | ${wonDeals.length} (${formatCurrency(wonValue)}) |`,
|
|
84
|
+
`| Lost Deals | ${lostDeals.length} |`,
|
|
85
|
+
"",
|
|
86
|
+
"## Pipeline Stages",
|
|
87
|
+
""
|
|
88
|
+
];
|
|
89
|
+
lines.push("| Stage | Deals | Value |");
|
|
90
|
+
lines.push("|-------|-------|-------|");
|
|
91
|
+
for (const stage of stageList.sort((a, b) => a.position - b.position)) {
|
|
92
|
+
const stageDeals = openDeals.filter((d) => d.stageId === stage.id);
|
|
93
|
+
const stageValue = stageDeals.reduce((sum, d) => sum + d.value, 0);
|
|
94
|
+
lines.push(`| ${stage.name} | ${stageDeals.length} | ${formatCurrency(stageValue)} |`);
|
|
95
|
+
}
|
|
96
|
+
lines.push("");
|
|
97
|
+
lines.push("## Recent Deals");
|
|
98
|
+
lines.push("");
|
|
99
|
+
const recentDeals = deals.slice(0, 10);
|
|
100
|
+
if (recentDeals.length === 0) lines.push("_No deals yet._");
|
|
101
|
+
else {
|
|
102
|
+
lines.push("| Deal | Value | Stage | Status |");
|
|
103
|
+
lines.push("|------|-------|-------|--------|");
|
|
104
|
+
for (const deal of recentDeals) {
|
|
105
|
+
const stage = stageList.find((s) => s.id === deal.stageId);
|
|
106
|
+
lines.push(`| ${deal.name} | ${formatCurrency(deal.value, deal.currency)} | ${stage?.name ?? "-"} | ${deal.status} |`);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
return {
|
|
110
|
+
mimeType: "text/markdown",
|
|
111
|
+
body: lines.join("\n")
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
};
|
|
115
|
+
|
|
116
|
+
//#endregion
|
|
117
|
+
export { crmDashboardMarkdownRenderer, crmPipelineMarkdownRenderer };
|
|
118
|
+
//# sourceMappingURL=pipeline.markdown.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pipeline.markdown.js","names":[],"sources":["../../../src/ui/renderers/pipeline.markdown.ts"],"sourcesContent":["/**\n * Markdown renderer for CRM Pipeline presentation\n *\n * Imports handlers from the hooks module to ensure correct build order.\n */\nimport type { PresentationRenderer } from '@contractspec/lib.contracts';\nimport {\n mockListDealsHandler,\n mockGetPipelineStagesHandler,\n} from '@contractspec/example.crm-pipeline/handlers';\n\ninterface DealItem {\n id: string;\n name: string;\n value: number;\n currency: string;\n stageId: string;\n status: string;\n}\n\ninterface StageItem {\n id: string;\n name: string;\n position: number;\n}\n\nfunction formatCurrency(value: number, currency = 'USD'): string {\n return new Intl.NumberFormat('en-US', {\n style: 'currency',\n currency,\n minimumFractionDigits: 0,\n }).format(value);\n}\n\n/**\n * Markdown renderer for CRM Pipeline Kanban view (crm-pipeline.deal.pipeline)\n * Only handles PipelineKanbanView component\n */\nexport const crmPipelineMarkdownRenderer: PresentationRenderer<{\n mimeType: string;\n body: string;\n}> = {\n target: 'markdown',\n render: async (desc, _ctx) => {\n // Only handle PipelineKanbanView\n if (\n desc.source.type !== 'component' ||\n desc.source.componentKey !== 'PipelineKanbanView'\n ) {\n throw new Error('crmPipelineMarkdownRenderer: not PipelineKanbanView');\n }\n\n const pipelineId = 'pipeline-1';\n const [dealsResult, stages] = await Promise.all([\n mockListDealsHandler({ pipelineId, limit: 50 }),\n mockGetPipelineStagesHandler({ pipelineId }),\n ]);\n\n const deals = dealsResult.deals as DealItem[];\n const stageList = stages as StageItem[];\n\n // Group deals by stage\n const dealsByStage: Record<string, DealItem[]> = {};\n for (const stage of stageList) {\n dealsByStage[stage.id] = deals.filter(\n (d) => d.stageId === stage.id && d.status === 'OPEN'\n );\n }\n\n // Build Markdown\n const lines: string[] = [\n '# CRM Pipeline',\n '',\n `**Total Value**: ${formatCurrency(dealsResult.totalValue)}`,\n `**Total Deals**: ${dealsResult.total}`,\n '',\n ];\n\n for (const stage of stageList.sort((a, b) => a.position - b.position)) {\n const stageDeals = dealsByStage[stage.id] ?? [];\n const stageValue = stageDeals.reduce((sum, d) => sum + d.value, 0);\n\n lines.push(`## ${stage.name}`);\n lines.push(\n `_${stageDeals.length} deals · ${formatCurrency(stageValue)}_`\n );\n lines.push('');\n\n if (stageDeals.length === 0) {\n lines.push('_No deals_');\n } else {\n for (const deal of stageDeals) {\n lines.push(\n `- **${deal.name}** - ${formatCurrency(deal.value, deal.currency)}`\n );\n }\n }\n\n lines.push('');\n }\n\n return {\n mimeType: 'text/markdown',\n body: lines.join('\\n'),\n };\n },\n};\n\n/**\n * Markdown renderer for CRM Dashboard (crm-pipeline.dashboard)\n * Only handles CrmDashboard component\n */\nexport const crmDashboardMarkdownRenderer: PresentationRenderer<{\n mimeType: string;\n body: string;\n}> = {\n target: 'markdown',\n render: async (desc, _ctx) => {\n // Only handle CrmDashboard\n if (\n desc.source.type !== 'component' ||\n desc.source.componentKey !== 'CrmDashboard'\n ) {\n throw new Error('crmDashboardMarkdownRenderer: not CrmDashboard');\n }\n\n const pipelineId = 'pipeline-1';\n const [dealsResult, stages] = await Promise.all([\n mockListDealsHandler({ pipelineId, limit: 100 }),\n mockGetPipelineStagesHandler({ pipelineId }),\n ]);\n\n const deals = dealsResult.deals as DealItem[];\n const stageList = stages as StageItem[];\n\n // Calculate stats\n const openDeals = deals.filter((d) => d.status === 'OPEN');\n const wonDeals = deals.filter((d) => d.status === 'WON');\n const lostDeals = deals.filter((d) => d.status === 'LOST');\n const openValue = openDeals.reduce((sum, d) => sum + d.value, 0);\n const wonValue = wonDeals.reduce((sum, d) => sum + d.value, 0);\n\n // Build dashboard markdown\n const lines: string[] = [\n '# CRM Dashboard',\n '',\n '> Sales pipeline overview and key metrics',\n '',\n '## Summary',\n '',\n '| Metric | Value |',\n '|--------|-------|',\n `| Total Deals | ${dealsResult.total} |`,\n `| Pipeline Value | ${formatCurrency(dealsResult.totalValue)} |`,\n `| Open Deals | ${openDeals.length} (${formatCurrency(openValue)}) |`,\n `| Won Deals | ${wonDeals.length} (${formatCurrency(wonValue)}) |`,\n `| Lost Deals | ${lostDeals.length} |`,\n '',\n '## Pipeline Stages',\n '',\n ];\n\n // Stage summary table\n lines.push('| Stage | Deals | Value |');\n lines.push('|-------|-------|-------|');\n for (const stage of stageList.sort((a, b) => a.position - b.position)) {\n const stageDeals = openDeals.filter((d) => d.stageId === stage.id);\n const stageValue = stageDeals.reduce((sum, d) => sum + d.value, 0);\n lines.push(\n `| ${stage.name} | ${stageDeals.length} | ${formatCurrency(stageValue)} |`\n );\n }\n\n lines.push('');\n lines.push('## Recent Deals');\n lines.push('');\n\n // Top 10 recent deals\n const recentDeals = deals.slice(0, 10);\n if (recentDeals.length === 0) {\n lines.push('_No deals yet._');\n } else {\n lines.push('| Deal | Value | Stage | Status |');\n lines.push('|------|-------|-------|--------|');\n for (const deal of recentDeals) {\n const stage = stageList.find((s) => s.id === deal.stageId);\n lines.push(\n `| ${deal.name} | ${formatCurrency(deal.value, deal.currency)} | ${stage?.name ?? '-'} | ${deal.status} |`\n );\n }\n }\n\n return {\n mimeType: 'text/markdown',\n body: lines.join('\\n'),\n };\n },\n};\n"],"mappings":"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"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { PresentationRenderer } from "@contractspec/lib.contracts";
|
|
2
|
+
import * as React from "react";
|
|
3
|
+
|
|
4
|
+
//#region src/ui/renderers/pipeline.renderer.d.ts
|
|
5
|
+
|
|
6
|
+
declare const crmPipelineReactRenderer: PresentationRenderer<React.ReactElement>;
|
|
7
|
+
//#endregion
|
|
8
|
+
export { crmPipelineReactRenderer };
|
|
9
|
+
//# sourceMappingURL=pipeline.renderer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pipeline.renderer.d.ts","names":[],"sources":["../../../src/ui/renderers/pipeline.renderer.tsx"],"sourcesContent":[],"mappings":";;;;;cAmBa,0BAA0B,qBAAqB,KAAA,CAAM"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { useDealList } from "../hooks/useDealList.js";
|
|
2
|
+
import { CrmPipelineBoard } from "../CrmPipelineBoard.js";
|
|
3
|
+
import "react";
|
|
4
|
+
import { jsx } from "react/jsx-runtime";
|
|
5
|
+
|
|
6
|
+
//#region src/ui/renderers/pipeline.renderer.tsx
|
|
7
|
+
/**
|
|
8
|
+
* Wrapper component that provides data to CrmPipelineBoard
|
|
9
|
+
*/
|
|
10
|
+
function CrmPipelineBoardWrapper() {
|
|
11
|
+
const { dealsByStage, stages } = useDealList();
|
|
12
|
+
return /* @__PURE__ */ jsx(CrmPipelineBoard, {
|
|
13
|
+
dealsByStage,
|
|
14
|
+
stages
|
|
15
|
+
});
|
|
16
|
+
}
|
|
17
|
+
const crmPipelineReactRenderer = {
|
|
18
|
+
target: "react",
|
|
19
|
+
render: async (desc, _ctx) => {
|
|
20
|
+
if (desc.source.type !== "component") throw new Error("Invalid source type");
|
|
21
|
+
if (desc.source.componentKey !== "CrmPipelineView") throw new Error(`Unknown component: ${desc.source.componentKey}`);
|
|
22
|
+
return /* @__PURE__ */ jsx(CrmPipelineBoardWrapper, {});
|
|
23
|
+
}
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
//#endregion
|
|
27
|
+
export { crmPipelineReactRenderer };
|
|
28
|
+
//# sourceMappingURL=pipeline.renderer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pipeline.renderer.js","names":[],"sources":["../../../src/ui/renderers/pipeline.renderer.tsx"],"sourcesContent":["/**\n * React renderer for CRM Pipeline presentation\n *\n * Renders the CRM pipeline board component.\n * Data is fetched via the CrmPipelineBoard component's internal hooks.\n */\nimport * as React from 'react';\nimport type { PresentationRenderer } from '@contractspec/lib.contracts';\nimport { CrmPipelineBoard } from '../CrmPipelineBoard';\nimport { useDealList } from '../hooks/useDealList';\n\n/**\n * Wrapper component that provides data to CrmPipelineBoard\n */\nfunction CrmPipelineBoardWrapper() {\n const { dealsByStage, stages } = useDealList();\n return <CrmPipelineBoard dealsByStage={dealsByStage} stages={stages} />;\n}\n\nexport const crmPipelineReactRenderer: PresentationRenderer<React.ReactElement> =\n {\n target: 'react',\n render: async (desc, _ctx) => {\n if (desc.source.type !== 'component') {\n throw new Error('Invalid source type');\n }\n\n if (desc.source.componentKey !== 'CrmPipelineView') {\n throw new Error(`Unknown component: ${desc.source.componentKey}`);\n }\n\n // Note: The wrapper component will fetch data internally\n return <CrmPipelineBoardWrapper />;\n },\n };\n"],"mappings":";;;;;;;;;AAcA,SAAS,0BAA0B;CACjC,MAAM,EAAE,cAAc,WAAW,aAAa;AAC9C,QAAO,oBAAC;EAA+B;EAAsB;GAAU;;AAGzE,MAAa,2BACX;CACE,QAAQ;CACR,QAAQ,OAAO,MAAM,SAAS;AAC5B,MAAI,KAAK,OAAO,SAAS,YACvB,OAAM,IAAI,MAAM,sBAAsB;AAGxC,MAAI,KAAK,OAAO,iBAAiB,kBAC/B,OAAM,IAAI,MAAM,sBAAsB,KAAK,OAAO,eAAe;AAInE,SAAO,oBAAC,4BAA0B;;CAErC"}
|
package/example.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default } from './src/example';
|
package/package.json
ADDED
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@contractspec/example.crm-pipeline",
|
|
3
|
+
"version": "0.0.0-canary-20260113170453",
|
|
4
|
+
"description": "CRM Pipeline - Contacts, Companies, Deals, Tasks",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"types": "./dist/index.d.ts",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": "./dist/index.js",
|
|
9
|
+
"./crm-pipeline.feature": "./dist/crm-pipeline.feature.js",
|
|
10
|
+
"./deal": "./dist/deal/index.js",
|
|
11
|
+
"./deal/deal.enum": "./dist/deal/deal.enum.js",
|
|
12
|
+
"./deal/deal.operation": "./dist/deal/deal.operation.js",
|
|
13
|
+
"./deal/deal.schema": "./dist/deal/deal.schema.js",
|
|
14
|
+
"./deal/deal.test-spec": "./dist/deal/deal.test-spec.js",
|
|
15
|
+
"./docs": "./dist/docs/index.js",
|
|
16
|
+
"./docs/crm-pipeline.docblock": "./dist/docs/crm-pipeline.docblock.js",
|
|
17
|
+
"./entities": "./dist/entities/index.js",
|
|
18
|
+
"./entities/company.entity": "./dist/entities/company.entity.js",
|
|
19
|
+
"./entities/contact.entity": "./dist/entities/contact.entity.js",
|
|
20
|
+
"./entities/deal.entity": "./dist/entities/deal.entity.js",
|
|
21
|
+
"./entities/task.entity": "./dist/entities/task.entity.js",
|
|
22
|
+
"./events": "./dist/events/index.js",
|
|
23
|
+
"./events/contact.event": "./dist/events/contact.event.js",
|
|
24
|
+
"./events/deal.event": "./dist/events/deal.event.js",
|
|
25
|
+
"./events/task.event": "./dist/events/task.event.js",
|
|
26
|
+
"./example": "./dist/example.js",
|
|
27
|
+
"./handlers": "./dist/handlers/index.js",
|
|
28
|
+
"./handlers/crm.handlers": "./dist/handlers/crm.handlers.js",
|
|
29
|
+
"./handlers/deal.handlers": "./dist/handlers/deal.handlers.js",
|
|
30
|
+
"./handlers/mock-data": "./dist/handlers/mock-data.js",
|
|
31
|
+
"./operations": "./dist/operations/index.js",
|
|
32
|
+
"./presentations": "./dist/presentations/index.js",
|
|
33
|
+
"./presentations/dashboard.presentation": "./dist/presentations/dashboard.presentation.js",
|
|
34
|
+
"./presentations/pipeline.presentation": "./dist/presentations/pipeline.presentation.js",
|
|
35
|
+
"./seeders": "./dist/seeders/index.js",
|
|
36
|
+
"./shared/overlay-types": "./dist/shared/overlay-types.js",
|
|
37
|
+
"./ui": "./dist/ui/index.js",
|
|
38
|
+
"./ui/CrmDashboard": "./dist/ui/CrmDashboard.js",
|
|
39
|
+
"./ui/CrmDealCard": "./dist/ui/CrmDealCard.js",
|
|
40
|
+
"./ui/CrmPipelineBoard": "./dist/ui/CrmPipelineBoard.js",
|
|
41
|
+
"./ui/hooks": "./dist/ui/hooks/index.js",
|
|
42
|
+
"./ui/hooks/useDealList": "./dist/ui/hooks/useDealList.js",
|
|
43
|
+
"./ui/hooks/useDealMutations": "./dist/ui/hooks/useDealMutations.js",
|
|
44
|
+
"./ui/modals": "./dist/ui/modals/index.js",
|
|
45
|
+
"./ui/modals/CreateDealModal": "./dist/ui/modals/CreateDealModal.js",
|
|
46
|
+
"./ui/modals/DealActionsModal": "./dist/ui/modals/DealActionsModal.js",
|
|
47
|
+
"./ui/overlays": "./dist/ui/overlays/index.js",
|
|
48
|
+
"./ui/overlays/demo-overlays": "./dist/ui/overlays/demo-overlays.js",
|
|
49
|
+
"./ui/renderers": "./dist/ui/renderers/index.js",
|
|
50
|
+
"./ui/renderers/pipeline.markdown": "./dist/ui/renderers/pipeline.markdown.js",
|
|
51
|
+
"./ui/renderers/pipeline.renderer": "./dist/ui/renderers/pipeline.renderer.js",
|
|
52
|
+
"./*": "./*"
|
|
53
|
+
},
|
|
54
|
+
"scripts": {
|
|
55
|
+
"publish:pkg": "bun publish --tolerate-republish --ignore-scripts --verbose",
|
|
56
|
+
"publish:pkg:canary": "bun publish:pkg --tag canary",
|
|
57
|
+
"build": "bun build:types && bun build:bundle",
|
|
58
|
+
"build:bundle": "tsdown",
|
|
59
|
+
"build:types": "tsc --noEmit",
|
|
60
|
+
"dev": "bun build:bundle --watch",
|
|
61
|
+
"clean": "rimraf dist .turbo",
|
|
62
|
+
"lint": "bun lint:fix",
|
|
63
|
+
"lint:fix": "eslint src --fix",
|
|
64
|
+
"lint:check": "eslint src",
|
|
65
|
+
"test": "bun test"
|
|
66
|
+
},
|
|
67
|
+
"dependencies": {
|
|
68
|
+
"@contractspec/lib.contracts": "0.0.0-canary-20260113170453",
|
|
69
|
+
"@contractspec/lib.design-system": "0.0.0-canary-20260113170453",
|
|
70
|
+
"@contractspec/lib.example-shared-ui": "0.0.0-canary-20260113170453",
|
|
71
|
+
"@contractspec/lib.identity-rbac": "0.0.0-canary-20260113170453",
|
|
72
|
+
"@contractspec/lib.runtime-sandbox": "0.0.0-canary-20260113170453",
|
|
73
|
+
"@contractspec/lib.schema": "0.0.0-canary-20260113170453",
|
|
74
|
+
"@contractspec/lib.ui-kit-web": "0.0.0-canary-20260113170453",
|
|
75
|
+
"@contractspec/module.audit-trail": "0.0.0-canary-20260113170453",
|
|
76
|
+
"@contractspec/module.notifications": "0.0.0-canary-20260113170453",
|
|
77
|
+
"react": "19.2.3",
|
|
78
|
+
"react-dom": "19.2.3"
|
|
79
|
+
},
|
|
80
|
+
"devDependencies": {
|
|
81
|
+
"@contractspec/tool.tsdown": "0.0.0-canary-20260113170453",
|
|
82
|
+
"@contractspec/tool.typescript": "0.0.0-canary-20260113170453",
|
|
83
|
+
"tsdown": "^0.19.0",
|
|
84
|
+
"typescript": "^5.9.3",
|
|
85
|
+
"@types/react": "^19.2.8",
|
|
86
|
+
"@types/react-dom": "^19.2.2"
|
|
87
|
+
},
|
|
88
|
+
"publishConfig": {
|
|
89
|
+
"exports": {
|
|
90
|
+
".": "./dist/index.js",
|
|
91
|
+
"./contracts": "./dist/contracts/index.js",
|
|
92
|
+
"./crm-pipeline.feature": "./dist/crm-pipeline.feature.js",
|
|
93
|
+
"./deal": "./dist/deal/index.js",
|
|
94
|
+
"./deal/deal.contracts": "./dist/deal/deal.operations.js",
|
|
95
|
+
"./deal/deal.enum": "./dist/deal/deal.enum.js",
|
|
96
|
+
"./deal/deal.schema": "./dist/deal/deal.schema.js",
|
|
97
|
+
"./docs": "./dist/docs/index.js",
|
|
98
|
+
"./docs/crm-pipeline.docblock": "./dist/docs/crm-pipeline.docblock.js",
|
|
99
|
+
"./entities": "./dist/entities/index.js",
|
|
100
|
+
"./entities/company.entity": "./dist/entities/company.entity.js",
|
|
101
|
+
"./entities/contact.entity": "./dist/entities/contact.entity.js",
|
|
102
|
+
"./entities/deal.entity": "./dist/entities/deal.entity.js",
|
|
103
|
+
"./entities/task.entity": "./dist/entities/task.entity.js",
|
|
104
|
+
"./events": "./dist/events/index.js",
|
|
105
|
+
"./events/contact.event": "./dist/events/contact.event.js",
|
|
106
|
+
"./events/deal.event": "./dist/events/deal.event.js",
|
|
107
|
+
"./events/task.event": "./dist/events/task.event.js",
|
|
108
|
+
"./example": "./dist/example.js",
|
|
109
|
+
"./handlers": "./dist/handlers/index.js",
|
|
110
|
+
"./handlers/deal.handlers": "./dist/handlers/deal.handlers.js",
|
|
111
|
+
"./handlers/mock-data": "./dist/handlers/mock-data.js",
|
|
112
|
+
"./presentations": "./dist/presentations/index.js",
|
|
113
|
+
"./presentations/dashboard.presentation": "./dist/presentations/dashboard.presentation.js",
|
|
114
|
+
"./presentations/pipeline.presentation": "./dist/presentations/pipeline.presentation.js",
|
|
115
|
+
"./*": "./*"
|
|
116
|
+
},
|
|
117
|
+
"registry": "https://registry.npmjs.org/",
|
|
118
|
+
"access": "public"
|
|
119
|
+
},
|
|
120
|
+
"license": "MIT",
|
|
121
|
+
"repository": {
|
|
122
|
+
"type": "git",
|
|
123
|
+
"url": "https://github.com/lssm-tech/contractspec.git",
|
|
124
|
+
"directory": "packages/examples/crm-pipeline"
|
|
125
|
+
},
|
|
126
|
+
"homepage": "https://contractspec.io"
|
|
127
|
+
}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CRM Pipeline Feature Module Specification
|
|
3
|
+
*
|
|
4
|
+
* Defines the feature module for CRM and sales pipeline capabilities.
|
|
5
|
+
*/
|
|
6
|
+
import { defineFeature } from '@contractspec/lib.contracts';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* CRM Pipeline feature module that bundles deal management,
|
|
10
|
+
* pipeline operations, and contact management into an installable feature.
|
|
11
|
+
*/
|
|
12
|
+
export const CrmPipelineFeature = defineFeature({
|
|
13
|
+
meta: {
|
|
14
|
+
key: 'crm-pipeline',
|
|
15
|
+
title: 'CRM Pipeline',
|
|
16
|
+
description:
|
|
17
|
+
'CRM and sales pipeline management with deals, contacts, and companies',
|
|
18
|
+
domain: 'crm',
|
|
19
|
+
owners: ['@crm-team'],
|
|
20
|
+
tags: ['crm', 'sales', 'pipeline', 'deals'],
|
|
21
|
+
stability: 'experimental',
|
|
22
|
+
version: '1.0.0',
|
|
23
|
+
},
|
|
24
|
+
|
|
25
|
+
// All contract operations included in this feature
|
|
26
|
+
operations: [
|
|
27
|
+
// Deal operations
|
|
28
|
+
{ key: 'crm.deal.create', version: '1.0.0' },
|
|
29
|
+
{ key: 'crm.deal.move', version: '1.0.0' },
|
|
30
|
+
{ key: 'crm.deal.win', version: '1.0.0' },
|
|
31
|
+
{ key: 'crm.deal.lose', version: '1.0.0' },
|
|
32
|
+
{ key: 'crm.deal.list', version: '1.0.0' },
|
|
33
|
+
],
|
|
34
|
+
|
|
35
|
+
// Events emitted by this feature
|
|
36
|
+
events: [
|
|
37
|
+
// Deal events
|
|
38
|
+
{ key: 'deal.created', version: '1.0.0' },
|
|
39
|
+
{ key: 'deal.moved', version: '1.0.0' },
|
|
40
|
+
{ key: 'deal.won', version: '1.0.0' },
|
|
41
|
+
{ key: 'deal.lost', version: '1.0.0' },
|
|
42
|
+
|
|
43
|
+
// Contact events
|
|
44
|
+
{ key: 'contact.created', version: '1.0.0' },
|
|
45
|
+
|
|
46
|
+
// Task events
|
|
47
|
+
{ key: 'task.completed', version: '1.0.0' },
|
|
48
|
+
],
|
|
49
|
+
|
|
50
|
+
// Presentations associated with this feature
|
|
51
|
+
presentations: [
|
|
52
|
+
{ key: 'crm.dashboard', version: '1.0.0' },
|
|
53
|
+
{ key: 'crm.pipeline.kanban', version: '1.0.0' },
|
|
54
|
+
{ key: 'crm.deal.list', version: '1.0.0' },
|
|
55
|
+
{ key: 'crm.deal.detail', version: '1.0.0' },
|
|
56
|
+
{ key: 'crm.deal.card', version: '1.0.0' },
|
|
57
|
+
{ key: 'crm.pipeline.metrics', version: '1.0.0' },
|
|
58
|
+
],
|
|
59
|
+
|
|
60
|
+
// Link operations to their primary presentations
|
|
61
|
+
opToPresentation: [
|
|
62
|
+
{
|
|
63
|
+
op: { key: 'crm.deal.list', version: '1.0.0' },
|
|
64
|
+
pres: { key: 'crm.pipeline.kanban', version: '1.0.0' },
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
op: { key: 'crm.deal.move', version: '1.0.0' },
|
|
68
|
+
pres: { key: 'crm.pipeline.kanban', version: '1.0.0' },
|
|
69
|
+
},
|
|
70
|
+
],
|
|
71
|
+
|
|
72
|
+
// Target requirements for multi-surface rendering
|
|
73
|
+
presentationsTargets: [
|
|
74
|
+
{ key: 'crm.dashboard', version: '1.0.0', targets: ['react', 'markdown'] },
|
|
75
|
+
{
|
|
76
|
+
key: 'crm.pipeline.kanban',
|
|
77
|
+
version: '1.0.0',
|
|
78
|
+
targets: ['react', 'markdown'],
|
|
79
|
+
},
|
|
80
|
+
{
|
|
81
|
+
key: 'crm.deal.list',
|
|
82
|
+
version: '1.0.0',
|
|
83
|
+
targets: ['react', 'markdown', 'application/json'],
|
|
84
|
+
},
|
|
85
|
+
{
|
|
86
|
+
key: 'crm.pipeline.metrics',
|
|
87
|
+
version: '1.0.0',
|
|
88
|
+
targets: ['react', 'markdown'],
|
|
89
|
+
},
|
|
90
|
+
],
|
|
91
|
+
|
|
92
|
+
// Capability requirements
|
|
93
|
+
capabilities: {
|
|
94
|
+
requires: [
|
|
95
|
+
{ key: 'identity', version: '1.0.0' },
|
|
96
|
+
{ key: 'audit-trail', version: '1.0.0' },
|
|
97
|
+
{ key: 'notifications', version: '1.0.0' },
|
|
98
|
+
],
|
|
99
|
+
},
|
|
100
|
+
});
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { defineEnum } from '@contractspec/lib.schema';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Deal status enum.
|
|
5
|
+
*/
|
|
6
|
+
export const DealStatusEnum = defineEnum('DealStatus', [
|
|
7
|
+
'OPEN',
|
|
8
|
+
'WON',
|
|
9
|
+
'LOST',
|
|
10
|
+
'STALE',
|
|
11
|
+
]);
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Deal status filter enum.
|
|
15
|
+
*/
|
|
16
|
+
export const DealStatusFilterEnum = defineEnum('DealStatusFilter', [
|
|
17
|
+
'OPEN',
|
|
18
|
+
'WON',
|
|
19
|
+
'LOST',
|
|
20
|
+
'all',
|
|
21
|
+
]);
|