@contractspec/example.crm-pipeline 3.7.6 → 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 (130) hide show
  1. package/.turbo/turbo-build.log +45 -42
  2. package/AGENTS.md +51 -33
  3. package/CHANGELOG.md +36 -0
  4. package/README.md +67 -148
  5. package/dist/browser/docs/crm-pipeline.docblock.js +1 -1
  6. package/dist/browser/docs/index.js +1 -1
  7. package/dist/browser/events/contact.event.js +1 -1
  8. package/dist/browser/events/deal.event.js +1 -1
  9. package/dist/browser/events/index.js +3 -3
  10. package/dist/browser/events/task.event.js +1 -1
  11. package/dist/browser/handlers/crm.handlers.js +13 -2
  12. package/dist/browser/handlers/index.js +13 -2
  13. package/dist/browser/index.js +680 -447
  14. package/dist/browser/ui/CrmDashboard.js +574 -352
  15. package/dist/browser/ui/CrmDealCard.js +5 -5
  16. package/dist/browser/ui/CrmPipelineBoard.js +13 -13
  17. package/dist/browser/ui/hooks/index.js +21 -10
  18. package/dist/browser/ui/hooks/useDealList.js +20 -9
  19. package/dist/browser/ui/hooks/useDealMutations.js +1 -1
  20. package/dist/browser/ui/index.js +683 -450
  21. package/dist/browser/ui/modals/CreateDealModal.js +12 -12
  22. package/dist/browser/ui/modals/DealActionsModal.js +21 -21
  23. package/dist/browser/ui/modals/index.js +33 -33
  24. package/dist/browser/ui/renderers/index.js +140 -118
  25. package/dist/browser/ui/renderers/pipeline.markdown.js +13 -2
  26. package/dist/browser/ui/renderers/pipeline.renderer.js +108 -97
  27. package/dist/browser/ui/tables/DealListTab.js +390 -0
  28. package/dist/deal/index.d.ts +2 -2
  29. package/dist/docs/crm-pipeline.docblock.js +1 -1
  30. package/dist/docs/index.js +1 -1
  31. package/dist/events/contact.event.js +1 -1
  32. package/dist/events/deal.event.js +1 -1
  33. package/dist/events/index.js +3 -3
  34. package/dist/events/task.event.js +1 -1
  35. package/dist/handlers/crm.handlers.d.ts +2 -0
  36. package/dist/handlers/crm.handlers.js +13 -2
  37. package/dist/handlers/index.d.ts +2 -2
  38. package/dist/handlers/index.js +13 -2
  39. package/dist/index.d.ts +3 -3
  40. package/dist/index.js +680 -447
  41. package/dist/node/docs/crm-pipeline.docblock.js +1 -1
  42. package/dist/node/docs/index.js +1 -1
  43. package/dist/node/events/contact.event.js +1 -1
  44. package/dist/node/events/deal.event.js +1 -1
  45. package/dist/node/events/index.js +3 -3
  46. package/dist/node/events/task.event.js +1 -1
  47. package/dist/node/handlers/crm.handlers.js +13 -2
  48. package/dist/node/handlers/index.js +13 -2
  49. package/dist/node/index.js +680 -447
  50. package/dist/node/ui/CrmDashboard.js +574 -352
  51. package/dist/node/ui/CrmDealCard.js +5 -5
  52. package/dist/node/ui/CrmPipelineBoard.js +13 -13
  53. package/dist/node/ui/hooks/index.js +21 -10
  54. package/dist/node/ui/hooks/useDealList.js +20 -9
  55. package/dist/node/ui/hooks/useDealMutations.js +1 -1
  56. package/dist/node/ui/index.js +683 -450
  57. package/dist/node/ui/modals/CreateDealModal.js +12 -12
  58. package/dist/node/ui/modals/DealActionsModal.js +21 -21
  59. package/dist/node/ui/modals/index.js +33 -33
  60. package/dist/node/ui/renderers/index.js +140 -118
  61. package/dist/node/ui/renderers/pipeline.markdown.js +13 -2
  62. package/dist/node/ui/renderers/pipeline.renderer.js +108 -97
  63. package/dist/node/ui/tables/DealListTab.js +390 -0
  64. package/dist/operations/index.d.ts +1 -1
  65. package/dist/ui/CrmDashboard.js +574 -352
  66. package/dist/ui/CrmDealCard.js +5 -5
  67. package/dist/ui/CrmPipelineBoard.js +13 -13
  68. package/dist/ui/hooks/index.d.ts +2 -2
  69. package/dist/ui/hooks/index.js +21 -10
  70. package/dist/ui/hooks/useDealList.d.ts +8 -2
  71. package/dist/ui/hooks/useDealList.js +20 -9
  72. package/dist/ui/hooks/useDealMutations.d.ts +9 -0
  73. package/dist/ui/hooks/useDealMutations.js +1 -1
  74. package/dist/ui/index.d.ts +3 -3
  75. package/dist/ui/index.js +683 -450
  76. package/dist/ui/modals/CreateDealModal.js +12 -12
  77. package/dist/ui/modals/DealActionsModal.js +21 -21
  78. package/dist/ui/modals/index.js +33 -33
  79. package/dist/ui/renderers/index.d.ts +1 -1
  80. package/dist/ui/renderers/index.js +140 -118
  81. package/dist/ui/renderers/pipeline.markdown.js +13 -2
  82. package/dist/ui/renderers/pipeline.renderer.d.ts +1 -1
  83. package/dist/ui/renderers/pipeline.renderer.js +108 -97
  84. package/dist/ui/tables/DealListTab.d.ts +20 -0
  85. package/dist/ui/tables/DealListTab.js +391 -0
  86. package/dist/ui/tables/DealListTab.smoke.test.d.ts +1 -0
  87. package/package.json +29 -14
  88. package/src/crm-pipeline.feature.ts +86 -86
  89. package/src/deal/deal.enum.ts +8 -8
  90. package/src/deal/deal.operation.ts +255 -255
  91. package/src/deal/deal.schema.ts +92 -92
  92. package/src/deal/deal.test-spec.ts +48 -48
  93. package/src/deal/index.ts +17 -19
  94. package/src/docs/crm-pipeline.docblock.ts +44 -44
  95. package/src/entities/company.entity.ts +52 -52
  96. package/src/entities/contact.entity.ts +67 -67
  97. package/src/entities/deal.entity.ts +134 -134
  98. package/src/entities/index.ts +27 -27
  99. package/src/entities/task.entity.ts +105 -105
  100. package/src/events/contact.event.ts +22 -22
  101. package/src/events/deal.event.ts +77 -77
  102. package/src/events/task.event.ts +19 -19
  103. package/src/example.ts +32 -32
  104. package/src/handlers/crm.handlers.ts +375 -357
  105. package/src/handlers/deal.handlers.ts +179 -179
  106. package/src/handlers/index.ts +18 -19
  107. package/src/handlers/mock-data.ts +167 -167
  108. package/src/index.ts +11 -11
  109. package/src/operations/index.ts +16 -16
  110. package/src/presentations/dashboard.presentation.ts +45 -45
  111. package/src/presentations/pipeline.presentation.ts +90 -90
  112. package/src/seeders/index.ts +26 -26
  113. package/src/shared/overlay-types.ts +23 -23
  114. package/src/ui/CrmDashboard.tsx +210 -279
  115. package/src/ui/CrmDealCard.tsx +64 -64
  116. package/src/ui/CrmPipelineBoard.tsx +105 -105
  117. package/src/ui/hooks/index.ts +3 -3
  118. package/src/ui/hooks/useDealList.ts +113 -85
  119. package/src/ui/hooks/useDealMutations.ts +151 -150
  120. package/src/ui/index.ts +5 -10
  121. package/src/ui/modals/CreateDealModal.tsx +217 -217
  122. package/src/ui/modals/DealActionsModal.tsx +390 -390
  123. package/src/ui/overlays/demo-overlays.ts +43 -43
  124. package/src/ui/renderers/index.ts +4 -3
  125. package/src/ui/renderers/pipeline.markdown.ts +165 -165
  126. package/src/ui/renderers/pipeline.renderer.tsx +17 -16
  127. package/src/ui/tables/DealListTab.smoke.test.tsx +149 -0
  128. package/src/ui/tables/DealListTab.tsx +276 -0
  129. package/tsconfig.json +7 -8
  130. package/tsdown.config.js +7 -3
