@fayz-ai/plugin-financial 0.27.0 → 0.27.1

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.
@@ -6,7 +6,7 @@ import { formatCurrency, FinancialContextProvider, useFinancialConfig, useFinanc
6
6
  import * as React15 from 'react';
7
7
  import React15__default, { memo, useState, useMemo, useCallback, useEffect, useRef } from 'react';
8
8
  import { useTranslation, navigateApp, appHref, useUnitMode, useDataChanged, describeError, resolveCurrency, exportCSV, formatCurrency as formatCurrency$1 } from '@fayz-ai/core';
9
- import { Badge, Select, SelectTrigger, SelectValue, SelectContent, SelectItem, Input, PageTransition, ModulePage, Button, DashboardCanvas, ComingSoon, SubpageHeader, PageTabs, StatTiles, Tooltip, TooltipTrigger, TooltipContent, TooltipProvider, ListView, DatePicker, DataTable, DateRangeControl, usePageSize, PageHeaderActions, FilterPanel, FilterPanelField, SearchSelect, SegmentedControl, Card, Pagination, Hint, RequiredFilter, FilterMenuRow, toast, printDocument, ChoiceList, Skeleton, Modal, ModalContent, ModalHeader, ModalTitle, ModalDescription, ModalBody, ModalFooter, RefreshButton, AiActionButton, CurrencyInput, ModalFlow, useSaveBar, Switch, Textarea, RowActions, WizardSteps } from '@fayz-ai/ui';
9
+ import { Badge, Select, SelectTrigger, SelectValue, SelectContent, SelectItem, Input, PageTransition, ModulePage, Button, DashboardCanvas, ComingSoon, SubpageHeader, PageTabs, StatTiles, Tooltip, TooltipTrigger, TooltipContent, TooltipProvider, ListView, DatePicker, DataTable, DateRangeControl, useFilterDraft, usePageSize, PageHeaderActions, FilterPanel, FilterPanelField, SearchSelect, SegmentedControl, Card, Pagination, Hint, RequiredFilter, FilterMenuRow, toast, printDocument, ChoiceList, Skeleton, Modal, ModalContent, ModalHeader, ModalTitle, ModalDescription, ModalBody, ModalFooter, RefreshButton, AiActionButton, CurrencyInput, ModalFlow, useSaveBar, Switch, Textarea, RowActions, WizardSteps } from '@fayz-ai/ui';
10
10
  import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
11
11
  import { useTenantPluginSettings, useModuleNavigation, usePluginOnboardingGate, usePermissionOptional, useModuleNavAccess, PluginOnboardingGateSkeleton, PluginSettingsPanel, ModuleActionBar, EntitlementGate, UpgradePrompt, parseViewId, GetStarted, PermissionGate, PageActions, useUnitFilter, adminNavigateTo, PersonLink, createOneShotAsk, useLookupCreate, createArchetypeLookup, OrderFormSkeleton, OrderFormView, OrderFormBlock, OrderFormItemsCard, OrderFormItemRow, OrderFormAddItemStep, useAgentSurface, shrinkForVision, toInlineFile } from '@fayz-ai/admin';
12
12
  import { ChevronDown, ChevronRight, DollarSign, Landmark, CreditCard, BookOpen, Check, Wallet, Receipt, CalendarClock, Plus, Loader2, BadgeCheck, Gift, Pencil, Target, Settings, Play, ArrowRight, Users, RefreshCw, ListChecks, Search, ArrowRightLeft, Building2, Download, Paperclip, CircleDashed, CircleEllipsis, CircleCheckBig, CircleAlert, Ban, Printer, FileText, Camera, AlertCircle, Sparkles, Link2, FileSearch, Undo2, Eye, TriangleAlert, Trash2, CheckCheck, X, Pause, ShoppingCart, Car, Home, Utensils, Zap, Film, HeartPulse, Dumbbell, Music, ShoppingBag, CircleDollarSign, ArrowLeft, FileDown, AlertTriangle } from 'lucide-react';
@@ -1096,14 +1096,7 @@ function InvoiceListView({ direction, onNew, onNewReceipt, onEdit }) {
1096
1096
  const fetchPaymentMethods = useFinancialStore((s) => s.fetchPaymentMethods);
1097
1097
  const fetchBankAccounts = useFinancialStore((s) => s.fetchBankAccounts);
1098
1098
  const [search, setSearch] = useState("");
1099
- const [statusFilter, setStatusFilter] = useState([]);
1100
- const [accountId, setAccountId] = useState("");
1101
- const [costCenterId, setCostCenterId] = useState("");
1102
1099
  const [unitId, setUnitId] = useState("");
1103
- const [contactId, setContactId] = useState("");
1104
- const [contactName, setContactName] = useState("");
1105
- const [fiscalNumber, setFiscalNumber] = useState("");
1106
- const [bankAccountId, setBankAccountId] = useState("");
1107
1100
  const unitMode = useUnitMode();
1108
1101
  const unitFilter = useUnitFilter();
1109
1102
  const effectiveUnitId = unitMode ? unitFilter.value : unitId || void 0;
@@ -1117,35 +1110,66 @@ function InvoiceListView({ direction, onNew, onNewReceipt, onEdit }) {
1117
1110
  to: isoDate(new Date(hoje.getFullYear(), hoje.getMonth() + 2, 0))
1118
1111
  };
1119
1112
  }, []);
