@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/ui/index.js
CHANGED
|
@@ -441,19 +441,177 @@ async function mockGetDealsByStageHandler(input) {
|
|
|
441
441
|
async function mockGetPipelineStagesHandler(input) {
|
|
442
442
|
return MOCK_STAGES.filter((s) => s.pipelineId === input.pipelineId);
|
|
443
443
|
}
|
|
444
|
+
// src/ui/CrmDealCard.tsx
|
|
445
|
+
import { jsxDEV } from "react/jsx-dev-runtime";
|
|
446
|
+
"use client";
|
|
447
|
+
function formatCurrency(value, currency) {
|
|
448
|
+
return new Intl.NumberFormat("en-US", {
|
|
449
|
+
style: "currency",
|
|
450
|
+
currency,
|
|
451
|
+
minimumFractionDigits: 0,
|
|
452
|
+
maximumFractionDigits: 0
|
|
453
|
+
}).format(value);
|
|
454
|
+
}
|
|
455
|
+
function CrmDealCard({ deal, onClick }) {
|
|
456
|
+
const daysUntilClose = deal.expectedCloseDate ? Math.ceil((deal.expectedCloseDate.getTime() - Date.now()) / (1000 * 60 * 60 * 24)) : null;
|
|
457
|
+
return /* @__PURE__ */ jsxDEV("div", {
|
|
458
|
+
onClick,
|
|
459
|
+
className: "cursor-pointer rounded-lg border border-border bg-card p-3 shadow-sm transition-shadow hover:shadow-md",
|
|
460
|
+
role: "button",
|
|
461
|
+
tabIndex: 0,
|
|
462
|
+
onKeyDown: (e) => {
|
|
463
|
+
if (e.key === "Enter" || e.key === " ")
|
|
464
|
+
onClick?.();
|
|
465
|
+
},
|
|
466
|
+
children: [
|
|
467
|
+
/* @__PURE__ */ jsxDEV("h4", {
|
|
468
|
+
className: "font-medium leading-snug",
|
|
469
|
+
children: deal.name
|
|
470
|
+
}, undefined, false, undefined, this),
|
|
471
|
+
/* @__PURE__ */ jsxDEV("div", {
|
|
472
|
+
className: "mt-2 font-semibold text-lg text-primary",
|
|
473
|
+
children: formatCurrency(deal.value, deal.currency)
|
|
474
|
+
}, undefined, false, undefined, this),
|
|
475
|
+
/* @__PURE__ */ jsxDEV("div", {
|
|
476
|
+
className: "mt-3 flex items-center justify-between text-muted-foreground text-xs",
|
|
477
|
+
children: [
|
|
478
|
+
daysUntilClose !== null && /* @__PURE__ */ jsxDEV("span", {
|
|
479
|
+
className: daysUntilClose < 0 ? "text-red-500" : daysUntilClose <= 7 ? "text-yellow-600 dark:text-yellow-500" : "",
|
|
480
|
+
children: daysUntilClose < 0 ? `${Math.abs(daysUntilClose)}d overdue` : daysUntilClose === 0 ? "Due today" : `${daysUntilClose}d left`
|
|
481
|
+
}, undefined, false, undefined, this),
|
|
482
|
+
/* @__PURE__ */ jsxDEV("span", {
|
|
483
|
+
className: `rounded px-1.5 py-0.5 font-medium text-xs ${deal.status === "WON" ? "bg-green-100 text-green-700 dark:bg-green-900/30 dark:text-green-400" : deal.status === "LOST" ? "bg-red-100 text-red-700 dark:bg-red-900/30 dark:text-red-400" : "bg-blue-100 text-blue-700 dark:bg-blue-900/30 dark:text-blue-400"}`,
|
|
484
|
+
children: deal.status
|
|
485
|
+
}, undefined, false, undefined, this)
|
|
486
|
+
]
|
|
487
|
+
}, undefined, true, undefined, this)
|
|
488
|
+
]
|
|
489
|
+
}, undefined, true, undefined, this);
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
// src/ui/CrmPipelineBoard.tsx
|
|
493
|
+
import { useState } from "react";
|
|
494
|
+
import { jsxDEV as jsxDEV2 } from "react/jsx-dev-runtime";
|
|
495
|
+
"use client";
|
|
496
|
+
function formatCurrency2(value) {
|
|
497
|
+
if (value >= 1e6)
|
|
498
|
+
return `$${(value / 1e6).toFixed(1)}M`;
|
|
499
|
+
if (value >= 1000)
|
|
500
|
+
return `$${(value / 1000).toFixed(0)}K`;
|
|
501
|
+
return `$${value}`;
|
|
502
|
+
}
|
|
503
|
+
function CrmPipelineBoard({
|
|
504
|
+
dealsByStage,
|
|
505
|
+
stages,
|
|
506
|
+
onDealClick,
|
|
507
|
+
onDealMove
|
|
508
|
+
}) {
|
|
509
|
+
const [quickMoveOpen, setQuickMoveOpen] = useState(null);
|
|
510
|
+
const sortedStages = [...stages].sort((a, b) => a.position - b.position);
|
|
511
|
+
const handleQuickMove = (dealId, toStageId) => {
|
|
512
|
+
onDealMove?.(dealId, toStageId);
|
|
513
|
+
setQuickMoveOpen(null);
|
|
514
|
+
};
|
|
515
|
+
return /* @__PURE__ */ jsxDEV2("div", {
|
|
516
|
+
className: "flex gap-4 overflow-x-auto pb-4",
|
|
517
|
+
children: sortedStages.map((stage) => {
|
|
518
|
+
const deals = dealsByStage[stage.id] ?? [];
|
|
519
|
+
const stageValue = deals.reduce((sum, d) => sum + d.value, 0);
|
|
520
|
+
return /* @__PURE__ */ jsxDEV2("div", {
|
|
521
|
+
className: "flex w-72 flex-shrink-0 flex-col rounded-lg bg-muted/30",
|
|
522
|
+
children: [
|
|
523
|
+
/* @__PURE__ */ jsxDEV2("div", {
|
|
524
|
+
className: "flex items-center justify-between border-border border-b px-3 py-2",
|
|
525
|
+
children: [
|
|
526
|
+
/* @__PURE__ */ jsxDEV2("div", {
|
|
527
|
+
children: [
|
|
528
|
+
/* @__PURE__ */ jsxDEV2("h3", {
|
|
529
|
+
className: "font-medium",
|
|
530
|
+
children: stage.name
|
|
531
|
+
}, undefined, false, undefined, this),
|
|
532
|
+
/* @__PURE__ */ jsxDEV2("p", {
|
|
533
|
+
className: "text-muted-foreground text-xs",
|
|
534
|
+
children: [
|
|
535
|
+
deals.length,
|
|
536
|
+
" deals \xB7 ",
|
|
537
|
+
formatCurrency2(stageValue)
|
|
538
|
+
]
|
|
539
|
+
}, undefined, true, undefined, this)
|
|
540
|
+
]
|
|
541
|
+
}, undefined, true, undefined, this),
|
|
542
|
+
/* @__PURE__ */ jsxDEV2("span", {
|
|
543
|
+
className: "flex h-6 w-6 items-center justify-center rounded-full bg-muted font-medium text-xs",
|
|
544
|
+
children: deals.length
|
|
545
|
+
}, undefined, false, undefined, this)
|
|
546
|
+
]
|
|
547
|
+
}, undefined, true, undefined, this),
|
|
548
|
+
/* @__PURE__ */ jsxDEV2("div", {
|
|
549
|
+
className: "flex flex-1 flex-col gap-2 p-2",
|
|
550
|
+
children: deals.length === 0 ? /* @__PURE__ */ jsxDEV2("div", {
|
|
551
|
+
className: "flex h-24 items-center justify-center rounded-md border-2 border-muted-foreground/20 border-dashed text-muted-foreground text-xs",
|
|
552
|
+
children: "No deals"
|
|
553
|
+
}, undefined, false, undefined, this) : deals.map((deal) => /* @__PURE__ */ jsxDEV2("div", {
|
|
554
|
+
className: "group relative",
|
|
555
|
+
children: [
|
|
556
|
+
/* @__PURE__ */ jsxDEV2(CrmDealCard, {
|
|
557
|
+
deal,
|
|
558
|
+
onClick: () => onDealClick?.(deal.id)
|
|
559
|
+
}, undefined, false, undefined, this),
|
|
560
|
+
deal.status === "OPEN" && onDealMove && /* @__PURE__ */ jsxDEV2("div", {
|
|
561
|
+
className: "absolute top-1 right-1 opacity-0 transition-opacity group-hover:opacity-100",
|
|
562
|
+
children: [
|
|
563
|
+
/* @__PURE__ */ jsxDEV2("button", {
|
|
564
|
+
type: "button",
|
|
565
|
+
onClick: (e) => {
|
|
566
|
+
e.stopPropagation();
|
|
567
|
+
setQuickMoveOpen(quickMoveOpen === deal.id ? null : deal.id);
|
|
568
|
+
},
|
|
569
|
+
className: "flex h-6 w-6 items-center justify-center rounded border border-border bg-background text-xs shadow-sm hover:bg-muted",
|
|
570
|
+
title: "Quick move",
|
|
571
|
+
children: "\u27A1\uFE0F"
|
|
572
|
+
}, undefined, false, undefined, this),
|
|
573
|
+
quickMoveOpen === deal.id && /* @__PURE__ */ jsxDEV2("div", {
|
|
574
|
+
className: "absolute top-7 right-0 z-20 min-w-[140px] rounded-lg border border-border bg-card py-1 shadow-lg",
|
|
575
|
+
children: [
|
|
576
|
+
/* @__PURE__ */ jsxDEV2("p", {
|
|
577
|
+
className: "px-3 py-1 font-medium text-muted-foreground text-xs",
|
|
578
|
+
children: "Move to:"
|
|
579
|
+
}, undefined, false, undefined, this),
|
|
580
|
+
sortedStages.filter((s) => s.id !== deal.stageId).map((s) => /* @__PURE__ */ jsxDEV2("button", {
|
|
581
|
+
type: "button",
|
|
582
|
+
onClick: (e) => {
|
|
583
|
+
e.stopPropagation();
|
|
584
|
+
handleQuickMove(deal.id, s.id);
|
|
585
|
+
},
|
|
586
|
+
className: "w-full px-3 py-1.5 text-left text-sm hover:bg-muted",
|
|
587
|
+
children: s.name
|
|
588
|
+
}, s.id, false, undefined, this))
|
|
589
|
+
]
|
|
590
|
+
}, undefined, true, undefined, this)
|
|
591
|
+
]
|
|
592
|
+
}, undefined, true, undefined, this)
|
|
593
|
+
]
|
|
594
|
+
}, deal.id, true, undefined, this))
|
|
595
|
+
}, undefined, false, undefined, this)
|
|
596
|
+
]
|
|
597
|
+
}, stage.id, true, undefined, this);
|
|
598
|
+
})
|
|
599
|
+
}, undefined, false, undefined, this);
|
|
600
|
+
}
|
|
601
|
+
|
|
444
602
|
// src/ui/hooks/useDealList.ts
|
|
445
|
-
import { useCallback, useEffect, useMemo, useState } from "react";
|
|
446
603
|
import { useTemplateRuntime } from "@contractspec/lib.example-shared-ui";
|
|
604
|
+
import { useCallback, useEffect, useMemo, useState as useState2 } from "react";
|
|
447
605
|
"use client";
|
|
448
606
|
function useDealList(options = {}) {
|
|
449
607
|
const { handlers, projectId } = useTemplateRuntime();
|
|
450
608
|
const { crm: crm2 } = handlers;
|
|
451
|
-
const [data, setData] =
|
|
452
|
-
const [dealsByStage, setDealsByStage] =
|
|
453
|
-
const [stages, setStages] =
|
|
454
|
-
const [loading, setLoading] =
|
|
455
|
-
const [error, setError] =
|
|
456
|
-
const [page, setPage] =
|
|
609
|
+
const [data, setData] = useState2(null);
|
|
610
|
+
const [dealsByStage, setDealsByStage] = useState2({});
|
|
611
|
+
const [stages, setStages] = useState2([]);
|
|
612
|
+
const [loading, setLoading] = useState2(true);
|
|
613
|
+
const [error, setError] = useState2(null);
|
|
614
|
+
const [page, setPage] = useState2(1);
|
|
457
615
|
const pipelineId = options.pipelineId ?? "pipeline-1";
|
|
458
616
|
const fetchData = useCallback(async () => {
|
|
459
617
|
setLoading(true);
|
|
@@ -524,27 +682,27 @@ function useDealList(options = {}) {
|
|
|
524
682
|
}
|
|
525
683
|
|
|
526
684
|
// src/ui/hooks/useDealMutations.ts
|
|
527
|
-
import { useCallback as useCallback2, useState as useState2 } from "react";
|
|
528
685
|
import { useTemplateRuntime as useTemplateRuntime2 } from "@contractspec/lib.example-shared-ui";
|
|
686
|
+
import { useCallback as useCallback2, useState as useState3 } from "react";
|
|
529
687
|
function useDealMutations(options = {}) {
|
|
530
688
|
const { handlers, projectId } = useTemplateRuntime2();
|
|
531
689
|
const { crm: crm2 } = handlers;
|
|
532
|
-
const [createState, setCreateState] =
|
|
690
|
+
const [createState, setCreateState] = useState3({
|
|
533
691
|
loading: false,
|
|
534
692
|
error: null,
|
|
535
693
|
data: null
|
|
536
694
|
});
|
|
537
|
-
const [moveState, setMoveState] =
|
|
695
|
+
const [moveState, setMoveState] = useState3({
|
|
538
696
|
loading: false,
|
|
539
697
|
error: null,
|
|
540
698
|
data: null
|
|
541
699
|
});
|
|
542
|
-
const [winState, setWinState] =
|
|
700
|
+
const [winState, setWinState] = useState3({
|
|
543
701
|
loading: false,
|
|
544
702
|
error: null,
|
|
545
703
|
data: null
|
|
546
704
|
});
|
|
547
|
-
const [loseState, setLoseState] =
|
|
705
|
+
const [loseState, setLoseState] = useState3({
|
|
548
706
|
loading: false,
|
|
549
707
|
error: null,
|
|
550
708
|
data: null
|
|
@@ -621,167 +779,9 @@ function useDealMutations(options = {}) {
|
|
|
621
779
|
};
|
|
622
780
|
}
|
|
623
781
|
|
|
624
|
-
// src/ui/CrmDealCard.tsx
|
|
625
|
-
import { jsxDEV } from "react/jsx-dev-runtime";
|
|
626
|
-
"use client";
|
|
627
|
-
function formatCurrency(value, currency) {
|
|
628
|
-
return new Intl.NumberFormat("en-US", {
|
|
629
|
-
style: "currency",
|
|
630
|
-
currency,
|
|
631
|
-
minimumFractionDigits: 0,
|
|
632
|
-
maximumFractionDigits: 0
|
|
633
|
-
}).format(value);
|
|
634
|
-
}
|
|
635
|
-
function CrmDealCard({ deal, onClick }) {
|
|
636
|
-
const daysUntilClose = deal.expectedCloseDate ? Math.ceil((deal.expectedCloseDate.getTime() - Date.now()) / (1000 * 60 * 60 * 24)) : null;
|
|
637
|
-
return /* @__PURE__ */ jsxDEV("div", {
|
|
638
|
-
onClick,
|
|
639
|
-
className: "border-border bg-card cursor-pointer rounded-lg border p-3 shadow-sm transition-shadow hover:shadow-md",
|
|
640
|
-
role: "button",
|
|
641
|
-
tabIndex: 0,
|
|
642
|
-
onKeyDown: (e) => {
|
|
643
|
-
if (e.key === "Enter" || e.key === " ")
|
|
644
|
-
onClick?.();
|
|
645
|
-
},
|
|
646
|
-
children: [
|
|
647
|
-
/* @__PURE__ */ jsxDEV("h4", {
|
|
648
|
-
className: "leading-snug font-medium",
|
|
649
|
-
children: deal.name
|
|
650
|
-
}, undefined, false, undefined, this),
|
|
651
|
-
/* @__PURE__ */ jsxDEV("div", {
|
|
652
|
-
className: "text-primary mt-2 text-lg font-semibold",
|
|
653
|
-
children: formatCurrency(deal.value, deal.currency)
|
|
654
|
-
}, undefined, false, undefined, this),
|
|
655
|
-
/* @__PURE__ */ jsxDEV("div", {
|
|
656
|
-
className: "text-muted-foreground mt-3 flex items-center justify-between text-xs",
|
|
657
|
-
children: [
|
|
658
|
-
daysUntilClose !== null && /* @__PURE__ */ jsxDEV("span", {
|
|
659
|
-
className: daysUntilClose < 0 ? "text-red-500" : daysUntilClose <= 7 ? "text-yellow-600 dark:text-yellow-500" : "",
|
|
660
|
-
children: daysUntilClose < 0 ? `${Math.abs(daysUntilClose)}d overdue` : daysUntilClose === 0 ? "Due today" : `${daysUntilClose}d left`
|
|
661
|
-
}, undefined, false, undefined, this),
|
|
662
|
-
/* @__PURE__ */ jsxDEV("span", {
|
|
663
|
-
className: `rounded px-1.5 py-0.5 text-xs font-medium ${deal.status === "WON" ? "bg-green-100 text-green-700 dark:bg-green-900/30 dark:text-green-400" : deal.status === "LOST" ? "bg-red-100 text-red-700 dark:bg-red-900/30 dark:text-red-400" : "bg-blue-100 text-blue-700 dark:bg-blue-900/30 dark:text-blue-400"}`,
|
|
664
|
-
children: deal.status
|
|
665
|
-
}, undefined, false, undefined, this)
|
|
666
|
-
]
|
|
667
|
-
}, undefined, true, undefined, this)
|
|
668
|
-
]
|
|
669
|
-
}, undefined, true, undefined, this);
|
|
670
|
-
}
|
|
671
|
-
|
|
672
|
-
// src/ui/CrmPipelineBoard.tsx
|
|
673
|
-
import { useState as useState3 } from "react";
|
|
674
|
-
import { jsxDEV as jsxDEV2 } from "react/jsx-dev-runtime";
|
|
675
|
-
"use client";
|
|
676
|
-
function formatCurrency2(value) {
|
|
677
|
-
if (value >= 1e6)
|
|
678
|
-
return `$${(value / 1e6).toFixed(1)}M`;
|
|
679
|
-
if (value >= 1000)
|
|
680
|
-
return `$${(value / 1000).toFixed(0)}K`;
|
|
681
|
-
return `$${value}`;
|
|
682
|
-
}
|
|
683
|
-
function CrmPipelineBoard({
|
|
684
|
-
dealsByStage,
|
|
685
|
-
stages,
|
|
686
|
-
onDealClick,
|
|
687
|
-
onDealMove
|
|
688
|
-
}) {
|
|
689
|
-
const [quickMoveOpen, setQuickMoveOpen] = useState3(null);
|
|
690
|
-
const sortedStages = [...stages].sort((a, b) => a.position - b.position);
|
|
691
|
-
const handleQuickMove = (dealId, toStageId) => {
|
|
692
|
-
onDealMove?.(dealId, toStageId);
|
|
693
|
-
setQuickMoveOpen(null);
|
|
694
|
-
};
|
|
695
|
-
return /* @__PURE__ */ jsxDEV2("div", {
|
|
696
|
-
className: "flex gap-4 overflow-x-auto pb-4",
|
|
697
|
-
children: sortedStages.map((stage) => {
|
|
698
|
-
const deals = dealsByStage[stage.id] ?? [];
|
|
699
|
-
const stageValue = deals.reduce((sum, d) => sum + d.value, 0);
|
|
700
|
-
return /* @__PURE__ */ jsxDEV2("div", {
|
|
701
|
-
className: "bg-muted/30 flex w-72 flex-shrink-0 flex-col rounded-lg",
|
|
702
|
-
children: [
|
|
703
|
-
/* @__PURE__ */ jsxDEV2("div", {
|
|
704
|
-
className: "border-border flex items-center justify-between border-b px-3 py-2",
|
|
705
|
-
children: [
|
|
706
|
-
/* @__PURE__ */ jsxDEV2("div", {
|
|
707
|
-
children: [
|
|
708
|
-
/* @__PURE__ */ jsxDEV2("h3", {
|
|
709
|
-
className: "font-medium",
|
|
710
|
-
children: stage.name
|
|
711
|
-
}, undefined, false, undefined, this),
|
|
712
|
-
/* @__PURE__ */ jsxDEV2("p", {
|
|
713
|
-
className: "text-muted-foreground text-xs",
|
|
714
|
-
children: [
|
|
715
|
-
deals.length,
|
|
716
|
-
" deals \xB7 ",
|
|
717
|
-
formatCurrency2(stageValue)
|
|
718
|
-
]
|
|
719
|
-
}, undefined, true, undefined, this)
|
|
720
|
-
]
|
|
721
|
-
}, undefined, true, undefined, this),
|
|
722
|
-
/* @__PURE__ */ jsxDEV2("span", {
|
|
723
|
-
className: "bg-muted flex h-6 w-6 items-center justify-center rounded-full text-xs font-medium",
|
|
724
|
-
children: deals.length
|
|
725
|
-
}, undefined, false, undefined, this)
|
|
726
|
-
]
|
|
727
|
-
}, undefined, true, undefined, this),
|
|
728
|
-
/* @__PURE__ */ jsxDEV2("div", {
|
|
729
|
-
className: "flex flex-1 flex-col gap-2 p-2",
|
|
730
|
-
children: deals.length === 0 ? /* @__PURE__ */ jsxDEV2("div", {
|
|
731
|
-
className: "border-muted-foreground/20 text-muted-foreground flex h-24 items-center justify-center rounded-md border-2 border-dashed text-xs",
|
|
732
|
-
children: "No deals"
|
|
733
|
-
}, undefined, false, undefined, this) : deals.map((deal) => /* @__PURE__ */ jsxDEV2("div", {
|
|
734
|
-
className: "group relative",
|
|
735
|
-
children: [
|
|
736
|
-
/* @__PURE__ */ jsxDEV2(CrmDealCard, {
|
|
737
|
-
deal,
|
|
738
|
-
onClick: () => onDealClick?.(deal.id)
|
|
739
|
-
}, undefined, false, undefined, this),
|
|
740
|
-
deal.status === "OPEN" && onDealMove && /* @__PURE__ */ jsxDEV2("div", {
|
|
741
|
-
className: "absolute top-1 right-1 opacity-0 transition-opacity group-hover:opacity-100",
|
|
742
|
-
children: [
|
|
743
|
-
/* @__PURE__ */ jsxDEV2("button", {
|
|
744
|
-
type: "button",
|
|
745
|
-
onClick: (e) => {
|
|
746
|
-
e.stopPropagation();
|
|
747
|
-
setQuickMoveOpen(quickMoveOpen === deal.id ? null : deal.id);
|
|
748
|
-
},
|
|
749
|
-
className: "bg-background border-border hover:bg-muted flex h-6 w-6 items-center justify-center rounded border text-xs shadow-sm",
|
|
750
|
-
title: "Quick move",
|
|
751
|
-
children: "\u27A1\uFE0F"
|
|
752
|
-
}, undefined, false, undefined, this),
|
|
753
|
-
quickMoveOpen === deal.id && /* @__PURE__ */ jsxDEV2("div", {
|
|
754
|
-
className: "bg-card border-border absolute top-7 right-0 z-20 min-w-[140px] rounded-lg border py-1 shadow-lg",
|
|
755
|
-
children: [
|
|
756
|
-
/* @__PURE__ */ jsxDEV2("p", {
|
|
757
|
-
className: "text-muted-foreground px-3 py-1 text-xs font-medium",
|
|
758
|
-
children: "Move to:"
|
|
759
|
-
}, undefined, false, undefined, this),
|
|
760
|
-
sortedStages.filter((s) => s.id !== deal.stageId).map((s) => /* @__PURE__ */ jsxDEV2("button", {
|
|
761
|
-
type: "button",
|
|
762
|
-
onClick: (e) => {
|
|
763
|
-
e.stopPropagation();
|
|
764
|
-
handleQuickMove(deal.id, s.id);
|
|
765
|
-
},
|
|
766
|
-
className: "hover:bg-muted w-full px-3 py-1.5 text-left text-sm",
|
|
767
|
-
children: s.name
|
|
768
|
-
}, s.id, false, undefined, this))
|
|
769
|
-
]
|
|
770
|
-
}, undefined, true, undefined, this)
|
|
771
|
-
]
|
|
772
|
-
}, undefined, true, undefined, this)
|
|
773
|
-
]
|
|
774
|
-
}, deal.id, true, undefined, this))
|
|
775
|
-
}, undefined, false, undefined, this)
|
|
776
|
-
]
|
|
777
|
-
}, stage.id, true, undefined, this);
|
|
778
|
-
})
|
|
779
|
-
}, undefined, false, undefined, this);
|
|
780
|
-
}
|
|
781
|
-
|
|
782
782
|
// src/ui/modals/CreateDealModal.tsx
|
|
783
|
-
import { useState as useState4 } from "react";
|
|
784
783
|
import { Button, Input } from "@contractspec/lib.design-system";
|
|
784
|
+
import { useState as useState4 } from "react";
|
|
785
785
|
import { jsxDEV as jsxDEV3 } from "react/jsx-dev-runtime";
|
|
786
786
|
"use client";
|
|
787
787
|
var CURRENCIES = ["USD", "EUR", "GBP", "CAD"];
|
|
@@ -840,7 +840,7 @@ function CreateDealModal({
|
|
|
840
840
|
className: "fixed inset-0 z-50 flex items-center justify-center",
|
|
841
841
|
children: [
|
|
842
842
|
/* @__PURE__ */ jsxDEV3("div", {
|
|
843
|
-
className: "bg-background/80
|
|
843
|
+
className: "absolute inset-0 bg-background/80 backdrop-blur-sm",
|
|
844
844
|
onClick: onClose,
|
|
845
845
|
role: "button",
|
|
846
846
|
tabIndex: 0,
|
|
@@ -851,10 +851,10 @@ function CreateDealModal({
|
|
|
851
851
|
"aria-label": "Close modal"
|
|
852
852
|
}, undefined, false, undefined, this),
|
|
853
853
|
/* @__PURE__ */ jsxDEV3("div", {
|
|
854
|
-
className: "
|
|
854
|
+
className: "relative z-10 w-full max-w-md rounded-xl border border-border bg-card p-6 shadow-xl",
|
|
855
855
|
children: [
|
|
856
856
|
/* @__PURE__ */ jsxDEV3("h2", {
|
|
857
|
-
className: "mb-4 text-xl
|
|
857
|
+
className: "mb-4 font-semibold text-xl",
|
|
858
858
|
children: "Create New Deal"
|
|
859
859
|
}, undefined, false, undefined, this),
|
|
860
860
|
/* @__PURE__ */ jsxDEV3("form", {
|
|
@@ -865,7 +865,7 @@ function CreateDealModal({
|
|
|
865
865
|
children: [
|
|
866
866
|
/* @__PURE__ */ jsxDEV3("label", {
|
|
867
867
|
htmlFor: "deal-name",
|
|
868
|
-
className: "
|
|
868
|
+
className: "mb-1 block font-medium text-muted-foreground text-sm",
|
|
869
869
|
children: "Deal Name *"
|
|
870
870
|
}, undefined, false, undefined, this),
|
|
871
871
|
/* @__PURE__ */ jsxDEV3(Input, {
|
|
@@ -885,7 +885,7 @@ function CreateDealModal({
|
|
|
885
885
|
children: [
|
|
886
886
|
/* @__PURE__ */ jsxDEV3("label", {
|
|
887
887
|
htmlFor: "deal-value",
|
|
888
|
-
className: "
|
|
888
|
+
className: "mb-1 block font-medium text-muted-foreground text-sm",
|
|
889
889
|
children: "Value *"
|
|
890
890
|
}, undefined, false, undefined, this),
|
|
891
891
|
/* @__PURE__ */ jsxDEV3(Input, {
|
|
@@ -905,7 +905,7 @@ function CreateDealModal({
|
|
|
905
905
|
children: [
|
|
906
906
|
/* @__PURE__ */ jsxDEV3("label", {
|
|
907
907
|
htmlFor: "deal-currency",
|
|
908
|
-
className: "
|
|
908
|
+
className: "mb-1 block font-medium text-muted-foreground text-sm",
|
|
909
909
|
children: "Currency"
|
|
910
910
|
}, undefined, false, undefined, this),
|
|
911
911
|
/* @__PURE__ */ jsxDEV3("select", {
|
|
@@ -913,7 +913,7 @@ function CreateDealModal({
|
|
|
913
913
|
value: currency,
|
|
914
914
|
onChange: (e) => setCurrency(e.target.value),
|
|
915
915
|
disabled: isLoading,
|
|
916
|
-
className: "
|
|
916
|
+
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",
|
|
917
917
|
children: CURRENCIES.map((c) => /* @__PURE__ */ jsxDEV3("option", {
|
|
918
918
|
value: c,
|
|
919
919
|
children: c
|
|
@@ -927,7 +927,7 @@ function CreateDealModal({
|
|
|
927
927
|
children: [
|
|
928
928
|
/* @__PURE__ */ jsxDEV3("label", {
|
|
929
929
|
htmlFor: "deal-stage",
|
|
930
|
-
className: "
|
|
930
|
+
className: "mb-1 block font-medium text-muted-foreground text-sm",
|
|
931
931
|
children: "Pipeline Stage *"
|
|
932
932
|
}, undefined, false, undefined, this),
|
|
933
933
|
/* @__PURE__ */ jsxDEV3("select", {
|
|
@@ -935,7 +935,7 @@ function CreateDealModal({
|
|
|
935
935
|
value: stageId,
|
|
936
936
|
onChange: (e) => setStageId(e.target.value),
|
|
937
937
|
disabled: isLoading,
|
|
938
|
-
className: "
|
|
938
|
+
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",
|
|
939
939
|
children: stages.map((stage) => /* @__PURE__ */ jsxDEV3("option", {
|
|
940
940
|
value: stage.id,
|
|
941
941
|
children: stage.name
|
|
@@ -947,7 +947,7 @@ function CreateDealModal({
|
|
|
947
947
|
children: [
|
|
948
948
|
/* @__PURE__ */ jsxDEV3("label", {
|
|
949
949
|
htmlFor: "deal-close-date",
|
|
950
|
-
className: "
|
|
950
|
+
className: "mb-1 block font-medium text-muted-foreground text-sm",
|
|
951
951
|
children: "Expected Close Date"
|
|
952
952
|
}, undefined, false, undefined, this),
|
|
953
953
|
/* @__PURE__ */ jsxDEV3(Input, {
|
|
@@ -960,7 +960,7 @@ function CreateDealModal({
|
|
|
960
960
|
]
|
|
961
961
|
}, undefined, true, undefined, this),
|
|
962
962
|
error && /* @__PURE__ */ jsxDEV3("div", {
|
|
963
|
-
className: "bg-destructive/10
|
|
963
|
+
className: "rounded-md bg-destructive/10 p-3 text-destructive text-sm",
|
|
964
964
|
children: error
|
|
965
965
|
}, undefined, false, undefined, this),
|
|
966
966
|
/* @__PURE__ */ jsxDEV3("div", {
|
|
@@ -989,8 +989,8 @@ function CreateDealModal({
|
|
|
989
989
|
}
|
|
990
990
|
|
|
991
991
|
// src/ui/modals/DealActionsModal.tsx
|
|
992
|
-
import { useState as useState5 } from "react";
|
|
993
992
|
import { Button as Button2 } from "@contractspec/lib.design-system";
|
|
993
|
+
import { useState as useState5 } from "react";
|
|
994
994
|
import { jsxDEV as jsxDEV4, Fragment } from "react/jsx-dev-runtime";
|
|
995
995
|
"use client";
|
|
996
996
|
function formatCurrency3(value, currency) {
|
|
@@ -1091,7 +1091,7 @@ function DealActionsModal({
|
|
|
1091
1091
|
className: "fixed inset-0 z-50 flex items-center justify-center",
|
|
1092
1092
|
children: [
|
|
1093
1093
|
/* @__PURE__ */ jsxDEV4("div", {
|
|
1094
|
-
className: "bg-background/80
|
|
1094
|
+
className: "absolute inset-0 bg-background/80 backdrop-blur-sm",
|
|
1095
1095
|
onClick: handleClose,
|
|
1096
1096
|
role: "button",
|
|
1097
1097
|
tabIndex: 0,
|
|
@@ -1102,21 +1102,21 @@ function DealActionsModal({
|
|
|
1102
1102
|
"aria-label": "Close modal"
|
|
1103
1103
|
}, undefined, false, undefined, this),
|
|
1104
1104
|
/* @__PURE__ */ jsxDEV4("div", {
|
|
1105
|
-
className: "
|
|
1105
|
+
className: "relative z-10 w-full max-w-md rounded-xl border border-border bg-card p-6 shadow-xl",
|
|
1106
1106
|
children: [
|
|
1107
1107
|
/* @__PURE__ */ jsxDEV4("div", {
|
|
1108
|
-
className: "
|
|
1108
|
+
className: "mb-4 border-border border-b pb-4",
|
|
1109
1109
|
children: [
|
|
1110
1110
|
/* @__PURE__ */ jsxDEV4("h2", {
|
|
1111
|
-
className: "text-xl
|
|
1111
|
+
className: "font-semibold text-xl",
|
|
1112
1112
|
children: deal.name
|
|
1113
1113
|
}, undefined, false, undefined, this),
|
|
1114
1114
|
/* @__PURE__ */ jsxDEV4("p", {
|
|
1115
|
-
className: "
|
|
1115
|
+
className: "font-medium text-lg text-primary",
|
|
1116
1116
|
children: formatCurrency3(deal.value, deal.currency)
|
|
1117
1117
|
}, undefined, false, undefined, this),
|
|
1118
1118
|
/* @__PURE__ */ jsxDEV4("span", {
|
|
1119
|
-
className: `mt-2 inline-flex rounded-full px-2 py-0.5 text-xs
|
|
1119
|
+
className: `mt-2 inline-flex rounded-full px-2 py-0.5 font-medium text-xs ${deal.status === "WON" ? "bg-green-100 text-green-700 dark:bg-green-900/30 dark:text-green-400" : deal.status === "LOST" ? "bg-red-100 text-red-700 dark:bg-red-900/30 dark:text-red-400" : "bg-blue-100 text-blue-700 dark:bg-blue-900/30 dark:text-blue-400"}`,
|
|
1120
1120
|
children: deal.status
|
|
1121
1121
|
}, undefined, false, undefined, this)
|
|
1122
1122
|
]
|
|
@@ -1168,7 +1168,7 @@ function DealActionsModal({
|
|
|
1168
1168
|
]
|
|
1169
1169
|
}, undefined, true, undefined, this),
|
|
1170
1170
|
deal.status !== "OPEN" && /* @__PURE__ */ jsxDEV4("p", {
|
|
1171
|
-
className: "
|
|
1171
|
+
className: "py-4 text-center text-muted-foreground",
|
|
1172
1172
|
children: [
|
|
1173
1173
|
"This deal is already ",
|
|
1174
1174
|
deal.status.toLowerCase(),
|
|
@@ -1193,14 +1193,14 @@ function DealActionsModal({
|
|
|
1193
1193
|
children: [
|
|
1194
1194
|
/* @__PURE__ */ jsxDEV4("label", {
|
|
1195
1195
|
htmlFor: "won-source",
|
|
1196
|
-
className: "
|
|
1196
|
+
className: "mb-1 block font-medium text-muted-foreground text-sm",
|
|
1197
1197
|
children: "How did you win this deal?"
|
|
1198
1198
|
}, undefined, false, undefined, this),
|
|
1199
1199
|
/* @__PURE__ */ jsxDEV4("select", {
|
|
1200
1200
|
id: "won-source",
|
|
1201
1201
|
value: wonSource,
|
|
1202
1202
|
onChange: (e) => setWonSource(e.target.value),
|
|
1203
|
-
className: "
|
|
1203
|
+
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",
|
|
1204
1204
|
children: [
|
|
1205
1205
|
/* @__PURE__ */ jsxDEV4("option", {
|
|
1206
1206
|
value: "",
|
|
@@ -1234,7 +1234,7 @@ function DealActionsModal({
|
|
|
1234
1234
|
children: [
|
|
1235
1235
|
/* @__PURE__ */ jsxDEV4("label", {
|
|
1236
1236
|
htmlFor: "win-notes",
|
|
1237
|
-
className: "
|
|
1237
|
+
className: "mb-1 block font-medium text-muted-foreground text-sm",
|
|
1238
1238
|
children: "Notes (optional)"
|
|
1239
1239
|
}, undefined, false, undefined, this),
|
|
1240
1240
|
/* @__PURE__ */ jsxDEV4("textarea", {
|
|
@@ -1243,12 +1243,12 @@ function DealActionsModal({
|
|
|
1243
1243
|
onChange: (e) => setNotes(e.target.value),
|
|
1244
1244
|
placeholder: "Any additional notes about the win...",
|
|
1245
1245
|
rows: 3,
|
|
1246
|
-
className: "
|
|
1246
|
+
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"
|
|
1247
1247
|
}, undefined, false, undefined, this)
|
|
1248
1248
|
]
|
|
1249
1249
|
}, undefined, true, undefined, this),
|
|
1250
1250
|
error && /* @__PURE__ */ jsxDEV4("div", {
|
|
1251
|
-
className: "bg-destructive/10
|
|
1251
|
+
className: "rounded-md bg-destructive/10 p-3 text-destructive text-sm",
|
|
1252
1252
|
children: error
|
|
1253
1253
|
}, undefined, false, undefined, this),
|
|
1254
1254
|
/* @__PURE__ */ jsxDEV4("div", {
|
|
@@ -1276,14 +1276,14 @@ function DealActionsModal({
|
|
|
1276
1276
|
children: [
|
|
1277
1277
|
/* @__PURE__ */ jsxDEV4("label", {
|
|
1278
1278
|
htmlFor: "lost-reason",
|
|
1279
|
-
className: "
|
|
1279
|
+
className: "mb-1 block font-medium text-muted-foreground text-sm",
|
|
1280
1280
|
children: "Why was this deal lost? *"
|
|
1281
1281
|
}, undefined, false, undefined, this),
|
|
1282
1282
|
/* @__PURE__ */ jsxDEV4("select", {
|
|
1283
1283
|
id: "lost-reason",
|
|
1284
1284
|
value: lostReason,
|
|
1285
1285
|
onChange: (e) => setLostReason(e.target.value),
|
|
1286
|
-
className: "
|
|
1286
|
+
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",
|
|
1287
1287
|
children: [
|
|
1288
1288
|
/* @__PURE__ */ jsxDEV4("option", {
|
|
1289
1289
|
value: "",
|
|
@@ -1325,7 +1325,7 @@ function DealActionsModal({
|
|
|
1325
1325
|
children: [
|
|
1326
1326
|
/* @__PURE__ */ jsxDEV4("label", {
|
|
1327
1327
|
htmlFor: "lose-notes",
|
|
1328
|
-
className: "
|
|
1328
|
+
className: "mb-1 block font-medium text-muted-foreground text-sm",
|
|
1329
1329
|
children: "Notes (optional)"
|
|
1330
1330
|
}, undefined, false, undefined, this),
|
|
1331
1331
|
/* @__PURE__ */ jsxDEV4("textarea", {
|
|
@@ -1334,12 +1334,12 @@ function DealActionsModal({
|
|
|
1334
1334
|
onChange: (e) => setNotes(e.target.value),
|
|
1335
1335
|
placeholder: "Any additional details...",
|
|
1336
1336
|
rows: 3,
|
|
1337
|
-
className: "
|
|
1337
|
+
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"
|
|
1338
1338
|
}, undefined, false, undefined, this)
|
|
1339
1339
|
]
|
|
1340
1340
|
}, undefined, true, undefined, this),
|
|
1341
1341
|
error && /* @__PURE__ */ jsxDEV4("div", {
|
|
1342
|
-
className: "bg-destructive/10
|
|
1342
|
+
className: "rounded-md bg-destructive/10 p-3 text-destructive text-sm",
|
|
1343
1343
|
children: error
|
|
1344
1344
|
}, undefined, false, undefined, this),
|
|
1345
1345
|
/* @__PURE__ */ jsxDEV4("div", {
|
|
@@ -1368,14 +1368,14 @@ function DealActionsModal({
|
|
|
1368
1368
|
children: [
|
|
1369
1369
|
/* @__PURE__ */ jsxDEV4("label", {
|
|
1370
1370
|
htmlFor: "move-stage",
|
|
1371
|
-
className: "
|
|
1371
|
+
className: "mb-1 block font-medium text-muted-foreground text-sm",
|
|
1372
1372
|
children: "Move to Stage"
|
|
1373
1373
|
}, undefined, false, undefined, this),
|
|
1374
1374
|
/* @__PURE__ */ jsxDEV4("select", {
|
|
1375
1375
|
id: "move-stage",
|
|
1376
1376
|
value: selectedStageId,
|
|
1377
1377
|
onChange: (e) => setSelectedStageId(e.target.value),
|
|
1378
|
-
className: "
|
|
1378
|
+
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",
|
|
1379
1379
|
children: stages.map((stage) => /* @__PURE__ */ jsxDEV4("option", {
|
|
1380
1380
|
value: stage.id,
|
|
1381
1381
|
children: [
|
|
@@ -1387,7 +1387,7 @@ function DealActionsModal({
|
|
|
1387
1387
|
]
|
|
1388
1388
|
}, undefined, true, undefined, this),
|
|
1389
1389
|
error && /* @__PURE__ */ jsxDEV4("div", {
|
|
1390
|
-
className: "bg-destructive/10
|
|
1390
|
+
className: "rounded-md bg-destructive/10 p-3 text-destructive text-sm",
|
|
1391
1391
|
children: error
|
|
1392
1392
|
}, undefined, false, undefined, this),
|
|
1393
1393
|
/* @__PURE__ */ jsxDEV4("div", {
|
|
@@ -1415,7 +1415,6 @@ function DealActionsModal({
|
|
|
1415
1415
|
}
|
|
1416
1416
|
|
|
1417
1417
|
// src/ui/CrmDashboard.tsx
|
|
1418
|
-
import { useCallback as useCallback3, useState as useState6 } from "react";
|
|
1419
1418
|
import {
|
|
1420
1419
|
Button as Button3,
|
|
1421
1420
|
ErrorState,
|
|
@@ -1429,6 +1428,7 @@ import {
|
|
|
1429
1428
|
TabsList,
|
|
1430
1429
|
TabsTrigger
|
|
1431
1430
|
} from "@contractspec/lib.ui-kit-web/ui/tabs";
|
|
1431
|
+
import { useCallback as useCallback3, useState as useState6 } from "react";
|
|
1432
1432
|
import { jsxDEV as jsxDEV5 } from "react/jsx-dev-runtime";
|
|
1433
1433
|
"use client";
|
|
1434
1434
|
function formatCurrency4(value, currency = "USD") {
|
|
@@ -1479,7 +1479,7 @@ function CrmDashboard() {
|
|
|
1479
1479
|
className: "flex items-center justify-between",
|
|
1480
1480
|
children: [
|
|
1481
1481
|
/* @__PURE__ */ jsxDEV5("h2", {
|
|
1482
|
-
className: "text-2xl
|
|
1482
|
+
className: "font-bold text-2xl",
|
|
1483
1483
|
children: "CRM Pipeline"
|
|
1484
1484
|
}, undefined, false, undefined, this),
|
|
1485
1485
|
/* @__PURE__ */ jsxDEV5(Button3, {
|
|
@@ -1618,44 +1618,44 @@ function CrmDashboard() {
|
|
|
1618
1618
|
function DealListTab({ data, onDealClick }) {
|
|
1619
1619
|
if (!data?.deals.length) {
|
|
1620
1620
|
return /* @__PURE__ */ jsxDEV5("div", {
|
|
1621
|
-
className: "
|
|
1621
|
+
className: "flex h-64 items-center justify-center text-muted-foreground",
|
|
1622
1622
|
children: "No deals found"
|
|
1623
1623
|
}, undefined, false, undefined, this);
|
|
1624
1624
|
}
|
|
1625
1625
|
return /* @__PURE__ */ jsxDEV5("div", {
|
|
1626
|
-
className: "
|
|
1626
|
+
className: "rounded-lg border border-border",
|
|
1627
1627
|
children: /* @__PURE__ */ jsxDEV5("table", {
|
|
1628
1628
|
className: "w-full",
|
|
1629
1629
|
children: [
|
|
1630
1630
|
/* @__PURE__ */ jsxDEV5("thead", {
|
|
1631
|
-
className: "border-border bg-muted/30
|
|
1631
|
+
className: "border-border border-b bg-muted/30",
|
|
1632
1632
|
children: /* @__PURE__ */ jsxDEV5("tr", {
|
|
1633
1633
|
children: [
|
|
1634
1634
|
/* @__PURE__ */ jsxDEV5("th", {
|
|
1635
|
-
className: "px-4 py-3 text-left text-sm
|
|
1635
|
+
className: "px-4 py-3 text-left font-medium text-sm",
|
|
1636
1636
|
children: "Deal"
|
|
1637
1637
|
}, undefined, false, undefined, this),
|
|
1638
1638
|
/* @__PURE__ */ jsxDEV5("th", {
|
|
1639
|
-
className: "px-4 py-3 text-left text-sm
|
|
1639
|
+
className: "px-4 py-3 text-left font-medium text-sm",
|
|
1640
1640
|
children: "Value"
|
|
1641
1641
|
}, undefined, false, undefined, this),
|
|
1642
1642
|
/* @__PURE__ */ jsxDEV5("th", {
|
|
1643
|
-
className: "px-4 py-3 text-left text-sm
|
|
1643
|
+
className: "px-4 py-3 text-left font-medium text-sm",
|
|
1644
1644
|
children: "Status"
|
|
1645
1645
|
}, undefined, false, undefined, this),
|
|
1646
1646
|
/* @__PURE__ */ jsxDEV5("th", {
|
|
1647
|
-
className: "px-4 py-3 text-left text-sm
|
|
1647
|
+
className: "px-4 py-3 text-left font-medium text-sm",
|
|
1648
1648
|
children: "Expected Close"
|
|
1649
1649
|
}, undefined, false, undefined, this),
|
|
1650
1650
|
/* @__PURE__ */ jsxDEV5("th", {
|
|
1651
|
-
className: "px-4 py-3 text-left text-sm
|
|
1651
|
+
className: "px-4 py-3 text-left font-medium text-sm",
|
|
1652
1652
|
children: "Actions"
|
|
1653
1653
|
}, undefined, false, undefined, this)
|
|
1654
1654
|
]
|
|
1655
1655
|
}, undefined, true, undefined, this)
|
|
1656
1656
|
}, undefined, false, undefined, this),
|
|
1657
1657
|
/* @__PURE__ */ jsxDEV5("tbody", {
|
|
1658
|
-
className: "divide-
|
|
1658
|
+
className: "divide-y divide-border",
|
|
1659
1659
|
children: data.deals.map((deal) => /* @__PURE__ */ jsxDEV5("tr", {
|
|
1660
1660
|
className: "hover:bg-muted/50",
|
|
1661
1661
|
children: [
|
|
@@ -1673,12 +1673,12 @@ function DealListTab({ data, onDealClick }) {
|
|
|
1673
1673
|
/* @__PURE__ */ jsxDEV5("td", {
|
|
1674
1674
|
className: "px-4 py-3",
|
|
1675
1675
|
children: /* @__PURE__ */ jsxDEV5("span", {
|
|
1676
|
-
className: `inline-flex rounded-full px-2 py-0.5 text-xs
|
|
1676
|
+
className: `inline-flex rounded-full px-2 py-0.5 font-medium text-xs ${deal.status === "WON" ? "bg-green-100 text-green-700 dark:bg-green-900/30 dark:text-green-400" : deal.status === "LOST" ? "bg-red-100 text-red-700 dark:bg-red-900/30 dark:text-red-400" : "bg-blue-100 text-blue-700 dark:bg-blue-900/30 dark:text-blue-400"}`,
|
|
1677
1677
|
children: deal.status
|
|
1678
1678
|
}, undefined, false, undefined, this)
|
|
1679
1679
|
}, undefined, false, undefined, this),
|
|
1680
1680
|
/* @__PURE__ */ jsxDEV5("td", {
|
|
1681
|
-
className: "
|
|
1681
|
+
className: "px-4 py-3 text-muted-foreground",
|
|
1682
1682
|
children: deal.expectedCloseDate?.toLocaleDateString() ?? "-"
|
|
1683
1683
|
}, undefined, false, undefined, this),
|
|
1684
1684
|
/* @__PURE__ */ jsxDEV5("td", {
|
|
@@ -1705,10 +1705,10 @@ function MetricsTab({
|
|
|
1705
1705
|
return /* @__PURE__ */ jsxDEV5("div", {
|
|
1706
1706
|
className: "space-y-6",
|
|
1707
1707
|
children: /* @__PURE__ */ jsxDEV5("div", {
|
|
1708
|
-
className: "border-border bg-card
|
|
1708
|
+
className: "rounded-xl border border-border bg-card p-6",
|
|
1709
1709
|
children: [
|
|
1710
1710
|
/* @__PURE__ */ jsxDEV5("h3", {
|
|
1711
|
-
className: "mb-4 text-lg
|
|
1711
|
+
className: "mb-4 font-semibold text-lg",
|
|
1712
1712
|
children: "Pipeline Overview"
|
|
1713
1713
|
}, undefined, false, undefined, this),
|
|
1714
1714
|
/* @__PURE__ */ jsxDEV5("dl", {
|
|
@@ -1721,7 +1721,7 @@ function MetricsTab({
|
|
|
1721
1721
|
children: "Win Rate"
|
|
1722
1722
|
}, undefined, false, undefined, this),
|
|
1723
1723
|
/* @__PURE__ */ jsxDEV5("dd", {
|
|
1724
|
-
className: "text-2xl
|
|
1724
|
+
className: "font-semibold text-2xl",
|
|
1725
1725
|
children: [
|
|
1726
1726
|
stats.total > 0 ? (stats.wonCount / stats.total * 100).toFixed(0) : 0,
|
|
1727
1727
|
"%"
|
|
@@ -1736,7 +1736,7 @@ function MetricsTab({
|
|
|
1736
1736
|
children: "Avg Deal Size"
|
|
1737
1737
|
}, undefined, false, undefined, this),
|
|
1738
1738
|
/* @__PURE__ */ jsxDEV5("dd", {
|
|
1739
|
-
className: "text-2xl
|
|
1739
|
+
className: "font-semibold text-2xl",
|
|
1740
1740
|
children: formatCurrency4(stats.total > 0 ? stats.totalValue / stats.total : 0)
|
|
1741
1741
|
}, undefined, false, undefined, this)
|
|
1742
1742
|
]
|
|
@@ -1748,7 +1748,7 @@ function MetricsTab({
|
|
|
1748
1748
|
children: "Conversion"
|
|
1749
1749
|
}, undefined, false, undefined, this),
|
|
1750
1750
|
/* @__PURE__ */ jsxDEV5("dd", {
|
|
1751
|
-
className: "text-2xl
|
|
1751
|
+
className: "font-semibold text-2xl",
|
|
1752
1752
|
children: [
|
|
1753
1753
|
stats.wonCount,
|
|
1754
1754
|
" / ",
|
|
@@ -1763,31 +1763,59 @@ function MetricsTab({
|
|
|
1763
1763
|
}, undefined, true, undefined, this)
|
|
1764
1764
|
}, undefined, false, undefined, this);
|
|
1765
1765
|
}
|
|
1766
|
+
|
|
1766
1767
|
// src/ui/hooks/index.ts
|
|
1767
1768
|
"use client";
|
|
1768
|
-
|
|
1769
|
-
|
|
1770
|
-
|
|
1771
|
-
|
|
1772
|
-
|
|
1773
|
-
|
|
1774
|
-
|
|
1775
|
-
|
|
1776
|
-
},
|
|
1777
|
-
|
|
1778
|
-
|
|
1779
|
-
|
|
1780
|
-
|
|
1781
|
-
|
|
1782
|
-
|
|
1783
|
-
|
|
1784
|
-
|
|
1785
|
-
|
|
1769
|
+
// src/ui/overlays/demo-overlays.ts
|
|
1770
|
+
var crmDemoOverlay = {
|
|
1771
|
+
overlayId: "crm-pipeline.demo-user",
|
|
1772
|
+
version: "1.0.0",
|
|
1773
|
+
description: "Demo mode with sample data",
|
|
1774
|
+
appliesTo: {
|
|
1775
|
+
feature: "crm-pipeline",
|
|
1776
|
+
role: "demo"
|
|
1777
|
+
},
|
|
1778
|
+
modifications: [
|
|
1779
|
+
{
|
|
1780
|
+
type: "hideField",
|
|
1781
|
+
field: "importButton",
|
|
1782
|
+
reason: "Not available in demo"
|
|
1783
|
+
},
|
|
1784
|
+
{
|
|
1785
|
+
type: "hideField",
|
|
1786
|
+
field: "exportButton",
|
|
1787
|
+
reason: "Not available in demo"
|
|
1788
|
+
},
|
|
1789
|
+
{
|
|
1790
|
+
type: "addBadge",
|
|
1791
|
+
position: "header",
|
|
1792
|
+
label: "Demo Mode",
|
|
1793
|
+
variant: "warning"
|
|
1786
1794
|
}
|
|
1787
|
-
|
|
1788
|
-
}
|
|
1795
|
+
]
|
|
1789
1796
|
};
|
|
1790
|
-
|
|
1797
|
+
var crmSalesRepOverlay = {
|
|
1798
|
+
overlayId: "crm-pipeline.sales-rep",
|
|
1799
|
+
version: "1.0.0",
|
|
1800
|
+
description: "Sales rep focused view",
|
|
1801
|
+
appliesTo: {
|
|
1802
|
+
feature: "crm-pipeline",
|
|
1803
|
+
role: "sales-rep"
|
|
1804
|
+
},
|
|
1805
|
+
modifications: [
|
|
1806
|
+
{
|
|
1807
|
+
type: "hideField",
|
|
1808
|
+
field: "teamMetrics",
|
|
1809
|
+
reason: "Team metrics for managers only"
|
|
1810
|
+
},
|
|
1811
|
+
{ type: "hideField", field: "pipelineSettings", reason: "Admin only" },
|
|
1812
|
+
{ type: "renameLabel", field: "deals", newLabel: "My Deals" }
|
|
1813
|
+
]
|
|
1814
|
+
};
|
|
1815
|
+
var crmOverlays = [
|
|
1816
|
+
crmDemoOverlay,
|
|
1817
|
+
crmSalesRepOverlay
|
|
1818
|
+
];
|
|
1791
1819
|
// src/ui/renderers/pipeline.markdown.ts
|
|
1792
1820
|
function formatCurrency5(value, currency = "USD") {
|
|
1793
1821
|
return new Intl.NumberFormat("en-US", {
|
|
@@ -1906,56 +1934,28 @@ var crmDashboardMarkdownRenderer = {
|
|
|
1906
1934
|
};
|
|
1907
1935
|
}
|
|
1908
1936
|
};
|
|
1909
|
-
|
|
1910
|
-
|
|
1911
|
-
|
|
1912
|
-
|
|
1913
|
-
|
|
1914
|
-
|
|
1915
|
-
|
|
1916
|
-
|
|
1917
|
-
},
|
|
1918
|
-
|
|
1919
|
-
|
|
1920
|
-
|
|
1921
|
-
|
|
1922
|
-
|
|
1923
|
-
|
|
1924
|
-
{
|
|
1925
|
-
type: "hideField",
|
|
1926
|
-
field: "exportButton",
|
|
1927
|
-
reason: "Not available in demo"
|
|
1928
|
-
},
|
|
1929
|
-
{
|
|
1930
|
-
type: "addBadge",
|
|
1931
|
-
position: "header",
|
|
1932
|
-
label: "Demo Mode",
|
|
1933
|
-
variant: "warning"
|
|
1937
|
+
|
|
1938
|
+
// src/ui/renderers/pipeline.renderer.tsx
|
|
1939
|
+
import { jsxDEV as jsxDEV6 } from "react/jsx-dev-runtime";
|
|
1940
|
+
function CrmPipelineBoardWrapper() {
|
|
1941
|
+
const { dealsByStage, stages } = useDealList();
|
|
1942
|
+
return /* @__PURE__ */ jsxDEV6(CrmPipelineBoard, {
|
|
1943
|
+
dealsByStage,
|
|
1944
|
+
stages
|
|
1945
|
+
}, undefined, false, undefined, this);
|
|
1946
|
+
}
|
|
1947
|
+
var crmPipelineReactRenderer = {
|
|
1948
|
+
target: "react",
|
|
1949
|
+
render: async (desc, _ctx) => {
|
|
1950
|
+
if (desc.source.type !== "component") {
|
|
1951
|
+
throw new Error("Invalid source type");
|
|
1934
1952
|
}
|
|
1935
|
-
|
|
1936
|
-
};
|
|
1937
|
-
|
|
1938
|
-
|
|
1939
|
-
|
|
1940
|
-
description: "Sales rep focused view",
|
|
1941
|
-
appliesTo: {
|
|
1942
|
-
feature: "crm-pipeline",
|
|
1943
|
-
role: "sales-rep"
|
|
1944
|
-
},
|
|
1945
|
-
modifications: [
|
|
1946
|
-
{
|
|
1947
|
-
type: "hideField",
|
|
1948
|
-
field: "teamMetrics",
|
|
1949
|
-
reason: "Team metrics for managers only"
|
|
1950
|
-
},
|
|
1951
|
-
{ type: "hideField", field: "pipelineSettings", reason: "Admin only" },
|
|
1952
|
-
{ type: "renameLabel", field: "deals", newLabel: "My Deals" }
|
|
1953
|
-
]
|
|
1953
|
+
if (desc.source.componentKey !== "CrmPipelineView") {
|
|
1954
|
+
throw new Error(`Unknown component: ${desc.source.componentKey}`);
|
|
1955
|
+
}
|
|
1956
|
+
return /* @__PURE__ */ jsxDEV6(CrmPipelineBoardWrapper, {}, undefined, false, undefined, this);
|
|
1957
|
+
}
|
|
1954
1958
|
};
|
|
1955
|
-
var crmOverlays = [
|
|
1956
|
-
crmDemoOverlay,
|
|
1957
|
-
crmSalesRepOverlay
|
|
1958
|
-
];
|
|
1959
1959
|
export {
|
|
1960
1960
|
useDealMutations,
|
|
1961
1961
|
useDealList,
|