@fayz-ai/plugin-financial 0.25.9 → 0.26.0

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 (34) hide show
  1. package/dist/CashRegistersView-2G7DTIAA.js +4 -0
  2. package/dist/CashRegistersView-2G7DTIAA.js.map +1 -0
  3. package/dist/CommissionRulesView-2RW4ZCDT.js +878 -0
  4. package/dist/CommissionRulesView-2RW4ZCDT.js.map +1 -0
  5. package/dist/FinancialGeneralSettings-WXJOCJPZ.js +3 -0
  6. package/dist/FinancialGeneralSettings-WXJOCJPZ.js.map +1 -0
  7. package/dist/FinancialPage-PGODULVH.js +6484 -0
  8. package/dist/FinancialPage-PGODULVH.js.map +1 -0
  9. package/dist/PersonStatementWidget-ULXXXYZ4.js +214 -0
  10. package/dist/PersonStatementWidget-ULXXXYZ4.js.map +1 -0
  11. package/dist/chunk-7VKJLBYY.js +1736 -0
  12. package/dist/chunk-7VKJLBYY.js.map +1 -0
  13. package/dist/chunk-CNXAVGSW.js +13 -0
  14. package/dist/chunk-CNXAVGSW.js.map +1 -0
  15. package/dist/chunk-K37Q7SKX.js +4340 -0
  16. package/dist/chunk-K37Q7SKX.js.map +1 -0
  17. package/dist/chunk-MGDAJLUQ.js +823 -0
  18. package/dist/chunk-MGDAJLUQ.js.map +1 -0
  19. package/dist/chunk-POYZFEAN.js +64 -0
  20. package/dist/chunk-POYZFEAN.js.map +1 -0
  21. package/dist/components/BatchClassify.d.ts +26 -0
  22. package/dist/components/BatchClassify.d.ts.map +1 -0
  23. package/dist/components/CashSessionHeaderControl.d.ts.map +1 -1
  24. package/dist/index.d.ts.map +1 -1
  25. package/dist/index.js +4944 -45345
  26. package/dist/index.js.map +1 -1
  27. package/dist/migrations/main.browser.js +143 -0
  28. package/dist/migrations/main.browser.js.map +1 -0
  29. package/dist/migrations/main.js +26230 -0
  30. package/dist/migrations/main.js.map +1 -0
  31. package/dist/payable-agent-TCKHUAQG.js +3 -0
  32. package/dist/payable-agent-TCKHUAQG.js.map +1 -0
  33. package/dist/views/ReconciliationView.d.ts.map +1 -1
  34. package/package.json +11 -5
