@wealthx/shadcn 1.5.1 → 1.5.3

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 (36) hide show
  1. package/.turbo/turbo-build.log +115 -115
  2. package/CHANGELOG.md +12 -0
  3. package/dist/chunk-G2EWIP2N.mjs +960 -0
  4. package/dist/{chunk-MHHA7QGO.mjs → chunk-ODO6BUOF.mjs} +1 -1
  5. package/dist/chunk-PX4M67XQ.mjs +301 -0
  6. package/dist/{chunk-FYUSF5KO.mjs → chunk-QRVEI6J3.mjs} +1 -1
  7. package/dist/{chunk-42NEC57Y.mjs → chunk-RAKBWNQH.mjs} +272 -3
  8. package/dist/components/ui/{contact-alert-dialog.js → contact-alert-dialog/index.js} +1029 -593
  9. package/dist/components/ui/contact-alert-dialog/index.mjs +31 -0
  10. package/dist/components/ui/file-preview-dialog.js +407 -100
  11. package/dist/components/ui/file-preview-dialog.mjs +3 -1
  12. package/dist/components/ui/kanban-column.js +408 -113
  13. package/dist/components/ui/kanban-column.mjs +3 -2
  14. package/dist/components/ui/opportunity-card.js +383 -88
  15. package/dist/components/ui/opportunity-card.mjs +2 -1
  16. package/dist/components/ui/pipeline-board.js +424 -129
  17. package/dist/components/ui/pipeline-board.mjs +4 -3
  18. package/dist/index.js +3081 -2282
  19. package/dist/index.mjs +39 -35
  20. package/dist/styles.css +1 -1
  21. package/package.json +5 -4
  22. package/src/components/index.tsx +3 -2
  23. package/src/components/ui/contact-alert-dialog/builder-ui.tsx +556 -0
  24. package/src/components/ui/contact-alert-dialog/config.ts +262 -0
  25. package/src/components/ui/contact-alert-dialog/contact-alert-dialog.tsx +214 -0
  26. package/src/components/ui/contact-alert-dialog/index.tsx +15 -0
  27. package/src/components/ui/contact-alert-dialog/types.ts +61 -0
  28. package/src/components/ui/contact-alert-dialog/utils.ts +93 -0
  29. package/src/components/ui/file-preview-dialog.tsx +299 -99
  30. package/src/components/ui/opportunity-card.tsx +328 -1
  31. package/src/styles/styles-css.ts +1 -1
  32. package/tsup.config.ts +1 -1
  33. package/dist/chunk-5WMFKQZ6.mjs +0 -180
  34. package/dist/chunk-Y24TXIFJ.mjs +0 -518
  35. package/dist/components/ui/contact-alert-dialog.mjs +0 -27
  36. package/src/components/ui/contact-alert-dialog.tsx +0 -710
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  LeadCard,
3
3
  OpportunityCard
4
- } from "./chunk-42NEC57Y.mjs";
4
+ } from "./chunk-RAKBWNQH.mjs";
5
5
  import {
6
6
  Spinner
7
7
  } from "./chunk-JVMXMFBB.mjs";
