@wealthx/shadcn 1.5.0 → 1.5.2

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 +119 -119
  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 +6 -5
  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
@@ -0,0 +1,960 @@
1
+ import {
2
+ InputGroup,
3
+ InputGroupAddon,
4
+ InputGroupInput,
5
+ InputGroupText
6
+ } from "./chunk-7YI3HEBH.mjs";
7
+ import {
8
+ Field,
9
+ FieldLabel
10
+ } from "./chunk-MUV4EGDW.mjs";
11
+ import {
12
+ Checkbox
13
+ } from "./chunk-IKXYTCSB.mjs";
14
+ import {
15
+ Select,
16
+ SelectContent,
17
+ SelectItem,
18
+ SelectTrigger,
19
+ SelectValue
20
+ } from "./chunk-TAX3KL66.mjs";
21
+ import {
22
+ Dialog,
23
+ DialogContent,
24
+ DialogFooter,
25
+ DialogHeader,
26
+ DialogTitle
27
+ } from "./chunk-NCUH54IZ.mjs";
28
+ import {
29
+ Label
30
+ } from "./chunk-P7CEBZM6.mjs";
31
+ import {
32
+ ToggleGroup,
33
+ ToggleGroupItem
34
+ } from "./chunk-OWFQSXVD.mjs";
35
+ import {
36
+ Input
37
+ } from "./chunk-LBTHZSBT.mjs";
38
+ import {
39
+ Button
40
+ } from "./chunk-NOOEKOWY.mjs";
41
+ import {
42
+ cn
43
+ } from "./chunk-AFML43VJ.mjs";
44
+ import {
45
+ __spreadProps,
46
+ __spreadValues
47
+ } from "./chunk-WNQUEZJF.mjs";
48
+
49
+ // src/components/ui/contact-alert-dialog/contact-alert-dialog.tsx
50
+ import * as React2 from "react";
51
+ import {
52
+ Query,
53
+ Utils as QbUtils4
54
+ } from "@react-awesome-query-builder/ui";
55
+
56
+ // src/components/ui/contact-alert-dialog/types.ts
57
+ var AlertSharingType = /* @__PURE__ */ ((AlertSharingType2) => {
58
+ AlertSharingType2["PRIVATE"] = "PRIVATE";
59
+ AlertSharingType2["COMPANY"] = "COMPANY";
60
+ return AlertSharingType2;
61
+ })(AlertSharingType || {});
62
+
63
+ // src/components/ui/contact-alert-dialog/config.ts
64
+ import {
65
+ BasicConfig,
66
+ Utils as QbUtils
67
+ } from "@react-awesome-query-builder/ui";
68
+ var ALERT_QUERY_FIELDS = [
69
+ {
70
+ key: "userMetric.max_loan_amount",
71
+ label: "Borrowing Capacity",
72
+ type: "number",
73
+ unit: "dollar",
74
+ operators: [
75
+ "equal",
76
+ "less",
77
+ "less_or_equal",
78
+ "greater",
79
+ "greater_or_equal",
80
+ "between"
81
+ ]
82
+ },
83
+ {
84
+ key: "userMetric.debt_outstanding",
85
+ label: "Outstanding Debt",
86
+ type: "number",
87
+ unit: "dollar",
88
+ operators: [
89
+ "equal",
90
+ "less",
91
+ "less_or_equal",
92
+ "greater",
93
+ "greater_or_equal"
94
+ ]
95
+ },
96
+ {
97
+ key: "userMetric.lvr",
98
+ label: "Current LVR",
99
+ type: "number",
100
+ unit: "percent",
101
+ operators: [
102
+ "equal",
103
+ "less",
104
+ "less_or_equal",
105
+ "greater",
106
+ "greater_or_equal"
107
+ ]
108
+ },
109
+ {
110
+ key: "userMetric.has_met_buying_goal",
111
+ label: "Has Met Buying Goal",
112
+ type: "boolean"
113
+ },
114
+ {
115
+ key: "userMetric.excess_monthly_surplus",
116
+ label: "Excess Monthly Surplus",
117
+ type: "number",
118
+ unit: "dollar",
119
+ operators: [
120
+ "equal",
121
+ "less",
122
+ "less_or_equal",
123
+ "greater",
124
+ "greater_or_equal"
125
+ ]
126
+ },
127
+ {
128
+ key: "userMetric.equity",
129
+ label: "Equity Amount",
130
+ type: "number",
131
+ unit: "dollar",
132
+ operators: [
133
+ "equal",
134
+ "less",
135
+ "less_or_equal",
136
+ "greater",
137
+ "greater_or_equal"
138
+ ]
139
+ },
140
+ {
141
+ key: "userMetric.max_debt_interest_rate",
142
+ label: "Max Debt Interest Rate",
143
+ type: "number",
144
+ unit: "percent",
145
+ operators: [
146
+ "equal",
147
+ "less",
148
+ "less_or_equal",
149
+ "greater",
150
+ "greater_or_equal"
151
+ ]
152
+ },
153
+ {
154
+ key: "userMetric.min_debt_interest_rate",
155
+ label: "Min Debt Interest Rate",
156
+ type: "number",
157
+ unit: "percent",
158
+ operators: [
159
+ "equal",
160
+ "less",
161
+ "less_or_equal",
162
+ "greater",
163
+ "greater_or_equal"
164
+ ]
165
+ }
166
+ ];
167
+ var ALL_NUMERIC_OPERATORS = [
168
+ "equal",
169
+ "not_equal",
170
+ "less",
171
+ "less_or_equal",
172
+ "greater",
173
+ "greater_or_equal",
174
+ "between"
175
+ ];
176
+ var BOOLEAN_OPERATORS = ["equal"];
177
+ var OPERATOR_LABELS = {
178
+ equal: "=",
179
+ not_equal: "\u2260",
180
+ less: "<",
181
+ less_or_equal: "\u2264",
182
+ greater: ">",
183
+ greater_or_equal: "\u2265",
184
+ between: "between"
185
+ };
186
+ var SEVERITY_LABELS = {
187
+ INSIGHT: "Insight",
188
+ WATCH: "Watch",
189
+ NEED_ACTION: "Need Action"
190
+ };
191
+ var QB_CONFIG = __spreadProps(__spreadValues({}, BasicConfig), {
192
+ fields: {
193
+ "userMetric.max_loan_amount": {
194
+ label: "Borrowing Capacity",
195
+ type: "number",
196
+ operators: [
197
+ "equal",
198
+ "less",
199
+ "less_or_equal",
200
+ "greater",
201
+ "greater_or_equal",
202
+ "between"
203
+ ],
204
+ valueSources: ["value"]
205
+ },
206
+ "userMetric.debt_outstanding": {
207
+ label: "Outstanding Debt",
208
+ type: "number",
209
+ operators: [
210
+ "equal",
211
+ "less",
212
+ "less_or_equal",
213
+ "greater",
214
+ "greater_or_equal"
215
+ ],
216
+ valueSources: ["value"]
217
+ },
218
+ "userMetric.lvr": {
219
+ label: "Current LVR",
220
+ type: "number",
221
+ operators: [
222
+ "equal",
223
+ "less",
224
+ "less_or_equal",
225
+ "greater",
226
+ "greater_or_equal"
227
+ ],
228
+ valueSources: ["value"]
229
+ },
230
+ "userMetric.has_met_buying_goal": {
231
+ label: "Has Met Buying Goal",
232
+ type: "boolean",
233
+ operators: ["equal"],
234
+ valueSources: ["value"]
235
+ },
236
+ "userMetric.excess_monthly_surplus": {
237
+ label: "Excess Monthly Surplus",
238
+ type: "number",
239
+ operators: [
240
+ "equal",
241
+ "less",
242
+ "less_or_equal",
243
+ "greater",
244
+ "greater_or_equal"
245
+ ],
246
+ valueSources: ["value"]
247
+ },
248
+ "userMetric.equity": {
249
+ label: "Equity Amount",
250
+ type: "number",
251
+ operators: [
252
+ "equal",
253
+ "less",
254
+ "less_or_equal",
255
+ "greater",
256
+ "greater_or_equal"
257
+ ],
258
+ valueSources: ["value"]
259
+ },
260
+ "userMetric.max_debt_interest_rate": {
261
+ label: "Max Debt Interest Rate",
262
+ type: "number",
263
+ operators: [
264
+ "equal",
265
+ "less",
266
+ "less_or_equal",
267
+ "greater",
268
+ "greater_or_equal"
269
+ ],
270
+ valueSources: ["value"]
271
+ },
272
+ "userMetric.min_debt_interest_rate": {
273
+ label: "Min Debt Interest Rate",
274
+ type: "number",
275
+ operators: [
276
+ "equal",
277
+ "less",
278
+ "less_or_equal",
279
+ "greater",
280
+ "greater_or_equal"
281
+ ],
282
+ valueSources: ["value"]
283
+ }
284
+ }
285
+ });
286
+ var EMPTY_QUERY_VALUE = {
287
+ id: "root",
288
+ type: "group",
289
+ properties: { conjunction: "AND", not: false },
290
+ children1: [
291
+ {
292
+ id: "rule-init",
293
+ type: "rule",
294
+ properties: {
295
+ field: "userMetric.max_loan_amount",
296
+ operator: "greater_or_equal",
297
+ value: [null],
298
+ valueSrc: ["value"]
299
+ }
300
+ }
301
+ ]
302
+ };
303
+ function createAlertTree(query) {
304
+ const q = query != null ? query : EMPTY_QUERY_VALUE;
305
+ const loaded = QbUtils.loadTree(q);
306
+ return QbUtils.sanitizeTree(loaded, QB_CONFIG).fixedTree;
307
+ }
308
+
309
+ // src/components/ui/contact-alert-dialog/utils.ts
310
+ import {
311
+ Utils as QbUtils2
312
+ } from "@react-awesome-query-builder/ui";
313
+ function longestOf(labels) {
314
+ return labels.reduce((a, b) => a.length >= b.length ? a : b, "");
315
+ }
316
+ function allOperatorLabels(fields) {
317
+ var _a;
318
+ const ops = /* @__PURE__ */ new Set();
319
+ for (const f of fields) {
320
+ const fieldOps = f.type === "boolean" ? BOOLEAN_OPERATORS : (_a = f.operators) != null ? _a : ALL_NUMERIC_OPERATORS;
321
+ fieldOps.forEach((op) => ops.add(op));
322
+ }
323
+ return Array.from(ops).map((op) => OPERATOR_LABELS[op]);
324
+ }
325
+ function formatWithCommas(raw) {
326
+ if (!raw) return "";
327
+ const [int, dec] = raw.split(".");
328
+ const formatted = int.replace(/\B(?=(\d{3})+(?!\d))/g, ",");
329
+ return dec !== void 0 ? `${formatted}.${dec}` : formatted;
330
+ }
331
+ function parseCommas(display) {
332
+ return display.replace(/[^\d.]/g, "").replace(/(\..*)\./g, "$1");
333
+ }
334
+ function ruleSummary(ruleProps, fields) {
335
+ var _a, _b, _c, _d, _e, _f;
336
+ const field = (_a = ruleProps == null ? void 0 : ruleProps.field) != null ? _a : "";
337
+ const operator = (_b = ruleProps == null ? void 0 : ruleProps.operator) != null ? _b : "equal";
338
+ const value0 = (_c = ruleProps == null ? void 0 : ruleProps.value) == null ? void 0 : _c[0];
339
+ const value1 = (_d = ruleProps == null ? void 0 : ruleProps.value) == null ? void 0 : _d[1];
340
+ const fieldDef = fields.find((f) => f.key === field);
341
+ const fieldLabel = (_e = fieldDef == null ? void 0 : fieldDef.label) != null ? _e : field;
342
+ const opLabel = (_f = OPERATOR_LABELS[operator]) != null ? _f : operator;
343
+ const formatVal = (v) => {
344
+ if (v === null || v === void 0) return "\u2026";
345
+ if ((fieldDef == null ? void 0 : fieldDef.type) === "boolean") return v ? "Yes" : "No";
346
+ const n = typeof v === "number" ? v : parseFloat(String(v));
347
+ if (!isFinite(n)) return "\u2026";
348
+ if ((fieldDef == null ? void 0 : fieldDef.unit) === "dollar")
349
+ return `$${formatWithCommas(n.toString())}`;
350
+ if ((fieldDef == null ? void 0 : fieldDef.unit) === "percent") return `${n}%`;
351
+ return String(v);
352
+ };
353
+ if (operator === "between") {
354
+ return `${fieldLabel} between ${formatVal(value0)} and ${formatVal(value1)}`;
355
+ }
356
+ return `${fieldLabel} ${opLabel} ${formatVal(value0)}`;
357
+ }
358
+ function checkGroupValid(children) {
359
+ return children.some((child) => {
360
+ var _a, _b, _c, _d;
361
+ const c = child;
362
+ if (c.type === "rule") {
363
+ const field = (_a = c.properties) == null ? void 0 : _a.field;
364
+ if (!field) return false;
365
+ const fieldDef = ALERT_QUERY_FIELDS.find((f) => f.key === field);
366
+ if ((fieldDef == null ? void 0 : fieldDef.type) === "boolean") return true;
367
+ const v = (_c = (_b = c.properties) == null ? void 0 : _b.value) == null ? void 0 : _c[0];
368
+ return v !== null && v !== void 0;
369
+ }
370
+ if (c.type === "group") return checkGroupValid((_d = c.children1) != null ? _d : []);
371
+ return false;
372
+ });
373
+ }
374
+ function isTreeValid(tree) {
375
+ var _a;
376
+ const json = QbUtils2.getTree(tree);
377
+ return checkGroupValid((_a = json == null ? void 0 : json.children1) != null ? _a : []);
378
+ }
379
+
380
+ // src/components/ui/contact-alert-dialog/builder-ui.tsx
381
+ import * as React from "react";
382
+ import { ChevronDownIcon, PlusIcon, Trash2Icon } from "lucide-react";
383
+ import { Accordion as AccordionPrimitive } from "@base-ui/react/accordion";
384
+ import {
385
+ Utils as QbUtils3
386
+ } from "@react-awesome-query-builder/ui";
387
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
388
+ function SelectAutoWidth({
389
+ longestLabel,
390
+ children
391
+ }) {
392
+ return /* @__PURE__ */ jsxs("div", { className: "relative inline-block shrink-0", children: [
393
+ /* @__PURE__ */ jsx(
394
+ "span",
395
+ {
396
+ "aria-hidden": true,
397
+ className: "invisible block h-8 whitespace-nowrap pl-3 pr-10 text-body-medium",
398
+ children: longestLabel
399
+ }
400
+ ),
401
+ /* @__PURE__ */ jsx("div", { className: "absolute inset-0", children })
402
+ ] });
403
+ }
404
+ function ValueInput({
405
+ value,
406
+ onChange,
407
+ unit,
408
+ placeholder = "0"
409
+ }) {
410
+ return /* @__PURE__ */ jsxs(InputGroup, { className: "w-36", children: [
411
+ unit === "dollar" && /* @__PURE__ */ jsx(InputGroupAddon, { align: "inline-start", children: /* @__PURE__ */ jsx(InputGroupText, { children: "$" }) }),
412
+ /* @__PURE__ */ jsx(
413
+ InputGroupInput,
414
+ {
415
+ type: "text",
416
+ inputMode: "numeric",
417
+ value: formatWithCommas(value),
418
+ onChange: (e) => onChange(parseCommas(e.target.value)),
419
+ placeholder
420
+ }
421
+ ),
422
+ unit === "percent" && /* @__PURE__ */ jsx(InputGroupAddon, { align: "inline-end", children: /* @__PURE__ */ jsx(InputGroupText, { children: "%" }) })
423
+ ] });
424
+ }
425
+ function RuleEditorFields({
426
+ ruleProps,
427
+ path,
428
+ actions,
429
+ fields,
430
+ longestFieldLabel,
431
+ longestOperatorLabel
432
+ }) {
433
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k;
434
+ const field = (_c = (_b = ruleProps == null ? void 0 : ruleProps.field) != null ? _b : (_a = fields[0]) == null ? void 0 : _a.key) != null ? _c : "";
435
+ const operator = (_d = ruleProps == null ? void 0 : ruleProps.operator) != null ? _d : "greater_or_equal";
436
+ const value0 = (_e = ruleProps == null ? void 0 : ruleProps.value) == null ? void 0 : _e[0];
437
+ const value1 = (_f = ruleProps == null ? void 0 : ruleProps.value) == null ? void 0 : _f[1];
438
+ const fieldDef = (_g = fields.find((f) => f.key === field)) != null ? _g : fields[0];
439
+ const isBooleanField = (fieldDef == null ? void 0 : fieldDef.type) === "boolean";
440
+ const availableOperators = isBooleanField ? BOOLEAN_OPERATORS : (_h = fieldDef == null ? void 0 : fieldDef.operators) != null ? _h : ALL_NUMERIC_OPERATORS;
441
+ function handleFieldChange(key) {
442
+ actions.setField(path, key);
443
+ }
444
+ function handleOperatorChange(op) {
445
+ actions.setOperator(path, op);
446
+ }
447
+ function handleValueChange(idx, raw) {
448
+ const n = parseFloat(parseCommas(raw));
449
+ if (!isNaN(n)) {
450
+ actions.setValue(path, idx, n, "number");
451
+ } else if (!raw) {
452
+ actions.setValue(path, idx, null, "number");
453
+ }
454
+ }
455
+ function handleBoolChange(v) {
456
+ actions.setValue(path, 0, v === "true", "boolean");
457
+ }
458
+ const valStr = (v) => {
459
+ if (v === null || v === void 0) return "";
460
+ return String(v);
461
+ };
462
+ return /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center gap-1.5", children: [
463
+ /* @__PURE__ */ jsx(SelectAutoWidth, { longestLabel: longestFieldLabel, children: /* @__PURE__ */ jsxs(
464
+ Select,
465
+ {
466
+ value: field,
467
+ onValueChange: (v) => handleFieldChange(v),
468
+ children: [
469
+ /* @__PURE__ */ jsx(SelectTrigger, { size: "sm", className: "w-full", children: /* @__PURE__ */ jsx(SelectValue, { children: (_j = (_i = fields.find((f) => f.key === field)) == null ? void 0 : _i.label) != null ? _j : field }) }),
470
+ /* @__PURE__ */ jsx(SelectContent, { children: fields.map((f) => /* @__PURE__ */ jsx(SelectItem, { value: f.key, children: f.label }, f.key)) })
471
+ ]
472
+ }
473
+ ) }),
474
+ /* @__PURE__ */ jsx(SelectAutoWidth, { longestLabel: longestOperatorLabel, children: /* @__PURE__ */ jsxs(
475
+ Select,
476
+ {
477
+ value: operator,
478
+ onValueChange: (v) => handleOperatorChange(v),
479
+ children: [
480
+ /* @__PURE__ */ jsx(SelectTrigger, { size: "sm", className: "w-full", children: /* @__PURE__ */ jsx(SelectValue, { children: (_k = OPERATOR_LABELS[operator]) != null ? _k : operator }) }),
481
+ /* @__PURE__ */ jsx(SelectContent, { children: availableOperators.map((op) => /* @__PURE__ */ jsx(SelectItem, { value: op, children: OPERATOR_LABELS[op] }, op)) })
482
+ ]
483
+ }
484
+ ) }),
485
+ isBooleanField ? /* @__PURE__ */ jsxs(
486
+ Select,
487
+ {
488
+ value: String(value0 != null ? value0 : true),
489
+ onValueChange: (v) => handleBoolChange(v),
490
+ children: [
491
+ /* @__PURE__ */ jsx(SelectTrigger, { size: "sm", className: "w-36", children: /* @__PURE__ */ jsx(SelectValue, { children: (value0 != null ? value0 : true) ? "Yes" : "No" }) }),
492
+ /* @__PURE__ */ jsxs(SelectContent, { children: [
493
+ /* @__PURE__ */ jsx(SelectItem, { value: "true", children: "Yes" }),
494
+ /* @__PURE__ */ jsx(SelectItem, { value: "false", children: "No" })
495
+ ] })
496
+ ]
497
+ }
498
+ ) : /* @__PURE__ */ jsxs(Fragment, { children: [
499
+ /* @__PURE__ */ jsx(
500
+ ValueInput,
501
+ {
502
+ value: valStr(value0),
503
+ onChange: (v) => handleValueChange(0, v),
504
+ unit: fieldDef == null ? void 0 : fieldDef.unit
505
+ }
506
+ ),
507
+ operator === "between" && /* @__PURE__ */ jsxs(Fragment, { children: [
508
+ /* @__PURE__ */ jsx("span", { className: "text-xs text-muted-foreground", children: "and" }),
509
+ /* @__PURE__ */ jsx(
510
+ ValueInput,
511
+ {
512
+ value: valStr(value1),
513
+ onChange: (v) => handleValueChange(1, v),
514
+ unit: fieldDef == null ? void 0 : fieldDef.unit
515
+ }
516
+ )
517
+ ] })
518
+ ] })
519
+ ] });
520
+ }
521
+ function RuleAccordionItem({
522
+ ruleId,
523
+ ruleProps,
524
+ path,
525
+ actions,
526
+ fields,
527
+ longestFieldLabel,
528
+ longestOperatorLabel,
529
+ removable
530
+ }) {
531
+ const summary = ruleSummary(ruleProps, fields);
532
+ return /* @__PURE__ */ jsxs(AccordionPrimitive.Item, { value: ruleId, className: "border-b", children: [
533
+ /* @__PURE__ */ jsxs(AccordionPrimitive.Header, { className: "flex items-center", children: [
534
+ /* @__PURE__ */ jsxs(
535
+ AccordionPrimitive.Trigger,
536
+ {
537
+ className: cn(
538
+ "flex flex-1 items-center gap-3 py-3 text-left text-sm outline-none",
539
+ "rounded-none hover:underline",
540
+ "focus-visible:ring-2 focus-visible:ring-foreground/30",
541
+ "[&[data-panel-open]>svg:last-child]:rotate-180"
542
+ ),
543
+ children: [
544
+ /* @__PURE__ */ jsx("span", { className: "flex-1 text-sm text-foreground", children: summary }),
545
+ /* @__PURE__ */ jsx(ChevronDownIcon, { className: "size-4 shrink-0 text-muted-foreground transition-transform duration-200" })
546
+ ]
547
+ }
548
+ ),
549
+ /* @__PURE__ */ jsx(
550
+ Button,
551
+ {
552
+ type: "button",
553
+ variant: "ghost",
554
+ size: "sm",
555
+ className: "shrink-0 px-2",
556
+ onClick: () => actions.removeRule(path),
557
+ disabled: !removable,
558
+ "aria-label": "Remove rule",
559
+ children: /* @__PURE__ */ jsx(Trash2Icon, { className: "size-4" })
560
+ }
561
+ )
562
+ ] }),
563
+ /* @__PURE__ */ jsx(AccordionPrimitive.Panel, { className: "overflow-hidden h-(--accordion-panel-height) transition-[height] duration-200 ease-out data-starting-style:h-0 data-ending-style:h-0", children: /* @__PURE__ */ jsx("div", { className: "pb-3", children: /* @__PURE__ */ jsx(
564
+ RuleEditorFields,
565
+ {
566
+ ruleProps,
567
+ path,
568
+ actions,
569
+ fields,
570
+ longestFieldLabel,
571
+ longestOperatorLabel
572
+ }
573
+ ) }) })
574
+ ] });
575
+ }
576
+ function SubGroupAccordionItem({
577
+ groupId,
578
+ group,
579
+ path,
580
+ actions,
581
+ fields,
582
+ longestFieldLabel,
583
+ longestOperatorLabel
584
+ }) {
585
+ var _a, _b, _c;
586
+ const conjunction = (_b = (_a = group.properties) == null ? void 0 : _a.conjunction) != null ? _b : "AND";
587
+ const nestedChildren = (_c = group.children1) != null ? _c : [];
588
+ const count = nestedChildren.length;
589
+ const triggerLabel = `Group (${count} ${count === 1 ? "rule" : "rules"})`;
590
+ return /* @__PURE__ */ jsxs(AccordionPrimitive.Item, { value: groupId, className: "border-b", children: [
591
+ /* @__PURE__ */ jsxs(AccordionPrimitive.Header, { className: "flex items-center", children: [
592
+ /* @__PURE__ */ jsxs(
593
+ AccordionPrimitive.Trigger,
594
+ {
595
+ className: cn(
596
+ "flex flex-1 items-center gap-3 py-3 text-left text-sm outline-none",
597
+ "rounded-none hover:underline",
598
+ "focus-visible:ring-2 focus-visible:ring-foreground/30",
599
+ "[&[data-panel-open]>svg:last-child]:rotate-180"
600
+ ),
601
+ children: [
602
+ /* @__PURE__ */ jsx("span", { className: "flex-1 text-sm font-medium text-foreground", children: triggerLabel }),
603
+ /* @__PURE__ */ jsx(ChevronDownIcon, { className: "size-4 shrink-0 text-muted-foreground transition-transform duration-200" })
604
+ ]
605
+ }
606
+ ),
607
+ /* @__PURE__ */ jsx(
608
+ Button,
609
+ {
610
+ type: "button",
611
+ variant: "ghost",
612
+ size: "sm",
613
+ className: "shrink-0 px-2",
614
+ onClick: () => actions.removeGroup(path),
615
+ "aria-label": "Remove group",
616
+ children: /* @__PURE__ */ jsx(Trash2Icon, { className: "size-4" })
617
+ }
618
+ )
619
+ ] }),
620
+ /* @__PURE__ */ jsx(AccordionPrimitive.Panel, { className: "overflow-hidden h-(--accordion-panel-height) transition-[height] duration-200 ease-out data-starting-style:h-0 data-ending-style:h-0", children: /* @__PURE__ */ jsxs("div", { className: "pb-3 pl-4 border-l ml-2 flex flex-col gap-3", children: [
621
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
622
+ /* @__PURE__ */ jsx(
623
+ Checkbox,
624
+ {
625
+ id: `subgroup-${groupId}-combinator`,
626
+ checked: conjunction === "AND",
627
+ onCheckedChange: (checked) => actions.setConjunction(path, checked ? "AND" : "OR")
628
+ }
629
+ ),
630
+ /* @__PURE__ */ jsx(
631
+ Label,
632
+ {
633
+ htmlFor: `subgroup-${groupId}-combinator`,
634
+ className: "cursor-pointer font-normal text-sm",
635
+ children: "Match all conditions"
636
+ }
637
+ ),
638
+ /* @__PURE__ */ jsxs("span", { className: "text-xs text-muted-foreground", children: [
639
+ "(",
640
+ conjunction,
641
+ ")"
642
+ ] })
643
+ ] }),
644
+ nestedChildren.map((child) => {
645
+ var _a2;
646
+ const c = child;
647
+ const ruleId = (_a2 = c.id) != null ? _a2 : "";
648
+ const rulePath = [...path, ruleId];
649
+ return /* @__PURE__ */ jsxs("div", { className: "flex items-start gap-1.5", children: [
650
+ /* @__PURE__ */ jsx("div", { className: "flex-1", children: /* @__PURE__ */ jsx(
651
+ RuleEditorFields,
652
+ {
653
+ ruleProps: c.properties,
654
+ path: rulePath,
655
+ actions,
656
+ fields,
657
+ longestFieldLabel,
658
+ longestOperatorLabel
659
+ }
660
+ ) }),
661
+ /* @__PURE__ */ jsx(
662
+ Button,
663
+ {
664
+ type: "button",
665
+ variant: "ghost",
666
+ size: "sm",
667
+ className: "shrink-0 px-2",
668
+ onClick: () => actions.removeRule(rulePath),
669
+ disabled: nestedChildren.length <= 1,
670
+ "aria-label": "Remove rule",
671
+ children: /* @__PURE__ */ jsx(Trash2Icon, { className: "size-4" })
672
+ }
673
+ )
674
+ ] }, ruleId);
675
+ }),
676
+ /* @__PURE__ */ jsxs(
677
+ Button,
678
+ {
679
+ type: "button",
680
+ variant: "ghost",
681
+ size: "sm",
682
+ onClick: () => actions.addRule(path),
683
+ className: "w-fit",
684
+ children: [
685
+ /* @__PURE__ */ jsx(PlusIcon, { className: "size-4" }),
686
+ "Add rule"
687
+ ]
688
+ }
689
+ )
690
+ ] }) })
691
+ ] });
692
+ }
693
+ function CustomBuilderUI({
694
+ tree,
695
+ actions,
696
+ fields,
697
+ defaultOpenItems,
698
+ className
699
+ }) {
700
+ var _a, _b, _c, _d;
701
+ const treeJson = QbUtils3.getTree(tree);
702
+ const rootId = (_a = treeJson == null ? void 0 : treeJson.id) != null ? _a : "root";
703
+ const conjunction = (_c = (_b = treeJson == null ? void 0 : treeJson.properties) == null ? void 0 : _b.conjunction) != null ? _c : "AND";
704
+ const children = (_d = treeJson == null ? void 0 : treeJson.children1) != null ? _d : [];
705
+ const longestFieldLabel = React.useMemo(
706
+ () => longestOf(fields.map((f) => f.label)),
707
+ [fields]
708
+ );
709
+ const longestOperatorLabel = React.useMemo(
710
+ () => longestOf(allOperatorLabels(fields)),
711
+ [fields]
712
+ );
713
+ return /* @__PURE__ */ jsxs("div", { className: cn("flex flex-col gap-3", className), children: [
714
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
715
+ /* @__PURE__ */ jsx(
716
+ Checkbox,
717
+ {
718
+ id: "qb-root-combinator",
719
+ checked: conjunction === "AND",
720
+ onCheckedChange: (checked) => actions.setConjunction([rootId], checked ? "AND" : "OR")
721
+ }
722
+ ),
723
+ /* @__PURE__ */ jsx(
724
+ Label,
725
+ {
726
+ htmlFor: "qb-root-combinator",
727
+ className: "cursor-pointer font-normal text-sm",
728
+ children: "Match all conditions"
729
+ }
730
+ ),
731
+ /* @__PURE__ */ jsxs("span", { className: "text-xs text-muted-foreground", children: [
732
+ "(",
733
+ conjunction,
734
+ ")"
735
+ ] })
736
+ ] }),
737
+ /* @__PURE__ */ jsx(
738
+ AccordionPrimitive.Root,
739
+ {
740
+ multiple: true,
741
+ defaultValue: defaultOpenItems,
742
+ className: "border-t",
743
+ children: children.map((child) => {
744
+ var _a2;
745
+ const c = child;
746
+ const childId = (_a2 = c.id) != null ? _a2 : "";
747
+ const childPath = [rootId, childId];
748
+ if (c.type === "group") {
749
+ return /* @__PURE__ */ jsx(
750
+ SubGroupAccordionItem,
751
+ {
752
+ groupId: childId,
753
+ group: c,
754
+ path: childPath,
755
+ actions,
756
+ fields,
757
+ longestFieldLabel,
758
+ longestOperatorLabel
759
+ },
760
+ childId
761
+ );
762
+ }
763
+ return /* @__PURE__ */ jsx(
764
+ RuleAccordionItem,
765
+ {
766
+ ruleId: childId,
767
+ ruleProps: c.properties,
768
+ path: childPath,
769
+ actions,
770
+ fields,
771
+ longestFieldLabel,
772
+ longestOperatorLabel,
773
+ removable: children.length > 1
774
+ },
775
+ childId
776
+ );
777
+ })
778
+ }
779
+ ),
780
+ /* @__PURE__ */ jsxs("div", { className: "flex gap-2", children: [
781
+ /* @__PURE__ */ jsxs(
782
+ Button,
783
+ {
784
+ type: "button",
785
+ variant: "outline",
786
+ size: "sm",
787
+ onClick: () => actions.addRule([rootId]),
788
+ children: [
789
+ /* @__PURE__ */ jsx(PlusIcon, { className: "size-4" }),
790
+ "Add rule"
791
+ ]
792
+ }
793
+ ),
794
+ /* @__PURE__ */ jsxs(
795
+ Button,
796
+ {
797
+ type: "button",
798
+ variant: "outline",
799
+ size: "sm",
800
+ onClick: () => actions.addGroup([rootId]),
801
+ children: [
802
+ /* @__PURE__ */ jsx(PlusIcon, { className: "size-4" }),
803
+ "Add group"
804
+ ]
805
+ }
806
+ )
807
+ ] })
808
+ ] });
809
+ }
810
+
811
+ // src/components/ui/contact-alert-dialog/contact-alert-dialog.tsx
812
+ import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
813
+ function ContactAlertQueryBuilder({
814
+ value,
815
+ onChange,
816
+ fields = ALERT_QUERY_FIELDS,
817
+ className
818
+ }) {
819
+ const defaultOpenItems = React2.useMemo(() => {
820
+ var _a;
821
+ const json = QbUtils4.getTree(value);
822
+ return ((_a = json == null ? void 0 : json.children1) != null ? _a : []).map((c) => {
823
+ var _a2;
824
+ return (_a2 = c.id) != null ? _a2 : "";
825
+ }).filter(Boolean);
826
+ }, []);
827
+ const renderBuilder = React2.useCallback(
828
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
829
+ (props) => /* @__PURE__ */ jsx2(
830
+ CustomBuilderUI,
831
+ {
832
+ tree: props.tree,
833
+ actions: props.actions,
834
+ fields,
835
+ defaultOpenItems,
836
+ className
837
+ }
838
+ ),
839
+ [fields, defaultOpenItems, className]
840
+ );
841
+ return /* @__PURE__ */ jsx2(
842
+ Query,
843
+ __spreadProps(__spreadValues({}, QB_CONFIG), {
844
+ value,
845
+ onChange: (newTree) => onChange(newTree),
846
+ renderBuilder
847
+ })
848
+ );
849
+ }
850
+ function ContactAlertDialog({
851
+ open,
852
+ onOpenChange,
853
+ mode = "create",
854
+ initialName = "",
855
+ initialSeverity = "NEED_ACTION",
856
+ initialQuery,
857
+ isCompanyAdmin = false,
858
+ initialShareAcrossCompany = false,
859
+ onSave,
860
+ isLoading = false,
861
+ className
862
+ }) {
863
+ const [name, setName] = React2.useState(initialName);
864
+ const [severity, setSeverity] = React2.useState(initialSeverity);
865
+ const [tree, setTree] = React2.useState(
866
+ () => createAlertTree(initialQuery)
867
+ );
868
+ const [shareAcrossCompany, setShareAcrossCompany] = React2.useState(
869
+ initialShareAcrossCompany
870
+ );
871
+ React2.useEffect(() => {
872
+ if (open) {
873
+ setName(initialName);
874
+ setSeverity(initialSeverity);
875
+ setTree(createAlertTree(initialQuery));
876
+ setShareAcrossCompany(initialShareAcrossCompany);
877
+ }
878
+ }, [open]);
879
+ const hasValidRule = React2.useMemo(() => isTreeValid(tree), [tree]);
880
+ const canSave = name.trim().length > 0 && hasValidRule && !isLoading;
881
+ function handleSave() {
882
+ if (!canSave) return;
883
+ onSave({
884
+ name: name.trim(),
885
+ severity,
886
+ filterSegment: QbUtils4.sanitizeTree(tree, QB_CONFIG).fixedTree,
887
+ sharingType: shareAcrossCompany ? "COMPANY" /* COMPANY */ : "PRIVATE" /* PRIVATE */
888
+ });
889
+ }
890
+ return /* @__PURE__ */ jsx2(Dialog, { open, onOpenChange: isLoading ? void 0 : onOpenChange, children: /* @__PURE__ */ jsxs2(DialogContent, { size: "2xl", className, children: [
891
+ /* @__PURE__ */ jsx2(DialogHeader, { children: /* @__PURE__ */ jsx2(DialogTitle, { children: mode === "edit" ? "Update Alert" : "Create Alert" }) }),
892
+ /* @__PURE__ */ jsxs2("div", { className: "flex flex-col gap-1.5", children: [
893
+ /* @__PURE__ */ jsx2("p", { className: "text-sm font-medium text-foreground", children: "Alert trigger severity" }),
894
+ /* @__PURE__ */ jsx2(
895
+ ToggleGroup,
896
+ {
897
+ type: "single",
898
+ variant: "outline",
899
+ size: "sm",
900
+ value: severity,
901
+ onValueChange: (v) => v && setSeverity(v),
902
+ children: ["NEED_ACTION", "WATCH", "INSIGHT"].map((s) => /* @__PURE__ */ jsx2(ToggleGroupItem, { value: s, children: SEVERITY_LABELS[s] }, s))
903
+ }
904
+ )
905
+ ] }),
906
+ /* @__PURE__ */ jsxs2(Field, { children: [
907
+ /* @__PURE__ */ jsx2(FieldLabel, { children: "Alert name" }),
908
+ /* @__PURE__ */ jsx2(
909
+ Input,
910
+ {
911
+ value: name,
912
+ onChange: (e) => setName(e.target.value),
913
+ placeholder: "e.g. High equity opportunity"
914
+ }
915
+ )
916
+ ] }),
917
+ isCompanyAdmin && /* @__PURE__ */ jsxs2("div", { className: "flex items-center gap-2", children: [
918
+ /* @__PURE__ */ jsx2(
919
+ Checkbox,
920
+ {
921
+ id: "alert-share",
922
+ checked: shareAcrossCompany,
923
+ onCheckedChange: (v) => setShareAcrossCompany(!!v)
924
+ }
925
+ ),
926
+ /* @__PURE__ */ jsx2(Label, { htmlFor: "alert-share", className: "cursor-pointer font-normal", children: "Share across company" })
927
+ ] }),
928
+ /* @__PURE__ */ jsxs2("div", { className: "flex flex-col gap-1.5", children: [
929
+ /* @__PURE__ */ jsx2("p", { className: "text-sm font-medium text-foreground", children: "Filter conditions" }),
930
+ /* @__PURE__ */ jsx2(
931
+ ContactAlertQueryBuilder,
932
+ {
933
+ value: tree,
934
+ onChange: setTree,
935
+ fields: ALERT_QUERY_FIELDS
936
+ }
937
+ )
938
+ ] }),
939
+ /* @__PURE__ */ jsxs2(DialogFooter, { children: [
940
+ /* @__PURE__ */ jsx2(
941
+ Button,
942
+ {
943
+ variant: "outline",
944
+ onClick: () => onOpenChange(false),
945
+ disabled: isLoading,
946
+ children: "Cancel"
947
+ }
948
+ ),
949
+ /* @__PURE__ */ jsx2(Button, { disabled: !canSave, onClick: handleSave, children: mode === "edit" ? "Update Alert" : "Create Alert" })
950
+ ] })
951
+ ] }) });
952
+ }
953
+
954
+ export {
955
+ AlertSharingType,
956
+ ALERT_QUERY_FIELDS,
957
+ createAlertTree,
958
+ ContactAlertQueryBuilder,
959
+ ContactAlertDialog
960
+ };