@contractspec/example.crm-pipeline 3.7.7 → 3.7.10

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