@@ -14,7 +14,7 @@ function CrmDealCard({ deal, onClick }) {
14
14
  const daysUntilClose = deal.expectedCloseDate ? Math.ceil((deal.expectedCloseDate.getTime() - Date.now()) / (1000 * 60 * 60 * 24)) : null;
15
15
  return /* @__PURE__ */ jsxDEV("div", {
16
16
  onClick,
17
- className: "border-border bg-card cursor-pointer rounded-lg border p-3 shadow-sm transition-shadow hover:shadow-md",
17
+ className: "cursor-pointer rounded-lg border border-border bg-card p-3 shadow-sm transition-shadow hover:shadow-md",
18
18
  role: "button",
19
19
  tabIndex: 0,
20
20
  onKeyDown: (e) => {
@@ -23,22 +23,22 @@ function CrmDealCard({ deal, onClick }) {
23
23
  },
24
24
  children: [
25
25
  /* @__PURE__ */ jsxDEV("h4", {
26
- className: "leading-snug font-medium",
26
+ className: "font-medium leading-snug",
27
27
  children: deal.name
28
28
  }, undefined, false, undefined, this),
29
29
  /* @__PURE__ */ jsxDEV("div", {
30
- className: "text-primary mt-2 text-lg font-semibold",
30
+ className: "mt-2 font-semibold text-lg text-primary",
31
31
  children: formatCurrency(deal.value, deal.currency)
32
32
  }, undefined, false, undefined, this),
33
33
  /* @__PURE__ */ jsxDEV("div", {
34
- className: "text-muted-foreground mt-3 flex items-center justify-between text-xs",
34
+ className: "mt-3 flex items-center justify-between text-muted-foreground text-xs",
35
35
  children: [
36
36
  daysUntilClose !== null && /* @__PURE__ */ jsxDEV("span", {
37
37
  className: daysUntilClose < 0 ? "text-red-500" : daysUntilClose <= 7 ? "text-yellow-600 dark:text-yellow-500" : "",
38
38
  children: daysUntilClose < 0 ? `${Math.abs(daysUntilClose)}d overdue` : daysUntilClose === 0 ? "Due today" : `${daysUntilClose}d left`
39
39
  }, undefined, false, undefined, this),
40
40
  /* @__PURE__ */ jsxDEV("span", {
41
- 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"}`,
41
+ 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"}`,
42
42
  children: deal.status
43
43
  }, undefined, false, undefined, this)
44
44
  ]
@@ -14,7 +14,7 @@ function CrmDealCard({ deal, onClick }) {
14
14
  const daysUntilClose = deal.expectedCloseDate ? Math.ceil((deal.expectedCloseDate.getTime() - Date.now()) / (1000 * 60 * 60 * 24)) : null;
15
15
  return /* @__PURE__ */ jsxDEV("div", {
16
16
  onClick,
17
- className: "border-border bg-card cursor-pointer rounded-lg border p-3 shadow-sm transition-shadow hover:shadow-md",
17
+ className: "cursor-pointer rounded-lg border border-border bg-card p-3 shadow-sm transition-shadow hover:shadow-md",
18
18
  role: "button",
19
19
  tabIndex: 0,
20
20
  onKeyDown: (e) => {
@@ -23,22 +23,22 @@ function CrmDealCard({ deal, onClick }) {
23
23
  },
24
24
  children: [
25
25
  /* @__PURE__ */ jsxDEV("h4", {
26
- className: "leading-snug font-medium",
26
+ className: "font-medium leading-snug",
27
27
  children: deal.name
28
28
  }, undefined, false, undefined, this),
29
29
  /* @__PURE__ */ jsxDEV("div", {
30
- className: "text-primary mt-2 text-lg font-semibold",
30
+ className: "mt-2 font-semibold text-lg text-primary",
31
31
  children: formatCurrency(deal.value, deal.currency)
32
32
  }, undefined, false, undefined, this),
33
33
  /* @__PURE__ */ jsxDEV("div", {
34
- className: "text-muted-foreground mt-3 flex items-center justify-between text-xs",
34
+ className: "mt-3 flex items-center justify-between text-muted-foreground text-xs",
35
35
  children: [
36
36
  daysUntilClose !== null && /* @__PURE__ */ jsxDEV("span", {
37
37
  className: daysUntilClose < 0 ? "text-red-500" : daysUntilClose <= 7 ? "text-yellow-600 dark:text-yellow-500" : "",
38
38
  children: daysUntilClose < 0 ? `${Math.abs(daysUntilClose)}d overdue` : daysUntilClose === 0 ? "Due today" : `${daysUntilClose}d left`
39
39
  }, undefined, false, undefined, this),
40
40
  /* @__PURE__ */ jsxDEV("span", {
41
- 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"}`,
41
+ 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"}`,
42
42
  children: deal.status
43
43
  }, undefined, false, undefined, this)
44
44
  ]
@@ -76,10 +76,10 @@ function CrmPipelineBoard({
76
76
  const deals = dealsByStage[stage.id] ?? [];
77
77
  const stageValue = deals.reduce((sum, d) => sum + d.value, 0);
78
78
  return /* @__PURE__ */ jsxDEV2("div", {
79
- className: "bg-muted/30 flex w-72 flex-shrink-0 flex-col rounded-lg",
79
+ className: "flex w-72 flex-shrink-0 flex-col rounded-lg bg-muted/30",
80
80
  children: [
81
81
  /* @__PURE__ */ jsxDEV2("div", {
82
- className: "border-border flex items-center justify-between border-b px-3 py-2",
82
+ className: "flex items-center justify-between border-border border-b px-3 py-2",
83
83
  children: [
84
84
  /* @__PURE__ */ jsxDEV2("div", {
85
85
  children: [
@@ -98,7 +98,7 @@ function CrmPipelineBoard({
98
98
  ]
99
99
  }, undefined, true, undefined, this),
100
100
  /* @__PURE__ */ jsxDEV2("span", {
101
- className: "bg-muted flex h-6 w-6 items-center justify-center rounded-full text-xs font-medium",
101
+ className: "flex h-6 w-6 items-center justify-center rounded-full bg-muted font-medium text-xs",
102
102
  children: deals.length
103
103
  }, undefined, false, undefined, this)
104
104
  ]
@@ -106,7 +106,7 @@ function CrmPipelineBoard({
106
106
  /* @__PURE__ */ jsxDEV2("div", {
107
107
  className: "flex flex-1 flex-col gap-2 p-2",
108
108
  children: deals.length === 0 ? /* @__PURE__ */ jsxDEV2("div", {
109
- className: "border-muted-foreground/20 text-muted-foreground flex h-24 items-center justify-center rounded-md border-2 border-dashed text-xs",
109
+ className: "flex h-24 items-center justify-center rounded-md border-2 border-muted-foreground/20 border-dashed text-muted-foreground text-xs",
110
110
  children: "No deals"
111
111
  }, undefined, false, undefined, this) : deals.map((deal) => /* @__PURE__ */ jsxDEV2("div", {
112
112
  className: "group relative",
@@ -124,15 +124,15 @@ function CrmPipelineBoard({
124
124
  e.stopPropagation();
125
125
  setQuickMoveOpen(quickMoveOpen === deal.id ? null : deal.id);
126
126
  },
127
- className: "bg-background border-border hover:bg-muted flex h-6 w-6 items-center justify-center rounded border text-xs shadow-sm",
127
+ className: "flex h-6 w-6 items-center justify-center rounded border border-border bg-background text-xs shadow-sm hover:bg-muted",
128
128
  title: "Quick move",
129
129
  children: "\u27A1\uFE0F"
130
130
  }, undefined, false, undefined, this),
131
131
  quickMoveOpen === deal.id && /* @__PURE__ */ jsxDEV2("div", {
132
- className: "bg-card border-border absolute top-7 right-0 z-20 min-w-[140px] rounded-lg border py-1 shadow-lg",
132
+ className: "absolute top-7 right-0 z-20 min-w-[140px] rounded-lg border border-border bg-card py-1 shadow-lg",
133
133
  children: [
134
134
  /* @__PURE__ */ jsxDEV2("p", {
135
- className: "text-muted-foreground px-3 py-1 text-xs font-medium",
135
+ className: "px-3 py-1 font-medium text-muted-foreground text-xs",
136
136
  children: "Move to:"
137
137
  }, undefined, false, undefined, this),
138
138
  sortedStages.filter((s) => s.id !== deal.stageId).map((s) => /* @__PURE__ */ jsxDEV2("button", {
@@ -141,7 +141,7 @@ function CrmPipelineBoard({
141
141
  e.stopPropagation();
142
142
  handleQuickMove(deal.id, s.id);
143
143
  },
144
- className: "hover:bg-muted w-full px-3 py-1.5 text-left text-sm",
144
+ className: "w-full px-3 py-1.5 text-left text-sm hover:bg-muted",
145
145
  children: s.name
146
146
  }, s.id, false, undefined, this))
147
147
  ]
@@ -1,2 +1,2 @@
1
- export { useDealList, type UseDealListOptions } from './useDealList';
2
- export { useDealMutations, type UseDealMutationsOptions, } from './useDealMutations';
1
+ export { type UseDealListOptions, useDealList } from './useDealList';
2
+ export { type UseDealMutationsOptions, useDealMutations, } from './useDealMutations';
@@ -1,7 +1,7 @@
1
1
  // @bun
2
2
  // src/ui/hooks/useDealList.ts
3
- import { useCallback, useEffect, useMemo, useState } from "react";
4
3
  import { useTemplateRuntime } from "@contractspec/lib.example-shared-ui";
4
+ import { useCallback, useEffect, useMemo, useState } from "react";
5
5
  "use client";
6
6
  function useDealList(options = {}) {
7
7
  const { handlers, projectId } = useTemplateRuntime();
@@ -11,8 +11,13 @@ function useDealList(options = {}) {
11
11
  const [stages, setStages] = useState([]);
12
12
  const [loading, setLoading] = useState(true);
13
13
  const [error, setError] = useState(null);
14
- const [page, setPage] = useState(1);
14
+ const [internalPage, setInternalPage] = useState(0);
15
15
  const pipelineId = options.pipelineId ?? "pipeline-1";
16
+ const pageIndex = options.pageIndex ?? internalPage;
17
+ const pageSize = options.pageSize ?? options.limit ?? 50;
18
+ const [sort] = options.sorting ?? [];
19
+ const sortBy = sort?.id;
20
+ const sortDirection = sort ? sort.desc ? "desc" : "asc" : undefined;
16
21
  const fetchData = useCallback(async () => {
17
22
  setLoading(true);
18
23
  setError(null);
@@ -24,8 +29,10 @@ function useDealList(options = {}) {
24
29
  stageId: options.stageId,
25
30
  status: options.status === "all" ? undefined : options.status,
26
31
  search: options.search,
27
- limit: options.limit ?? 50,
28
- offset: (page - 1) * (options.limit ?? 50)
32
+ limit: pageSize,
33
+ offset: pageIndex * pageSize,
34
+ sortBy: sortBy === "name" || sortBy === "value" || sortBy === "status" || sortBy === "expectedCloseDate" || sortBy === "updatedAt" ? sortBy : undefined,
35
+ sortDirection
29
36
  }),
30
37
  crm.getDealsByStage({ projectId, pipelineId }),
31
38
  crm.getPipelineStages({ pipelineId })
@@ -45,8 +52,10 @@ function useDealList(options = {}) {
45
52
  options.stageId,
46
53
  options.status,
47
54
  options.search,
48
- options.limit,
49
- page
55
+ pageIndex,
56
+ pageSize,
57
+ sortBy,
58
+ sortDirection
50
59
  ]);
51
60
  useEffect(() => {
52
61
  fetchData();
@@ -74,16 +83,18 @@ function useDealList(options = {}) {
74
83
  loading,
75
84
  error,
76
85
  stats,
77
- page,
86
+ page: pageIndex + 1,
87
+ pageIndex,
88
+ pageSize,
78
89
  refetch: fetchData,
79
- nextPage: () => setPage((p) => p + 1),
80
- prevPage: () => page > 1 && setPage((p) => p - 1)
90
+ nextPage: options.pageIndex === undefined ? () => setInternalPage((page) => page + 1) : undefined,
91
+ prevPage: options.pageIndex === undefined ? () => pageIndex > 0 && setInternalPage((page) => page - 1) : undefined
81
92
  };
82
93
  }
83
94
 
84
95
  // src/ui/hooks/useDealMutations.ts
85
- import { useCallback as useCallback2, useState as useState2 } from "react";
86
96
  import { useTemplateRuntime as useTemplateRuntime2 } from "@contractspec/lib.example-shared-ui";
97
+ import { useCallback as useCallback2, useState as useState2 } from "react";
87
98
  function useDealMutations(options = {}) {
88
99
  const { handlers, projectId } = useTemplateRuntime2();
89
100
  const { crm } = handlers;
@@ -1,3 +1,4 @@
1
+ import type { ContractTableSort } from '@contractspec/lib.presentation-runtime-core';
1
2
  import { type Deal as RuntimeDeal, type ListDealsOutput as RuntimeListDealsOutput, type Stage } from '../../handlers/crm.handlers';
2
3
  export type Deal = RuntimeDeal;
3
4
  export type ListDealsOutput = RuntimeListDealsOutput;
@@ -7,6 +8,9 @@ export interface UseDealListOptions {
7
8
  status?: 'OPEN' | 'WON' | 'LOST' | 'all';
8
9
  search?: string;
9
10
  limit?: number;
11
+ pageIndex?: number;
12
+ pageSize?: number;
13
+ sorting?: ContractTableSort[];
10
14
  }
11
15
  export declare function useDealList(options?: UseDealListOptions): {
12
16
  data: RuntimeListDealsOutput | null;
@@ -24,7 +28,9 @@ export declare function useDealList(options?: UseDealListOptions): {
24
28
  lostCount: number;
25
29
  } | null;
26
30
  page: number;
31
+ pageIndex: number;
32
+ pageSize: number;
27
33
  refetch: () => Promise<void>;
28
- nextPage: () => void;
29
- prevPage: () => false | void;
34
+ nextPage: (() => void) | undefined;
35
+ prevPage: (() => false | void) | undefined;
30
36
  };
@@ -1,7 +1,7 @@
1
1
  // @bun
2
2
  // src/ui/hooks/useDealList.ts
3
- import { useCallback, useEffect, useMemo, useState } from "react";
4
3
  import { useTemplateRuntime } from "@contractspec/lib.example-shared-ui";
4
+ import { useCallback, useEffect, useMemo, useState } from "react";
5
5
  "use client";
6
6
  function useDealList(options = {}) {
7
7
  const { handlers, projectId } = useTemplateRuntime();
@@ -11,8 +11,13 @@ function useDealList(options = {}) {
11
11
  const [stages, setStages] = useState([]);
12
12
  const [loading, setLoading] = useState(true);
13
13
  const [error, setError] = useState(null);
14
- const [page, setPage] = useState(1);
14
+ const [internalPage, setInternalPage] = useState(0);
15
15
  const pipelineId = options.pipelineId ?? "pipeline-1";
16
+ const pageIndex = options.pageIndex ?? internalPage;
17
+ const pageSize = options.pageSize ?? options.limit ?? 50;
18
+ const [sort] = options.sorting ?? [];
19
+ const sortBy = sort?.id;
20
+ const sortDirection = sort ? sort.desc ? "desc" : "asc" : undefined;
16
21
  const fetchData = useCallback(async () => {
17
22
  setLoading(true);
18
23
  setError(null);
@@ -24,8 +29,10 @@ function useDealList(options = {}) {
24
29
  stageId: options.stageId,
25
30
  status: options.status === "all" ? undefined : options.status,
26
31
  search: options.search,
27
- limit: options.limit ?? 50,
28
- offset: (page - 1) * (options.limit ?? 50)
32
+ limit: pageSize,
33
+ offset: pageIndex * pageSize,
34
+ sortBy: sortBy === "name" || sortBy === "value" || sortBy === "status" || sortBy === "expectedCloseDate" || sortBy === "updatedAt" ? sortBy : undefined,
35
+ sortDirection
29
36
  }),
30
37
  crm.getDealsByStage({ projectId, pipelineId }),
31
38
  crm.getPipelineStages({ pipelineId })
@@ -45,8 +52,10 @@ function useDealList(options = {}) {
45
52
  options.stageId,
46
53
  options.status,
47
54
  options.search,
48
- options.limit,
49
- page
55
+ pageIndex,
56
+ pageSize,
57
+ sortBy,
58
+ sortDirection
50
59
  ]);
51
60
  useEffect(() => {
52
61
  fetchData();
@@ -74,10 +83,12 @@ function useDealList(options = {}) {
74
83
  loading,
75
84
  error,
76
85
  stats,
77
- page,
86
+ page: pageIndex + 1,
87
+ pageIndex,
88
+ pageSize,
78
89
  refetch: fetchData,
79
- nextPage: () => setPage((p) => p + 1),
80
- prevPage: () => page > 1 && setPage((p) => p - 1)
90
+ nextPage: options.pageIndex === undefined ? () => setInternalPage((page) => page + 1) : undefined,
91
+ prevPage: options.pageIndex === undefined ? () => pageIndex > 0 && setInternalPage((page) => page - 1) : undefined
81
92
  };
82
93
  }
83
94
  export {
@@ -1,3 +1,12 @@
1
+ /**
2
+ * Hook for CRM deal mutations (commands)
3
+ *
4
+ * Uses runtime-local database-backed handlers for:
5
+ * - CreateDealContract
6
+ * - MoveDealContract
7
+ * - WinDealContract
8
+ * - LoseDealContract
9
+ */
1
10
  import type { CreateDealInput, Deal, LoseDealInput, MoveDealInput, WinDealInput } from '../../handlers/crm.handlers';
2
11
  export interface MutationState<T> {
3
12
  loading: boolean;
@@ -1,7 +1,7 @@
1
1
  // @bun
2
2
  // src/ui/hooks/useDealMutations.ts
3
- import { useCallback, useState } from "react";
4
3
  import { useTemplateRuntime } from "@contractspec/lib.example-shared-ui";
4
+ import { useCallback, useState } from "react";
5
5
  function useDealMutations(options = {}) {
6
6
  const { handlers, projectId } = useTemplateRuntime();
7
7
  const { crm } = handlers;
@@ -1,7 +1,7 @@
1
1
  export * from './CrmDashboard';
2
- export * from './CrmPipelineBoard';
3
2
  export * from './CrmDealCard';
4
- export * from './modals';
3
+ export * from './CrmPipelineBoard';
5
4
  export * from './hooks';
6
- export * from './renderers';
5
+ export * from './modals';
7
6
  export * from './overlays';
7
+ export * from './renderers';