@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,823 @@
1
+ import { useFinancialConfig, useFinancialProvider, useFinancialStore, formatCurrency } from './chunk-CNXAVGSW.js';
2
+ import React2, { useState, useEffect, useMemo } from 'react';
3
+ import { ChevronDown, Eye, Inbox, Landmark, Clock, ClipboardCheck, Play, ChevronUp, Calculator, Square, ChevronRight, Printer, X, Check } from 'lucide-react';
4
+ import { useTranslation, currentAppPath, appHref } from '@fayz-ai/core';
5
+ import { Button, SubpageHeader, PageTabs, CurrencyInput, Textarea, Select, SelectTrigger, SelectValue, SelectContent, SelectItem, Skeleton, Modal, ModalContent, ModalHeader, ModalTitle, ModalDescription, ModalBody, ModalFooter, openPrintWindow, printDocument, Input } from '@fayz-ai/ui';
6
+ import { useAuth, GetStarted } from '@fayz-ai/admin';
7
+ import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
8
+
9
+ function CashSessionReviewModal({ sessionId, open, onOpenChange, mode, onReviewed }) {
10
+ const t = useTranslation();
11
+ const { currency } = useFinancialConfig();
12
+ const provider = useFinancialProvider();
13
+ const { user } = useAuth();
14
+ const me = user?.id ?? null;
15
+ const [summary, setSummary] = useState(null);
16
+ const [movements, setMovements] = useState(null);
17
+ const [review, setReview] = useState(null);
18
+ const [error, setError] = useState(null);
19
+ const [busy, setBusy] = useState(false);
20
+ useEffect(() => {
21
+ if (!open) return;
22
+ let cancelled = false;
23
+ setSummary(null);
24
+ setMovements(null);
25
+ setReview(null);
26
+ setError(null);
27
+ async function load() {
28
+ try {
29
+ const [s, m] = await Promise.all([
30
+ provider.getCashSessionSummary(sessionId),
31
+ provider.getMovements({ cashSessionId: sessionId, status: "paid", pageSize: 200 })
32
+ ]);
33
+ if (cancelled) return;
34
+ setSummary(s);
35
+ setMovements(m.data);
36
+ if (mode === "details") {
37
+ const reviews = await provider.getCashSessionReviews?.() ?? [];
38
+ if (cancelled) return;
39
+ setReview(reviews.find((r) => r.sessionId === sessionId) ?? null);
40
+ }
41
+ } catch (e) {
42
+ if (!cancelled) setError(e?.message ?? String(e));
43
+ }
44
+ }
45
+ void load();
46
+ return () => {
47
+ cancelled = true;
48
+ };
49
+ }, [open, sessionId, mode, provider]);
50
+ const session = summary?.session;
51
+ const fechei = !!me && session?.closedByUserId === me;
52
+ const loading = summary === null || movements === null;
53
+ async function decide(verdict) {
54
+ setBusy(true);
55
+ setError(null);
56
+ try {
57
+ await provider.reviewCashSession?.(sessionId, verdict);
58
+ onReviewed?.();
59
+ onOpenChange(false);
60
+ } catch (e) {
61
+ setError(e?.message ?? String(e));
62
+ } finally {
63
+ setBusy(false);
64
+ }
65
+ }
66
+ function handlePrint() {
67
+ if (!session) return;
68
+ const popup = openPrintWindow("width=720,height=900");
69
+ if (!popup) return;
70
+ const title = session.bankAccountName ?? t("financial.cash.title");
71
+ const rows = (movements ?? []).map((m) => `<tr><td>${m.paymentDate ? new Date(m.paymentDate).toLocaleString() : "\u2014"}</td><td>${m.method ? t(`financial.method.${m.method}`) : "\u2014"}</td><td style="text-align:right">${m.direction === "credit" ? "+" : "-"}${formatCurrency(m.paidAmount, currency)}</td></tr>`).join("");
72
+ printDocument({
73
+ title,
74
+ css: "body{font:12px sans-serif}table{width:100%;border-collapse:collapse;margin-top:16px}th,td{border-bottom:1px solid #ddd;padding:8px;text-align:left}h1{font-size:16px;margin-bottom:8px}p{margin:2px 0}",
75
+ body: `<h1>${title}</h1><p>${t("financial.cash.opened")}: ${new Date(session.openedAt).toLocaleString()}${session.openedByName ? ` ${t("financial.cash.by")} ${session.openedByName}` : ""}</p>` + (session.closedAt ? `<p>${t("financial.cash.closeLabel")}: ${new Date(session.closedAt).toLocaleString()}${session.closedByName ? ` ${t("financial.cash.by")} ${session.closedByName}` : ""}</p>` : "") + `<p>${t("financial.cash.openingBalance")}: ${formatCurrency(session.openingBalance, currency)}</p><p>${t("financial.cash.finalValue")}: ${formatCurrency(session.closingBalance ?? 0, currency)}</p><p>${t("financial.cash.difference")}: ${(session.difference ?? 0) >= 0 ? "+" : ""}${formatCurrency(session.difference ?? 0, currency)}</p><table><thead><tr><th>${t("financial.cash.opened")}</th><th>${t("financial.cash.method")}</th><th style="text-align:right">${t("financial.cash.finalValue")}</th></tr></thead><tbody>${rows}</tbody></table>`,
76
+ target: popup
77
+ });
78
+ }
79
+ return /* @__PURE__ */ jsx(Modal, { open, onOpenChange, children: /* @__PURE__ */ jsxs(ModalContent, { size: "lg", noPadding: true, className: "gap-0", children: [
80
+ /* @__PURE__ */ jsxs(ModalHeader, { className: "border-b px-4 py-3", children: [
81
+ /* @__PURE__ */ jsx(ModalTitle, { className: "text-sm", children: mode === "review" ? t("financial.cash.reviewModalTitle") : t("financial.cash.detailsModalTitle") }),
82
+ /* @__PURE__ */ jsx(ModalDescription, { className: "text-xs", children: session?.bankAccountName ?? t("financial.cash.title") })
83
+ ] }),
84
+ /* @__PURE__ */ jsxs(ModalBody, { className: "p-4 space-y-4", children: [
85
+ error && /* @__PURE__ */ jsx("p", { className: "text-xs text-destructive", children: error }),
86
+ loading ? /* @__PURE__ */ jsx("div", { className: "space-y-2", children: [0, 1, 2].map((i) => /* @__PURE__ */ jsx(Skeleton, { className: "h-5 w-full" }, i)) }) : /* @__PURE__ */ jsxs(Fragment, { children: [
87
+ /* @__PURE__ */ jsxs("div", { className: "rounded-lg border bg-muted/30 p-3 space-y-1", children: [
88
+ /* @__PURE__ */ jsx("p", { className: "text-[10px] font-semibold text-muted-foreground uppercase mb-1", children: t("financial.cash.summary") }),
89
+ /* @__PURE__ */ jsx(SummaryRow, { label: t("financial.cash.openingBalance"), value: formatCurrency(session.openingBalance, currency) }),
90
+ /* @__PURE__ */ jsx(SummaryRow, { label: t("financial.cash.finalValue"), value: formatCurrency(session.closingBalance ?? 0, currency), strong: true }),
91
+ /* @__PURE__ */ jsx(
92
+ SummaryRow,
93
+ {
94
+ label: t("financial.cash.difference"),
95
+ value: `${(session.difference ?? 0) >= 0 ? "+" : ""}${formatCurrency(session.difference ?? 0, currency)}`,
96
+ tone: (session.difference ?? 0) > 0 ? "success" : (session.difference ?? 0) < 0 ? "destructive" : void 0
97
+ }
98
+ ),
99
+ /* @__PURE__ */ jsx(SummaryRow, { label: t("financial.cash.movementCount"), value: String(summary.movementCount) }),
100
+ /* @__PURE__ */ jsx(SummaryRow, { label: t("financial.cash.totalIn"), value: formatCurrency(summary.totalInflow, currency) }),
101
+ /* @__PURE__ */ jsx(SummaryRow, { label: t("financial.cash.totalOut"), value: formatCurrency(summary.totalOutflow, currency) })
102
+ ] }),
103
+ /* @__PURE__ */ jsxs("div", { className: "rounded-lg border", children: [
104
+ /* @__PURE__ */ jsx("p", { className: "px-3 py-2 text-[10px] font-semibold text-muted-foreground uppercase border-b", children: t("financial.cash.transactions") }),
105
+ (movements ?? []).length === 0 ? /* @__PURE__ */ jsx("p", { className: "px-3 py-4 text-center text-xs text-muted-foreground", children: t("financial.cash.noTransactions") }) : /* @__PURE__ */ jsx("div", { className: "max-h-64 overflow-y-auto divide-y", children: movements.map((m) => /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between px-3 py-2 text-xs", children: [
106
+ /* @__PURE__ */ jsxs("div", { className: "min-w-0", children: [
107
+ /* @__PURE__ */ jsx("p", { className: "font-medium", children: m.method ? t(`financial.method.${m.method}`) : "\u2014" }),
108
+ /* @__PURE__ */ jsx("p", { className: "text-muted-foreground", children: m.paymentDate ? new Date(m.paymentDate).toLocaleString() : "\u2014" })
109
+ ] }),
110
+ /* @__PURE__ */ jsxs("span", { className: `shrink-0 tabular-nums font-medium ${m.direction === "credit" ? "text-success" : "text-destructive"}`, children: [
111
+ m.direction === "credit" ? "+" : "-",
112
+ formatCurrency(m.paidAmount, currency)
113
+ ] })
114
+ ] }, m.id)) })
115
+ ] }),
116
+ mode === "details" && /* @__PURE__ */ jsxs("p", { className: "text-xs text-muted-foreground", children: [
117
+ review?.reviewStatus === "approved" ? t("financial.cash.verdictApproved") : review?.reviewStatus === "rejected" ? t("financial.cash.verdictRejected") : t("financial.cash.verdictPending"),
118
+ review?.reviewerName ? ` \xB7 ${t("financial.cash.reviewedBy")} ${review.reviewerName}` : ""
119
+ ] }),
120
+ mode === "review" && fechei && /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground", children: t("financial.cash.cannotReviewOwn") })
121
+ ] })
122
+ ] }),
123
+ /* @__PURE__ */ jsxs(ModalFooter, { className: "border-t px-4 py-3", children: [
124
+ /* @__PURE__ */ jsxs(Button, { variant: "outline", size: "sm", onClick: handlePrint, disabled: loading, children: [
125
+ /* @__PURE__ */ jsx(Printer, { className: "h-3.5 w-3.5" }),
126
+ " ",
127
+ t("financial.cash.print")
128
+ ] }),
129
+ mode === "review" && !fechei && /* @__PURE__ */ jsxs(Fragment, { children: [
130
+ /* @__PURE__ */ jsxs(Button, { variant: "outline", size: "sm", disabled: busy || loading, onClick: () => void decide("rejected"), children: [
131
+ /* @__PURE__ */ jsx(X, { className: "h-3.5 w-3.5" }),
132
+ " ",
133
+ t("financial.cash.reject")
134
+ ] }),
135
+ /* @__PURE__ */ jsxs(Button, { size: "sm", disabled: busy || loading, onClick: () => void decide("approved"), children: [
136
+ /* @__PURE__ */ jsx(Check, { className: "h-3.5 w-3.5" }),
137
+ " ",
138
+ t("financial.cash.confirmAndApprove")
139
+ ] })
140
+ ] })
141
+ ] })
142
+ ] }) });
143
+ }
144
+ function SummaryRow({ label, value, strong, tone }) {
145
+ return /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between text-xs", children: [
146
+ /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: label }),
147
+ /* @__PURE__ */ jsx("span", { className: `tabular-nums ${strong ? "text-sm font-bold" : "font-medium"} ${tone === "success" ? "text-success" : tone === "destructive" ? "text-destructive" : ""}`, children: value })
148
+ ] });
149
+ }
150
+ var BRL_DENOMINATIONS = [
151
+ { label: "R$ 200", value: 200, type: "bill" },
152
+ { label: "R$ 100", value: 100, type: "bill" },
153
+ { label: "R$ 50", value: 50, type: "bill" },
154
+ { label: "R$ 20", value: 20, type: "bill" },
155
+ { label: "R$ 10", value: 10, type: "bill" },
156
+ { label: "R$ 5", value: 5, type: "bill" },
157
+ { label: "R$ 2", value: 2, type: "bill" },
158
+ { label: "R$ 1", value: 1, type: "coin" },
159
+ { label: "R$ 0,50", value: 0.5, type: "coin" },
160
+ { label: "R$ 0,25", value: 0.25, type: "coin" },
161
+ { label: "R$ 0,10", value: 0.1, type: "coin" },
162
+ { label: "R$ 0,05", value: 0.05, type: "coin" }
163
+ ];
164
+ function DenominationCounter({
165
+ denominations,
166
+ counts,
167
+ onChange,
168
+ currency
169
+ }) {
170
+ const t = useTranslation();
171
+ const bills = denominations.filter((d) => d.type === "bill");
172
+ const coins = denominations.filter((d) => d.type === "coin");
173
+ function setCount(value, count) {
174
+ onChange({ ...counts, [value]: Math.max(0, count) });
175
+ }
176
+ function renderRow(d) {
177
+ const qty = counts[d.value] ?? 0;
178
+ const subtotal = qty * d.value;
179
+ return (
180
+ // Larguras fixas somavam ~304px por coluna; dentro do diálogo a coluna
181
+ // tem ~200px e "R$ 200" quebrava em duas linhas, deixando as notas com
182
+ // alturas diferentes. O rótulo não quebra e o subtotal é quem cede.
183
+ // `max-w`: numa coluna de 1125px o `flex-1` jogava o subtotal a 380px do
184
+ // "=", e o olho perdia a linha entre a nota e o valor dela.
185
+ /* @__PURE__ */ jsxs("div", { className: "flex max-w-[17rem] items-center gap-1.5 py-1", children: [
186
+ /* @__PURE__ */ jsx("span", { className: "w-14 shrink-0 whitespace-nowrap text-xs font-medium text-muted-foreground", children: d.label }),
187
+ /* @__PURE__ */ jsx("span", { className: "shrink-0 text-muted-foreground text-xs", children: "\xD7" }),
188
+ /* @__PURE__ */ jsx("div", { className: "w-12 shrink-0", children: /* @__PURE__ */ jsx(
189
+ Input,
190
+ {
191
+ type: "number",
192
+ min: 0,
193
+ value: qty || "",
194
+ onChange: (e) => setCount(d.value, parseInt(e.target.value) || 0),
195
+ placeholder: "0",
196
+ className: "h-auto rounded border-border bg-background px-1.5 py-1 text-center text-xs tabular-nums shadow-none"
197
+ }
198
+ ) }),
199
+ /* @__PURE__ */ jsx("span", { className: "shrink-0 text-xs text-muted-foreground", children: "=" }),
200
+ /* @__PURE__ */ jsx("span", { className: "min-w-0 flex-1 whitespace-nowrap text-xs text-right tabular-nums font-medium", children: formatCurrency(subtotal, currency) })
201
+ ] }, d.value)
202
+ );
203
+ }
204
+ return (
205
+ // O contador leva o PRÓPRIO ponto de medida. `fz-fields-2` responde ao
206
+ // `fz-container` mais próximo, e a página do Financeiro não marca um — as
207
+ // notas ficavam numa coluna só com 1125px de largura, enquanto no diálogo
208
+ // (que marca) o `sm:` antigo lia a JANELA e insistia em duas colunas de
209
+ // 200px. Medindo a si mesmo, acerta nos dois lugares.
210
+ /* @__PURE__ */ jsx("div", { className: "fz-container", children: /* @__PURE__ */ jsxs("div", { className: "fz-fields fz-fields-2", children: [
211
+ bills.length > 0 && /* @__PURE__ */ jsxs("div", { children: [
212
+ /* @__PURE__ */ jsx("p", { className: "text-[10px] font-semibold text-muted-foreground uppercase mb-1", children: t("financial.cash.bills") }),
213
+ bills.map(renderRow)
214
+ ] }),
215
+ coins.length > 0 && /* @__PURE__ */ jsxs("div", { children: [
216
+ /* @__PURE__ */ jsx("p", { className: "text-[10px] font-semibold text-muted-foreground uppercase mb-1", children: t("financial.cash.coins") }),
217
+ coins.map(renderRow)
218
+ ] })
219
+ ] }) })
220
+ );
221
+ }
222
+ function CashOpeningPanel({
223
+ cashAccounts,
224
+ currency,
225
+ onOpen
226
+ }) {
227
+ const [selectedAccountId, setSelectedAccountId] = useState(cashAccounts[0]?.id ?? "");
228
+ useEffect(() => {
229
+ if (!cashAccounts.length) return;
230
+ if (!cashAccounts.some((a) => a.id === selectedAccountId)) {
231
+ setSelectedAccountId(cashAccounts[0].id);
232
+ }
233
+ }, [cashAccounts, selectedAccountId]);
234
+ const [balance, setBalance] = useState(0);
235
+ const [submitting, setSubmitting] = useState(false);
236
+ const t = useTranslation();
237
+ const { user } = useAuth();
238
+ if (cashAccounts.length === 0) {
239
+ return /* @__PURE__ */ jsx(
240
+ GetStarted,
241
+ {
242
+ feature: "financial.caixas",
243
+ title: t("financial.cash.title"),
244
+ heading: t("financial.cash.empty.heading"),
245
+ because: t("financial.cash.empty.because"),
246
+ steps: [
247
+ {
248
+ label: t("financial.cash.empty.step"),
249
+ where: t("financial.cash.empty.stepWhere")
250
+ }
251
+ ]
252
+ }
253
+ );
254
+ }
255
+ async function handleOpen() {
256
+ setSubmitting(true);
257
+ try {
258
+ await onOpen(selectedAccountId, balance);
259
+ setBalance(0);
260
+ } finally {
261
+ setSubmitting(false);
262
+ }
263
+ }
264
+ return /* @__PURE__ */ jsxs("div", { className: "p-4 space-y-4", children: [
265
+ /* @__PURE__ */ jsx("div", { className: "fz-container", children: /* @__PURE__ */ jsxs("div", { className: "fz-fields fz-fields-2", children: [
266
+ /* @__PURE__ */ jsxs("div", { children: [
267
+ /* @__PURE__ */ jsx("label", { className: "text-[10px] font-medium text-muted-foreground uppercase", children: t("financial.cash.user") }),
268
+ /* @__PURE__ */ jsx("p", { className: "mt-1 text-sm font-medium truncate", children: user?.email ?? "\u2014" })
269
+ ] }),
270
+ /* @__PURE__ */ jsxs("div", { children: [
271
+ /* @__PURE__ */ jsx("label", { className: "text-[10px] font-medium text-muted-foreground uppercase", children: t("financial.cash.openingDate") }),
272
+ /* @__PURE__ */ jsx("p", { className: "mt-1 text-sm font-medium capitalize", children: (/* @__PURE__ */ new Date()).toLocaleDateString("pt-BR", { weekday: "long", day: "2-digit", month: "long", year: "numeric" }) })
273
+ ] })
274
+ ] }) }),
275
+ /* @__PURE__ */ jsx("div", { className: "fz-container", children: /* @__PURE__ */ jsxs("div", { className: "fz-fields fz-fields-2", children: [
276
+ /* @__PURE__ */ jsx(
277
+ CurrencyInput,
278
+ {
279
+ value: balance,
280
+ onChange: setBalance,
281
+ symbol: currency.symbol,
282
+ locale: currency.locale,
283
+ currencyCode: currency.code,
284
+ label: t("financial.cash.openingBalance")
285
+ }
286
+ ),
287
+ /* @__PURE__ */ jsxs("div", { children: [
288
+ /* @__PURE__ */ jsx("label", { className: "text-[10px] font-medium text-muted-foreground uppercase", children: t("financial.cash.accountLabel") }),
289
+ /* @__PURE__ */ jsxs(Select, { value: selectedAccountId, onValueChange: setSelectedAccountId, children: [
290
+ /* @__PURE__ */ jsx(SelectTrigger, { className: "mt-0.5 h-auto bg-card px-2 py-1.5 text-xs shadow-[inset_0_1px_0_rgb(0_0_0_/0.06)]", children: /* @__PURE__ */ jsx(SelectValue, {}) }),
291
+ /* @__PURE__ */ jsx(SelectContent, { children: cashAccounts.map((a) => /* @__PURE__ */ jsx(SelectItem, { value: a.id, children: a.name }, a.id)) })
292
+ ] })
293
+ ] })
294
+ ] }) }),
295
+ /* @__PURE__ */ jsxs(
296
+ Button,
297
+ {
298
+ variant: "bare",
299
+ size: "bare",
300
+ "data-tour": "financial.cash-open",
301
+ onClick: () => void handleOpen(),
302
+ disabled: submitting || balance < 0,
303
+ className: "inline-flex items-center gap-1.5 rounded-button bg-primary border border-primary px-4 py-1.5 text-xs font-medium text-primary-foreground hover:bg-primary/90 shadow-button-primary active:shadow-button-inset transition-colors disabled:opacity-50",
304
+ children: [
305
+ /* @__PURE__ */ jsx(Inbox, { className: "h-3 w-3" }),
306
+ " ",
307
+ submitting ? t("financial.cash.opening") : t("financial.quickActions.openCashRegister")
308
+ ]
309
+ }
310
+ )
311
+ ] });
312
+ }
313
+ function CashClosingPanel({
314
+ session,
315
+ currency,
316
+ onClose
317
+ }) {
318
+ const [mode, setMode] = useState("quick");
319
+ const [quickBalance, setQuickBalance] = useState(0);
320
+ const [counts, setCounts] = useState({});
321
+ const [notes, setNotes] = useState("");
322
+ const [submitting, setSubmitting] = useState(false);
323
+ const t = useTranslation();
324
+ const countedTotal = useMemo(() => {
325
+ return BRL_DENOMINATIONS.reduce((sum, d) => sum + (counts[d.value] ?? 0) * d.value, 0);
326
+ }, [counts]);
327
+ const effectiveBalance = mode === "count" ? countedTotal : quickBalance;
328
+ const expected = session.expectedCash ?? session.openingBalance;
329
+ const difference = effectiveBalance - expected;
330
+ async function handleClose() {
331
+ setSubmitting(true);
332
+ try {
333
+ await onClose(session.id, effectiveBalance, notes || void 0);
334
+ } finally {
335
+ setSubmitting(false);
336
+ }
337
+ }
338
+ return /* @__PURE__ */ jsxs("div", { className: "space-y-3 pt-3 border-t", children: [
339
+ /* @__PURE__ */ jsxs("div", { className: "flex gap-1 rounded-lg border p-0.5 w-fit", children: [
340
+ /* @__PURE__ */ jsx(
341
+ Button,
342
+ {
343
+ variant: "bare",
344
+ size: "bare",
345
+ onClick: () => setMode("quick"),
346
+ className: `px-3 py-1 text-xs rounded-md font-medium transition-colors ${mode === "quick" ? "bg-primary text-primary-foreground" : "hover:bg-muted"}`,
347
+ children: t("financial.cash.quickAmount")
348
+ }
349
+ ),
350
+ /* @__PURE__ */ jsxs(
351
+ Button,
352
+ {
353
+ variant: "bare",
354
+ size: "bare",
355
+ onClick: () => setMode("count"),
356
+ className: `inline-flex items-center gap-1 px-3 py-1 text-xs rounded-md font-medium transition-colors ${mode === "count" ? "bg-primary text-primary-foreground" : "hover:bg-muted"}`,
357
+ children: [
358
+ /* @__PURE__ */ jsx(Calculator, { className: "h-3 w-3" }),
359
+ " ",
360
+ t("financial.cash.count")
361
+ ]
362
+ }
363
+ )
364
+ ] }),
365
+ mode === "quick" ? /* @__PURE__ */ jsx(
366
+ CurrencyInput,
367
+ {
368
+ value: quickBalance,
369
+ onChange: setQuickBalance,
370
+ symbol: currency.symbol,
371
+ locale: currency.locale,
372
+ currencyCode: currency.code,
373
+ label: t("financial.cash.closingBalance")
374
+ }
375
+ ) : /* @__PURE__ */ jsxs("div", { className: "space-y-3", children: [
376
+ /* @__PURE__ */ jsx(
377
+ DenominationCounter,
378
+ {
379
+ denominations: BRL_DENOMINATIONS,
380
+ counts,
381
+ onChange: setCounts,
382
+ currency
383
+ }
384
+ ),
385
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between pt-2 border-t", children: [
386
+ /* @__PURE__ */ jsx("span", { className: "text-xs font-medium text-muted-foreground uppercase", children: t("financial.cash.countedTotal") }),
387
+ /* @__PURE__ */ jsx("span", { className: "text-lg font-bold", children: formatCurrency(countedTotal, currency) })
388
+ ] })
389
+ ] }),
390
+ session.receivedByMethod && Object.keys(session.receivedByMethod).length > 0 && /* @__PURE__ */ jsxs("div", { className: "rounded-lg border px-3 py-2 space-y-1", children: [
391
+ /* @__PURE__ */ jsx("p", { className: "text-[10px] font-medium text-muted-foreground uppercase", children: t("financial.cash.receivedInShift") }),
392
+ Object.entries(session.receivedByMethod).map(([method, total]) => /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between text-xs", children: [
393
+ /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: t(`financial.method.${method}`) }),
394
+ /* @__PURE__ */ jsx("span", { className: "tabular-nums", children: formatCurrency(Number(total), currency) })
395
+ ] }, method))
396
+ ] }),
397
+ /* @__PURE__ */ jsxs("div", { className: "rounded-lg bg-muted/50 px-3 py-2 space-y-1", children: [
398
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between text-xs", children: [
399
+ /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: t("financial.cash.expectedInDrawer") }),
400
+ /* @__PURE__ */ jsx("span", { className: "tabular-nums font-medium", children: formatCurrency(expected, currency) })
401
+ ] }),
402
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between text-xs", children: [
403
+ /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: t("financial.cash.countedTotal") }),
404
+ /* @__PURE__ */ jsx("span", { className: "tabular-nums font-medium", children: formatCurrency(effectiveBalance, currency) })
405
+ ] }),
406
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between border-t pt-1", children: [
407
+ /* @__PURE__ */ jsx("span", { className: "text-xs font-medium", children: t("financial.cash.difference") }),
408
+ /* @__PURE__ */ jsxs("span", { className: `text-sm font-bold tabular-nums ${difference > 0 ? "text-success" : difference < 0 ? "text-destructive" : "text-muted-foreground"}`, children: [
409
+ difference >= 0 ? "+" : "",
410
+ formatCurrency(difference, currency)
411
+ ] })
412
+ ] })
413
+ ] }),
414
+ /* @__PURE__ */ jsxs("div", { children: [
415
+ /* @__PURE__ */ jsx("label", { className: "text-[10px] font-medium text-muted-foreground uppercase", children: t("financial.cash.closingNotes") }),
416
+ /* @__PURE__ */ jsx(
417
+ Textarea,
418
+ {
419
+ value: notes,
420
+ onChange: (e) => setNotes(e.target.value),
421
+ rows: 2,
422
+ placeholder: t("financial.cash.closingObservations"),
423
+ className: "mt-0.5 px-2 py-1.5 text-xs resize-none"
424
+ }
425
+ )
426
+ ] }),
427
+ /* @__PURE__ */ jsxs(
428
+ Button,
429
+ {
430
+ variant: "destructive",
431
+ size: "sm",
432
+ onClick: handleClose,
433
+ disabled: submitting || effectiveBalance < 0,
434
+ children: [
435
+ /* @__PURE__ */ jsx(Square, { className: "h-3.5 w-3.5" }),
436
+ submitting ? t("financial.cash.closing") : t("financial.cash.closeSession")
437
+ ]
438
+ }
439
+ )
440
+ ] });
441
+ }
442
+ function dayKeyOf(iso) {
443
+ if (!iso) return "";
444
+ const d = new Date(iso);
445
+ return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, "0")}-${String(d.getDate()).padStart(2, "0")}`;
446
+ }
447
+ function groupByClosingDay(rows) {
448
+ const days = [];
449
+ const sorted = [...rows].sort((a, b) => (b.closedAt ?? "").localeCompare(a.closedAt ?? ""));
450
+ for (const r of sorted) {
451
+ const key = dayKeyOf(r.closedAt);
452
+ const last = days[days.length - 1];
453
+ if (last && last.key === key) last.rows.push(r);
454
+ else days.push({ key, rows: [r] });
455
+ }
456
+ return days;
457
+ }
458
+ function DayHeader({ dayKey, count }) {
459
+ const t = useTranslation();
460
+ let label = "\u2014";
461
+ if (dayKey === dayKeyOf((/* @__PURE__ */ new Date()).toISOString())) label = t("financial.cash.reviewToday");
462
+ else if (dayKey === dayKeyOf(new Date(Date.now() - 864e5).toISOString())) label = t("financial.cash.reviewYesterday");
463
+ else if (dayKey) {
464
+ const [y, m, d] = dayKey.split("-").map(Number);
465
+ label = new Date(y, m - 1, d).toLocaleDateString(void 0, { weekday: "long", day: "2-digit", month: "2-digit" });
466
+ }
467
+ return (
468
+ // Stays on screen while its day scrolls, stopping under the page's tab band
469
+ // like a list's column header. Opaque: rows pass underneath it.
470
+ /* @__PURE__ */ jsxs(
471
+ "div",
472
+ {
473
+ className: "sticky z-10 flex items-center gap-2 border-b bg-muted px-4 py-1.5 text-xs font-medium text-muted-foreground",
474
+ style: { top: "var(--fz-page-band-h, 0px)" },
475
+ children: [
476
+ /* @__PURE__ */ jsx("span", { className: "first-letter:uppercase", children: label }),
477
+ /* @__PURE__ */ jsx("span", { className: "rounded-full bg-background px-1.5 text-[10px] tabular-nums", children: count })
478
+ ]
479
+ }
480
+ )
481
+ );
482
+ }
483
+ var HOUR_MINUTE = { hour: "2-digit", minute: "2-digit" };
484
+ var PANEL_REVIEW_LIMIT = 3;
485
+ var REVIEW_TAB_QUERY = "tab=review";
486
+ function ReviewQueue({
487
+ variant,
488
+ rows,
489
+ error,
490
+ onReload,
491
+ showHeader = true
492
+ }) {
493
+ const t = useTranslation();
494
+ const { currency } = useFinancialConfig();
495
+ const { user } = useAuth();
496
+ const me = user?.id ?? null;
497
+ const [reviewing, setReviewing] = useState(null);
498
+ const pendentes = (rows ?? []).filter((r) => r.reviewStatus === "pending");
499
+ const setCashSessionModalOpen = useFinancialStore((s) => s.setCashSessionModalOpen);
500
+ const compact = variant === "panel";
501
+ const shown = compact ? [...pendentes].sort((a, b) => Math.abs(b.difference) - Math.abs(a.difference) || (a.closedAt ?? "").localeCompare(b.closedAt ?? "")).slice(0, PANEL_REVIEW_LIMIT) : pendentes;
502
+ const hidden = pendentes.length - shown.length;
503
+ const days = compact ? [] : groupByClosingDay(pendentes);
504
+ const sectionClass = variant === "panel" ? "" : "rounded-card border bg-card shadow-sm";
505
+ return /* @__PURE__ */ jsxs("div", { className: sectionClass, children: [
506
+ showHeader && /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 border-b px-4 py-3", children: [
507
+ /* @__PURE__ */ jsx(ClipboardCheck, { className: "h-4 w-4 text-info" }),
508
+ /* @__PURE__ */ jsx("h3", { className: "text-sm font-semibold", children: t("financial.cash.reviewQueue") }),
509
+ pendentes.length > 0 && /* @__PURE__ */ jsx("span", { className: "rounded-full bg-info/10 px-2 py-0.5 text-[10px] font-semibold text-info", children: pendentes.length })
510
+ ] }),
511
+ showHeader && !compact && /* @__PURE__ */ jsx("p", { className: "px-4 pt-3 text-[11px] text-muted-foreground", children: "Quem abre e fecha o caixa n\xE3o \xE9 quem confere. Um fechamento fica aqui at\xE9 algu\xE9m da ger\xEAncia ou do financeiro aprovar." }),
512
+ error && /* @__PURE__ */ jsx("p", { className: "px-4 pt-2 text-xs text-destructive", children: error }),
513
+ rows === null ? /* @__PURE__ */ jsx("div", { className: "space-y-2 p-4", children: [0, 1].map((i) => /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
514
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-4 w-48" }),
515
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-7 w-32" })
516
+ ] }, i)) }) : pendentes.length === 0 ? /* @__PURE__ */ jsx("p", { className: "px-4 py-6 text-center text-sm text-muted-foreground", children: t("financial.cash.reviewQueueEmpty") }) : /* @__PURE__ */ jsxs("div", { className: "divide-y", children: [
517
+ (compact ? [{ key: "", rows: shown }] : days).map((day) => /* @__PURE__ */ jsxs(React2.Fragment, { children: [
518
+ !compact && /* @__PURE__ */ jsx(DayHeader, { dayKey: day.key, count: day.rows.length }),
519
+ day.rows.map((r) => {
520
+ const fechei = !!me && r.closedByUserId === me;
521
+ const amount = /* @__PURE__ */ jsxs(Fragment, { children: [
522
+ formatCurrency(r.closingBalance, currency),
523
+ r.difference !== 0 && /* @__PURE__ */ jsxs("span", { className: `ml-2 text-xs tabular-nums ${r.difference > 0 ? "text-success" : "text-destructive"}`, children: [
524
+ r.difference > 0 ? "+" : "",
525
+ formatCurrency(r.difference, currency)
526
+ ] })
527
+ ] });
528
+ const action = fechei ? (
529
+ // Estado que impede não oferece a ação — e diz por quê.
530
+ /* @__PURE__ */ jsx("p", { className: "text-[11px] text-muted-foreground", children: t("financial.cash.cannotReviewOwn") })
531
+ ) : /* @__PURE__ */ jsxs(Button, { variant: "outline", size: "sm", className: "shrink-0", onClick: () => setReviewing(r.sessionId), children: [
532
+ /* @__PURE__ */ jsx(ClipboardCheck, { className: "h-3.5 w-3.5" }),
533
+ " ",
534
+ t("financial.cash.review")
535
+ ] });
536
+ if (compact) {
537
+ return /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3 px-4 py-2", children: [
538
+ /* @__PURE__ */ jsx("p", { className: "shrink-0 text-sm font-medium tabular-nums text-foreground", children: amount }),
539
+ /* @__PURE__ */ jsxs("p", { className: "min-w-0 flex-1 truncate text-xs text-muted-foreground", children: [
540
+ r.closedByName ?? "\u2014",
541
+ r.closedAt ? ` \xB7 ${new Date(r.closedAt).toLocaleDateString(void 0, { day: "2-digit", month: "2-digit" })}` : ""
542
+ ] }),
543
+ action
544
+ ] }, r.sessionId);
545
+ }
546
+ return /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center justify-between gap-3 px-4 py-3", children: [
547
+ /* @__PURE__ */ jsxs("div", { className: "min-w-0", children: [
548
+ /* @__PURE__ */ jsx("p", { className: "text-sm font-medium text-foreground", children: amount }),
549
+ /* @__PURE__ */ jsxs("p", { className: "text-xs text-muted-foreground", children: [
550
+ t("financial.cash.closedBy"),
551
+ " ",
552
+ r.closedByName ?? "\u2014",
553
+ r.closedAt ? ` \xB7 ${new Date(r.closedAt).toLocaleTimeString(void 0, HOUR_MINUTE)}` : ""
554
+ ] })
555
+ ] }),
556
+ action
557
+ ] }, r.sessionId);
558
+ })
559
+ ] }, day.key || "all")),
560
+ hidden > 0 && /* @__PURE__ */ jsxs(
561
+ "a",
562
+ {
563
+ href: appHref(`/financial/cash/registers?${REVIEW_TAB_QUERY}`),
564
+ onClick: () => setCashSessionModalOpen(false),
565
+ className: "flex items-center justify-between px-4 py-2.5 text-xs font-medium text-primary transition-colors hover:bg-muted/50",
566
+ children: [
567
+ t("financial.cash.reviewSeeAll", { count: String(pendentes.length) }),
568
+ /* @__PURE__ */ jsx(ChevronRight, { className: "h-3.5 w-3.5" })
569
+ ]
570
+ }
571
+ )
572
+ ] }),
573
+ reviewing && /* @__PURE__ */ jsx(
574
+ CashSessionReviewModal,
575
+ {
576
+ sessionId: reviewing,
577
+ mode: "review",
578
+ open: true,
579
+ onOpenChange: (o) => {
580
+ if (!o) setReviewing(null);
581
+ },
582
+ onReviewed: () => {
583
+ setReviewing(null);
584
+ onReload();
585
+ }
586
+ }
587
+ )
588
+ ] });
589
+ }
590
+ function CashRegistersView({ variant = "page" } = {}) {
591
+ const t = useTranslation();
592
+ const { currency, labels } = useFinancialConfig();
593
+ const provider = useFinancialProvider();
594
+ const bankAccounts = useFinancialStore((s) => s.bankAccounts);
595
+ const cashSessions = useFinancialStore((s) => s.cashSessions);
596
+ const fetchBankAccounts = useFinancialStore((s) => s.fetchBankAccounts);
597
+ const fetchCashSessions = useFinancialStore((s) => s.fetchCashSessions);
598
+ const openCashSession = useFinancialStore((s) => s.openCashSession);
599
+ const closeCashSession = useFinancialStore((s) => s.closeCashSession);
600
+ const setCashSessionModalOpen = useFinancialStore((s) => s.setCashSessionModalOpen);
601
+ const [expandedClosing, setExpandedClosing] = useState(null);
602
+ const [viewingDetails, setViewingDetails] = useState(null);
603
+ const [tab, setTab] = useState(
604
+ () => currentAppPath().includes(REVIEW_TAB_QUERY) ? "review" : "open"
605
+ );
606
+ const [reviewRows, setReviewRows] = useState(null);
607
+ const [reviewError, setReviewError] = useState(null);
608
+ const loadReviews = React2.useCallback(async () => {
609
+ try {
610
+ setReviewError(null);
611
+ setReviewRows(await provider.getCashSessionReviews?.() ?? []);
612
+ } catch (e) {
613
+ setReviewError(e?.message ?? String(e));
614
+ setReviewRows([]);
615
+ }
616
+ }, [provider]);
617
+ useEffect(() => {
618
+ fetchBankAccounts();
619
+ fetchCashSessions();
620
+ void loadReviews();
621
+ }, []);
622
+ const cashAccounts = bankAccounts.filter((a) => a.accountType === "cash_physical");
623
+ const openSessions = cashSessions.filter((s) => s.status === "open");
624
+ const closedSessions = cashSessions.filter((s) => s.status === "closed");
625
+ const pendingReviews = (reviewRows ?? []).filter((r) => r.reviewStatus === "pending");
626
+ const inPanel = variant === "panel";
627
+ const sectionClass = inPanel ? "" : "rounded-card border bg-card shadow-sm";
628
+ async function handleOpen(accountId, balance, notes) {
629
+ await openCashSession({ bankAccountId: accountId, openingBalance: balance, notes });
630
+ }
631
+ async function handleClose(sessionId, balance, notes) {
632
+ await closeCashSession({ sessionId, closingBalance: balance, notes });
633
+ setExpandedClosing(null);
634
+ }
635
+ const openSessionsList = /* @__PURE__ */ jsx("div", { className: "divide-y", children: openSessions.map((session) => /* @__PURE__ */ jsxs("div", { className: "p-4 space-y-3", children: [
636
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-3", children: [
637
+ /* @__PURE__ */ jsxs("div", { className: "min-w-0", children: [
638
+ /* @__PURE__ */ jsx("p", { className: "text-sm font-medium text-foreground truncate", children: session.bankAccountName ?? t("financial.cash.title") }),
639
+ /* @__PURE__ */ jsxs("p", { className: "text-xs text-muted-foreground", children: [
640
+ t("financial.cash.opened"),
641
+ " ",
642
+ new Date(session.openedAt).toLocaleString(),
643
+ session.openedByName ? ` ${t("financial.cash.by")} ${session.openedByName}` : ""
644
+ ] })
645
+ ] }),
646
+ /* @__PURE__ */ jsxs("div", { className: "text-right shrink-0", children: [
647
+ /* @__PURE__ */ jsx("p", { className: "text-[10px] text-muted-foreground uppercase", children: t("financial.cash.openingBalance") }),
648
+ /* @__PURE__ */ jsx("p", { className: "text-lg font-bold tabular-nums text-foreground", children: formatCurrency(session.openingBalance, currency) })
649
+ ] })
650
+ ] }),
651
+ expandedClosing === session.id ? /* @__PURE__ */ jsx(CashClosingPanel, { session, currency, onClose: handleClose }) : /* @__PURE__ */ jsxs(
652
+ Button,
653
+ {
654
+ variant: "bare",
655
+ size: "bare",
656
+ "data-tour": "financial.cash-close",
657
+ onClick: () => setExpandedClosing(session.id),
658
+ className: "inline-flex items-center gap-1.5 text-xs text-destructive hover:text-destructive font-medium transition-colors",
659
+ children: [
660
+ /* @__PURE__ */ jsx(ChevronDown, { className: "h-3 w-3" }),
661
+ " ",
662
+ t("financial.cash.closeThisSession")
663
+ ]
664
+ }
665
+ )
666
+ ] }, session.id)) });
667
+ const closedSessionsList = /* @__PURE__ */ jsx("div", { className: "divide-y", children: groupByClosingDay(closedSessions).map((day) => /* @__PURE__ */ jsxs(React2.Fragment, { children: [
668
+ /* @__PURE__ */ jsx(DayHeader, { dayKey: day.key, count: day.rows.length }),
669
+ day.rows.map((session) => /* @__PURE__ */ jsx("div", { className: "px-4 py-3", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-3", children: [
670
+ /* @__PURE__ */ jsxs("div", { className: "min-w-0", children: [
671
+ /* @__PURE__ */ jsx("p", { className: "text-sm font-medium", children: session.bankAccountName ?? t("financial.cash.title") }),
672
+ /* @__PURE__ */ jsxs("p", { className: "text-xs text-muted-foreground", children: [
673
+ dayKeyOf(session.openedAt) === dayKeyOf(session.closedAt) ? new Date(session.openedAt).toLocaleTimeString(void 0, HOUR_MINUTE) : new Date(session.openedAt).toLocaleString(void 0, { day: "2-digit", month: "2-digit", ...HOUR_MINUTE }),
674
+ " \u2014 ",
675
+ session.closedAt ? new Date(session.closedAt).toLocaleTimeString(void 0, HOUR_MINUTE) : ""
676
+ ] }),
677
+ session.openedByName && /* @__PURE__ */ jsxs("p", { className: "text-[10px] text-muted-foreground", children: [
678
+ t("financial.cash.by"),
679
+ " ",
680
+ session.openedByName
681
+ ] })
682
+ ] }),
683
+ /* @__PURE__ */ jsxs("div", { className: "flex shrink-0 items-start gap-3", children: [
684
+ /* @__PURE__ */ jsxs("div", { className: "text-right", children: [
685
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3 text-xs text-muted-foreground", children: [
686
+ /* @__PURE__ */ jsxs("span", { children: [
687
+ t("financial.cash.openLabel"),
688
+ ": ",
689
+ formatCurrency(session.openingBalance, currency)
690
+ ] }),
691
+ /* @__PURE__ */ jsxs("span", { children: [
692
+ t("financial.cash.closeLabel"),
693
+ ": ",
694
+ formatCurrency(session.closingBalance ?? 0, currency)
695
+ ] })
696
+ ] }),
697
+ session.difference !== void 0 && session.difference !== 0 && /* @__PURE__ */ jsxs("p", { className: `text-xs font-semibold tabular-nums mt-0.5 ${session.difference > 0 ? "text-success" : "text-destructive"}`, children: [
698
+ t("financial.cash.diff"),
699
+ ": ",
700
+ session.difference >= 0 ? "+" : "",
701
+ formatCurrency(session.difference, currency)
702
+ ] }),
703
+ session.notes && /* @__PURE__ */ jsx("p", { className: "text-[10px] text-muted-foreground mt-0.5 max-w-[200px] truncate", title: session.notes, children: session.notes })
704
+ ] }),
705
+ /* @__PURE__ */ jsxs(Button, { variant: "ghost", size: "sm", onClick: () => setViewingDetails(session.id), children: [
706
+ /* @__PURE__ */ jsx(Eye, { className: "h-3.5 w-3.5" }),
707
+ " ",
708
+ t("financial.cash.details")
709
+ ] })
710
+ ] })
711
+ ] }) }, session.id))
712
+ ] }, day.key || "all")) });
713
+ return /* @__PURE__ */ jsxs("div", { className: inPanel ? "" : "space-y-4", children: [
714
+ !inPanel && /* @__PURE__ */ jsx(
715
+ SubpageHeader,
716
+ {
717
+ title: labels.cashRegisters ?? t("financial.cash.title"),
718
+ subtitle: t("financial.cash.subtitle"),
719
+ actions: cashAccounts.length > openSessions.length ? (
720
+ // A ABERTURA mora no diálogo da casca, não na página: este botão
721
+ // abre O MESMO modal do ícone do cabeçalho, em vez de desenhar o
722
+ // formulário de novo aqui dentro.
723
+ /* @__PURE__ */ jsxs(Button, { "data-tour": "financial.cash-open", size: "sm", onClick: () => setCashSessionModalOpen(true), children: [
724
+ /* @__PURE__ */ jsx(Inbox, { className: "h-3.5 w-3.5" }),
725
+ " ",
726
+ t("financial.quickActions.openCashRegister")
727
+ ] })
728
+ ) : void 0
729
+ }
730
+ ),
731
+ inPanel ? /* @__PURE__ */ jsxs(Fragment, { children: [
732
+ /* @__PURE__ */ jsxs("div", { className: sectionClass, children: [
733
+ /* @__PURE__ */ jsx("div", { className: "flex items-center justify-between px-4 py-3 border-b", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
734
+ /* @__PURE__ */ jsx(Landmark, { className: "h-4 w-4 text-info" }),
735
+ /* @__PURE__ */ jsx("h3", { className: "text-sm font-semibold", children: t("financial.cash.openSessions") }),
736
+ openSessions.length > 0 && /* @__PURE__ */ jsx("span", { className: "rounded-full bg-info/10 text-info px-2 py-0.5 text-[10px] font-semibold", children: openSessions.length })
737
+ ] }) }),
738
+ openSessions.length === 0 ? /* @__PURE__ */ jsx(CashOpeningPanel, { cashAccounts, currency, onOpen: handleOpen }) : openSessionsList
739
+ ] }),
740
+ openSessions.length > 0 && cashAccounts.length > openSessions.length && /* @__PURE__ */ jsx("div", { className: "border-t", children: /* @__PURE__ */ jsx(OpenAnotherCollapsible, { cashAccounts, openSessions, currency, onOpen: handleOpen, variant }) }),
741
+ /* @__PURE__ */ jsx(ReviewQueue, { variant, rows: reviewRows, error: reviewError, onReload: loadReviews }),
742
+ /* @__PURE__ */ jsxs(
743
+ "a",
744
+ {
745
+ href: appHref("/financial/cash/registers"),
746
+ className: "flex items-center gap-2 border-t px-4 py-3 text-xs font-medium text-muted-foreground transition-colors hover:bg-muted/50 hover:text-foreground",
747
+ children: [
748
+ /* @__PURE__ */ jsx(Clock, { className: "h-3.5 w-3.5" }),
749
+ t("financial.cash.sessionHistory"),
750
+ closedSessions.length > 0 && /* @__PURE__ */ jsxs("span", { className: "text-[10px] text-muted-foreground", children: [
751
+ "(",
752
+ closedSessions.length,
753
+ ")"
754
+ ] })
755
+ ]
756
+ }
757
+ )
758
+ ] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
759
+ /* @__PURE__ */ jsx(
760
+ PageTabs,
761
+ {
762
+ "aria-label": labels.cashRegisters ?? t("financial.cash.title"),
763
+ value: tab,
764
+ onChange: setTab,
765
+ tabs: [
766
+ { value: "open", label: t("financial.cash.tabOpen"), icon: Landmark, count: openSessions.length },
767
+ { value: "closed", label: t("financial.cash.tabClosed"), icon: Clock, count: closedSessions.length },
768
+ { value: "review", label: t("financial.cash.tabReview"), icon: ClipboardCheck, count: pendingReviews.length }
769
+ ]
770
+ }
771
+ ),
772
+ tab === "open" && /* @__PURE__ */ jsx("div", { className: sectionClass, children: openSessions.length === 0 ? /* @__PURE__ */ jsx("p", { className: "px-4 py-8 text-center text-sm text-muted-foreground", children: t("financial.cash.noOpenSessions") }) : openSessionsList }),
773
+ tab === "closed" && /* @__PURE__ */ jsx("div", { className: sectionClass, children: closedSessions.length === 0 ? /* @__PURE__ */ jsx("div", { className: "px-4 py-8 text-center text-sm text-muted-foreground", children: t("financial.cash.noClosedSessions") }) : closedSessionsList }),
774
+ tab === "review" && /* @__PURE__ */ jsx(ReviewQueue, { variant, rows: reviewRows, error: reviewError, onReload: loadReviews, showHeader: false })
775
+ ] }),
776
+ viewingDetails && /* @__PURE__ */ jsx(
777
+ CashSessionReviewModal,
778
+ {
779
+ sessionId: viewingDetails,
780
+ mode: "details",
781
+ open: true,
782
+ onOpenChange: (o) => {
783
+ if (!o) setViewingDetails(null);
784
+ }
785
+ }
786
+ )
787
+ ] });
788
+ }
789
+ function OpenAnotherCollapsible({
790
+ cashAccounts,
791
+ openSessions,
792
+ currency,
793
+ onOpen,
794
+ variant = "page"
795
+ }) {
796
+ const t = useTranslation();
797
+ const [expanded, setExpanded] = useState(false);
798
+ const availableAccounts = cashAccounts.filter((a) => !openSessions.some((s) => s.bankAccountId === a.id));
799
+ if (availableAccounts.length === 0) return null;
800
+ return /* @__PURE__ */ jsxs("div", { className: variant === "panel" ? "" : "rounded-card border bg-card shadow-sm", children: [
801
+ /* @__PURE__ */ jsxs(
802
+ Button,
803
+ {
804
+ variant: "bare",
805
+ size: "bare",
806
+ onClick: () => setExpanded(!expanded),
807
+ className: "gap-0 rounded-none whitespace-normal w-full flex items-center justify-between px-4 py-3 text-xs font-medium hover:bg-muted/50 transition-colors",
808
+ children: [
809
+ /* @__PURE__ */ jsxs("span", { className: "flex items-center gap-2", children: [
810
+ /* @__PURE__ */ jsx(Play, { className: "h-3 w-3 text-primary" }),
811
+ t("financial.cash.openAnother")
812
+ ] }),
813
+ expanded ? /* @__PURE__ */ jsx(ChevronUp, { className: "h-3 w-3" }) : /* @__PURE__ */ jsx(ChevronDown, { className: "h-3 w-3" })
814
+ ]
815
+ }
816
+ ),
817
+ expanded && /* @__PURE__ */ jsx(CashOpeningPanel, { cashAccounts: availableAccounts, currency, onOpen })
818
+ ] });
819
+ }
820
+
821
+ export { CashRegistersView };
822
+ //# sourceMappingURL=chunk-MGDAJLUQ.js.map
823
+ //# sourceMappingURL=chunk-MGDAJLUQ.js.map