@@ -0,0 +1,301 @@
1
+ import {
2
+ Progress
3
+ } from "./chunk-JPGL36WQ.mjs";
4
+ import {
5
+ Skeleton
6
+ } from "./chunk-GTAVSBDO.mjs";
7
+ import {
8
+ Table,
9
+ TableBody,
10
+ TableCell,
11
+ TableHead,
12
+ TableHeader,
13
+ TableRow
14
+ } from "./chunk-GT3RU6GA.mjs";
15
+ import {
16
+ Select,
17
+ SelectContent,
18
+ SelectItem,
19
+ SelectTrigger,
20
+ SelectValue
21
+ } from "./chunk-TAX3KL66.mjs";
22
+ import {
23
+ Spinner
24
+ } from "./chunk-JVMXMFBB.mjs";
25
+ import {
26
+ Tooltip,
27
+ TooltipContent,
28
+ TooltipProvider,
29
+ TooltipTrigger
30
+ } from "./chunk-6SR4K5T5.mjs";
31
+ import {
32
+ Dialog,
33
+ DialogContent,
34
+ DialogFooter,
35
+ DialogHeader,
36
+ DialogTitle
37
+ } from "./chunk-NCUH54IZ.mjs";
38
+ import {
39
+ Button
40
+ } from "./chunk-NOOEKOWY.mjs";
41
+ import {
42
+ cn
43
+ } from "./chunk-AFML43VJ.mjs";
44
+
45
+ // src/components/ui/file-preview-dialog.tsx
46
+ import * as React from "react";
47
+ import {
48
+ AlertCircleIcon,
49
+ CheckCircle2Icon,
50
+ CircleAlertIcon,
51
+ FileTextIcon,
52
+ Trash2Icon
53
+ } from "lucide-react";
54
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
55
+ function LoadingState({ columnCount }) {
56
+ const cols = Math.max(columnCount, 3);
57
+ return /* @__PURE__ */ jsxs(Table, { children: [
58
+ /* @__PURE__ */ jsx(TableHeader, { children: /* @__PURE__ */ jsx(TableRow, { children: Array.from({ length: cols }).map((_, i) => /* @__PURE__ */ jsx(TableHead, { children: /* @__PURE__ */ jsx(Skeleton, { className: "h-4 w-24" }) }, i)) }) }),
59
+ /* @__PURE__ */ jsx(TableBody, { children: Array.from({ length: 4 }).map((_, rowIdx) => /* @__PURE__ */ jsx(TableRow, { children: Array.from({ length: cols }).map((_2, colIdx) => /* @__PURE__ */ jsx(TableCell, { children: /* @__PURE__ */ jsx(Skeleton, { className: "h-4 w-full" }) }, colIdx)) }, rowIdx)) })
60
+ ] });
61
+ }
62
+ function EmptyState() {
63
+ return /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center gap-3 py-12 text-center", children: [
64
+ /* @__PURE__ */ jsx(FileTextIcon, { className: "size-10 text-muted-foreground/40" }),
65
+ /* @__PURE__ */ jsx("p", { className: "text-sm font-medium text-foreground", children: "No data found" }),
66
+ /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground", children: "The CSV file appears to be empty or contains only headers." })
67
+ ] });
68
+ }
69
+ function ErrorState({ message }) {
70
+ return /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center gap-3 py-12 text-center", children: [
71
+ /* @__PURE__ */ jsx(AlertCircleIcon, { className: "size-10 text-destructive/60" }),
72
+ /* @__PURE__ */ jsx("p", { className: "text-sm font-medium text-foreground", children: "Unable to parse file" }),
73
+ /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground", children: message != null ? message : "The file could not be read. Please check the format and try again." })
74
+ ] });
75
+ }
76
+ function ImportingState({
77
+ progress,
78
+ successCount,
79
+ failedCount
80
+ }) {
81
+ return /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center gap-4 py-8", children: [
82
+ /* @__PURE__ */ jsx(Spinner, { className: "size-6" }),
83
+ /* @__PURE__ */ jsxs("div", { className: "w-full max-w-sm space-y-2", children: [
84
+ /* @__PURE__ */ jsx(Progress, { value: progress, className: "h-1.5" }),
85
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between text-xs text-muted-foreground", children: [
86
+ /* @__PURE__ */ jsxs("span", { children: [
87
+ "Importing\u2026 ",
88
+ progress,
89
+ "%"
90
+ ] }),
91
+ (successCount > 0 || failedCount > 0) && /* @__PURE__ */ jsxs("span", { children: [
92
+ successCount,
93
+ " success \xB7 ",
94
+ failedCount,
95
+ " failed"
96
+ ] })
97
+ ] })
98
+ ] })
99
+ ] });
100
+ }
101
+ function RowStatusCell({ row }) {
102
+ const { _status, _statusMessage } = row;
103
+ if (_status === "success") {
104
+ return /* @__PURE__ */ jsx("div", { className: "flex items-center justify-center h-full px-2", children: /* @__PURE__ */ jsx(CheckCircle2Icon, { className: "size-4 text-success" }) });
105
+ }
106
+ if (_status === "failed") {
107
+ return /* @__PURE__ */ jsx(TooltipProvider, { children: /* @__PURE__ */ jsxs(Tooltip, { children: [
108
+ /* @__PURE__ */ jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx("div", { className: "flex items-center justify-center h-full px-2 cursor-default", children: /* @__PURE__ */ jsx(CircleAlertIcon, { className: "size-4 text-destructive" }) }) }),
109
+ _statusMessage && /* @__PURE__ */ jsx(TooltipContent, { side: "top", children: _statusMessage })
110
+ ] }) });
111
+ }
112
+ return null;
113
+ }
114
+ function FilePreviewDialog({
115
+ open,
116
+ onOpenChange,
117
+ fileName,
118
+ state = "preview",
119
+ errorMessage,
120
+ columns = [],
121
+ rows = [],
122
+ onRowChange,
123
+ onRowDelete,
124
+ onImport,
125
+ onCancelImport,
126
+ importProgress = 0,
127
+ totalRows,
128
+ validRows,
129
+ pageSize = 10,
130
+ staffOptions,
131
+ selectedStaffId,
132
+ onStaffSelect,
133
+ className
134
+ }) {
135
+ const [page, setPage] = React.useState(0);
136
+ React.useEffect(() => {
137
+ setPage(0);
138
+ }, [rows.length]);
139
+ const totalPages = Math.ceil(rows.length / pageSize);
140
+ const pagedRows = rows.slice(page * pageSize, (page + 1) * pageSize);
141
+ const pageStart = page * pageSize;
142
+ const isImporting = state === "importing";
143
+ const hasStaffSelector = !!staffOptions && staffOptions.length > 0;
144
+ const canImport = state === "preview" && rows.length > 0 && (!hasStaffSelector || !!selectedStaffId);
145
+ const successCount = rows.filter((r) => r._status === "success").length;
146
+ const failedCount = rows.filter((r) => r._status === "failed").length;
147
+ const hasStatus = rows.some((r) => r._status !== void 0);
148
+ return /* @__PURE__ */ jsx(Dialog, { open, onOpenChange: isImporting ? void 0 : onOpenChange, children: /* @__PURE__ */ jsxs(DialogContent, { size: "3xl", className, children: [
149
+ /* @__PURE__ */ jsx(DialogHeader, { children: /* @__PURE__ */ jsx(DialogTitle, { children: "Preview Import" }) }),
150
+ fileName && state !== "error" && /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between text-xs text-muted-foreground", children: [
151
+ /* @__PURE__ */ jsx("span", { className: "font-medium text-foreground", children: fileName }),
152
+ state === "preview" && totalRows !== void 0 && /* @__PURE__ */ jsxs("span", { children: [
153
+ validRows != null ? validRows : rows.length,
154
+ " valid row",
155
+ (validRows != null ? validRows : rows.length) !== 1 ? "s" : "",
156
+ " / ",
157
+ totalRows,
158
+ " ",
159
+ "total"
160
+ ] }),
161
+ hasStatus && /* @__PURE__ */ jsxs("span", { children: [
162
+ successCount,
163
+ " success \xB7 ",
164
+ failedCount,
165
+ " failed"
166
+ ] })
167
+ ] }),
168
+ state === "loading" && /* @__PURE__ */ jsx(LoadingState, { columnCount: columns.length }),
169
+ state === "empty" && /* @__PURE__ */ jsx(EmptyState, {}),
170
+ state === "error" && /* @__PURE__ */ jsx(ErrorState, { message: errorMessage }),
171
+ state === "importing" && /* @__PURE__ */ jsx(
172
+ ImportingState,
173
+ {
174
+ progress: importProgress,
175
+ successCount,
176
+ failedCount
177
+ }
178
+ ),
179
+ state === "preview" && /* @__PURE__ */ jsxs(Fragment, { children: [
180
+ hasStaffSelector && /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1", children: [
181
+ /* @__PURE__ */ jsxs("label", { className: "text-label-medium text-foreground", children: [
182
+ "Assign staff",
183
+ " ",
184
+ /* @__PURE__ */ jsx("span", { className: "text-destructive", "aria-hidden": "true", children: "*" })
185
+ ] }),
186
+ /* @__PURE__ */ jsxs(
187
+ Select,
188
+ {
189
+ value: selectedStaffId != null ? selectedStaffId : "",
190
+ onValueChange: (id) => onStaffSelect == null ? void 0 : onStaffSelect(id),
191
+ children: [
192
+ /* @__PURE__ */ jsx(SelectTrigger, { className: "w-full", children: /* @__PURE__ */ jsx(SelectValue, { placeholder: "Select a staff member" }) }),
193
+ /* @__PURE__ */ jsx(SelectContent, { children: staffOptions.map((s) => /* @__PURE__ */ jsx(SelectItem, { value: s.id, children: s.name }, s.id)) })
194
+ ]
195
+ }
196
+ ),
197
+ /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground", children: "All contacts in this import will be assigned to the selected staff member." })
198
+ ] }),
199
+ /* @__PURE__ */ jsx("div", { className: "max-h-[360px] overflow-auto border border-border", children: /* @__PURE__ */ jsxs(Table, { children: [
200
+ /* @__PURE__ */ jsx(TableHeader, { className: "sticky top-0 z-10 bg-muted/80 backdrop-blur-sm", children: /* @__PURE__ */ jsxs(TableRow, { children: [
201
+ /* @__PURE__ */ jsx(TableHead, { className: "w-10 text-center select-none", children: "#" }),
202
+ columns.map((col) => /* @__PURE__ */ jsx(TableHead, { className: "select-none", children: col.label }, col.key)),
203
+ hasStatus && /* @__PURE__ */ jsx(TableHead, { className: "w-16 text-center select-none", children: "Status" }),
204
+ onRowDelete && /* @__PURE__ */ jsx(TableHead, { className: "w-10 select-none" })
205
+ ] }) }),
206
+ /* @__PURE__ */ jsx(TableBody, { children: pagedRows.map((row, pageRowIdx) => {
207
+ const absoluteIdx = pageStart + pageRowIdx;
208
+ return /* @__PURE__ */ jsxs(
209
+ TableRow,
210
+ {
211
+ className: cn(
212
+ row._status === "failed" && "bg-destructive/5",
213
+ row._status === "success" && "bg-success/5"
214
+ ),
215
+ children: [
216
+ /* @__PURE__ */ jsx(TableCell, { className: "text-center text-xs text-muted-foreground select-none w-10", children: absoluteIdx + 1 }),
217
+ columns.map((col) => {
218
+ var _a;
219
+ return /* @__PURE__ */ jsx(TableCell, { className: "p-0", children: /* @__PURE__ */ jsx(
220
+ "input",
221
+ {
222
+ type: "text",
223
+ value: (_a = row[col.key]) != null ? _a : "",
224
+ onChange: (e) => onRowChange == null ? void 0 : onRowChange(
225
+ absoluteIdx,
226
+ col.key,
227
+ e.target.value
228
+ ),
229
+ className: cn(
230
+ "w-full bg-transparent px-4 py-3 text-sm text-foreground",
231
+ "focus:outline-none focus:ring-1 focus:ring-inset focus:ring-primary"
232
+ )
233
+ }
234
+ ) }, col.key);
235
+ }),
236
+ hasStatus && /* @__PURE__ */ jsx(TableCell, { className: "text-center w-16 p-0", children: /* @__PURE__ */ jsx(RowStatusCell, { row }) }),
237
+ onRowDelete && /* @__PURE__ */ jsx(TableCell, { className: "w-10 p-0 text-center", children: /* @__PURE__ */ jsx(
238
+ Button,
239
+ {
240
+ variant: "ghost",
241
+ size: "icon-sm",
242
+ "aria-label": `Delete row ${absoluteIdx + 1}`,
243
+ onClick: () => onRowDelete(absoluteIdx),
244
+ className: "text-muted-foreground hover:text-destructive",
245
+ children: /* @__PURE__ */ jsx(Trash2Icon, { className: "size-3.5" })
246
+ }
247
+ ) })
248
+ ]
249
+ },
250
+ absoluteIdx
251
+ );
252
+ }) })
253
+ ] }) }),
254
+ totalPages > 1 && /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between text-xs text-muted-foreground pt-1", children: [
255
+ /* @__PURE__ */ jsxs("span", { children: [
256
+ "Showing ",
257
+ pageStart + 1,
258
+ "\u2013",
259
+ Math.min(pageStart + pageSize, rows.length),
260
+ " of ",
261
+ rows.length
262
+ ] }),
263
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1", children: [
264
+ /* @__PURE__ */ jsx(
265
+ Button,
266
+ {
267
+ variant: "outline",
268
+ size: "sm",
269
+ onClick: () => setPage((p) => Math.max(0, p - 1)),
270
+ disabled: page === 0,
271
+ children: "Previous"
272
+ }
273
+ ),
274
+ /* @__PURE__ */ jsxs("span", { className: "px-2", children: [
275
+ page + 1,
276
+ " / ",
277
+ totalPages
278
+ ] }),
279
+ /* @__PURE__ */ jsx(
280
+ Button,
281
+ {
282
+ variant: "outline",
283
+ size: "sm",
284
+ onClick: () => setPage((p) => Math.min(totalPages - 1, p + 1)),
285
+ disabled: page >= totalPages - 1,
286
+ children: "Next"
287
+ }
288
+ )
289
+ ] })
290
+ ] })
291
+ ] }),
292
+ /* @__PURE__ */ jsx(DialogFooter, { children: isImporting ? /* @__PURE__ */ jsx(Button, { variant: "outline", onClick: onCancelImport, children: "Cancel Import" }) : /* @__PURE__ */ jsxs(Fragment, { children: [
293
+ /* @__PURE__ */ jsx(Button, { variant: "outline", onClick: () => onOpenChange(false), children: "Cancel" }),
294
+ /* @__PURE__ */ jsx(Button, { disabled: !canImport, onClick: onImport, children: "Import" })
295
+ ] }) })
296
+ ] }) });
297
+ }
298
+
299
+ export {
300
+ FilePreviewDialog
301
+ };
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  KanbanColumn
3
- } from "./chunk-MHHA7QGO.mjs";
3
+ } from "./chunk-ODO6BUOF.mjs";
4
4
  import {
5
5
  ToggleGroup,
6
6
  ToggleGroupItem
@@ -1,6 +1,9 @@
1
1
  import {
2
2
  TaskCheckItem
3
3
  } from "./chunk-2WCIORP7.mjs";
4
+ import {
5
+ Progress
6
+ } from "./chunk-JPGL36WQ.mjs";
4
7
  import {
5
8
  DropdownMenu,
6
9
  DropdownMenuContent,
@@ -42,16 +45,20 @@ import {
42
45
  } from "./chunk-AFML43VJ.mjs";
43
46
 
44
47
  // src/components/ui/opportunity-card.tsx
48
+ import { useState } from "react";
45
49
  import {
46
50
  Phone,
47
51
  Mail,
48
52
  User,
49
53
  Users,
50
54
  Calendar,
55
+ Check,
51
56
  MoreVertical,
52
57
  Clock,
53
58
  ArrowRight,
54
- Bot
59
+ Bot,
60
+ ChevronDown,
61
+ ChevronRight
55
62
  } from "lucide-react";
56
63
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
57
64
  var PRIORITY_COLORS = {
@@ -76,7 +83,233 @@ function resolvePriority(days, warningDays, priorityDays, priority) {
76
83
  function formatLoanType(type) {
77
84
  return type.split("-").map((w) => w.charAt(0).toUpperCase() + w.slice(1)).join(" ");
78
85
  }
86
+ function TaskViewCard({
87
+ customerName,
88
+ loanType,
89
+ loanPurposeLabel,
90
+ amount,
91
+ priority,
92
+ daysSinceColumnChanged,
93
+ warningDays,
94
+ priorityDays,
95
+ tasks = [],
96
+ nextTask,
97
+ onCardClick,
98
+ onViewDetails,
99
+ onTaskToggle,
100
+ onMarkAsDone,
101
+ onMoveToNextStage,
102
+ onChangePriority,
103
+ onDelete,
104
+ onPutOnHold,
105
+ isSubmitting = false,
106
+ draggable = false,
107
+ onDragStart,
108
+ className
109
+ }) {
110
+ var _a;
111
+ const resolvedPriority = resolvePriority(
112
+ daysSinceColumnChanged,
113
+ warningDays,
114
+ priorityDays,
115
+ priority
116
+ );
117
+ const priorityColor = PRIORITY_COLORS[resolvedPriority];
118
+ const completedCount = tasks.filter((t) => t.completed).length;
119
+ const totalCount = tasks.length;
120
+ const hasTasks = totalCount > 0;
121
+ const allDone = hasTasks && completedCount === totalCount;
122
+ const nextPendingTask = tasks.find((t) => !t.completed);
123
+ const agentName = (_a = nextPendingTask == null ? void 0 : nextPendingTask.aiAgentName) != null ? _a : null;
124
+ const [subtasksExpanded, setSubtasksExpanded] = useState(false);
125
+ const hasMenu = onViewDetails || onChangePriority || onPutOnHold || onDelete;
126
+ const stopProp = (e) => {
127
+ e.stopPropagation();
128
+ };
129
+ const purposeLabel = loanPurposeLabel != null ? loanPurposeLabel : loanType ? formatLoanType(loanType) : null;
130
+ const dealRef = [
131
+ customerName,
132
+ purposeLabel,
133
+ amount > 0 ? formatCurrency(amount) : null
134
+ ].filter(Boolean).join(" \xB7 ");
135
+ let taskHeader;
136
+ if (allDone) {
137
+ taskHeader = /* @__PURE__ */ jsxs(
138
+ "p",
139
+ {
140
+ className: "flex items-center gap-1.5 text-sm font-semibold",
141
+ style: { color: "var(--color-success-text)" },
142
+ children: [
143
+ /* @__PURE__ */ jsx(Check, { className: "size-3.5 shrink-0" }),
144
+ "All tasks complete"
145
+ ]
146
+ }
147
+ );
148
+ } else if (nextTask) {
149
+ taskHeader = /* @__PURE__ */ jsxs(Fragment, { children: [
150
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5", children: [
151
+ agentName && /* @__PURE__ */ jsx(
152
+ Bot,
153
+ {
154
+ className: "size-3.5 shrink-0 text-primary",
155
+ "aria-hidden": "true"
156
+ }
157
+ ),
158
+ /* @__PURE__ */ jsx("p", { className: "truncate text-sm font-semibold leading-snug", children: nextTask })
159
+ ] }),
160
+ agentName && /* @__PURE__ */ jsx("p", { className: "mt-0.5 text-xs text-muted-foreground", children: agentName })
161
+ ] });
162
+ } else {
163
+ taskHeader = /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground", children: "No tasks defined for this stage" });
164
+ }
165
+ return /* @__PURE__ */ jsxs(
166
+ "div",
167
+ {
168
+ className: cn(
169
+ "flex flex-col gap-2.5 border border-border bg-background p-3 text-foreground shadow-sm",
170
+ onCardClick && "cursor-pointer",
171
+ draggable && "cursor-grab active:cursor-grabbing",
172
+ isSubmitting && "opacity-60",
173
+ className
174
+ ),
175
+ "data-slot": "opportunity-card",
176
+ draggable,
177
+ onDragStart,
178
+ onClick: onCardClick,
179
+ children: [
180
+ /* @__PURE__ */ jsxs("div", { className: "flex items-start gap-2", children: [
181
+ /* @__PURE__ */ jsx("div", { className: "min-w-0 flex-1", children: taskHeader }),
182
+ /* @__PURE__ */ jsx(
183
+ "span",
184
+ {
185
+ role: "img",
186
+ className: "mt-0.5 inline-block size-2.5 shrink-0 rounded-full",
187
+ style: { backgroundColor: priorityColor },
188
+ "aria-label": `Priority: ${resolvedPriority}`
189
+ }
190
+ )
191
+ ] }),
192
+ hasTasks && /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
193
+ /* @__PURE__ */ jsxs("span", { className: "shrink-0 tabular-nums text-xs text-muted-foreground", children: [
194
+ completedCount,
195
+ "/",
196
+ totalCount
197
+ ] }),
198
+ /* @__PURE__ */ jsx(
199
+ Progress,
200
+ {
201
+ value: completedCount / totalCount * 100,
202
+ className: cn(
203
+ "h-1.5 flex-1",
204
+ allDone && "[&_[data-slot=progress-indicator]]:bg-success"
205
+ )
206
+ }
207
+ )
208
+ ] }),
209
+ hasTasks && /* @__PURE__ */ jsxs(
210
+ "div",
211
+ {
212
+ className: "space-y-1 border-t border-border pt-2",
213
+ onClick: stopProp,
214
+ role: "presentation",
215
+ onKeyDown: (e) => e.stopPropagation(),
216
+ children: [
217
+ /* @__PURE__ */ jsxs(
218
+ "button",
219
+ {
220
+ type: "button",
221
+ onClick: () => setSubtasksExpanded((v) => !v),
222
+ className: "flex w-full items-center justify-between text-xs text-muted-foreground hover:text-foreground",
223
+ children: [
224
+ /* @__PURE__ */ jsxs("span", { className: "flex items-center gap-1", children: [
225
+ subtasksExpanded ? /* @__PURE__ */ jsx(ChevronDown, { className: "size-3" }) : /* @__PURE__ */ jsx(ChevronRight, { className: "size-3" }),
226
+ "Subtasks"
227
+ ] }),
228
+ /* @__PURE__ */ jsxs("span", { children: [
229
+ completedCount,
230
+ " / ",
231
+ totalCount
232
+ ] })
233
+ ]
234
+ }
235
+ ),
236
+ subtasksExpanded && /* @__PURE__ */ jsx("ul", { className: "space-y-1.5 pt-1", children: tasks.map((task) => /* @__PURE__ */ jsx(
237
+ TaskCheckItem,
238
+ {
239
+ title: task.title,
240
+ completed: task.completed,
241
+ aiAgentName: task.aiAgentName,
242
+ onToggle: () => onTaskToggle == null ? void 0 : onTaskToggle(task.id),
243
+ size: "xs"
244
+ },
245
+ task.id
246
+ )) })
247
+ ]
248
+ }
249
+ ),
250
+ /* @__PURE__ */ jsx("p", { className: "truncate text-xs text-muted-foreground", children: dealRef }),
251
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5", onClick: stopProp, children: [
252
+ daysSinceColumnChanged !== void 0 && /* @__PURE__ */ jsxs(Badge, { variant: "secondary", className: "px-1.5 text-[10px] font-normal", children: [
253
+ daysSinceColumnChanged,
254
+ "d"
255
+ ] }),
256
+ hasMenu && /* @__PURE__ */ jsx("div", { className: "ml-auto", children: /* @__PURE__ */ jsxs(DropdownMenu, { children: [
257
+ /* @__PURE__ */ jsx(
258
+ DropdownMenuTrigger,
259
+ {
260
+ className: cn(
261
+ buttonVariants({ variant: "ghost", size: "icon" }),
262
+ "size-7 shrink-0"
263
+ ),
264
+ "aria-label": "Opportunity actions",
265
+ children: /* @__PURE__ */ jsx(MoreVertical, { className: "size-4" })
266
+ }
267
+ ),
268
+ /* @__PURE__ */ jsxs(DropdownMenuContent, { align: "end", children: [
269
+ onViewDetails && /* @__PURE__ */ jsx(DropdownMenuItem, { onClick: onViewDetails, children: "View details" }),
270
+ onChangePriority && /* @__PURE__ */ jsx(DropdownMenuItem, { onClick: onChangePriority, children: "Change priority" }),
271
+ onPutOnHold && /* @__PURE__ */ jsx(DropdownMenuItem, { onClick: onPutOnHold, children: "Put on hold" }),
272
+ onDelete && /* @__PURE__ */ jsxs(Fragment, { children: [
273
+ /* @__PURE__ */ jsx(DropdownMenuSeparator, {}),
274
+ /* @__PURE__ */ jsx(DropdownMenuItem, { onClick: onDelete, variant: "destructive", children: "Delete" })
275
+ ] })
276
+ ] })
277
+ ] }) })
278
+ ] }),
279
+ allDone && onMoveToNextStage && /* @__PURE__ */ jsxs("div", { onClick: stopProp, children: [
280
+ /* @__PURE__ */ jsx(Separator, {}),
281
+ /* @__PURE__ */ jsx("div", { className: "pt-2", children: /* @__PURE__ */ jsx(
282
+ Button,
283
+ {
284
+ variant: "outline",
285
+ size: "sm",
286
+ className: "w-full text-caption",
287
+ onClick: onMoveToNextStage,
288
+ disabled: isSubmitting,
289
+ children: "Move to next stage"
290
+ }
291
+ ) })
292
+ ] }),
293
+ !allDone && nextTask && onMarkAsDone && /* @__PURE__ */ jsxs("div", { onClick: stopProp, children: [
294
+ /* @__PURE__ */ jsx(Separator, {}),
295
+ /* @__PURE__ */ jsx("div", { className: "pt-2", children: /* @__PURE__ */ jsx(
296
+ Button,
297
+ {
298
+ variant: "default",
299
+ size: "sm",
300
+ className: "w-full text-caption",
301
+ onClick: onMarkAsDone,
302
+ disabled: isSubmitting,
303
+ children: "Mark as done"
304
+ }
305
+ ) })
306
+ ] })
307
+ ]
308
+ }
309
+ );
310
+ }
79
311
  function OpportunityCard({
312
+ id,
80
313
  customerName,
81
314
  customerPhone,
82
315
  customerEmail,
@@ -105,8 +338,42 @@ function OpportunityCard({
105
338
  isSubmitting = false,
106
339
  draggable = false,
107
340
  onDragStart,
108
- className
341
+ className,
342
+ viewMode = "deal"
109
343
  }) {
344
+ if (viewMode === "task") {
345
+ return /* @__PURE__ */ jsx(
346
+ TaskViewCard,
347
+ {
348
+ customerName,
349
+ customerPhone,
350
+ customerEmail,
351
+ additionalContacts,
352
+ loanType,
353
+ loanPurposeLabel,
354
+ amount,
355
+ date,
356
+ priority,
357
+ daysSinceColumnChanged,
358
+ warningDays,
359
+ priorityDays,
360
+ tasks,
361
+ nextTask,
362
+ onCardClick,
363
+ onViewDetails,
364
+ onTaskToggle,
365
+ onMarkAsDone,
366
+ onMoveToNextStage,
367
+ onChangePriority,
368
+ onDelete,
369
+ onPutOnHold,
370
+ isSubmitting,
371
+ draggable,
372
+ onDragStart,
373
+ className
374
+ }
375
+ );
376
+ }
110
377
  const resolvedPriority = resolvePriority(
111
378
  daysSinceColumnChanged,
112
379
  warningDays,
@@ -119,7 +386,9 @@ function OpportunityCard({
119
386
  const hasTasks = tasks.length > 0;
120
387
  const hasActions = onMarkAsDone || onMoveToNextStage;
121
388
  const hasMenu = onViewDetails || onChangePriority || onPutOnHold || onDelete;
122
- const stopProp = (e) => e.stopPropagation();
389
+ const stopProp = (e) => {
390
+ e.stopPropagation();
391
+ };
123
392
  return /* @__PURE__ */ jsxs(
124
393
  "div",
125
394
  {