1120
- const [datePreset, setDatePreset] = useState("custom");
1121
- const [dateFrom, setDateFrom] = useState(mesCorrente.from);
1122
- const [dateTo, setDateTo] = useState(mesCorrente.to);
1113
+ const filtros = useFilterDraft(
1114
+ {
1115
+ status: [],
1116
+ contactId: "",
1117
+ contactName: "",
1118
+ fiscalNumber: "",
1119
+ bankAccountId: "",
1120
+ accountId: "",
1121
+ costCenterId: "",
1122
+ from: mesCorrente.from,
1123
+ to: mesCorrente.to,
1124
+ preset: "custom"
1125
+ },
1126
+ { persistKey: `financial.invoices.${direction}`, persistExclude: ["preset"] }
1127
+ );
1128
+ const { draft, applied: emVigor, patch } = filtros;
1129
+ const {
1130
+ status: statusFilter,
1131
+ contactId,
1132
+ contactName,
1133
+ fiscalNumber,
1134
+ bankAccountId,
1135
+ accountId,
1136
+ costCenterId,
1137
+ from: dateFrom,
1138
+ to: dateTo,
1139
+ preset: datePreset
1140
+ } = draft;
1141
+ const setStatusFilter = (status) => patch({ status });
1142
+ const setAccountId = (id) => patch({ accountId: id });
1143
+ const setCostCenterId = (id) => patch({ costCenterId: id });
1144
+ const setBankAccountId = (id) => patch({ bankAccountId: id });
1145
+ const setFiscalNumber = (value) => patch({ fiscalNumber: value });
1123
1146
  useMemo(() => ({ from: dateFrom, to: dateTo }), [dateFrom, dateTo]);
1124
1147
  const applyPreset = (value) => {
1125
- setDatePreset(value);
1126
- if (value === "custom") return;
1148
+ if (value === "custom") {
1149
+ patch({ preset: value });
1150
+ return;
1151
+ }
1127
1152
  const range = presetRange(value);
1128
- setDateFrom(range.from);
1129
- setDateTo(range.to);
1153
+ patch({ preset: value, from: range.from, to: range.to });
1130
1154
  };
1131
1155
  const setFromClamped = (from) => {
1132
1156
  if (!from) return;
1133
- setDatePreset("custom");
1134
- setDateFrom(from);
1135
1157
  if (dateTo && spanDays(from, dateTo) > MAX_RANGE_DAYS) {
1136
1158
  const to = /* @__PURE__ */ new Date(`${from}T00:00:00`);
1137
1159
  to.setDate(to.getDate() + (MAX_RANGE_DAYS - 1));
1138
- setDateTo(isoDate(to));
1160
+ patch({ preset: "custom", from, to: isoDate(to) });
1161
+ } else {
1162
+ patch({ preset: "custom", from });
1139
1163
  }
1140
1164
  };
1141
1165
  const setToClamped = (to) => {
1142
1166
  if (!to) return;
1143
- setDatePreset("custom");
1144
- setDateTo(to);
1145
1167
  if (dateFrom && spanDays(dateFrom, to) > MAX_RANGE_DAYS) {
1146
1168
  const from = /* @__PURE__ */ new Date(`${to}T00:00:00`);
1147
1169
  from.setDate(from.getDate() - (MAX_RANGE_DAYS - 1));
1148
- setDateFrom(isoDate(from));
1170
+ patch({ preset: "custom", to, from: isoDate(from) });
1171
+ } else {
1172
+ patch({ preset: "custom", to });
1149
1173
  }
1150
1174
  };