@@ -0,0 +1,878 @@
1
+ import React from 'react';
2
+ import { Plus, AlertTriangle, Filter, TrendingUp, Copy, Pencil, DollarSign, Trash2, Info } from 'lucide-react';
3
+ import { SubpageHeader, Button, Skeleton, Badge, TooltipProvider, ConfirmDialog, Tooltip, TooltipTrigger, TooltipContent, MultiSelect, Modal, ModalContent, ModalHeader, ModalTitle, ModalDescription, ModalBody, Input, Textarea, Checkbox, ModalFooter, Select, SelectTrigger, SelectValue, SelectContent, SelectItem } from '@fayz-ai/ui';
4
+ import { PageActions } from '@fayz-ai/admin';
5
+ import { UNENFORCED_CRITERIA } from '@fayz-ai/financial/domain/commission';
6
+ import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
7
+
8
+ // src/views/CommissionRulesView.tsx
9
+ var WEEKDAYS = [
10
+ { value: 1, label: "Segunda" },
11
+ { value: 2, label: "Ter\xE7a" },
12
+ { value: 3, label: "Quarta" },
13
+ { value: 4, label: "Quinta" },
14
+ { value: 5, label: "Sexta" },
15
+ { value: 6, label: "S\xE1bado" },
16
+ { value: 0, label: "Domingo" }
17
+ ];
18
+ function CommissionRuleDialog({
19
+ rule,
20
+ catalogs,
21
+ hasDefault,
22
+ provider,
23
+ onClose,
24
+ onSaved
25
+ }) {
26
+ const [name, setName] = React.useState(rule?.name ?? "");
27
+ const [description, setDescription] = React.useState(rule?.description ?? "");
28
+ const [priority, setPriority] = React.useState(String(rule?.priority ?? 1));
29
+ const [isActive, setIsActive] = React.useState(rule?.isActive ?? true);
30
+ const [isDefault, setIsDefault] = React.useState(rule?.isDefault ?? !hasDefault);
31
+ const [saving, setSaving] = React.useState(false);
32
+ const [error, setError] = React.useState(null);
33
+ const initial = React.useMemo(() => {
34
+ const get = (t, key = "ids") => rule?.criteria.find((c) => c.criteriaType === t)?.criteriaValue?.[key] ?? [];
35
+ return {
36
+ services: get("service"),
37
+ categories: get("category"),
38
+ professionals: get("professional"),
39
+ units: get("unit"),
40
+ weekdays: get("weekday", "days"),
41
+ ranges: get("time_range", "ranges")
42
+ };
43
+ }, [rule]);
44
+ const [services, setServices] = React.useState(initial.services);
45
+ const [categories, setCategories] = React.useState(initial.categories);
46
+ const [professionals, setProfessionals] = React.useState(initial.professionals);
47
+ const [units, setUnits] = React.useState(initial.units);
48
+ const [weekdays, setWeekdays] = React.useState(initial.weekdays);
49
+ const [ranges, setRanges] = React.useState(initial.ranges);
50
+ const criteriaCount = [services, categories, professionals, units].filter((a) => a.length > 0).length + (weekdays.length ? 1 : 0) + (ranges.length ? 1 : 0);
51
+ async function handleSave() {
52
+ if (!name.trim()) {
53
+ setError("A regra precisa de um nome.");
54
+ return;
55
+ }
56
+ setSaving(true);
57
+ setError(null);
58
+ try {
59
+ const criteria = [
60
+ { criteriaType: "service", criteriaValue: { ids: services } },
61
+ { criteriaType: "category", criteriaValue: { ids: categories } },
62
+ { criteriaType: "professional", criteriaValue: { ids: professionals } },
63
+ { criteriaType: "unit", criteriaValue: { ids: units } },
64
+ { criteriaType: "weekday", criteriaValue: { days: weekdays } },
65
+ // Faixa pela metade não é faixa: gravá-la tornaria a regra mais
66
+ // específica e restringiria por um horário que ninguém terminou de
67
+ // escrever.
68
+ { criteriaType: "time_range", criteriaValue: { ranges: ranges.filter((r) => r.from && r.to) } }
69
+ ];
70
+ await provider.saveCommissionRule?.({
71
+ id: rule?.id,
72
+ name: name.trim(),
73
+ description: description.trim() || null,
74
+ priority: Number(priority) || 0,
75
+ isDefault,
76
+ isActive,
77
+ criteria
78
+ });
79
+ await onSaved();
80
+ } catch (e) {
81
+ setError(e?.message ?? String(e));
82
+ } finally {
83
+ setSaving(false);
84
+ }
85
+ }
86
+ return /* @__PURE__ */ jsx(Modal, { open: true, onOpenChange: (o) => {
87
+ if (!o) onClose();
88
+ }, children: /* @__PURE__ */ jsxs(ModalContent, { size: "2xl", noPadding: true, className: "gap-0", children: [
89
+ /* @__PURE__ */ jsxs(ModalHeader, { className: "border-b px-5 py-4", children: [
90
+ /* @__PURE__ */ jsx(ModalTitle, { className: "text-base", children: rule ? "Editar regra de comiss\xE3o" : "Nova regra de comiss\xE3o" }),
91
+ /* @__PURE__ */ jsx(ModalDescription, { className: "text-xs", children: criteriaCount === 0 ? "Sem crit\xE9rios, esta regra vale para todos os atendimentos." : `${criteriaCount} crit\xE9rio${criteriaCount > 1 ? "s" : ""} \u2014 quanto mais casarem, mais forte a regra.` })
92
+ ] }),
93
+ /* @__PURE__ */ jsx(ModalBody, { className: "fz-container px-5 py-4", children: /* @__PURE__ */ jsxs("div", { className: "space-y-5", children: [
94
+ /* @__PURE__ */ jsxs("div", { className: "space-y-3", children: [
95
+ /* @__PURE__ */ jsxs("div", { children: [
96
+ /* @__PURE__ */ jsx("label", { className: "text-[10px] font-medium uppercase text-muted-foreground", children: "Nome da regra" }),
97
+ /* @__PURE__ */ jsx(
98
+ Input,
99
+ {
100
+ value: name,
101
+ onChange: (e) => setName(e.target.value),
102
+ placeholder: "Ex.: Ultrassom 15%",
103
+ className: "mt-0.5"
104
+ }
105
+ )
106
+ ] }),
107
+ /* @__PURE__ */ jsxs("div", { children: [
108
+ /* @__PURE__ */ jsx("label", { className: "text-[10px] font-medium uppercase text-muted-foreground", children: "Descri\xE7\xE3o" }),
109
+ /* @__PURE__ */ jsx(
110
+ Textarea,
111
+ {
112
+ value: description,
113
+ onChange: (e) => setDescription(e.target.value),
114
+ rows: 2,
115
+ placeholder: "O que esta regra faz, em uma frase.",
116
+ className: "mt-0.5 resize-none px-2 py-1.5 text-xs"
117
+ }
118
+ )
119
+ ] }),
120
+ /* @__PURE__ */ jsxs("div", { className: "fz-fields fz-fields-2", children: [
121
+ /* @__PURE__ */ jsxs("div", { children: [
122
+ /* @__PURE__ */ jsx("label", { className: "text-[10px] font-medium uppercase text-muted-foreground", children: "Prioridade" }),
123
+ /* @__PURE__ */ jsx(Input, { type: "number", value: priority, onChange: (e) => setPriority(e.target.value), className: "mt-0.5" }),
124
+ /* @__PURE__ */ jsx("p", { className: "mt-1 text-[10px] text-muted-foreground", children: "S\xF3 desempata quando duas regras casam o mesmo n\xFAmero de crit\xE9rios (maior vence)." })
125
+ ] }),
126
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-2 pt-4", children: [
127
+ /* @__PURE__ */ jsxs("label", { className: "flex items-center gap-2 text-xs", children: [
128
+ /* @__PURE__ */ jsx(Checkbox, { checked: isActive, onChange: setIsActive }),
129
+ " Regra ativa"
130
+ ] }),
131
+ /* @__PURE__ */ jsxs("label", { className: "flex items-center gap-2 text-xs", children: [
132
+ /* @__PURE__ */ jsx(Checkbox, { checked: isDefault, onChange: setIsDefault }),
133
+ " Regra padr\xE3o da casa"
134
+ ] }),
135
+ isDefault && /* @__PURE__ */ jsx("p", { className: "text-[10px] text-muted-foreground", children: "Vale quando nenhuma outra casa. Os crit\xE9rios abaixo deixam de importar." })
136
+ ] })
137
+ ] })
138
+ ] }),
139
+ !isDefault && /* @__PURE__ */ jsxs("div", { className: "space-y-3 border-t pt-4", children: [
140
+ /* @__PURE__ */ jsxs("div", { children: [
141
+ /* @__PURE__ */ jsx("h4", { className: "text-sm font-semibold", children: "Crit\xE9rios de aplica\xE7\xE3o" }),
142
+ /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground", children: "Crit\xE9rio vazio vale para todos. Quanto mais crit\xE9rios casarem com o atendimento, mais espec\xEDfica \u2014 e mais forte \u2014 a regra." })
143
+ ] }),
144
+ /* @__PURE__ */ jsxs("div", { className: "fz-fields fz-fields-2", children: [
145
+ /* @__PURE__ */ jsx(Field, { label: "Servi\xE7os", children: /* @__PURE__ */ jsx(
146
+ MultiSelect,
147
+ {
148
+ allLabel: "Todos os servi\xE7os",
149
+ value: services,
150
+ onChange: setServices,
151
+ options: catalogs.services.map((s) => ({ value: s.id, label: s.name }))
152
+ }
153
+ ) }),
154
+ /* @__PURE__ */ jsx(Field, { label: "Grupos de servi\xE7o", children: /* @__PURE__ */ jsx(
155
+ MultiSelect,
156
+ {
157
+ allLabel: "Todos os grupos",
158
+ value: categories,
159
+ onChange: setCategories,
160
+ options: catalogs.categories.map((c) => ({ value: c.id, label: c.name }))
161
+ }
162
+ ) }),
163
+ /* @__PURE__ */ jsx(Field, { label: "Profissionais", children: /* @__PURE__ */ jsx(
164
+ MultiSelect,
165
+ {
166
+ allLabel: "Todos os profissionais",
167
+ value: professionals,
168
+ onChange: setProfessionals,
169
+ options: catalogs.professionals.map((p) => ({ value: p.id, label: p.name }))
170
+ }
171
+ ) }),
172
+ /* @__PURE__ */ jsx(Field, { label: "Unidades", children: /* @__PURE__ */ jsx(
173
+ MultiSelect,
174
+ {
175
+ allLabel: "Todas as unidades",
176
+ value: units,
177
+ onChange: setUnits,
178
+ options: catalogs.units.map((u) => ({ value: u.id, label: u.name }))
179
+ }
180
+ ) })
181
+ ] }),
182
+ /* @__PURE__ */ jsx(Field, { label: "Dias da semana", children: /* @__PURE__ */ jsx("div", { className: "flex flex-wrap gap-3 rounded-input border border-input bg-card px-3 py-2", children: WEEKDAYS.map((d) => /* @__PURE__ */ jsxs("label", { className: "flex items-center gap-1.5 text-xs", children: [
183
+ /* @__PURE__ */ jsx(
184
+ Checkbox,
185
+ {
186
+ checked: weekdays.includes(d.value),
187
+ onChange: (on) => setWeekdays(on ? [...weekdays, d.value] : weekdays.filter((x) => x !== d.value))
188
+ }
189
+ ),
190
+ d.label
191
+ ] }, d.value)) }) }),
192
+ /* @__PURE__ */ jsx(Field, { label: "Faixas de hor\xE1rio", children: /* @__PURE__ */ jsxs("div", { className: "space-y-2 rounded-input border border-input bg-card px-3 py-2", children: [
193
+ ranges.length === 0 && /* @__PURE__ */ jsx("p", { className: "text-[10px] text-muted-foreground", children: "Sem faixa, a regra vale em qualquer hor\xE1rio." }),
194
+ ranges.map((r, i) => /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
195
+ /* @__PURE__ */ jsx(
196
+ Input,
197
+ {
198
+ type: "time",
199
+ value: r.from,
200
+ className: "h-8 w-32 text-xs",
201
+ onChange: (e) => setRanges(ranges.map((x, j) => j === i ? { ...x, from: e.target.value } : x))
202
+ }
203
+ ),
204
+ /* @__PURE__ */ jsx("span", { className: "text-xs text-muted-foreground", children: "\xE0s" }),
205
+ /* @__PURE__ */ jsx(
206
+ Input,
207
+ {
208
+ type: "time",
209
+ value: r.to,
210
+ className: "h-8 w-32 text-xs",
211
+ onChange: (e) => setRanges(ranges.map((x, j) => j === i ? { ...x, to: e.target.value } : x))
212
+ }
213
+ ),
214
+ /* @__PURE__ */ jsx(
215
+ Button,
216
+ {
217
+ variant: "bare",
218
+ size: "bare",
219
+ type: "button",
220
+ "aria-label": "Remover faixa",
221
+ onClick: () => setRanges(ranges.filter((_, j) => j !== i)),
222
+ className: "rounded-button p-1 text-destructive hover:bg-destructive/10",
223
+ children: /* @__PURE__ */ jsx(Trash2, { className: "h-3.5 w-3.5" })
224
+ }
225
+ )
226
+ ] }, i)),
227
+ /* @__PURE__ */ jsxs(Button, { variant: "outline", size: "sm", onClick: () => setRanges([...ranges, { from: "", to: "" }]), children: [
228
+ /* @__PURE__ */ jsx(Plus, { className: "h-3 w-3" }),
229
+ " Faixa"
230
+ ] }),
231
+ /* @__PURE__ */ jsx("p", { className: "text-[10px] text-muted-foreground", children: "Uma faixa que termina antes de come\xE7ar atravessa a meia-noite \u2014 \xE9 assim que se escreve o adicional noturno." })
232
+ ] }) }),
233
+ /* @__PURE__ */ jsxs("div", { className: "flex items-start gap-2 rounded-lg bg-muted/60 px-3 py-2", children: [
234
+ /* @__PURE__ */ jsx(Info, { className: "mt-0.5 h-3.5 w-3.5 shrink-0 text-muted-foreground" }),
235
+ /* @__PURE__ */ jsxs("p", { className: "text-[10px] text-muted-foreground", children: [
236
+ /* @__PURE__ */ jsx("strong", { children: "Ainda n\xE3o dispon\xEDveis:" }),
237
+ " ",
238
+ UNENFORCED_CRITERIA.map((c) => LABEL[c]).join(", "),
239
+ ". Profiss\xF5es e grupos de profissionais n\xE3o t\xEAm cadastro nesta vers\xE3o; a forma de pagamento s\xF3 se conhece quando o pagamento acontece, depois de a comiss\xE3o ser resolvida."
240
+ ] })
241
+ ] })
242
+ ] }),
243
+ error && /* @__PURE__ */ jsx("p", { className: "text-xs text-destructive", children: error })
244
+ ] }) }),
245
+ /* @__PURE__ */ jsxs(ModalFooter, { variant: "bar", children: [
246
+ /* @__PURE__ */ jsx(Button, { variant: "outline", size: "sm", onClick: onClose, children: "Cancelar" }),
247
+ /* @__PURE__ */ jsx(Button, { size: "sm", onClick: handleSave, disabled: saving || !name.trim(), children: saving ? "Salvando\u2026" : "Salvar" })
248
+ ] })
249
+ ] }) });
250
+ }
251
+ var LABEL = {
252
+ profession: "Profiss\xF5es",
253
+ professional_group: "Grupos de Profissionais",
254
+ payment_method_type: "Formas de Pagamento"
255
+ };
256
+ function Field({ label, children }) {
257
+ return /* @__PURE__ */ jsxs("div", { children: [
258
+ /* @__PURE__ */ jsx("label", { className: "text-[10px] font-medium uppercase text-muted-foreground", children: label }),
259
+ /* @__PURE__ */ jsx("div", { className: "mt-0.5", children })
260
+ ] });
261
+ }
262
+ var ACCOUNT_TYPES = [
263
+ { value: "professional_executor", label: "Profissional executor" },
264
+ { value: "professional", label: "Profissional espec\xEDfico" },
265
+ { value: "supplier", label: "Fornecedor" },
266
+ { value: "select_on_launch", label: "Selecionar no lan\xE7amento" }
267
+ ];
268
+ var BASES = [
269
+ { value: "total", label: "Total (bruto)" },
270
+ { value: "net", label: "L\xEDquido de descontos" }
271
+ ];
272
+ var TIER_MODES = [
273
+ { value: "none", label: "Nenhuma (valor por atendimento)" },
274
+ { value: "marginal", label: "Marginal (sobre o excedente de cada faixa)" },
275
+ { value: "retroactive", label: "Retroativa (faixa atingida aplica sobre o total)" },
276
+ { value: "guaranteed_min", label: "M\xEDnimo garantido (c\xE1lculo normal com piso)" }
277
+ ];
278
+ function blankFunction(order) {
279
+ return {
280
+ functionName: "Profissional",
281
+ accountType: "professional_executor",
282
+ valueType: "percentage",
283
+ valueAmount: 0,
284
+ calculationBase: "net",
285
+ tierMode: "none",
286
+ minGuaranteed: null,
287
+ tiers: [],
288
+ isVariable: false,
289
+ displayOrder: order,
290
+ isActive: true
291
+ };
292
+ }
293
+ function CommissionFunctionsDialog({ rule, provider, onClose, onSaved }) {
294
+ const [functions, setFunctions] = React.useState(
295
+ rule.functions.length ? rule.functions : [blankFunction(0)]
296
+ );
297
+ const [saving, setSaving] = React.useState(false);
298
+ const [error, setError] = React.useState(null);
299
+ function patch(i, changes) {
300
+ setFunctions((fs) => fs.map((f, j) => j === i ? { ...f, ...changes } : f));
301
+ }
302
+ async function handleSave() {
303
+ setSaving(true);
304
+ setError(null);
305
+ try {
306
+ await provider.saveCommissionFunctions?.(rule.id, functions);
307
+ await onSaved();
308
+ } catch (e) {
309
+ setError(e?.message ?? String(e));
310
+ } finally {
311
+ setSaving(false);
312
+ }
313
+ }
314
+ return /* @__PURE__ */ jsx(Modal, { open: true, onOpenChange: (o) => {
315
+ if (!o) onClose();
316
+ }, children: /* @__PURE__ */ jsxs(ModalContent, { size: "2xl", noPadding: true, className: "gap-0", children: [
317
+ /* @__PURE__ */ jsxs(ModalHeader, { className: "border-b px-5 py-4", children: [
318
+ /* @__PURE__ */ jsxs(ModalTitle, { className: "text-base", children: [
319
+ "Fun\xE7\xF5es para comiss\xE3o \u2014 ",
320
+ rule.name
321
+ ] }),
322
+ /* @__PURE__ */ jsx(ModalDescription, { className: "text-xs", children: "Quem recebe e quanto. Uma regra pode pagar mais de uma pessoa pelo mesmo atendimento." })
323
+ ] }),
324
+ /* @__PURE__ */ jsx(ModalBody, { className: "fz-container px-5 py-4", children: /* @__PURE__ */ jsxs("div", { className: "space-y-3", children: [
325
+ functions.map((fn, i) => /* @__PURE__ */ jsxs("div", { className: "rounded-card border bg-card p-3", children: [
326
+ /* @__PURE__ */ jsxs("div", { className: "fz-fields fz-fields-3", children: [
327
+ /* @__PURE__ */ jsx(Field2, { label: "Fun\xE7\xE3o", children: /* @__PURE__ */ jsx(
328
+ Input,
329
+ {
330
+ value: fn.functionName,
331
+ placeholder: "Ex.: Profissional",
332
+ className: "h-9 text-xs",
333
+ onChange: (e) => patch(i, { functionName: e.target.value })
334
+ }
335
+ ) }),
336
+ /* @__PURE__ */ jsx(Field2, { label: "Conta padr\xE3o", children: /* @__PURE__ */ jsx(
337
+ ChoiceSelect,
338
+ {
339
+ value: fn.accountType,
340
+ onChange: (v) => patch(i, { accountType: v }),
341
+ options: ACCOUNT_TYPES
342
+ }
343
+ ) }),
344
+ /* @__PURE__ */ jsx(Field2, { label: "Sobre", children: /* @__PURE__ */ jsx(
345
+ ChoiceSelect,
346
+ {
347
+ value: fn.calculationBase,
348
+ onChange: (v) => patch(i, { calculationBase: v }),
349
+ options: BASES
350
+ }
351
+ ) })
352
+ ] }),
353
+ /* @__PURE__ */ jsxs("div", { className: "fz-fields fz-fields-2 mt-3", children: [
354
+ /* @__PURE__ */ jsx(Field2, { label: "Faixa de produ\xE7\xE3o", children: /* @__PURE__ */ jsx(
355
+ ChoiceSelect,
356
+ {
357
+ value: fn.tierMode,
358
+ onChange: (v) => patch(i, { tierMode: v }),
359
+ options: TIER_MODES
360
+ }
361
+ ) }),
362
+ (fn.tierMode === "none" || fn.tierMode === "guaranteed_min") && /* @__PURE__ */ jsx(Field2, { label: "Valor", children: /* @__PURE__ */ jsxs("div", { className: "flex gap-2", children: [
363
+ /* @__PURE__ */ jsx(
364
+ Input,
365
+ {
366
+ type: "number",
367
+ value: String(fn.valueAmount),
368
+ className: "h-9 flex-1 text-xs",
369
+ onChange: (e) => patch(i, { valueAmount: Number(e.target.value) || 0 })
370
+ }
371
+ ),
372
+ /* @__PURE__ */ jsx(
373
+ ChoiceSelect,
374
+ {
375
+ className: "w-20",
376
+ value: fn.valueType,
377
+ onChange: (v) => patch(i, { valueType: v }),
378
+ options: [{ value: "percentage", label: "%" }, { value: "fixed", label: "R$" }]
379
+ }
380
+ )
381
+ ] }) })
382
+ ] }),
383
+ fn.tierMode === "guaranteed_min" && /* @__PURE__ */ jsx("div", { className: "mt-3", children: /* @__PURE__ */ jsxs(Field2, { label: "Piso mensal garantido (R$)", children: [
384
+ /* @__PURE__ */ jsx(
385
+ Input,
386
+ {
387
+ type: "number",
388
+ className: "h-9 text-xs",
389
+ value: fn.minGuaranteed == null ? "" : String(fn.minGuaranteed),
390
+ onChange: (e) => patch(i, { minGuaranteed: e.target.value === "" ? null : Number(e.target.value) })
391
+ }
392
+ ),
393
+ /* @__PURE__ */ jsx("p", { className: "mt-1 text-[10px] text-muted-foreground", children: "Recebe o maior entre o piso e a soma do c\xE1lculo normal no per\xEDodo." })
394
+ ] }) }),
395
+ (fn.tierMode === "marginal" || fn.tierMode === "retroactive") && /* @__PURE__ */ jsx(
396
+ TierTable,
397
+ {
398
+ tiers: fn.tiers,
399
+ onChange: (tiers) => patch(i, { tiers })
400
+ }
401
+ ),
402
+ /* @__PURE__ */ jsxs("div", { className: "mt-3 flex items-center justify-between", children: [
403
+ /* @__PURE__ */ jsxs("label", { className: "flex items-center gap-2 text-xs", children: [
404
+ /* @__PURE__ */ jsx(Checkbox, { checked: fn.isVariable, onChange: (v) => patch(i, { isVariable: v }) }),
405
+ "Valor vari\xE1vel"
406
+ ] }),
407
+ /* @__PURE__ */ jsx(
408
+ Button,
409
+ {
410
+ variant: "bare",
411
+ size: "bare",
412
+ type: "button",
413
+ "aria-label": "Remover fun\xE7\xE3o",
414
+ onClick: () => setFunctions(functions.filter((_, j) => j !== i)),
415
+ className: "rounded-button p-1.5 text-destructive hover:bg-destructive/10",
416
+ children: /* @__PURE__ */ jsx(Trash2, { className: "h-3.5 w-3.5" })
417
+ }
418
+ )
419
+ ] })
420
+ ] }, i)),
421
+ functions.length === 0 && /* @__PURE__ */ jsx("p", { className: "rounded-lg bg-warning/5 px-3 py-2 text-xs text-foreground", children: "Sem nenhuma fun\xE7\xE3o, a apura\xE7\xE3o paga o executor usando o valor da pr\xF3pria regra." }),
422
+ /* @__PURE__ */ jsxs(Button, { variant: "outline", size: "sm", onClick: () => setFunctions([...functions, blankFunction(functions.length)]), children: [
423
+ /* @__PURE__ */ jsx(Plus, { className: "h-3.5 w-3.5" }),
424
+ " Adicionar fun\xE7\xE3o"
425
+ ] }),
426
+ error && /* @__PURE__ */ jsx("p", { className: "text-xs text-destructive", children: error })
427
+ ] }) }),
428
+ /* @__PURE__ */ jsxs(ModalFooter, { variant: "bar", children: [
429
+ /* @__PURE__ */ jsx(Button, { variant: "outline", size: "sm", onClick: onClose, children: "Fechar" }),
430
+ /* @__PURE__ */ jsx(Button, { size: "sm", onClick: handleSave, disabled: saving, children: saving ? "Salvando\u2026" : "Salvar" })
431
+ ] })
432
+ ] }) });
433
+ }
434
+ function TierTable({ tiers, onChange }) {
435
+ function patch(i, changes) {
436
+ onChange(tiers.map((t, j) => j === i ? { ...t, ...changes } : t));
437
+ }
438
+ return /* @__PURE__ */ jsxs("div", { className: "mt-3 rounded-lg border px-3 py-2", children: [
439
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
440
+ /* @__PURE__ */ jsx("p", { className: "text-xs font-medium", children: "Faixas sobre a produ\xE7\xE3o do per\xEDodo" }),
441
+ /* @__PURE__ */ jsxs(
442
+ Button,
443
+ {
444
+ variant: "outline",
445
+ size: "sm",
446
+ onClick: () => onChange([...tiers, { from: tiers.length ? 0 : 0, to: null, fixed: null, percent: null }]),
447
+ children: [
448
+ /* @__PURE__ */ jsx(Plus, { className: "h-3 w-3" }),
449
+ " Faixa"
450
+ ]
451
+ }
452
+ )
453
+ ] }),
454
+ tiers.length > 0 && /* @__PURE__ */ jsxs("div", { className: "mt-2 space-y-1.5", children: [
455
+ /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-[1fr_1fr_1fr_1fr_auto] gap-2 text-[10px] uppercase text-muted-foreground", children: [
456
+ /* @__PURE__ */ jsx("span", { children: "De (R$)" }),
457
+ /* @__PURE__ */ jsx("span", { children: "At\xE9 (vazio = sem limite)" }),
458
+ /* @__PURE__ */ jsx("span", { children: "Fixo (R$)" }),
459
+ /* @__PURE__ */ jsx("span", { children: "ou %" }),
460
+ /* @__PURE__ */ jsx("span", {})
461
+ ] }),
462
+ tiers.map((t, i) => /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-[1fr_1fr_1fr_1fr_auto] items-center gap-2", children: [
463
+ /* @__PURE__ */ jsx(
464
+ Input,
465
+ {
466
+ type: "number",
467
+ className: "h-8 text-xs",
468
+ value: String(t.from ?? 0),
469
+ onChange: (e) => patch(i, { from: Number(e.target.value) || 0 })
470
+ }
471
+ ),
472
+ /* @__PURE__ */ jsx(
473
+ Input,
474
+ {
475
+ type: "number",
476
+ className: "h-8 text-xs",
477
+ value: t.to == null ? "" : String(t.to),
478
+ onChange: (e) => patch(i, { to: e.target.value === "" ? null : Number(e.target.value) })
479
+ }
480
+ ),
481
+ /* @__PURE__ */ jsx(
482
+ Input,
483
+ {
484
+ type: "number",
485
+ className: "h-8 text-xs",
486
+ value: t.fixed == null ? "" : String(t.fixed),
487
+ onChange: (e) => patch(i, { fixed: e.target.value === "" ? null : Number(e.target.value) })
488
+ }
489
+ ),
490
+ /* @__PURE__ */ jsx(
491
+ Input,
492
+ {
493
+ type: "number",
494
+ className: "h-8 text-xs",
495
+ value: t.percent == null ? "" : String(t.percent),
496
+ onChange: (e) => patch(i, { percent: e.target.value === "" ? null : Number(e.target.value) })
497
+ }
498
+ ),
499
+ /* @__PURE__ */ jsx(
500
+ Button,
501
+ {
502
+ variant: "bare",
503
+ size: "bare",
504
+ type: "button",
505
+ "aria-label": "Remover faixa",
506
+ onClick: () => onChange(tiers.filter((_, j) => j !== i)),
507
+ className: "rounded-button p-1 text-destructive hover:bg-destructive/10",
508
+ children: /* @__PURE__ */ jsx(Trash2, { className: "h-3.5 w-3.5" })
509
+ }
510
+ )
511
+ ] }, i))
512
+ ] }),
513
+ /* @__PURE__ */ jsx("p", { className: "mt-2 text-[10px] text-muted-foreground", children: "Ex.: 0\u20131.800 fixo R$ 180; acima de 1.800 \u2192 20% s\xF3 do que passar de 1.800." })
514
+ ] });
515
+ }
516
+ function Field2({ label, children }) {
517
+ return /* @__PURE__ */ jsxs("div", { children: [
518
+ /* @__PURE__ */ jsx("label", { className: "text-[10px] font-medium uppercase text-muted-foreground", children: label }),
519
+ /* @__PURE__ */ jsx("div", { className: "mt-0.5", children })
520
+ ] });
521
+ }
522
+ function ChoiceSelect({
523
+ value,
524
+ onChange,
525
+ options,
526
+ className
527
+ }) {
528
+ return /* @__PURE__ */ jsxs(Select, { value, onValueChange: onChange, children: [
529
+ /* @__PURE__ */ jsx(SelectTrigger, { className: `bg-card px-2 text-xs shadow-[inset_0_1px_0_rgb(0_0_0_/0.06)] ${className ?? ""}`, children: /* @__PURE__ */ jsx(SelectValue, {}) }),
530
+ /* @__PURE__ */ jsx(SelectContent, { children: options.map((o) => /* @__PURE__ */ jsx(SelectItem, { value: o.value, children: o.label }, o.value)) })
531
+ ] });
532
+ }
533
+ var CRITERIA_LABEL = {
534
+ service: "Servi\xE7os",
535
+ category: "Grupos de Servi\xE7o",
536
+ professional: "Profissionais",
537
+ professional_group: "Grupos de Profissionais",
538
+ profession: "Profiss\xF5es",
539
+ unit: "Unidades",
540
+ payment_method_type: "Formas de Pagamento",
541
+ weekday: "Dias da Semana",
542
+ time_range: "Faixas de Hor\xE1rio"
543
+ };
544
+ function ruleMatches(rule, f, catalogs) {
545
+ for (const c of rule.criteria) {
546
+ const ids = c.criteriaValue?.ids ?? [];
547
+ switch (c.criteriaType) {
548
+ case "service":
549
+ if (!f.serviceId || !ids.includes(f.serviceId)) return false;
550
+ break;
551
+ case "category": {
552
+ const viaService = f.serviceId ? catalogs.services.find((s) => s.id === f.serviceId)?.categoryId ?? void 0 : void 0;
553
+ const cat = f.categoryId ?? viaService;
554
+ if (!cat || !ids.includes(cat)) return false;
555
+ break;
556
+ }
557
+ case "professional":
558
+ if (!f.professionalId || !ids.includes(f.professionalId)) return false;
559
+ break;
560
+ case "unit":
561
+ if (!f.unitId || !ids.includes(f.unitId)) return false;
562
+ break;
563
+ }
564
+ }
565
+ return true;
566
+ }
567
+ function rankRules(rules) {
568
+ return rules.slice().sort((a, b) => {
569
+ if (a.criteria.length !== b.criteria.length) return b.criteria.length - a.criteria.length;
570
+ if (a.priority !== b.priority) return b.priority - a.priority;
571
+ return Number(a.isDefault) - Number(b.isDefault);
572
+ });
573
+ }
574
+ function functionChip(fn) {
575
+ const who = fn.functionName || "Fun\xE7\xE3o";
576
+ if (fn.tierMode === "guaranteed_min") return `${who}: m\xEDnimo garantido`;
577
+ if (fn.tierMode === "marginal" || fn.tierMode === "retroactive") return `${who}: por faixa`;
578
+ return fn.valueType === "percentage" ? `${who}: ${fn.valueAmount}%` : `${who}: R$ ${fn.valueAmount.toFixed(2)}`;
579
+ }
580
+ function CommissionRulesView({ provider }) {
581
+ const [rules, setRules] = React.useState(null);
582
+ const [catalogs, setCatalogs] = React.useState({
583
+ services: [],
584
+ categories: [],
585
+ professionals: [],
586
+ units: []
587
+ });
588
+ const [error, setError] = React.useState(null);
589
+ const [funnel, setFunnel] = React.useState({});
590
+ const [editing, setEditing] = React.useState(null);
591
+ const [functionsFor, setFunctionsFor] = React.useState(null);
592
+ const [deleting, setDeleting] = React.useState(null);
593
+ const load = React.useCallback(async () => {
594
+ try {
595
+ setError(null);
596
+ const [r, c] = await Promise.all([
597
+ provider.getCommissionRules?.() ?? Promise.resolve([]),
598
+ provider.getCommissionCatalogs?.() ?? Promise.resolve(catalogs)
599
+ ]);
600
+ setRules(r);
601
+ setCatalogs(c);
602
+ } catch (e) {
603
+ setError(e?.message ?? String(e));
604
+ setRules([]);
605
+ }
606
+ }, [provider]);
607
+ React.useEffect(() => {
608
+ void load();
609
+ }, [load]);
610
+ const funnelActive = Object.values(funnel).some(Boolean);
611
+ const visible = React.useMemo(() => {
612
+ if (!rules) return [];
613
+ const ranked = rankRules(rules);
614
+ if (!funnelActive) return ranked;
615
+ return ranked.filter((r) => r.isDefault || ruleMatches(r, funnel, catalogs));
616
+ }, [rules, funnel, funnelActive, catalogs]);
617
+ const winner = React.useMemo(() => {
618
+ if (!funnelActive) return null;
619
+ return visible.find((r) => r.isActive && !r.isDefault) ?? visible.find((r) => r.isActive && r.isDefault) ?? null;
620
+ }, [visible, funnelActive]);
621
+ const hasDefault = (rules ?? []).some((r) => r.isDefault && r.isActive);
622
+ async function handleDelete() {
623
+ if (!deleting) return;
624
+ await provider.deleteCommissionRule?.(deleting.id);
625
+ setDeleting(null);
626
+ await load();
627
+ }
628
+ async function handleDuplicate(rule) {
629
+ await provider.duplicateCommissionRule?.(rule.id);
630
+ await load();
631
+ }
632
+ const headerActions = React.useMemo(() => [{
633
+ id: "new-rule",
634
+ label: "Adicionar regra",
635
+ icon: Plus,
636
+ intent: "primary",
637
+ creates: true,
638
+ onSelect: () => setEditing("new")
639
+ }], []);
640
+ return /* @__PURE__ */ jsxs("div", { className: "space-y-4", children: [
641
+ /* @__PURE__ */ jsx(
642
+ SubpageHeader,
643
+ {
644
+ title: "Regras de Comiss\xE3o",
645
+ actions: /* @__PURE__ */ jsx(PageActions, { actions: headerActions })
646
+ }
647
+ ),
648
+ /* @__PURE__ */ jsxs("p", { className: "text-xs text-muted-foreground", children: [
649
+ "A regra ",
650
+ /* @__PURE__ */ jsx("strong", { className: "font-medium text-foreground", children: "mais espec\xEDfica" }),
651
+ " (mais crit\xE9rios casados) vence; a prioridade s\xF3 desempata; a padr\xE3o apanha o resto."
652
+ ] }),
653
+ error && /* @__PURE__ */ jsxs("div", { className: "rounded-card border border-destructive/30 bg-destructive/5 px-4 py-3 text-xs text-destructive", children: [
654
+ "N\xE3o foi poss\xEDvel carregar as regras: ",
655
+ error
656
+ ] }),
657
+ rules && rules.length > 0 && !hasDefault && /* @__PURE__ */ jsxs("div", { className: "flex items-start gap-2 rounded-card border border-warning/30 bg-warning/5 px-4 py-3", children: [
658
+ /* @__PURE__ */ jsx(AlertTriangle, { className: "mt-0.5 h-4 w-4 shrink-0 text-warning" }),
659
+ /* @__PURE__ */ jsxs("p", { className: "text-xs text-foreground", children: [
660
+ /* @__PURE__ */ jsx("strong", { children: "Nenhuma regra padr\xE3o ativa." }),
661
+ " O que n\xE3o casar com nenhuma regra espec\xEDfica n\xE3o vai comissionar \u2014 e isso s\xF3 aparece no fechamento."
662
+ ] })
663
+ ] }),
664
+ /* @__PURE__ */ jsxs("div", { className: "rounded-card border bg-card p-4 shadow-sm", children: [
665
+ /* @__PURE__ */ jsxs("div", { className: "mb-3 flex items-center gap-2", children: [
666
+ /* @__PURE__ */ jsx(Filter, { className: "h-4 w-4 text-muted-foreground" }),
667
+ /* @__PURE__ */ jsx("h3", { className: "text-sm font-semibold", children: "Simular um atendimento" }),
668
+ funnelActive && /* @__PURE__ */ jsx(
669
+ Button,
670
+ {
671
+ variant: "bare",
672
+ size: "bare",
673
+ onClick: () => setFunnel({}),
674
+ className: "font-normal ml-auto text-xs text-muted-foreground underline-offset-2 hover:text-foreground hover:underline",
675
+ children: "Limpar"
676
+ }
677
+ )
678
+ ] }),
679
+ /* @__PURE__ */ jsx("div", { className: "fz-container", children: /* @__PURE__ */ jsxs("div", { className: "fz-fields fz-fields-4", children: [
680
+ /* @__PURE__ */ jsx(
681
+ FunnelField,
682
+ {
683
+ label: "Grupo de Servi\xE7os",
684
+ options: catalogs.categories,
685
+ value: funnel.categoryId,
686
+ onChange: (v) => setFunnel((f) => ({ ...f, categoryId: v }))
687
+ }
688
+ ),
689
+ /* @__PURE__ */ jsx(
690
+ FunnelField,
691
+ {
692
+ label: "Servi\xE7o",
693
+ options: catalogs.services,
694
+ value: funnel.serviceId,
695
+ onChange: (v) => setFunnel((f) => ({ ...f, serviceId: v }))
696
+ }
697
+ ),
698
+ /* @__PURE__ */ jsx(
699
+ FunnelField,
700
+ {
701
+ label: "Profissional",
702
+ options: catalogs.professionals,
703
+ value: funnel.professionalId,
704
+ onChange: (v) => setFunnel((f) => ({ ...f, professionalId: v }))
705
+ }
706
+ ),
707
+ /* @__PURE__ */ jsx(
708
+ FunnelField,
709
+ {
710
+ label: "Unidade",
711
+ options: catalogs.units,
712
+ value: funnel.unitId,
713
+ onChange: (v) => setFunnel((f) => ({ ...f, unitId: v }))
714
+ }
715
+ )
716
+ ] }) }),
717
+ funnelActive && /* @__PURE__ */ jsx("p", { className: "mt-3 rounded-lg bg-muted/60 px-3 py-2 text-xs", children: winner ? /* @__PURE__ */ jsxs(Fragment, { children: [
718
+ "Venceria: ",
719
+ /* @__PURE__ */ jsx("strong", { className: "text-foreground", children: winner.name }),
720
+ winner.isDefault && /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: " (a padr\xE3o)" }),
721
+ winner.functions.length > 0 && /* @__PURE__ */ jsxs("span", { className: "text-muted-foreground", children: [
722
+ " \xB7 ",
723
+ winner.functions.map(functionChip).join(" \xB7 ")
724
+ ] })
725
+ ] }) : /* @__PURE__ */ jsx("span", { className: "text-destructive", children: "Nenhuma regra casa \u2014 este atendimento n\xE3o comissionaria." }) })
726
+ ] }),
727
+ rules === null ? /* @__PURE__ */ jsx("div", { className: "space-y-3", children: [0, 1].map((i) => /* @__PURE__ */ jsxs("div", { className: "rounded-card border bg-card p-4 shadow-sm", children: [
728
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
729
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-5 w-20 rounded-full" }),
730
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-5 w-40" })
731
+ ] }),
732
+ /* @__PURE__ */ jsx(Skeleton, { className: "mt-2 h-3 w-72" }),
733
+ /* @__PURE__ */ jsx(Skeleton, { className: "mt-3 h-5 w-32 rounded-full" })
734
+ ] }, i)) }) : visible.length === 0 ? /* @__PURE__ */ jsxs("div", { className: "rounded-card border bg-card px-4 py-10 text-center", children: [
735
+ /* @__PURE__ */ jsx(TrendingUp, { className: "mx-auto h-8 w-8 text-muted-foreground/40" }),
736
+ /* @__PURE__ */ jsx("p", { className: "mt-2 text-sm font-medium", children: funnelActive ? "Nenhuma regra casa com esta combina\xE7\xE3o" : "Nenhuma regra de comiss\xE3o" }),
737
+ /* @__PURE__ */ jsx("p", { className: "mt-1 text-xs text-muted-foreground", children: funnelActive ? "Este atendimento n\xE3o comissionaria. Crie uma regra padr\xE3o para que nada fique de fora." : "Comece pela regra padr\xE3o \u2014 ela \xE9 o que vale quando nenhuma outra casa." }),
738
+ !funnelActive && /* @__PURE__ */ jsxs(Button, { size: "sm", className: "mt-4", onClick: () => setEditing("new"), children: [
739
+ /* @__PURE__ */ jsx(Plus, { className: "h-3.5 w-3.5" }),
740
+ " Criar regra"
741
+ ] })
742
+ ] }) : /* @__PURE__ */ jsx("div", { className: "space-y-3", children: visible.map((rule) => /* @__PURE__ */ jsx(
743
+ "div",
744
+ {
745
+ className: `rounded-card border bg-card p-4 shadow-sm ${winner?.id === rule.id ? "border-primary/50 ring-1 ring-primary/20" : ""} ${!rule.isActive ? "opacity-60" : ""}`,
746
+ children: /* @__PURE__ */ jsxs("div", { className: "flex items-start justify-between gap-3", children: [
747
+ /* @__PURE__ */ jsxs("div", { className: "min-w-0", children: [
748
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [
749
+ rule.isDefault ? /* @__PURE__ */ jsx(Badge, { variant: "default", className: "text-[10px]", children: "PADR\xC3O" }) : /* @__PURE__ */ jsxs(Badge, { variant: "outline", className: "text-[10px]", children: [
750
+ "REGRA #",
751
+ rule.priority
752
+ ] }),
753
+ /* @__PURE__ */ jsx("span", { className: "text-sm font-semibold text-foreground", children: rule.name }),
754
+ !rule.isActive && /* @__PURE__ */ jsx(Badge, { variant: "secondary", className: "text-[10px]", children: "Inativa" })
755
+ ] }),
756
+ rule.description && /* @__PURE__ */ jsx("p", { className: "mt-1 text-xs italic text-muted-foreground", children: rule.description }),
757
+ /* @__PURE__ */ jsx("div", { className: "mt-2 flex flex-wrap gap-1.5", children: rule.criteria.length === 0 ? (
758
+ // "Sem critério" parece esquecido; "vale para todos" é o
759
+ // que a regra realmente faz.
760
+ /* @__PURE__ */ jsx("span", { className: "text-[10px] text-muted-foreground", children: rule.isDefault ? "Aplicada quando nenhuma outra casa." : "Sem crit\xE9rios \u2014 vale para todos os atendimentos." })
761
+ ) : rule.criteria.map((c) => /* @__PURE__ */ jsxs(Badge, { variant: "outline", className: "text-[10px]", children: [
762
+ CRITERIA_LABEL[c.criteriaType],
763
+ " (",
764
+ countCriteria(c.criteriaValue),
765
+ ")",
766
+ UNENFORCED_CRITERIA.includes(c.criteriaType) && " \u26A0"
767
+ ] }, c.criteriaType)) }),
768
+ /* @__PURE__ */ jsxs("div", { className: "mt-3", children: [
769
+ /* @__PURE__ */ jsx("p", { className: "text-[10px] font-medium uppercase text-muted-foreground", children: "Fun\xE7\xF5es para comiss\xE3o" }),
770
+ /* @__PURE__ */ jsx("div", { className: "mt-1 flex flex-wrap gap-1.5", children: rule.functions.length === 0 ? /* @__PURE__ */ jsx("span", { className: "text-[10px] text-warning", children: "Nenhuma fun\xE7\xE3o \u2014 a apura\xE7\xE3o vai pagar o executor com o valor da regra." }) : rule.functions.map((fn, i) => /* @__PURE__ */ jsx(Badge, { variant: "secondary", className: "text-[10px]", children: functionChip(fn) }, fn.id ?? i)) })
771
+ ] })
772
+ ] }),
773
+ /* @__PURE__ */ jsx(TooltipProvider, { delayDuration: 200, children: /* @__PURE__ */ jsxs("div", { className: "flex shrink-0 items-center gap-1", children: [
774
+ !rule.isDefault && /* @__PURE__ */ jsx(IconButton, { label: "Duplicar regra", onClick: () => void handleDuplicate(rule), children: /* @__PURE__ */ jsx(Copy, { className: "h-3.5 w-3.5" }) }),
775
+ /* @__PURE__ */ jsx(IconButton, { label: "Editar regra", onClick: () => setEditing(rule), children: /* @__PURE__ */ jsx(Pencil, { className: "h-3.5 w-3.5" }) }),
776
+ /* @__PURE__ */ jsx(IconButton, { label: "Fun\xE7\xF5es (quem recebe e quanto)", onClick: () => setFunctionsFor(rule), children: /* @__PURE__ */ jsx(DollarSign, { className: "h-3.5 w-3.5" }) }),
777
+ !rule.isDefault && /* @__PURE__ */ jsx(IconButton, { label: "Excluir regra", destructive: true, onClick: () => setDeleting(rule), children: /* @__PURE__ */ jsx(Trash2, { className: "h-3.5 w-3.5" }) })
778
+ ] }) })
779
+ ] })
780
+ },
781
+ rule.id
782
+ )) }),
783
+ editing && /* @__PURE__ */ jsx(
784
+ CommissionRuleDialog,
785
+ {
786
+ rule: editing === "new" ? null : editing,
787
+ catalogs,
788
+ hasDefault,
789
+ provider,
790
+ onClose: () => setEditing(null),
791
+ onSaved: async () => {
792
+ setEditing(null);
793
+ await load();
794
+ }
795
+ },
796
+ editing === "new" ? "new" : editing.id
797
+ ),
798
+ functionsFor && /* @__PURE__ */ jsx(
799
+ CommissionFunctionsDialog,
800
+ {
801
+ rule: functionsFor,
802
+ provider,
803
+ onClose: () => setFunctionsFor(null),
804
+ onSaved: async () => {
805
+ setFunctionsFor(null);
806
+ await load();
807
+ }
808
+ },
809
+ functionsFor.id
810
+ ),
811
+ /* @__PURE__ */ jsx(
812
+ ConfirmDialog,
813
+ {
814
+ open: !!deleting,
815
+ onCancel: () => setDeleting(null),
816
+ title: "Excluir regra de comiss\xE3o",
817
+ description: `"${deleting?.name ?? ""}" e os seus crit\xE9rios e fun\xE7\xF5es ser\xE3o removidos. Comiss\xF5es j\xE1 apuradas n\xE3o mudam.`,
818
+ confirmLabel: "Excluir",
819
+ variant: "destructive",
820
+ onConfirm: () => {
821
+ void handleDelete();
822
+ }
823
+ }
824
+ )
825
+ ] });
826
+ }
827
+ function countCriteria(v) {
828
+ for (const key of ["ids", "days", "ranges"]) {
829
+ const arr = v?.[key];
830
+ if (Array.isArray(arr)) return arr.length;
831
+ }
832
+ return 0;
833
+ }
834
+ function IconButton({
835
+ label,
836
+ onClick,
837
+ destructive,
838
+ children
839
+ }) {
840
+ return /* @__PURE__ */ jsxs(Tooltip, { children: [
841
+ /* @__PURE__ */ jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx(
842
+ Button,
843
+ {
844
+ variant: "bare",
845
+ size: "bare",
846
+ type: "button",
847
+ "aria-label": label,
848
+ onClick,
849
+ className: `font-normal whitespace-normal fz-tap inline-flex h-7 w-7 items-center justify-center rounded-button border bg-card transition-colors ${destructive ? "text-destructive hover:bg-destructive/10" : "text-muted-foreground hover:bg-muted hover:text-foreground"}`,
850
+ children
851
+ }
852
+ ) }),
853
+ /* @__PURE__ */ jsx(TooltipContent, { className: "text-xs", children: label })
854
+ ] });
855
+ }
856
+ function FunnelField({
857
+ label,
858
+ options,
859
+ value,
860
+ onChange
861
+ }) {
862
+ return /* @__PURE__ */ jsxs("div", { children: [
863
+ /* @__PURE__ */ jsx("label", { className: "text-[10px] font-medium uppercase text-muted-foreground", children: label }),
864
+ /* @__PURE__ */ jsx("div", { className: "mt-0.5", children: /* @__PURE__ */ jsx(
865
+ MultiSelect,
866
+ {
867
+ allLabel: `Qualquer ${label.toLowerCase()}`,
868
+ options: options.map((o) => ({ value: o.id, label: o.name })),
869
+ value: value ? [value] : [],
870
+ onChange: (v) => onChange(v.length ? v[v.length - 1] : void 0)
871
+ }
872
+ ) })
873
+ ] });
874
+ }
875
+
876
+ export { CommissionRulesView };
877
+ //# sourceMappingURL=CommissionRulesView-2RW4ZCDT.js.map
878
+ //# sourceMappingURL=CommissionRulesView-2RW4ZCDT.js.map