@contractspec/example.crm-pipeline 3.7.17 → 3.7.18

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 (135) hide show
  1. package/.turbo/turbo-build.log +135 -135
  2. package/CHANGELOG.md +20 -0
  3. package/dist/browser/crm-pipeline.feature.js +1 -82
  4. package/dist/browser/deal/deal.enum.js +1 -18
  5. package/dist/browser/deal/deal.operation.js +1 -396
  6. package/dist/browser/deal/deal.schema.js +1 -141
  7. package/dist/browser/deal/deal.test-spec.js +1 -58
  8. package/dist/browser/deal/index.js +1 -408
  9. package/dist/browser/docs/crm-pipeline.docblock.js +5 -49
  10. package/dist/browser/docs/index.js +5 -49
  11. package/dist/browser/entities/company.entity.js +1 -52
  12. package/dist/browser/entities/contact.entity.js +1 -66
  13. package/dist/browser/entities/deal.entity.js +1 -107
  14. package/dist/browser/entities/index.js +1 -343
  15. package/dist/browser/entities/task.entity.js +1 -99
  16. package/dist/browser/events/contact.event.js +1 -31
  17. package/dist/browser/events/deal.event.js +1 -101
  18. package/dist/browser/events/index.js +1 -158
  19. package/dist/browser/events/task.event.js +1 -28
  20. package/dist/browser/example.js +1 -39
  21. package/dist/browser/handlers/crm.handlers.js +2 -171
  22. package/dist/browser/handlers/deal.handlers.js +1 -293
  23. package/dist/browser/handlers/index.js +2 -467
  24. package/dist/browser/handlers/mock-data.js +1 -165
  25. package/dist/browser/index.js +8 -3461
  26. package/dist/browser/operations/index.js +1 -407
  27. package/dist/browser/presentations/dashboard.presentation.js +1 -55
  28. package/dist/browser/presentations/index.js +1 -290
  29. package/dist/browser/presentations/pipeline.presentation.js +1 -236
  30. package/dist/browser/seeders/index.js +1 -22
  31. package/dist/browser/ui/CrmDashboard.js +1 -1547
  32. package/dist/browser/ui/CrmDealCard.js +1 -50
  33. package/dist/browser/ui/CrmPipelineBoard.js +1 -160
  34. package/dist/browser/ui/hooks/index.js +1 -197
  35. package/dist/browser/ui/hooks/useDealList.js +1 -95
  36. package/dist/browser/ui/hooks/useDealMutations.js +1 -100
  37. package/dist/browser/ui/index.js +4 -2205
  38. package/dist/browser/ui/modals/CreateDealModal.js +1 -211
  39. package/dist/browser/ui/modals/DealActionsModal.js +1 -428
  40. package/dist/browser/ui/modals/index.js +1 -638
  41. package/dist/browser/ui/overlays/demo-overlays.js +1 -55
  42. package/dist/browser/ui/overlays/index.js +1 -55
  43. package/dist/browser/ui/renderers/index.js +4 -849
  44. package/dist/browser/ui/renderers/pipeline.markdown.js +4 -575
  45. package/dist/browser/ui/renderers/pipeline.renderer.js +1 -275
  46. package/dist/browser/ui/tables/DealListTab.js +1 -390
  47. package/dist/crm-pipeline.feature.js +1 -82
  48. package/dist/deal/deal.enum.js +1 -18
  49. package/dist/deal/deal.operation.js +1 -396
  50. package/dist/deal/deal.schema.js +1 -141
  51. package/dist/deal/deal.test-spec.js +1 -58
  52. package/dist/deal/index.js +1 -408
  53. package/dist/docs/crm-pipeline.docblock.js +5 -49
  54. package/dist/docs/index.js +5 -49
  55. package/dist/entities/company.entity.js +1 -52
  56. package/dist/entities/contact.entity.js +1 -66
  57. package/dist/entities/deal.entity.js +1 -107
  58. package/dist/entities/index.js +1 -343
  59. package/dist/entities/task.entity.js +1 -99
  60. package/dist/events/contact.event.js +1 -31
  61. package/dist/events/deal.event.js +1 -101
  62. package/dist/events/index.js +1 -158
  63. package/dist/events/task.event.js +1 -28
  64. package/dist/example.js +1 -39
  65. package/dist/handlers/crm.handlers.js +2 -171
  66. package/dist/handlers/deal.handlers.js +1 -293
  67. package/dist/handlers/index.js +2 -467
  68. package/dist/handlers/mock-data.js +1 -165
  69. package/dist/index.js +8 -3461
  70. package/dist/node/crm-pipeline.feature.js +1 -82
  71. package/dist/node/deal/deal.enum.js +1 -18
  72. package/dist/node/deal/deal.operation.js +1 -396
  73. package/dist/node/deal/deal.schema.js +1 -141
  74. package/dist/node/deal/deal.test-spec.js +1 -58
  75. package/dist/node/deal/index.js +1 -408
  76. package/dist/node/docs/crm-pipeline.docblock.js +5 -49
  77. package/dist/node/docs/index.js +5 -49
  78. package/dist/node/entities/company.entity.js +1 -52
  79. package/dist/node/entities/contact.entity.js +1 -66
  80. package/dist/node/entities/deal.entity.js +1 -107
  81. package/dist/node/entities/index.js +1 -343
  82. package/dist/node/entities/task.entity.js +1 -99
  83. package/dist/node/events/contact.event.js +1 -31
  84. package/dist/node/events/deal.event.js +1 -101
  85. package/dist/node/events/index.js +1 -158
  86. package/dist/node/events/task.event.js +1 -28
  87. package/dist/node/example.js +1 -39
  88. package/dist/node/handlers/crm.handlers.js +2 -171
  89. package/dist/node/handlers/deal.handlers.js +1 -293
  90. package/dist/node/handlers/index.js +2 -467
  91. package/dist/node/handlers/mock-data.js +1 -165
  92. package/dist/node/index.js +8 -3461
  93. package/dist/node/operations/index.js +1 -407
  94. package/dist/node/presentations/dashboard.presentation.js +1 -55
  95. package/dist/node/presentations/index.js +1 -290
  96. package/dist/node/presentations/pipeline.presentation.js +1 -236
  97. package/dist/node/seeders/index.js +1 -22
  98. package/dist/node/ui/CrmDashboard.js +1 -1547
  99. package/dist/node/ui/CrmDealCard.js +1 -50
  100. package/dist/node/ui/CrmPipelineBoard.js +1 -160
  101. package/dist/node/ui/hooks/index.js +1 -197
  102. package/dist/node/ui/hooks/useDealList.js +1 -95
  103. package/dist/node/ui/hooks/useDealMutations.js +1 -100
  104. package/dist/node/ui/index.js +4 -2205
  105. package/dist/node/ui/modals/CreateDealModal.js +1 -211
  106. package/dist/node/ui/modals/DealActionsModal.js +1 -428
  107. package/dist/node/ui/modals/index.js +1 -638
  108. package/dist/node/ui/overlays/demo-overlays.js +1 -55
  109. package/dist/node/ui/overlays/index.js +1 -55
  110. package/dist/node/ui/renderers/index.js +4 -849
  111. package/dist/node/ui/renderers/pipeline.markdown.js +4 -575
  112. package/dist/node/ui/renderers/pipeline.renderer.js +1 -275
  113. package/dist/node/ui/tables/DealListTab.js +1 -390
  114. package/dist/operations/index.js +1 -407
  115. package/dist/presentations/dashboard.presentation.js +1 -55
  116. package/dist/presentations/index.js +1 -290
  117. package/dist/presentations/pipeline.presentation.js +1 -236
  118. package/dist/seeders/index.js +1 -22
  119. package/dist/ui/CrmDashboard.js +1 -1547
  120. package/dist/ui/CrmDealCard.js +1 -50
  121. package/dist/ui/CrmPipelineBoard.js +1 -160
  122. package/dist/ui/hooks/index.js +1 -197
  123. package/dist/ui/hooks/useDealList.js +1 -95
  124. package/dist/ui/hooks/useDealMutations.js +1 -100
  125. package/dist/ui/index.js +4 -2205
  126. package/dist/ui/modals/CreateDealModal.js +1 -211
  127. package/dist/ui/modals/DealActionsModal.js +1 -428
  128. package/dist/ui/modals/index.js +1 -638
  129. package/dist/ui/overlays/demo-overlays.js +1 -55
  130. package/dist/ui/overlays/index.js +1 -55
  131. package/dist/ui/renderers/index.js +4 -849
  132. package/dist/ui/renderers/pipeline.markdown.js +4 -575
  133. package/dist/ui/renderers/pipeline.renderer.js +1 -275
  134. package/dist/ui/tables/DealListTab.js +1 -390
  135. package/package.json +13 -13