1151
1175
  useEffect(() => {
@@ -1166,28 +1190,13 @@ function InvoiceListView({ direction, onNew, onNewReceipt, onEdit }) {
1166
1190
  useEffect(() => {
1167
1191
  void Promise.all([fetchPaymentMethods(), fetchBankAccounts()]);
1168
1192
  }, [fetchPaymentMethods, fetchBankAccounts]);
1169
- const rascunho = useMemo(() => ({
1170
- status: statusFilter,
1171
- contactId,
1172
- fiscalNumber: fiscalNumber.trim(),
1173
- bankAccountId,
1174
- accountId,
1175
- costCenterId,
1176
- from: dateFrom,
1177
- to: dateTo
1178
- }), [statusFilter, contactId, fiscalNumber, bankAccountId, accountId, costCenterId, dateFrom, dateTo]);
1179
- const [emVigor, setEmVigor] = useState(rascunho);
1180
- const filtrosPendentes = useMemo(
1181
- () => JSON.stringify(rascunho) !== JSON.stringify(emVigor),
1182
- [rascunho, emVigor]
1183
- );
1184
- const aplicarFiltros = useCallback(() => setEmVigor(() => rascunho), [rascunho]);
1193
+ const aplicarFiltros = filtros.apply;
1185
1194
  const query = useMemo(() => ({
1186
1195
  direction,
1187
1196
  status: emVigor.status.length > 0 ? emVigor.status : void 0,
1188
1197
  search: search || void 0,
1189
1198
  contactId: emVigor.contactId || void 0,
1190
- fiscalNumber: emVigor.fiscalNumber || void 0,
1199
+ fiscalNumber: emVigor.fiscalNumber.trim() || void 0,
1191
1200
  bankAccountId: emVigor.bankAccountId || void 0,
1192
1201
  accountId: emVigor.accountId || void 0,
1193
1202
  costCenterId: emVigor.costCenterId || void 0,
@@ -1351,16 +1360,18 @@ function InvoiceListView({ direction, onNew, onNewReceipt, onEdit }) {
1351
1360
  );
1352
1361
  };
1353
1362
  const clearFilters = () => {
1354
- setAccountId("");
1355
- setCostCenterId("");
1356
1363
  setUnitId("");
1357
- setStatusFilter([]);
1358
- setContactId("");
1359
- setContactName("");
1360
- setFiscalNumber("");
1361
- setBankAccountId("");
1364
+ patch({
1365
+ accountId: "",
1366
+ costCenterId: "",
1367
+ status: [],
1368
+ contactId: "",
1369
+ contactName: "",
1370
+ fiscalNumber: "",
1371
+ bankAccountId: ""
1372
+ });
1362
1373
  };
1363
- const activeFilterCount = (accountId ? 1 : 0) + (costCenterId ? 1 : 0) + (unitId ? 1 : 0) + (statusFilter.length > 0 ? 1 : 0) + (contactId ? 1 : 0) + (fiscalNumber ? 1 : 0) + (bankAccountId ? 1 : 0);
1374
+ const activeFilterCount = (accountId ? 1 : 0) + (costCenterId ? 1 : 0) + (unitId ? 1 : 0) + (statusFilter.length > 0 ? 1 : 0) + (contactId ? 1 : 0) + (fiscalNumber.trim() ? 1 : 0) + (bankAccountId ? 1 : 0);
1364
1375
  const unitField = unitFilter.visible ? /* @__PURE__ */ jsx(
1365
1376
  RequiredFilter,
1366
1377
  {
@@ -1518,16 +1529,13 @@ function InvoiceListView({ direction, onNew, onNewReceipt, onEdit }) {
1518
1529
  FilterPanel,
1519
1530
  {
1520
1531
  title: t("financial.invoice.filtersTitle"),
1521
- dirty: filtrosPendentes,
1522
1532
  onApply: aplicarFiltros,
1523
1533
  applyLabel: t("financial.invoice.filterApply"),
1524
- pendingTitle: t("financial.invoice.filterPending"),
1525
- pendingHint: t("financial.invoice.filterPendingHint"),
1526
1534
  onClear: activeFilterCount > 0 ? clearFilters : void 0,
1527
1535
  clearLabel: t("financial.invoice.filterClear"),
1528
1536
  busy: invoicesLoading,
1529
1537
  advanced: filtrosAvancados,
1530
- advancedCount: (accountId ? 1 : 0) + (costCenterId ? 1 : 0) + (bankAccountId ? 1 : 0) + (fiscalNumber ? 1 : 0),
1538
+ advancedCount: (accountId ? 1 : 0) + (costCenterId ? 1 : 0) + (bankAccountId ? 1 : 0) + (fiscalNumber.trim() ? 1 : 0),
1531
1539
  moreLabel: t("financial.invoice.filterMore"),
1532
1540
  lessLabel: t("financial.invoice.filterLess"),
1533
1541
  children: [
@@ -1547,8 +1555,7 @@ function InvoiceListView({ direction, onNew, onNewReceipt, onEdit }) {
1547
1555
  loadOnOpen: false,
1548
1556
  clearLabel: t("financial.invoice.filterAllContacts"),
1549
1557
  onChange: (id, option) => {
1550
- setContactId(id);
1551
- setContactName(option?.label ?? "");
1558
+ patch({ contactId: id, contactName: option?.label ?? "" });
1552
1559
  },
1553
1560
  onSearch: async (termo) => {
1554
1561
  const results = await contactLookup.search(termo);
@@ -1914,8 +1921,6 @@ function StatementsView({ onNavigate }) {
1914
1921
  const paymentMethodTypes = useFinancialStore((s) => s.paymentMethodTypes);
1915
1922
  const fetchPaymentMethods = useFinancialStore((s) => s.fetchPaymentMethods);
1916
1923
  const fetchStatement = useFinancialStore((s) => s.fetchStatement);
1917
- const [accountId, setAccountId] = useState("");
1918
- const [selectedAccount, setSelectedAccount] = useState(null);
1919
1924
  const MAX_RANGE_DAYS2 = 90;
1920
1925
  const hojeIso = () => {
1921
1926
  const d = /* @__PURE__ */ new Date();
@@ -1926,44 +1931,58 @@ function StatementsView({ onNavigate }) {
1926
1931
  d.setDate(d.getDate() - 29);
1927
1932
  return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, "0")}-${String(d.getDate()).padStart(2, "0")}`;
1928
1933
  }, []);
1929
- const [dateFrom, setDateFrom] = useState(defaultFrom);
1930
- const [dateTo, setDateTo] = useState(hojeIso);
1934
+ const filtros = useFilterDraft(
1935
+ {
1936
+ accountId: "",
1937
+ accountName: "",
1938
+ from: defaultFrom,
1939
+ to: hojeIso(),
1940
+ // THE THREE OPERATION TYPES of V1 (credits · debits · transfers). They
1941
+ // cut the statement already in hand, so the list reads them from the
1942
+ // DRAFT (instant) and they never trigger a query; they live in the slice
1943
+ // only so they are remembered with it.
1944
+ credits: true,
1945
+ debits: true,
1946
+ transfers: true
1947
+ },
1948
+ { persistKey: "financial.statements" }
1949
+ );
1950
+ const { draft, applied, patch } = filtros;
1951
+ const accountId = draft.accountId;
1952
+ const dateFrom = draft.from;
1953
+ const dateTo = draft.to;
1954
+ const verCreditos = draft.credits;
1955
+ const verDebitos = draft.debits;
1956
+ const verTransferencias = draft.transfers;
1931
1957
  const spanDays2 = (from, to) => Math.round(((/* @__PURE__ */ new Date(`${to}T00:00:00`)).getTime() - (/* @__PURE__ */ new Date(`${from}T00:00:00`)).getTime()) / 864e5) + 1;
1932
1958
  const setFromClamped = (from) => {
1933
1959
  if (!from) return;
1934
- setDateFrom(from);
1935
1960
  if (dateTo && spanDays2(from, dateTo) > MAX_RANGE_DAYS2) {
1936
1961
  const d = /* @__PURE__ */ new Date(`${from}T00:00:00`);
1937
1962
  d.setDate(d.getDate() + (MAX_RANGE_DAYS2 - 1));
1938
- setDateTo(`${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, "0")}-${String(d.getDate()).padStart(2, "0")}`);
1963
+ patch({ from, to: `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, "0")}-${String(d.getDate()).padStart(2, "0")}` });
1964
+ } else {
1965
+ patch({ from });
1939
1966
  }
1940
1967
  };
1941
1968
  const setToClamped = (to) => {
1942
1969
  if (!to) return;
1943
- setDateTo(to);
1944
1970
  if (dateFrom && spanDays2(dateFrom, to) > MAX_RANGE_DAYS2) {
1945
1971
  const d = /* @__PURE__ */ new Date(`${to}T00:00:00`);
1946
1972
  d.setDate(d.getDate() - (MAX_RANGE_DAYS2 - 1));
1947
- setDateFrom(`${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, "0")}-${String(d.getDate()).padStart(2, "0")}`);
1973
+ patch({ to, from: `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, "0")}-${String(d.getDate()).padStart(2, "0")}` });
1974
+ } else {
1975
+ patch({ to });
1948
1976
  }
1949
1977
  };
1950
1978
  const [search, setSearch] = useState("");
1951
1979
  const [showTransfer, setShowTransfer] = useState(false);
1952
- const [verCreditos, setVerCreditos] = useState(true);
1953
- const [verDebitos, setVerDebitos] = useState(true);
1954
- const [verTransferencias, setVerTransferencias] = useState(true);
1955
1980
  const unidades = useUnitFilter();
1956
- const [aplicado, setAplicado] = useState({ accountId: "", from: defaultFrom, to: hojeIso() });
1957
- const filtrosPendentes = useMemo(
1958
- () => JSON.stringify({ accountId, from: dateFrom, to: dateTo }) !== JSON.stringify(aplicado),
1959
- [accountId, dateFrom, dateTo, aplicado]
1960
- );
1981
+ const [refreshTick, setRefreshTick] = useState(0);
1961
1982
  const gerar = useCallback(() => {
1962
- setAplicado({ accountId, from: dateFrom, to: dateTo });
1963
- }, [accountId, dateFrom, dateTo]);
1964
- useEffect(() => {
1965
- if (accountId && !aplicado.accountId) gerar();
1966
- }, [accountId, aplicado.accountId, gerar]);
1983
+ filtros.apply();
1984
+ setRefreshTick((n) => n + 1);
1985
+ }, [filtros.apply]);
1967
1986
  useEffect(() => {
1968
1987
  fetchPaymentMethods();
1969
1988
  }, [fetchPaymentMethods]);
@@ -1983,13 +2002,13 @@ function StatementsView({ onNavigate }) {
1983
2002
  onNavigate(`${base}-detail:${e.movement.invoiceId}`);
1984
2003
  }
1985
2004
  useEffect(() => {
1986
- if (aplicado.accountId) {
2005
+ if (applied.accountId) {
1987
2006
  fetchStatement({
1988
- bankAccountId: aplicado.accountId,
1989
- dateRange: { from: aplicado.from, to: aplicado.to }
2007
+ bankAccountId: applied.accountId,
2008
+ dateRange: { from: applied.from, to: applied.to }
1990
2009
  });
1991
2010
  }
1992
- }, [aplicado]);
2011
+ }, [applied.accountId, applied.from, applied.to, refreshTick]);
1993
2012
  const fmt = (n) => formatCurrency(n, currency);
1994
2013
  const columns = useMemo(() => [
1995
2014
  {
@@ -2096,7 +2115,7 @@ function StatementsView({ onNavigate }) {
2096
2115
  }
2097
2116
  ], [currency, t, methodName, onNavigate]);
2098
2117
  const entries = useMemo(() => {
2099
- const all = aplicado.accountId ? statement?.entries ?? [] : [];
2118
+ const all = applied.accountId ? statement?.entries ?? [] : [];
2100
2119
  const porTipo = all.filter((e) => {
2101
2120
  if (e.entryKind !== "movement") return verTransferencias;
2102
2121
  return e.movement.direction === "credit" ? verCreditos : verDebitos;
@@ -2107,7 +2126,7 @@ function StatementsView({ onNavigate }) {
2107
2126
  return haystack.some((v) => v?.toLowerCase().includes(term));
2108
2127
  });
2109
2128
  return newestStatementEntriesFirst(filtered);
2110
- }, [statement, search, methodName, aplicado.accountId, verCreditos, verDebitos, verTransferencias]);
2129
+ }, [statement, search, methodName, applied.accountId, verCreditos, verDebitos, verTransferencias]);
2111
2130
  const exportEntries = () => {
2112
2131
  exportCSV(
2113
2132
  [
@@ -2144,20 +2163,17 @@ function StatementsView({ onNavigate }) {
2144
2163
  FilterPanel,
2145
2164
  {
2146
2165
  title: t("financial.invoice.filtersTitle"),
2147
- dirty: filtrosPendentes,
2148
2166
  onApply: gerar,
2149
2167
  applyLabel: t("financial.statements.generate"),
2150
- pendingTitle: t("financial.invoice.filterPending"),
2151
- pendingHint: t("financial.statements.filterPendingHint"),
2152
2168
  applyDisabledReason: accountId ? void 0 : t("financial.statements.accountRequired"),
2153
2169
  busy: statementLoading,
2154
2170
  moreLabel: t("financial.invoice.filterMore"),
2155
2171
  lessLabel: t("financial.invoice.filterLess"),
2156
2172
  advancedCount: [verCreditos, verDebitos, verTransferencias].filter((v) => !v).length,
2157
2173
  advanced: /* @__PURE__ */ jsx(FilterPanelField, { label: t("financial.statements.operationTypes"), className: "sm:col-span-2", children: /* @__PURE__ */ jsx("div", { className: "flex flex-wrap items-center gap-1.5", children: [
2158
- [t("financial.statements.opCredits"), verCreditos, setVerCreditos],
2159
- [t("financial.statements.opDebits"), verDebitos, setVerDebitos],
2160
- [t("financial.statements.opTransfers"), verTransferencias, setVerTransferencias]
2174
+ [t("financial.statements.opCredits"), verCreditos, (v) => patch({ credits: v })],
2175
+ [t("financial.statements.opDebits"), verDebitos, (v) => patch({ debits: v })],
2176
+ [t("financial.statements.opTransfers"), verTransferencias, (v) => patch({ transfers: v })]
2161
2177
  ].map(([rotulo, ligado, alterna]) => /* @__PURE__ */ jsx(
2162
2178
  Button,
2163
2179
  {
@@ -2177,7 +2193,7 @@ function StatementsView({ onNavigate }) {
2177
2193
  {
2178
2194
  className: "w-full",
2179
2195
  value: accountId,
2180
- displayValue: selectedAccount?.name ?? "",
2196
+ displayValue: draft.accountName,
2181
2197
  icon: Landmark,
2182
2198
  placeholder: "Digite...",
2183
2199
  minChars: 2,
@@ -2187,8 +2203,7 @@ function StatementsView({ onNavigate }) {
2187
2203
  searchingLabel: "Buscando contas e pessoas...",
2188
2204
  clearLabel: "Limpar",
2189
2205
  onChange: (id, option) => {
2190
- setAccountId(id);
2191
- setSelectedAccount(option?.data ?? null);
2206
+ patch({ accountId: id, accountName: option?.data?.name ?? option?.label ?? "" });
2192
2207
  },
2193
2208
  onSearch: async (query) => {
2194
2209
  const accounts = provider.searchFinancialAccounts ? await provider.searchFinancialAccounts(query, 20) : (await provider.getBankAccounts()).filter((account) => account.name.toLocaleLowerCase("pt-BR").includes(query.toLocaleLowerCase("pt-BR"))).slice(0, 20);
@@ -2231,7 +2246,7 @@ function StatementsView({ onNavigate }) {
2231
2246
  ]
2232
2247
  }
2233
2248
  ),
2234
- aplicado.accountId && statement && /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-2 sm:grid-cols-4 gap-2", children: [
2249
+ applied.accountId && statement && /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-2 sm:grid-cols-4 gap-2", children: [
2235
2250
  /* @__PURE__ */ jsx(SummaryStat, { label: t("financial.statements.opening"), value: fmt(statement.openingBalance) }),
2236
2251
  /* @__PURE__ */ jsx(SummaryStat, { label: t("financial.statements.totalCredits"), value: fmt(statement.totalCredits), positive: true }),
2237
2252
  /* @__PURE__ */ jsx(SummaryStat, { label: t("financial.statements.totalDebits"), value: fmt(statement.totalDebits), negative: true }),
@@ -3709,10 +3724,11 @@ function ReconcileFlow({ line, initialIntent, initialTarget, initialStep = 0, on
3709
3724
  min: toAmountInput(line.amount * (1 - LINK_AMOUNT_TOLERANCE)),
3710
3725
  max: toAmountInput(line.amount * (1 + LINK_AMOUNT_TOLERANCE))
3711
3726
  });
3712
- const [rascunho, setRascunho] = useState(filtrosIniciais);
3713
- const [aplicado, setAplicado] = useState(filtrosIniciais);
3714
- const mudarFiltro = (patch) => setRascunho((prev) => ({ ...prev, ...patch }));
3715
- const filtrosPendentes = JSON.stringify(rascunho) !== JSON.stringify(aplicado);
3727
+ const filtros = useFilterDraft(filtrosIniciais(), {
3728
+ persistKey: "financial.reconcile-flow",
3729
+ persistExclude: ["dueFrom", "dueTo", "texto", "min", "max"]
3730
+ });
3731
+ const { draft: rascunho, applied: aplicado, patch: mudarFiltro, dirty: filtrosPendentes } = filtros;
3716
3732
  const [resultados, setResultados] = useState([]);
3717
3733
  const [paginaBusca, setPaginaBusca] = useState(1);
3718
3734
  const [temMais, setTemMais] = useState(false);
@@ -3763,8 +3779,8 @@ function ReconcileFlow({ line, initialIntent, initialTarget, initialStep = 0, on
3763
3779
  }, [podeBuscar, resultados, candidates, initialTarget]);
3764
3780
  const ampliarBusca = () => {
3765
3781
  const amplo = { ...rascunho, dueFrom: shiftDate(line.date, -WIDEN_DAYS), dueTo: shiftDate(line.date, WIDEN_DAYS), min: "", max: "" };
3766
- setRascunho(amplo);
3767
- setAplicado(amplo);
3782
+ filtros.setDraft(amplo);
3783
+ filtros.apply();
3768
3784
  };
3769
3785
  const contaDoExtrato = useMemo(
3770
3786
  () => contas.find((a) => a.id === line.bankAccountId) ?? null,
@@ -3976,7 +3992,7 @@ function ReconcileFlow({ line, initialIntent, initialTarget, initialStep = 0, on
3976
3992
  return item.candidate.installmentCount ? `${n}/${item.candidate.installmentCount}` : String(n);
3977
3993
  };
3978
3994
  const filtrar = () => {
3979
- if (filtrosPendentes) setAplicado(rascunho);
3995
+ if (filtrosPendentes) filtros.apply();
3980
3996
  else void buscar(1);
3981
3997
  };
3982
3998
  const colunasDaBusca = [
@@ -4057,11 +4073,8 @@ function ReconcileFlow({ line, initialIntent, initialTarget, initialStep = 0, on
4057
4073
  FilterPanel,
4058
4074
  {
4059
4075
  title: t("financial.reconciliation.filtersTitle"),
4060
- dirty: filtrosPendentes,
4061
4076
  onApply: filtrar,
4062
4077
  applyLabel: t("financial.reconciliation.filter"),
4063
- pendingTitle: t("financial.reconciliation.filterPending"),
4064
- pendingHint: t("financial.reconciliation.searchPendingHint"),
4065
4078
  busy: buscando,
4066
4079
  moreLabel: t("financial.reconciliation.filterMore"),
4067
4080
  lessLabel: t("financial.reconciliation.filterLess"),
@@ -4958,27 +4971,26 @@ function ReconciliationView() {
4958
4971
  const unidades = useUnitFilter({ scope: "list" });
4959
4972
  const fmt = (n) => formatCurrency(n, currency);
4960
4973
  const [unitId, setUnitId] = useState("");
4961
- const [accountId, setAccountId] = useState("");
4962
- const [selectedAccount, setSelectedAccount] = useState(null);
4963
4974
  const defaultFrom = useMemo(() => {
4964
4975
  const d = /* @__PURE__ */ new Date();
4965
4976
  d.setDate(d.getDate() - 29);
4966
4977
  return isoDay(d);
4967
4978
  }, []);
4968
- const [dateFrom, setDateFrom] = useState(defaultFrom);
4969
- const [dateTo, setDateTo] = useState(() => isoDay(/* @__PURE__ */ new Date()));
4970
- const [direction, setDirection] = useState("all");
4971
- const [status, setStatus] = useState("all");
4979
+ const filtros = useFilterDraft(
4980
+ {
4981
+ accountId: "",
4982
+ account: null,
4983
+ dateFrom: defaultFrom,
4984
+ dateTo: isoDay(/* @__PURE__ */ new Date()),
4985
+ direction: "all",
4986
+ status: "all",
4987
+ hideInvestments: true
4988
+ },
4989
+ { persistKey: "financial.reconciliation" }
4990
+ );
4991
+ const { draft, applied, patch } = filtros;
4992
+ const { accountId, account: selectedAccount, dateFrom, dateTo, direction, status, hideInvestments } = draft;
4972
4993
  const [search, setSearch] = useState("");
4973
- const [hideInvestments, setHideInvestments] = useState(true);
4974
- const [applied, setApplied] = useState({
4975
- accountId: "",
4976
- dateFrom: defaultFrom,
4977
- dateTo: isoDay(/* @__PURE__ */ new Date()),
4978
- direction: "all",
4979
- status: "all",
4980
- hideInvestments: true
4981
- });
4982
4994
  const [appliedSearch, setAppliedSearch] = useState("");
4983
4995
  const [page, setPage] = useState(1);
4984
4996
  const [pageSize, setPageSize] = usePageSize("financial.reconciliation", PAGE_SIZE);
@@ -5006,9 +5018,12 @@ function ReconciliationView() {
5006
5018
  const id = setTimeout(() => setAppliedSearch(termo), 300);
5007
5019
  return () => clearTimeout(id);
5008
5020
  }, [search, appliedSearch]);
5021
+ const loadSeq = React15__default.useRef(0);
5009
5022
  const load = useCallback(async () => {
5023
+ const seq = ++loadSeq.current;
5010
5024
  if (!provider.getStatementLines || !applied.accountId) {
5011
5025
  setResult(null);
5026
+ setLoading(false);
5012
5027
  return;
5013
5028
  }
5014
5029
  setLoading(true);
@@ -5023,9 +5038,9 @@ function ReconciliationView() {
5023
5038
  page,
5024
5039
  pageSize
5025
5040
  });
5026
- setResult(data);
5041
+ if (seq === loadSeq.current) setResult(data);
5027
5042
  } finally {
5028
- setLoading(false);
5043
+ if (seq === loadSeq.current) setLoading(false);
5029
5044
  }
5030
5045
  }, [provider, applied, appliedSearch, page, pageSize]);
5031
5046
  useEffect(() => {
@@ -5045,13 +5060,7 @@ function ReconciliationView() {
5045
5060
  vivo = false;
5046
5061
  };
5047
5062
  }, [provider, linhasAbertas]);
5048
- function filtrar() {
5049
- setApplied({ accountId, dateFrom, dateTo, direction, status, hideInvestments });
5050
- }
5051
- const filtrosPendentes = useMemo(
5052
- () => JSON.stringify({ accountId, dateFrom, dateTo, direction, status, hideInvestments }) !== JSON.stringify(applied),
5053
- [accountId, dateFrom, dateTo, direction, status, hideInvestments, applied]
5054
- );
5063
+ const filtrar = filtros.apply;
5055
5064
  async function sugerir(line) {
5056
5065
  if (!provider.suggestReconciliation) return;
5057
5066
  setSugerindo(line.id);
@@ -5170,11 +5179,8 @@ function ReconciliationView() {
5170
5179
  FilterPanel,
5171
5180
  {
5172
5181
  title: t("financial.reconciliation.filtersTitle"),
5173
- dirty: filtrosPendentes,
5174
5182
  onApply: filtrar,
5175
5183
  applyLabel: t("financial.reconciliation.filter"),
5176
- pendingTitle: t("financial.reconciliation.filterPending"),
5177
- pendingHint: t("financial.reconciliation.filterPendingHint"),
5178
5184
  applyDisabledReason: accountId ? void 0 : t("financial.reconciliation.pickAccountFirst"),
5179
5185
  busy: loading,
5180
5186
  moreLabel: t("financial.reconciliation.filterMore"),
@@ -5186,7 +5192,7 @@ function ReconciliationView() {
5186
5192
  {
5187
5193
  "aria-label": t("financial.reconciliation.type"),
5188
5194
  value: direction,
5189
- onChange: (v) => setDirection(v),
5195
+ onChange: (v) => patch({ direction: v }),
5190
5196
  options: [
5191
5197
  { value: "all", label: t("financial.reconciliation.typeAll") },
5192
5198
  { value: "credit", label: t("financial.reconciliation.typeIn") },
@@ -5199,7 +5205,7 @@ function ReconciliationView() {
5199
5205
  {
5200
5206
  "aria-label": t("financial.reconciliation.status"),
5201
5207
  value: status,
5202
- onChange: (v) => setStatus(v),
5208
+ onChange: (v) => patch({ status: v }),
5203
5209
  options: [
5204
5210
  { value: "all", label: t("financial.reconciliation.statusAll") },
5205
5211
  { value: "reconciled", label: t("financial.reconciliation.statusReconciled") },
@@ -5212,7 +5218,7 @@ function ReconciliationView() {
5212
5218
  {
5213
5219
  "aria-label": t("financial.reconciliation.investments"),
5214
5220
  value: hideInvestments ? "hide" : "show",
5215
- onChange: (v) => setHideInvestments(v === "hide"),
5221
+ onChange: (v) => patch({ hideInvestments: v === "hide" }),
5216
5222
  options: [
5217
5223
  { value: "hide", label: t("financial.reconciliation.investmentsHide") },
5218
5224
  { value: "show", label: t("financial.reconciliation.investmentsShow") }
@@ -5241,8 +5247,7 @@ function ReconciliationView() {
5241
5247
  searchingLabel: "Buscando contas...",
5242
5248
  clearLabel: "Limpar",
5243
5249
  onChange: (id, option) => {
5244
- setAccountId(id);
5245
- setSelectedAccount(option?.data ?? null);
5250
+ patch({ accountId: id, account: option?.data ?? null });
5246
5251
  },
5247
5252
  onSearch: async (query) => {
5248
5253
  const termo = query.trim().toLocaleLowerCase("pt-BR");
@@ -5260,8 +5265,8 @@ function ReconciliationView() {
5260
5265
  }
5261
5266
  }
5262
5267
  ) }),
5263
- /* @__PURE__ */ jsx(FilterPanelField, { label: t("financial.reconciliation.from"), children: /* @__PURE__ */ jsx(Input, { type: "date", value: dateFrom, onChange: (e) => setDateFrom(e.target.value), className: CAMPO }) }),
5264
- /* @__PURE__ */ jsx(FilterPanelField, { label: t("financial.reconciliation.to"), children: /* @__PURE__ */ jsx(Input, { type: "date", value: dateTo, onChange: (e) => setDateTo(e.target.value), className: CAMPO }) })
5268
+ /* @__PURE__ */ jsx(FilterPanelField, { label: t("financial.reconciliation.from"), children: /* @__PURE__ */ jsx(Input, { type: "date", value: dateFrom, onChange: (e) => patch({ dateFrom: e.target.value }), className: CAMPO }) }),
5269
+ /* @__PURE__ */ jsx(FilterPanelField, { label: t("financial.reconciliation.to"), children: /* @__PURE__ */ jsx(Input, { type: "date", value: dateTo, onChange: (e) => patch({ dateTo: e.target.value }), className: CAMPO }) })
5265
5270
  ]
5266
5271
  }
5267
5272
  ),
@@ -6565,5 +6570,5 @@ function FinancialPage({ config: appConfig, provider, store, registries }) {
6565
6570
  }
6566
6571
 
6567
6572
  export { FinancialPage };
6568
- //# sourceMappingURL=FinancialPage-HIVSEGJE.js.map
6569
- //# sourceMappingURL=FinancialPage-HIVSEGJE.js.map
6573
+ //# sourceMappingURL=FinancialPage-QGKOWJ6J.js.map
6574
+ //# sourceMappingURL=FinancialPage-QGKOWJ6J.js.map