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