@@ -1,212 +1,2 @@
1
1
  // @bun
2
- // src/ui/modals/CreateDealModal.tsx
3
- import { Button, Input } from "@contractspec/lib.design-system";
4
- import { useState } from "react";
5
- import { jsxDEV } from "react/jsx-dev-runtime";
6
- "use client";
7
- var CURRENCIES = ["USD", "EUR", "GBP", "CAD"];
8
- var DEFAULT_PIPELINE_ID = "pipeline-1";
9
- function CreateDealModal({
10
- isOpen,
11
- onClose,
12
- onSubmit,
13
- stages,
14
- isLoading = false
15
- }) {
16
- const [name, setName] = useState("");
17
- const [value, setValue] = useState("");
18
- const [currency, setCurrency] = useState("USD");
19
- const [stageId, setStageId] = useState(stages[0]?.id ?? "");
20
- const [expectedCloseDate, setExpectedCloseDate] = useState("");
21
- const [error, setError] = useState(null);
22
- const handleSubmit = async (e) => {
23
- e.preventDefault();
24
- setError(null);
25
- if (!name.trim()) {
26
- setError("Deal name is required");
27
- return;
28
- }
29
- const numericValue = parseFloat(value);
30
- if (isNaN(numericValue) || numericValue <= 0) {
31
- setError("Value must be a positive number");
32
- return;
33
- }
34
- if (!stageId) {
35
- setError("Please select a pipeline stage");
36
- return;
37
- }
38
- try {
39
- await onSubmit({
40
- name: name.trim(),
41
- value: numericValue,
42
- currency,
43
- pipelineId: DEFAULT_PIPELINE_ID,
44
- stageId,
45
- expectedCloseDate: expectedCloseDate ? new Date(expectedCloseDate) : undefined
46
- });
47
- setName("");
48
- setValue("");
49
- setCurrency("USD");
50
- setStageId(stages[0]?.id ?? "");
51
- setExpectedCloseDate("");
52
- onClose();
53
- } catch (err) {
54
- setError(err instanceof Error ? err.message : "Failed to create deal");
55
- }
56
- };
57
- if (!isOpen)
58
- return null;
59
- return /* @__PURE__ */ jsxDEV("div", {
60
- className: "fixed inset-0 z-50 flex items-center justify-center",
61
- children: [
62
- /* @__PURE__ */ jsxDEV("div", {
63
- className: "absolute inset-0 bg-background/80 backdrop-blur-sm",
64
- onClick: onClose,
65
- role: "button",
66
- tabIndex: 0,
67
- onKeyDown: (e) => {
68
- if (e.key === "Enter" || e.key === " ")
69
- onClose();
70
- },
71
- "aria-label": "Close modal"
72
- }, undefined, false, undefined, this),
73
- /* @__PURE__ */ jsxDEV("div", {
74
- className: "relative z-10 w-full max-w-md rounded-xl border border-border bg-card p-6 shadow-xl",
75
- children: [
76
- /* @__PURE__ */ jsxDEV("h2", {
77
- className: "mb-4 font-semibold text-xl",
78
- children: "Create New Deal"
79
- }, undefined, false, undefined, this),
80
- /* @__PURE__ */ jsxDEV("form", {
81
- onSubmit: handleSubmit,
82
- className: "space-y-4",
83
- children: [
84
- /* @__PURE__ */ jsxDEV("div", {
85
- children: [
86
- /* @__PURE__ */ jsxDEV("label", {
87
- htmlFor: "deal-name",
88
- className: "mb-1 block font-medium text-muted-foreground text-sm",
89
- children: "Deal Name *"
90
- }, undefined, false, undefined, this),
91
- /* @__PURE__ */ jsxDEV(Input, {
92
- id: "deal-name",
93
- value: name,
94
- onChange: (e) => setName(e.target.value),
95
- placeholder: "e.g., Enterprise License - Acme Corp",
96
- disabled: isLoading
97
- }, undefined, false, undefined, this)
98
- ]
99
- }, undefined, true, undefined, this),
100
- /* @__PURE__ */ jsxDEV("div", {
101
- className: "flex gap-3",
102
- children: [
103
- /* @__PURE__ */ jsxDEV("div", {
104
- className: "flex-1",
105
- children: [
106
- /* @__PURE__ */ jsxDEV("label", {
107
- htmlFor: "deal-value",
108
- className: "mb-1 block font-medium text-muted-foreground text-sm",
109
- children: "Value *"
110
- }, undefined, false, undefined, this),
111
- /* @__PURE__ */ jsxDEV(Input, {
112
- id: "deal-value",
113
- type: "number",
114
- min: "0",
115
- step: "0.01",
116
- value,
117
- onChange: (e) => setValue(e.target.value),
118
- placeholder: "50000",
119
- disabled: isLoading
120
- }, undefined, false, undefined, this)
121
- ]
122
- }, undefined, true, undefined, this),
123
- /* @__PURE__ */ jsxDEV("div", {
124
- className: "w-24",
125
- children: [
126
- /* @__PURE__ */ jsxDEV("label", {
127
- htmlFor: "deal-currency",
128
- className: "mb-1 block font-medium text-muted-foreground text-sm",
129
- children: "Currency"
130
- }, undefined, false, undefined, this),
131
- /* @__PURE__ */ jsxDEV("select", {
132
- id: "deal-currency",
133
- value: currency,
134
- onChange: (e) => setCurrency(e.target.value),
135
- disabled: isLoading,
136
- 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",
137
- children: CURRENCIES.map((c) => /* @__PURE__ */ jsxDEV("option", {
138
- value: c,
139
- children: c
140
- }, c, false, undefined, this))
141
- }, undefined, false, undefined, this)
142
- ]
143
- }, undefined, true, undefined, this)
144
- ]
145
- }, undefined, true, undefined, this),
146
- /* @__PURE__ */ jsxDEV("div", {
147
- children: [
148
- /* @__PURE__ */ jsxDEV("label", {
149
- htmlFor: "deal-stage",
150
- className: "mb-1 block font-medium text-muted-foreground text-sm",
151
- children: "Pipeline Stage *"
152
- }, undefined, false, undefined, this),
153
- /* @__PURE__ */ jsxDEV("select", {
154
- id: "deal-stage",
155
- value: stageId,
156
- onChange: (e) => setStageId(e.target.value),
157
- disabled: isLoading,
158
- 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",
159
- children: stages.map((stage) => /* @__PURE__ */ jsxDEV("option", {
160
- value: stage.id,
161
- children: stage.name
162
- }, stage.id, false, undefined, this))
163
- }, undefined, false, undefined, this)
164
- ]
165
- }, undefined, true, undefined, this),
166
- /* @__PURE__ */ jsxDEV("div", {
167
- children: [
168
- /* @__PURE__ */ jsxDEV("label", {
169
- htmlFor: "deal-close-date",
170
- className: "mb-1 block font-medium text-muted-foreground text-sm",
171
- children: "Expected Close Date"
172
- }, undefined, false, undefined, this),
173
- /* @__PURE__ */ jsxDEV(Input, {
174
- id: "deal-close-date",
175
- type: "date",
176
- value: expectedCloseDate,
177
- onChange: (e) => setExpectedCloseDate(e.target.value),
178
- disabled: isLoading
179
- }, undefined, false, undefined, this)
180
- ]
181
- }, undefined, true, undefined, this),
182
- error && /* @__PURE__ */ jsxDEV("div", {
183
- className: "rounded-md bg-destructive/10 p-3 text-destructive text-sm",
184
- children: error
185
- }, undefined, false, undefined, this),
186
- /* @__PURE__ */ jsxDEV("div", {
187
- className: "flex justify-end gap-3 pt-2",
188
- children: [
189
- /* @__PURE__ */ jsxDEV(Button, {
190
- type: "button",
191
- variant: "ghost",
192
- onPress: onClose,
193
- disabled: isLoading,
194
- children: "Cancel"
195
- }, undefined, false, undefined, this),
196
- /* @__PURE__ */ jsxDEV(Button, {
197
- type: "submit",
198
- disabled: isLoading,
199
- children: isLoading ? "Creating..." : "Create Deal"
200
- }, undefined, false, undefined, this)
201
- ]
202
- }, undefined, true, undefined, this)
203
- ]
204
- }, undefined, true, undefined, this)
205
- ]
206
- }, undefined, true, undefined, this)
207
- ]
208
- }, undefined, true, undefined, this);
209
- }
210
- export {
211
- CreateDealModal
212
- };
2
+ import{Button as U,Input as $}from"@contractspec/lib.design-system";import{useState as H}from"react";import{jsx as w,jsxs as z}from"react/jsx-runtime";var R=["USD","EUR","GBP","CAD"],b="pipeline-1";function V({isOpen:_,onClose:K,onSubmit:f,stages:Q,isLoading:G=!1}){let[W,h]=H(""),[k,F]=H(""),[T,v]=H("USD"),[X,A]=H(Q[0]?.id??""),[Y,M]=H(""),[O,J]=H(null),B=async(q)=>{if(q.preventDefault(),J(null),!W.trim()){J("Deal name is required");return}let Z=parseFloat(k);if(isNaN(Z)||Z<=0){J("Value must be a positive number");return}if(!X){J("Please select a pipeline stage");return}try{await f({name:W.trim(),value:Z,currency:T,pipelineId:b,stageId:X,expectedCloseDate:Y?new Date(Y):void 0}),h(""),F(""),v("USD"),A(Q[0]?.id??""),M(""),K()}catch(P){J(P instanceof Error?P.message:"Failed to create deal")}};if(!_)return null;return z("div",{className:"fixed inset-0 z-50 flex items-center justify-center",children:[w("div",{className:"absolute inset-0 bg-background/80 backdrop-blur-sm",onClick:K,role:"button",tabIndex:0,onKeyDown:(q)=>{if(q.key==="Enter"||q.key===" ")K()},"aria-label":"Close modal"}),z("div",{className:"relative z-10 w-full max-w-md rounded-xl border border-border bg-card p-6 shadow-xl",children:[w("h2",{className:"mb-4 font-semibold text-xl",children:"Create New Deal"}),z("form",{onSubmit:B,className:"space-y-4",children:[z("div",{children:[w("label",{htmlFor:"deal-name",className:"mb-1 block font-medium text-muted-foreground text-sm",children:"Deal Name *"}),w($,{id:"deal-name",value:W,onChange:(q)=>h(q.target.value),placeholder:"e.g., Enterprise License - Acme Corp",disabled:G})]}),z("div",{className:"flex gap-3",children:[z("div",{className:"flex-1",children:[w("label",{htmlFor:"deal-value",className:"mb-1 block font-medium text-muted-foreground text-sm",children:"Value *"}),w($,{id:"deal-value",type:"number",min:"0",step:"0.01",value:k,onChange:(q)=>F(q.target.value),placeholder:"50000",disabled:G})]}),z("div",{className:"w-24",children:[w("label",{htmlFor:"deal-currency",className:"mb-1 block font-medium text-muted-foreground text-sm",children:"Currency"}),w("select",{id:"deal-currency",value:T,onChange:(q)=>v(q.target.value),disabled:G,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",children:R.map((q)=>w("option",{value:q,children:q},q))})]})]}),z("div",{children:[w("label",{htmlFor:"deal-stage",className:"mb-1 block font-medium text-muted-foreground text-sm",children:"Pipeline Stage *"}),w("select",{id:"deal-stage",value:X,onChange:(q)=>A(q.target.value),disabled:G,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",children:Q.map((q)=>w("option",{value:q.id,children:q.name},q.id))})]}),z("div",{children:[w("label",{htmlFor:"deal-close-date",className:"mb-1 block font-medium text-muted-foreground text-sm",children:"Expected Close Date"}),w($,{id:"deal-close-date",type:"date",value:Y,onChange:(q)=>M(q.target.value),disabled:G})]}),O&&w("div",{className:"rounded-md bg-destructive/10 p-3 text-destructive text-sm",children:O}),z("div",{className:"flex justify-end gap-3 pt-2",children:[w(U,{type:"button",variant:"ghost",onPress:K,disabled:G,children:"Cancel"}),w(U,{type:"submit",disabled:G,children:G?"Creating...":"Create Deal"})]})]})]})]})}export{V as CreateDealModal};
@@ -1,429 +1,2 @@
1
1
  // @bun
2
- // src/ui/modals/DealActionsModal.tsx
3
- import { Button } from "@contractspec/lib.design-system";
4
- import { useState } from "react";
5
- import { jsxDEV, Fragment } from "react/jsx-dev-runtime";
6
- "use client";
7
- function formatCurrency(value, currency) {
8
- return new Intl.NumberFormat("en-US", {
9
- style: "currency",
10
- currency,
11
- minimumFractionDigits: 0,
12
- maximumFractionDigits: 0
13
- }).format(value);
14
- }
15
- function DealActionsModal({
16
- isOpen,
17
- deal,
18
- stages,
19
- onClose,
20
- onWin,
21
- onLose,
22
- onMove,
23
- isLoading = false
24
- }) {
25
- const [mode, setMode] = useState("menu");
26
- const [wonSource, setWonSource] = useState("");
27
- const [lostReason, setLostReason] = useState("");
28
- const [notes, setNotes] = useState("");
29
- const [selectedStageId, setSelectedStageId] = useState("");
30
- const [error, setError] = useState(null);
31
- const resetForm = () => {
32
- setMode("menu");
33
- setWonSource("");
34
- setLostReason("");
35
- setNotes("");
36
- setSelectedStageId("");
37
- setError(null);
38
- };
39
- const handleClose = () => {
40
- resetForm();
41
- onClose();
42
- };
43
- const handleWin = async () => {
44
- if (!deal)
45
- return;
46
- setError(null);
47
- try {
48
- await onWin({
49
- dealId: deal.id,
50
- wonSource: wonSource.trim() || undefined,
51
- notes: notes.trim() || undefined
52
- });
53
- handleClose();
54
- } catch (err) {
55
- setError(err instanceof Error ? err.message : "Failed to mark deal as won");
56
- }
57
- };
58
- const handleLose = async () => {
59
- if (!deal)
60
- return;
61
- setError(null);
62
- if (!lostReason.trim()) {
63
- setError("Please provide a reason for losing the deal");
64
- return;
65
- }
66
- try {
67
- await onLose({
68
- dealId: deal.id,
69
- lostReason: lostReason.trim(),
70
- notes: notes.trim() || undefined
71
- });
72
- handleClose();
73
- } catch (err) {
74
- setError(err instanceof Error ? err.message : "Failed to mark deal as lost");
75
- }
76
- };
77
- const handleMove = async () => {
78
- if (!deal)
79
- return;
80
- setError(null);
81
- if (!selectedStageId) {
82
- setError("Please select a stage");
83
- return;
84
- }
85
- if (selectedStageId === deal.stageId) {
86
- setError("Deal is already in this stage");
87
- return;
88
- }
89
- try {
90
- await onMove({
91
- dealId: deal.id,
92
- stageId: selectedStageId
93
- });
94
- handleClose();
95
- } catch (err) {
96
- setError(err instanceof Error ? err.message : "Failed to move deal");
97
- }
98
- };
99
- if (!isOpen || !deal)
100
- return null;
101
- return /* @__PURE__ */ jsxDEV("div", {
102
- className: "fixed inset-0 z-50 flex items-center justify-center",
103
- children: [
104
- /* @__PURE__ */ jsxDEV("div", {
105
- className: "absolute inset-0 bg-background/80 backdrop-blur-sm",
106
- onClick: handleClose,
107
- role: "button",
108
- tabIndex: 0,
109
- onKeyDown: (e) => {
110
- if (e.key === "Enter" || e.key === " ")
111
- handleClose();
112
- },
113
- "aria-label": "Close modal"
114
- }, undefined, false, undefined, this),
115
- /* @__PURE__ */ jsxDEV("div", {
116
- className: "relative z-10 w-full max-w-md rounded-xl border border-border bg-card p-6 shadow-xl",
117
- children: [
118
- /* @__PURE__ */ jsxDEV("div", {
119
- className: "mb-4 border-border border-b pb-4",
120
- children: [
121
- /* @__PURE__ */ jsxDEV("h2", {
122
- className: "font-semibold text-xl",
123
- children: deal.name
124
- }, undefined, false, undefined, this),
125
- /* @__PURE__ */ jsxDEV("p", {
126
- className: "font-medium text-lg text-primary",
127
- children: formatCurrency(deal.value, deal.currency)
128
- }, undefined, false, undefined, this),
129
- /* @__PURE__ */ jsxDEV("span", {
130
- 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"}`,
131
- children: deal.status
132
- }, undefined, false, undefined, this)
133
- ]
134
- }, undefined, true, undefined, this),
135
- mode === "menu" && /* @__PURE__ */ jsxDEV("div", {
136
- className: "space-y-3",
137
- children: [
138
- deal.status === "OPEN" && /* @__PURE__ */ jsxDEV(Fragment, {
139
- children: [
140
- /* @__PURE__ */ jsxDEV(Button, {
141
- className: "w-full justify-start",
142
- variant: "ghost",
143
- onPress: () => setMode("win"),
144
- children: [
145
- /* @__PURE__ */ jsxDEV("span", {
146
- className: "mr-2",
147
- children: "\uD83C\uDFC6"
148
- }, undefined, false, undefined, this),
149
- " Mark as Won"
150
- ]
151
- }, undefined, true, undefined, this),
152
- /* @__PURE__ */ jsxDEV(Button, {
153
- className: "w-full justify-start",
154
- variant: "ghost",
155
- onPress: () => setMode("lose"),
156
- children: [
157
- /* @__PURE__ */ jsxDEV("span", {
158
- className: "mr-2",
159
- children: "\u274C"
160
- }, undefined, false, undefined, this),
161
- " Mark as Lost"
162
- ]
163
- }, undefined, true, undefined, this),
164
- /* @__PURE__ */ jsxDEV(Button, {
165
- className: "w-full justify-start",
166
- variant: "ghost",
167
- onPress: () => {
168
- setSelectedStageId(deal.stageId);
169
- setMode("move");
170
- },
171
- children: [
172
- /* @__PURE__ */ jsxDEV("span", {
173
- className: "mr-2",
174
- children: "\u27A1\uFE0F"
175
- }, undefined, false, undefined, this),
176
- " Move to Stage"
177
- ]
178
- }, undefined, true, undefined, this)
179
- ]
180
- }, undefined, true, undefined, this),
181
- deal.status !== "OPEN" && /* @__PURE__ */ jsxDEV("p", {
182
- className: "py-4 text-center text-muted-foreground",
183
- children: [
184
- "This deal is already ",
185
- deal.status.toLowerCase(),
186
- ". No actions available."
187
- ]
188
- }, undefined, true, undefined, this),
189
- /* @__PURE__ */ jsxDEV("div", {
190
- className: "border-border border-t pt-3",
191
- children: /* @__PURE__ */ jsxDEV(Button, {
192
- className: "w-full",
193
- variant: "outline",
194
- onPress: handleClose,
195
- children: "Close"
196
- }, undefined, false, undefined, this)
197
- }, undefined, false, undefined, this)
198
- ]
199
- }, undefined, true, undefined, this),
200
- mode === "win" && /* @__PURE__ */ jsxDEV("div", {
201
- className: "space-y-4",
202
- children: [
203
- /* @__PURE__ */ jsxDEV("div", {
204
- children: [
205
- /* @__PURE__ */ jsxDEV("label", {
206
- htmlFor: "won-source",
207
- className: "mb-1 block font-medium text-muted-foreground text-sm",
208
- children: "How did you win this deal?"
209
- }, undefined, false, undefined, this),
210
- /* @__PURE__ */ jsxDEV("select", {
211
- id: "won-source",
212
- value: wonSource,
213
- onChange: (e) => setWonSource(e.target.value),
214
- 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",
215
- children: [
216
- /* @__PURE__ */ jsxDEV("option", {
217
- value: "",
218
- children: "Select a source..."
219
- }, undefined, false, undefined, this),
220
- /* @__PURE__ */ jsxDEV("option", {
221
- value: "referral",
222
- children: "Referral"
223
- }, undefined, false, undefined, this),
224
- /* @__PURE__ */ jsxDEV("option", {
225
- value: "cold_outreach",
226
- children: "Cold Outreach"
227
- }, undefined, false, undefined, this),
228
- /* @__PURE__ */ jsxDEV("option", {
229
- value: "inbound",
230
- children: "Inbound Lead"
231
- }, undefined, false, undefined, this),
232
- /* @__PURE__ */ jsxDEV("option", {
233
- value: "upsell",
234
- children: "Upsell"
235
- }, undefined, false, undefined, this),
236
- /* @__PURE__ */ jsxDEV("option", {
237
- value: "other",
238
- children: "Other"
239
- }, undefined, false, undefined, this)
240
- ]
241
- }, undefined, true, undefined, this)
242
- ]
243
- }, undefined, true, undefined, this),
244
- /* @__PURE__ */ jsxDEV("div", {
245
- children: [
246
- /* @__PURE__ */ jsxDEV("label", {
247
- htmlFor: "win-notes",
248
- className: "mb-1 block font-medium text-muted-foreground text-sm",
249
- children: "Notes (optional)"
250
- }, undefined, false, undefined, this),
251
- /* @__PURE__ */ jsxDEV("textarea", {
252
- id: "win-notes",
253
- value: notes,
254
- onChange: (e) => setNotes(e.target.value),
255
- placeholder: "Any additional notes about the win...",
256
- rows: 3,
257
- 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"
258
- }, undefined, false, undefined, this)
259
- ]
260
- }, undefined, true, undefined, this),
261
- error && /* @__PURE__ */ jsxDEV("div", {
262
- className: "rounded-md bg-destructive/10 p-3 text-destructive text-sm",
263
- children: error
264
- }, undefined, false, undefined, this),
265
- /* @__PURE__ */ jsxDEV("div", {
266
- className: "flex justify-end gap-3 pt-2",
267
- children: [
268
- /* @__PURE__ */ jsxDEV(Button, {
269
- variant: "ghost",
270
- onPress: () => setMode("menu"),
271
- disabled: isLoading,
272
- children: "Back"
273
- }, undefined, false, undefined, this),
274
- /* @__PURE__ */ jsxDEV(Button, {
275
- onPress: handleWin,
276
- disabled: isLoading,
277
- children: isLoading ? "Processing..." : "\uD83C\uDFC6 Confirm Win"
278
- }, undefined, false, undefined, this)
279
- ]
280
- }, undefined, true, undefined, this)
281
- ]
282
- }, undefined, true, undefined, this),
283
- mode === "lose" && /* @__PURE__ */ jsxDEV("div", {
284
- className: "space-y-4",
285
- children: [
286
- /* @__PURE__ */ jsxDEV("div", {
287
- children: [
288
- /* @__PURE__ */ jsxDEV("label", {
289
- htmlFor: "lost-reason",
290
- className: "mb-1 block font-medium text-muted-foreground text-sm",
291
- children: "Why was this deal lost? *"
292
- }, undefined, false, undefined, this),
293
- /* @__PURE__ */ jsxDEV("select", {
294
- id: "lost-reason",
295
- value: lostReason,
296
- onChange: (e) => setLostReason(e.target.value),
297
- 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",
298
- children: [
299
- /* @__PURE__ */ jsxDEV("option", {
300
- value: "",
301
- children: "Select a reason..."
302
- }, undefined, false, undefined, this),
303
- /* @__PURE__ */ jsxDEV("option", {
304
- value: "price",
305
- children: "Price too high"
306
- }, undefined, false, undefined, this),
307
- /* @__PURE__ */ jsxDEV("option", {
308
- value: "competitor",
309
- children: "Lost to competitor"
310
- }, undefined, false, undefined, this),
311
- /* @__PURE__ */ jsxDEV("option", {
312
- value: "no_budget",
313
- children: "No budget"
314
- }, undefined, false, undefined, this),
315
- /* @__PURE__ */ jsxDEV("option", {
316
- value: "no_decision",
317
- children: "No decision made"
318
- }, undefined, false, undefined, this),
319
- /* @__PURE__ */ jsxDEV("option", {
320
- value: "timing",
321
- children: "Bad timing"
322
- }, undefined, false, undefined, this),
323
- /* @__PURE__ */ jsxDEV("option", {
324
- value: "product_fit",
325
- children: "Product not a fit"
326
- }, undefined, false, undefined, this),
327
- /* @__PURE__ */ jsxDEV("option", {
328
- value: "other",
329
- children: "Other"
330
- }, undefined, false, undefined, this)
331
- ]
332
- }, undefined, true, undefined, this)
333
- ]
334
- }, undefined, true, undefined, this),
335
- /* @__PURE__ */ jsxDEV("div", {
336
- children: [
337
- /* @__PURE__ */ jsxDEV("label", {
338
- htmlFor: "lose-notes",
339
- className: "mb-1 block font-medium text-muted-foreground text-sm",
340
- children: "Notes (optional)"
341
- }, undefined, false, undefined, this),
342
- /* @__PURE__ */ jsxDEV("textarea", {
343
- id: "lose-notes",
344
- value: notes,
345
- onChange: (e) => setNotes(e.target.value),
346
- placeholder: "Any additional details...",
347
- rows: 3,
348
- 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"
349
- }, undefined, false, undefined, this)
350
- ]
351
- }, undefined, true, undefined, this),
352
- error && /* @__PURE__ */ jsxDEV("div", {
353
- className: "rounded-md bg-destructive/10 p-3 text-destructive text-sm",
354
- children: error
355
- }, undefined, false, undefined, this),
356
- /* @__PURE__ */ jsxDEV("div", {
357
- className: "flex justify-end gap-3 pt-2",
358
- children: [
359
- /* @__PURE__ */ jsxDEV(Button, {
360
- variant: "ghost",
361
- onPress: () => setMode("menu"),
362
- disabled: isLoading,
363
- children: "Back"
364
- }, undefined, false, undefined, this),
365
- /* @__PURE__ */ jsxDEV(Button, {
366
- variant: "destructive",
367
- onPress: handleLose,
368
- disabled: isLoading,
369
- children: isLoading ? "Processing..." : "\u274C Confirm Loss"
370
- }, undefined, false, undefined, this)
371
- ]
372
- }, undefined, true, undefined, this)
373
- ]
374
- }, undefined, true, undefined, this),
375
- mode === "move" && /* @__PURE__ */ jsxDEV("div", {
376
- className: "space-y-4",
377
- children: [
378
- /* @__PURE__ */ jsxDEV("div", {
379
- children: [
380
- /* @__PURE__ */ jsxDEV("label", {
381
- htmlFor: "move-stage",
382
- className: "mb-1 block font-medium text-muted-foreground text-sm",
383
- children: "Move to Stage"
384
- }, undefined, false, undefined, this),
385
- /* @__PURE__ */ jsxDEV("select", {
386
- id: "move-stage",
387
- value: selectedStageId,
388
- onChange: (e) => setSelectedStageId(e.target.value),
389
- 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",
390
- children: stages.map((stage) => /* @__PURE__ */ jsxDEV("option", {
391
- value: stage.id,
392
- children: [
393
- stage.name,
394
- stage.id === deal.stageId ? " (current)" : ""
395
- ]
396
- }, stage.id, true, undefined, this))
397
- }, undefined, false, undefined, this)
398
- ]
399
- }, undefined, true, undefined, this),
400
- error && /* @__PURE__ */ jsxDEV("div", {
401
- className: "rounded-md bg-destructive/10 p-3 text-destructive text-sm",
402
- children: error
403
- }, undefined, false, undefined, this),
404
- /* @__PURE__ */ jsxDEV("div", {
405
- className: "flex justify-end gap-3 pt-2",
406
- children: [
407
- /* @__PURE__ */ jsxDEV(Button, {
408
- variant: "ghost",
409
- onPress: () => setMode("menu"),
410
- disabled: isLoading,
411
- children: "Back"
412
- }, undefined, false, undefined, this),
413
- /* @__PURE__ */ jsxDEV(Button, {
414
- onPress: handleMove,
415
- disabled: isLoading,
416
- children: isLoading ? "Moving..." : "\u27A1\uFE0F Move Deal"
417
- }, undefined, false, undefined, this)
418
- ]
419
- }, undefined, true, undefined, this)
420
- ]
421
- }, undefined, true, undefined, this)
422
- ]
423
- }, undefined, true, undefined, this)
424
- ]
425
- }, undefined, true, undefined, this);
426
- }
427
- export {
428
- DealActionsModal
429
- };
2
+ import{Button as K}from"@contractspec/lib.design-system";import{useState as V}from"react";import{jsx as q,jsxs as A,Fragment as h}from"react/jsx-runtime";function I(_,G){return new Intl.NumberFormat("en-US",{style:"currency",currency:G,minimumFractionDigits:0,maximumFractionDigits:0}).format(_)}function B({isOpen:_,deal:G,stages:O,onClose:f,onWin:N,onLose:y,onMove:F,isLoading:P=!1}){let[X,Q]=V("menu"),[D,H]=V(""),[$,w]=V(""),[Y,b]=V(""),[Z,k]=V(""),[T,J]=V(null),R=()=>{Q("menu"),H(""),w(""),b(""),k(""),J(null)},U=()=>{R(),f()},v=async()=>{if(!G)return;J(null);try{await N({dealId:G.id,wonSource:D.trim()||void 0,notes:Y.trim()||void 0}),U()}catch(z){J(z instanceof Error?z.message:"Failed to mark deal as won")}},W=async()=>{if(!G)return;if(J(null),!$.trim()){J("Please provide a reason for losing the deal");return}try{await y({dealId:G.id,lostReason:$.trim(),notes:Y.trim()||void 0}),U()}catch(z){J(z instanceof Error?z.message:"Failed to mark deal as lost")}},p=async()=>{if(!G)return;if(J(null),!Z){J("Please select a stage");return}if(Z===G.stageId){J("Deal is already in this stage");return}try{await F({dealId:G.id,stageId:Z}),U()}catch(z){J(z instanceof Error?z.message:"Failed to move deal")}};if(!_||!G)return null;return A("div",{className:"fixed inset-0 z-50 flex items-center justify-center",children:[q("div",{className:"absolute inset-0 bg-background/80 backdrop-blur-sm",onClick:U,role:"button",tabIndex:0,onKeyDown:(z)=>{if(z.key==="Enter"||z.key===" ")U()},"aria-label":"Close modal"}),A("div",{className:"relative z-10 w-full max-w-md rounded-xl border border-border bg-card p-6 shadow-xl",children:[A("div",{className:"mb-4 border-border border-b pb-4",children:[q("h2",{className:"font-semibold text-xl",children:G.name}),q("p",{className:"font-medium text-lg text-primary",children:I(G.value,G.currency)}),q("span",{className:`mt-2 inline-flex rounded-full px-2 py-0.5 font-medium text-xs ${G.status==="WON"?"bg-green-100 text-green-700 dark:bg-green-900/30 dark:text-green-400":G.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"}`,children:G.status})]}),X==="menu"&&A("div",{className:"space-y-3",children:[G.status==="OPEN"&&A(h,{children:[A(K,{className:"w-full justify-start",variant:"ghost",onPress:()=>Q("win"),children:[q("span",{className:"mr-2",children:"\uD83C\uDFC6"})," Mark as Won"]}),A(K,{className:"w-full justify-start",variant:"ghost",onPress:()=>Q("lose"),children:[q("span",{className:"mr-2",children:"\u274C"})," Mark as Lost"]}),A(K,{className:"w-full justify-start",variant:"ghost",onPress:()=>{k(G.stageId),Q("move")},children:[q("span",{className:"mr-2",children:"\u27A1\uFE0F"})," Move to Stage"]})]}),G.status!=="OPEN"&&A("p",{className:"py-4 text-center text-muted-foreground",children:["This deal is already ",G.status.toLowerCase(),". No actions available."]}),q("div",{className:"border-border border-t pt-3",children:q(K,{className:"w-full",variant:"outline",onPress:U,children:"Close"})})]}),X==="win"&&A("div",{className:"space-y-4",children:[A("div",{children:[q("label",{htmlFor:"won-source",className:"mb-1 block font-medium text-muted-foreground text-sm",children:"How did you win this deal?"}),A("select",{id:"won-source",value:D,onChange:(z)=>H(z.target.value),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",children:[q("option",{value:"",children:"Select a source..."}),q("option",{value:"referral",children:"Referral"}),q("option",{value:"cold_outreach",children:"Cold Outreach"}),q("option",{value:"inbound",children:"Inbound Lead"}),q("option",{value:"upsell",children:"Upsell"}),q("option",{value:"other",children:"Other"})]})]}),A("div",{children:[q("label",{htmlFor:"win-notes",className:"mb-1 block font-medium text-muted-foreground text-sm",children:"Notes (optional)"}),q("textarea",{id:"win-notes",value:Y,onChange:(z)=>b(z.target.value),placeholder:"Any additional notes about the win...",rows:3,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"})]}),T&&q("div",{className:"rounded-md bg-destructive/10 p-3 text-destructive text-sm",children:T}),A("div",{className:"flex justify-end gap-3 pt-2",children:[q(K,{variant:"ghost",onPress:()=>Q("menu"),disabled:P,children:"Back"}),q(K,{onPress:v,disabled:P,children:P?"Processing...":"\uD83C\uDFC6 Confirm Win"})]})]}),X==="lose"&&A("div",{className:"space-y-4",children:[A("div",{children:[q("label",{htmlFor:"lost-reason",className:"mb-1 block font-medium text-muted-foreground text-sm",children:"Why was this deal lost? *"}),A("select",{id:"lost-reason",value:$,onChange:(z)=>w(z.target.value),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",children:[q("option",{value:"",children:"Select a reason..."}),q("option",{value:"price",children:"Price too high"}),q("option",{value:"competitor",children:"Lost to competitor"}),q("option",{value:"no_budget",children:"No budget"}),q("option",{value:"no_decision",children:"No decision made"}),q("option",{value:"timing",children:"Bad timing"}),q("option",{value:"product_fit",children:"Product not a fit"}),q("option",{value:"other",children:"Other"})]})]}),A("div",{children:[q("label",{htmlFor:"lose-notes",className:"mb-1 block font-medium text-muted-foreground text-sm",children:"Notes (optional)"}),q("textarea",{id:"lose-notes",value:Y,onChange:(z)=>b(z.target.value),placeholder:"Any additional details...",rows:3,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"})]}),T&&q("div",{className:"rounded-md bg-destructive/10 p-3 text-destructive text-sm",children:T}),A("div",{className:"flex justify-end gap-3 pt-2",children:[q(K,{variant:"ghost",onPress:()=>Q("menu"),disabled:P,children:"Back"}),q(K,{variant:"destructive",onPress:W,disabled:P,children:P?"Processing...":"\u274C Confirm Loss"})]})]}),X==="move"&&A("div",{className:"space-y-4",children:[A("div",{children:[q("label",{htmlFor:"move-stage",className:"mb-1 block font-medium text-muted-foreground text-sm",children:"Move to Stage"}),q("select",{id:"move-stage",value:Z,onChange:(z)=>k(z.target.value),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",children:O.map((z)=>A("option",{value:z.id,children:[z.name,z.id===G.stageId?" (current)":""]},z.id))})]}),T&&q("div",{className:"rounded-md bg-destructive/10 p-3 text-destructive text-sm",children:T}),A("div",{className:"flex justify-end gap-3 pt-2",children:[q(K,{variant:"ghost",onPress:()=>Q("menu"),disabled:P,children:"Back"}),q(K,{onPress:p,disabled:P,children:P?"Moving...":"\u27A1\uFE0F Move Deal"})]})]})]})]})}export{B as DealActionsModal};