@hed-hog/finance 0.0.328 → 0.0.330

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 (27) hide show
  1. package/hedhog/frontend/app/_components/category-picker-field.tsx.ejs +3 -0
  2. package/hedhog/frontend/app/_components/cost-center-picker-field.tsx.ejs +3 -0
  3. package/hedhog/frontend/app/_components/finance-entity-field-with-create.tsx.ejs +9 -4
  4. package/hedhog/frontend/app/_components/finance-picker.tsx.ejs +242 -0
  5. package/hedhog/frontend/app/accounts-payable/approvals/page.tsx.ejs +18 -15
  6. package/hedhog/frontend/app/accounts-payable/installments/page.tsx.ejs +13 -19
  7. package/hedhog/frontend/app/accounts-receivable/collections-default/page.tsx.ejs +4 -8
  8. package/hedhog/frontend/app/accounts-receivable/installments/page.tsx.ejs +13 -19
  9. package/hedhog/frontend/app/administration/audit-logs/page.tsx.ejs +10 -4
  10. package/hedhog/frontend/app/administration/categories/page.tsx.ejs +3 -5
  11. package/hedhog/frontend/app/administration/cost-centers/page.tsx.ejs +3 -5
  12. package/hedhog/frontend/app/administration/currencies/page.tsx.ejs +3 -5
  13. package/hedhog/frontend/app/administration/period-close/page.tsx.ejs +3 -5
  14. package/hedhog/frontend/app/cash-and-banks/bank-accounts/page.tsx.ejs +48 -72
  15. package/hedhog/frontend/app/cash-and-banks/bank-reconciliation/page.tsx.ejs +7 -9
  16. package/hedhog/frontend/app/cash-and-banks/statements/page.tsx.ejs +91 -73
  17. package/hedhog/frontend/app/cash-and-banks/transfers/page.tsx.ejs +33 -25
  18. package/hedhog/frontend/app/planning/scenarios/page.tsx.ejs +2 -2
  19. package/hedhog/frontend/app/reports/actual-vs-forecast/page.tsx.ejs +3 -1
  20. package/hedhog/frontend/app/reports/aging-default/page.tsx.ejs +3 -1
  21. package/hedhog/frontend/app/reports/cash-position/page.tsx.ejs +3 -1
  22. package/hedhog/frontend/app/reports/overview-results/page.tsx.ejs +15 -8
  23. package/hedhog/frontend/app/reports/top-customers/page.tsx.ejs +9 -5
  24. package/hedhog/frontend/app/reports/top-operational-expenses/page.tsx.ejs +9 -5
  25. package/hedhog/frontend/messages/en.json +110 -2
  26. package/hedhog/frontend/messages/pt.json +92 -2
  27. package/package.json +4 -4
@@ -88,23 +88,30 @@ type TransferDraftPayload = {
88
88
 
89
89
  const TRANSFER_FORM_DRAFT_STORAGE_KEY = 'finance-transfer-form-draft';
90
90
 
91
- const transferFormSchema = z
92
- .object({
93
- sourceAccountId: z.string().trim().min(1, 'Conta de origem é obrigatória'),
94
- destinationAccountId: z
95
- .string()
96
- .trim()
97
- .min(1, 'Conta de destino é obrigatória'),
98
- date: z.string().trim().min(1, 'Data é obrigatória'),
99
- amount: z.number().min(0.01, 'Valor deve ser maior que zero'),
100
- description: z.string().optional(),
101
- })
102
- .refine((values) => values.sourceAccountId !== values.destinationAccountId, {
103
- message: 'As contas de origem e destino devem ser diferentes',
104
- path: ['destinationAccountId'],
105
- });
91
+ const createTransferFormSchema = (t: ReturnType<typeof useTranslations>) =>
92
+ z
93
+ .object({
94
+ sourceAccountId: z
95
+ .string()
96
+ .trim()
97
+ .min(1, t('formErrors.sourceAccountRequired')),
98
+ destinationAccountId: z
99
+ .string()
100
+ .trim()
101
+ .min(1, t('formErrors.destinationAccountRequired')),
102
+ date: z.string().trim().min(1, t('formErrors.dateRequired')),
103
+ amount: z.number().min(0.01, t('formErrors.amountMustBePositive')),
104
+ description: z.string().optional(),
105
+ })
106
+ .refine(
107
+ (values) => values.sourceAccountId !== values.destinationAccountId,
108
+ {
109
+ message: t('formErrors.differentAccounts'),
110
+ path: ['destinationAccountId'],
111
+ }
112
+ );
106
113
 
107
- type TransferFormValues = z.infer<typeof transferFormSchema>;
114
+ type TransferFormValues = z.infer<ReturnType<typeof createTransferFormSchema>>;
108
115
 
109
116
  function NovaTransferenciaSheet({
110
117
  contasBancarias,
@@ -118,6 +125,7 @@ function NovaTransferenciaSheet({
118
125
  const { request, showToastHandler, currentLocaleCode, getSettingValue } =
119
126
  useApp();
120
127
  const [open, setOpen] = useState(false);
128
+ const transferFormSchema = useMemo(() => createTransferFormSchema(t), [t]);
121
129
 
122
130
  const form = useForm<TransferFormValues>({
123
131
  resolver: zodResolver(transferFormSchema),
@@ -187,10 +195,8 @@ function NovaTransferenciaSheet({
187
195
  currentLocaleCode
188
196
  );
189
197
 
190
- return currentLocaleCode.startsWith('pt')
191
- ? `Rascunho salvo ${relativeLabel} Último salvamento: ${absoluteLabel}`
192
- : `Draft saved ${relativeLabel} • Last saved: ${absoluteLabel}`;
193
- }, [draftSavedAt, currentLocaleCode, getSettingValue, hasDraft]);
198
+ return t('draftStatus', { relativeLabel, absoluteLabel });
199
+ }, [draftSavedAt, currentLocaleCode, getSettingValue, hasDraft, t]);
194
200
 
195
201
  useEffect(() => {
196
202
  if (!open) {
@@ -227,9 +233,9 @@ function NovaTransferenciaSheet({
227
233
  clearDraft();
228
234
  await onCreated();
229
235
  setOpen(false);
230
- showToastHandler?.('success', 'Transferência cadastrada com sucesso');
236
+ showToastHandler?.('success', t('transferCreatedSuccess'));
231
237
  } catch {
232
- showToastHandler?.('error', 'Erro ao cadastrar transferência');
238
+ showToastHandler?.('error', t('transferCreateError'));
233
239
  }
234
240
  };
235
241
 
@@ -540,7 +546,7 @@ export default function TransferenciasPage() {
540
546
  <SelectValue placeholder={t('common.select')} />
541
547
  </SelectTrigger>
542
548
  <SelectContent>
543
- <SelectItem value="all">Todas as contas</SelectItem>
549
+ <SelectItem value="all">{t('allAccounts')}</SelectItem>
544
550
  {contasBancarias.map((conta) => (
545
551
  <SelectItem key={conta.id} value={conta.id}>
546
552
  {conta.banco} - {conta.descricao}
@@ -551,7 +557,7 @@ export default function TransferenciasPage() {
551
557
 
552
558
  <div className="flex-1">
553
559
  <FilterBar
554
- searchPlaceholder="Buscar na descrição..."
560
+ searchPlaceholder={t('searchPlaceholder')}
555
561
  searchValue={search}
556
562
  onSearchChange={setSearch}
557
563
  />
@@ -575,7 +581,9 @@ export default function TransferenciasPage() {
575
581
  <TableRow>
576
582
  <TableHead>{t('table.headers.date')}</TableHead>
577
583
  <TableHead>{t('table.headers.source')}</TableHead>
578
- <TableHead className="text-center">→</TableHead>
584
+ <TableHead className="text-center">
585
+ {t('table.headers.arrow')}
586
+ </TableHead>
579
587
  <TableHead>{t('table.headers.destination')}</TableHead>
580
588
  <TableHead className="text-right">
581
589
  {t('table.headers.value')}
@@ -316,9 +316,9 @@ export default function CenariosPage() {
316
316
  });
317
317
 
318
318
  await refetch();
319
- showToastHandler?.('success', 'Cenário salvo com sucesso');
319
+ showToastHandler?.('success', t('messages.saveSuccess'));
320
320
  } catch {
321
- showToastHandler?.('error', 'Erro ao salvar cenário');
321
+ showToastHandler?.('error', t('messages.saveError'));
322
322
  } finally {
323
323
  setIsSaving(false);
324
324
  }
@@ -21,6 +21,7 @@ import {
21
21
  TableHeader,
22
22
  TableRow,
23
23
  } from '@/components/ui/table';
24
+ import { useApp } from '@hed-hog/next-app-provider';
24
25
  import {
25
26
  Download,
26
27
  Loader2,
@@ -47,6 +48,7 @@ type Scenario = 'base' | 'pessimista' | 'otimista';
47
48
 
48
49
  export default function ActualVsForecastPage() {
49
50
  const t = useTranslations('finance.ActualVsForecastPage');
51
+ const { currentLocaleCode } = useApp();
50
52
 
51
53
  const [horizonte, setHorizonte] = useState<string | null>(null);
52
54
  const [cenario, setCenario] = useState<Scenario | null>(null);
@@ -219,7 +221,7 @@ export default function ActualVsForecastPage() {
219
221
  />
220
222
  <Tooltip
221
223
  formatter={(value: number) =>
222
- new Intl.NumberFormat('pt-BR', {
224
+ new Intl.NumberFormat(currentLocaleCode || undefined, {
223
225
  style: 'currency',
224
226
  currency: 'BRL',
225
227
  }).format(value)
@@ -20,6 +20,7 @@ import {
20
20
  TableHeader,
21
21
  TableRow,
22
22
  } from '@/components/ui/table';
23
+ import { useApp } from '@hed-hog/next-app-provider';
23
24
  import { AlertTriangle, Loader2 } from 'lucide-react';
24
25
  import { useTranslations } from 'next-intl';
25
26
  import { useMemo, useState } from 'react';
@@ -46,6 +47,7 @@ function toPercent(value: number) {
46
47
 
47
48
  export default function AgingDefaultReportPage() {
48
49
  const t = useTranslations('finance.AgingDefaultReportPage');
50
+ const { currentLocaleCode } = useApp();
49
51
 
50
52
  const [horizonte, setHorizonte] = useState<string | null>(null);
51
53
  const [cenario, setCenario] = useState<Scenario | null>(null);
@@ -213,7 +215,7 @@ export default function AgingDefaultReportPage() {
213
215
  />
214
216
  <Tooltip
215
217
  formatter={(value: number) =>
216
- new Intl.NumberFormat('pt-BR', {
218
+ new Intl.NumberFormat(currentLocaleCode || undefined, {
217
219
  style: 'currency',
218
220
  currency: 'BRL',
219
221
  }).format(value)
@@ -21,6 +21,7 @@ import {
21
21
  TableHeader,
22
22
  TableRow,
23
23
  } from '@/components/ui/table';
24
+ import { useApp } from '@hed-hog/next-app-provider';
24
25
  import {
25
26
  Download,
26
27
  Loader2,
@@ -46,6 +47,7 @@ type Scenario = 'base' | 'pessimista' | 'otimista';
46
47
 
47
48
  export default function CashPositionReportPage() {
48
49
  const t = useTranslations('finance.CashPositionReportPage');
50
+ const { currentLocaleCode } = useApp();
49
51
 
50
52
  const [horizonte, setHorizonte] = useState<string | null>(null);
51
53
  const [cenario, setCenario] = useState<Scenario | null>(null);
@@ -309,7 +311,7 @@ export default function CashPositionReportPage() {
309
311
  />
310
312
  <Tooltip
311
313
  formatter={(value: number) =>
312
- new Intl.NumberFormat('pt-BR', {
314
+ new Intl.NumberFormat(currentLocaleCode || undefined, {
313
315
  style: 'currency',
314
316
  currency: 'BRL',
315
317
  }).format(value)
@@ -3,8 +3,8 @@
3
3
  import { FinancePageSection } from '@/app/(app)/(libraries)/finance/_components/finance-layout';
4
4
  import { Page, PageHeader } from '@/components/entity-list';
5
5
  import { Badge } from '@/components/ui/badge';
6
- import { KpiCardsGrid } from '@/components/ui/kpi-cards-grid';
7
6
  import { Input } from '@/components/ui/input';
7
+ import { KpiCardsGrid } from '@/components/ui/kpi-cards-grid';
8
8
  import { Label } from '@/components/ui/label';
9
9
  import { Money } from '@/components/ui/money';
10
10
  import {
@@ -49,16 +49,12 @@ const LINE_COLORS = {
49
49
  diferenca: '#16a34a',
50
50
  };
51
51
 
52
- const currencyFormatter = new Intl.NumberFormat('pt-BR', {
53
- style: 'currency',
54
- currency: 'BRL',
55
- });
56
-
57
52
  function renderSolidTooltip({
58
53
  active,
59
54
  payload,
60
55
  label,
61
- }: TooltipProps<number, string>) {
56
+ currencyFormatter,
57
+ }: TooltipProps<number, string> & { currencyFormatter: Intl.NumberFormat }) {
62
58
  if (!active || !payload?.length) return null;
63
59
  return (
64
60
  <div className="rounded-lg border bg-popover px-3 py-2 shadow-xl text-popover-foreground text-sm">
@@ -84,6 +80,10 @@ function renderSolidTooltip({
84
80
  export default function OverviewResultsReportPage() {
85
81
  const t = useTranslations('finance.OverviewResultsReportPage');
86
82
  const locale = useLocale();
83
+ const currencyFormatter = new Intl.NumberFormat(locale || undefined, {
84
+ style: 'currency',
85
+ currency: 'BRL',
86
+ });
87
87
  const defaults = getDefaultDateRange();
88
88
  const [from, setFrom] = useState(defaults.from);
89
89
  const [to, setTo] = useState(defaults.to);
@@ -225,7 +225,14 @@ export default function OverviewResultsReportPage() {
225
225
  tick={{ fontSize: 12 }}
226
226
  tickFormatter={(value) => `${(value / 1000).toFixed(0)}k`}
227
227
  />
228
- <Tooltip content={renderSolidTooltip} />
228
+ <Tooltip
229
+ content={(props) =>
230
+ renderSolidTooltip({
231
+ ...(props as TooltipProps<number, string>),
232
+ currencyFormatter,
233
+ })
234
+ }
235
+ />
229
236
  <Legend />
230
237
  <Line
231
238
  type="monotone"
@@ -28,6 +28,7 @@ import {
28
28
  TableHeader,
29
29
  TableRow,
30
30
  } from '@/components/ui/table';
31
+ import { useApp } from '@hed-hog/next-app-provider';
31
32
  import { Crown, PieChartIcon, Users } from 'lucide-react';
32
33
  import { useTranslations } from 'next-intl';
33
34
  import { type FormEvent, useState } from 'react';
@@ -64,13 +65,9 @@ const rankingColors = [
64
65
  '#B45309',
65
66
  ];
66
67
 
67
- const currencyFormatter = new Intl.NumberFormat('pt-BR', {
68
- style: 'currency',
69
- currency: 'BRL',
70
- });
71
-
72
68
  export default function TopCustomersReportPage() {
73
69
  const t = useTranslations('finance.TopCustomersReportPage');
70
+ const { currentLocaleCode } = useApp();
74
71
  const defaults = getDefaultDateRange();
75
72
  const [filters, setFilters] = useState({
76
73
  from: defaults.from,
@@ -79,6 +76,13 @@ export default function TopCustomersReportPage() {
79
76
  search: '',
80
77
  });
81
78
  const [appliedFilters, setAppliedFilters] = useState(filters);
79
+ const currencyFormatter = new Intl.NumberFormat(
80
+ currentLocaleCode || undefined,
81
+ {
82
+ style: 'currency',
83
+ currency: 'BRL',
84
+ }
85
+ );
82
86
  const { data: viewData, isFetching } = useTopCustomersReport({
83
87
  from: appliedFilters.from,
84
88
  to: appliedFilters.to,
@@ -28,6 +28,7 @@ import {
28
28
  TableHeader,
29
29
  TableRow,
30
30
  } from '@/components/ui/table';
31
+ import { useApp } from '@hed-hog/next-app-provider';
31
32
  import { Building2, CircleDollarSign, TriangleAlert } from 'lucide-react';
32
33
  import { useTranslations } from 'next-intl';
33
34
  import { type FormEvent, useState } from 'react';
@@ -62,13 +63,9 @@ const rankingColors = [
62
63
  '#1D4ED8',
63
64
  ];
64
65
 
65
- const currencyFormatter = new Intl.NumberFormat('pt-BR', {
66
- style: 'currency',
67
- currency: 'BRL',
68
- });
69
-
70
66
  export default function TopOperationalExpensesReportPage() {
71
67
  const t = useTranslations('finance.TopOperationalExpensesReportPage');
68
+ const { currentLocaleCode } = useApp();
72
69
  const defaults = getDefaultDateRange();
73
70
  const [filters, setFilters] = useState({
74
71
  from: defaults.from,
@@ -77,6 +74,13 @@ export default function TopOperationalExpensesReportPage() {
77
74
  search: '',
78
75
  });
79
76
  const [appliedFilters, setAppliedFilters] = useState(filters);
77
+ const currencyFormatter = new Intl.NumberFormat(
78
+ currentLocaleCode || undefined,
79
+ {
80
+ style: 'currency',
81
+ currency: 'BRL',
82
+ }
83
+ );
80
84
  const { data: viewData, isFetching } = useTopOperationalExpensesReport({
81
85
  from: appliedFilters.from,
82
86
  to: appliedFilters.to,
@@ -8,6 +8,13 @@
8
8
  "upcoming": {
9
9
  "payable": "To Pay",
10
10
  "receivable": "To Receive",
11
+ "messages": {
12
+ "selectBankAccount": "Select a bank account",
13
+ "createAdjustmentSuccess": "Adjustment created successfully",
14
+ "createAdjustmentError": "Could not create the adjustment",
15
+ "reconcileSuccess": "Reconciliation completed successfully",
16
+ "reconcileError": "Could not reconcile the records"
17
+ },
11
18
  "nextDueDates": "Upcoming due dates"
12
19
  },
13
20
  "alerts": {
@@ -135,6 +142,13 @@
135
142
  "description": "There are no pending approvals.",
136
143
  "refresh": "Refresh"
137
144
  }
145
+ "messages": {
146
+ "invalidTitleForApproval": "Invalid title for approval",
147
+ "approveSuccess": "Title approved successfully",
148
+ "approveError": "Could not approve the title",
149
+ "invalidTitleForRejection": "Invalid title for rejection",
150
+ "rejectSuccess": "Title rejected successfully",
151
+ "rejectError": "Could not reject the title"
138
152
  },
139
153
  "FinanceEntityFieldWithCreate": {
140
154
  "validation": {
@@ -542,6 +556,7 @@
542
556
  },
543
557
  "CollectionsDefaultPage": {
544
558
  "common": { "cancel": "Cancel" },
559
+ "draftStatus": "Draft saved {relativeLabel} • Last saved: {absoluteLabel}",
545
560
  "actions": {
546
561
  "history": "History",
547
562
  "collect": "Collect",
@@ -908,6 +923,12 @@
908
923
  "edit": "Edit",
909
924
  "save": "Save"
910
925
  },
926
+ "validation": {
927
+ "bankRequired": "Bank is required",
928
+ "typeRequired": "Type is required",
929
+ "initialBalanceInvalid": "Invalid initial balance"
930
+ },
931
+ "draftStatus": "Draft saved {relativeLabel} • Last saved: {absoluteLabel}",
911
932
  "messages": {
912
933
  "createSuccess": "Bank account created successfully",
913
934
  "createError": "Failed to create bank account",
@@ -945,6 +966,18 @@
945
966
  "type": "Type",
946
967
  "description": "Description",
947
968
  "descriptionPlaceholder": "Example: Main Account",
969
+ "currency": "Currency",
970
+ "currencyPlaceholder": "Select a currency",
971
+ "currencySearchPlaceholder": "Search currency...",
972
+ "currencyEntityLabel": "currency",
973
+ "currencyCreateTitle": "New currency",
974
+ "currencyCreateDescription": "Register a new currency to use in bank accounts.",
975
+ "currencyCode": "ISO Code",
976
+ "currencyCodePlaceholder": "Ex.: BRL",
977
+ "currencyName": "Name",
978
+ "currencyNamePlaceholder": "Ex.: Brazilian Real",
979
+ "currencySymbol": "Symbol",
980
+ "currencySymbolPlaceholder": "Ex.: R$",
948
981
  "initialBalance": "Initial Balance",
949
982
  "logo": "Logo",
950
983
  "logoAction": "Upload logo",
@@ -1002,6 +1035,7 @@
1002
1035
  "select": "Select...",
1003
1036
  "cancel": "Cancel"
1004
1037
  },
1038
+ "draftStatus": "Draft saved {relativeLabel} • Last saved: {absoluteLabel}",
1005
1039
  "adjustment": {
1006
1040
  "action": "Create Adjustment",
1007
1041
  "title": "Create Adjustment",
@@ -1071,6 +1105,43 @@
1071
1105
  },
1072
1106
  "StatementsPage": {
1073
1107
  "common": { "cancel": "Cancel" },
1108
+ "formErrors": {
1109
+ "dateRequired": "Date is required",
1110
+ "descriptionRequired": "Description is required",
1111
+ "amountMustBePositive": "Amount must be greater than zero",
1112
+ "bankAccountRequired": "Bank account is required",
1113
+ "fileRequired": "File is required",
1114
+ "fileTypeNotAllowed": "Only CSV or OFX files are allowed"
1115
+ },
1116
+ "draftStatus": "Draft saved {relativeLabel} • Last saved: {absoluteLabel}",
1117
+ "messages": {
1118
+ "importSuccess": "Statement imported successfully",
1119
+ "importError": "Could not import the statement",
1120
+ "selectBankAccount": "Select a bank account",
1121
+ "createEntrySuccess": "Transaction added successfully",
1122
+ "createEntryError": "Could not add the transaction",
1123
+ "selectBankAccountToExport": "Select a bank account to export",
1124
+ "exportError": "Could not export the statement",
1125
+ "saveChangesSuccess": "Changes saved successfully",
1126
+ "saveChangesError": "Could not save changes",
1127
+ "deleteEntrySuccess": "Transaction deleted successfully",
1128
+ "deleteEntryError": "Could not delete the transaction"
1129
+ },
1130
+ "aria": {
1131
+ "newBankAccount": "New bank account"
1132
+ },
1133
+ "newEntry": {
1134
+ "action": "New entry",
1135
+ "title": "New entry",
1136
+ "description": "Add a manual transaction to the bank account statement.",
1137
+ "submit": "Save",
1138
+ "fields": {
1139
+ "date": "Date",
1140
+ "type": "Type",
1141
+ "description": "Description",
1142
+ "amount": "Amount"
1143
+ }
1144
+ },
1074
1145
  "importDialog": {
1075
1146
  "action": "Import",
1076
1147
  "title": "Import Statement",
@@ -1090,7 +1161,11 @@
1090
1161
  "finance": "Finance",
1091
1162
  "current": "Statements"
1092
1163
  },
1093
- "actions": { "export": "Export" },
1164
+ "actions": {
1165
+ "export": "Export",
1166
+ "saveChanges": "Save changes",
1167
+ "savingChanges": "Saving..."
1168
+ },
1094
1169
  "filters": {
1095
1170
  "selectAccount": "Select account...",
1096
1171
  "searchPlaceholder": "Search in description..."
@@ -1115,6 +1190,12 @@
1115
1190
  "title": "No transactions found",
1116
1191
  "description": "Import a statement to view account transactions."
1117
1192
  },
1193
+ "deleteDialog": {
1194
+ "title": "Delete transaction",
1195
+ "description": "This action cannot be undone. The transaction will be permanently removed from the statement.",
1196
+ "confirm": "Delete",
1197
+ "deleting": "Deleting..."
1198
+ },
1118
1199
  "types": {
1119
1200
  "inflow": "Inflow",
1120
1201
  "outflow": "Outflow"
@@ -1125,6 +1206,13 @@
1125
1206
  "select": "Select...",
1126
1207
  "cancel": "Cancel"
1127
1208
  },
1209
+ "formErrors": {
1210
+ "sourceAccountRequired": "Source account is required",
1211
+ "destinationAccountRequired": "Destination account is required",
1212
+ "dateRequired": "Date is required",
1213
+ "amountMustBePositive": "Amount must be greater than zero",
1214
+ "differentAccounts": "Source and destination accounts must be different"
1215
+ },
1128
1216
  "newTransfer": {
1129
1217
  "action": "New Transfer",
1130
1218
  "title": "New Transfer",
@@ -1154,6 +1242,11 @@
1154
1242
  "activeAccounts": "Active Accounts",
1155
1243
  "available": "available"
1156
1244
  },
1245
+ "draftStatus": "Draft saved {relativeLabel} • Last saved: {absoluteLabel}",
1246
+ "transferCreatedSuccess": "Transfer created successfully",
1247
+ "transferCreateError": "Error creating transfer",
1248
+ "allAccounts": "All accounts",
1249
+ "searchPlaceholder": "Search in description...",
1157
1250
  "table": {
1158
1251
  "title": "Recent Transfers",
1159
1252
  "description": "Transfer history between accounts",
@@ -1161,6 +1254,7 @@
1161
1254
  "date": "Date",
1162
1255
  "source": "Source",
1163
1256
  "destination": "Destination",
1257
+ "arrow": "→",
1164
1258
  "value": "Value",
1165
1259
  "description": "Description"
1166
1260
  }
@@ -1184,6 +1278,11 @@
1184
1278
  "searchPlaceholder": "Search by action, entity, summary, id or IP",
1185
1279
  "action": "Action",
1186
1280
  "allActions": "All actions",
1281
+ "actionOptions": {
1282
+ "create": "Create",
1283
+ "update": "Update",
1284
+ "delete": "Delete"
1285
+ },
1187
1286
  "userPlaceholder": "Author (User ID)",
1188
1287
  "entity": "Entity",
1189
1288
  "allEntities": "All entities",
@@ -1196,7 +1295,8 @@
1196
1295
  "action": "Action",
1197
1296
  "entity": "Entity",
1198
1297
  "record": "Record",
1199
- "summary": "Summary"
1298
+ "summary": "Summary",
1299
+ "ip": "IP"
1200
1300
  },
1201
1301
  "loading": "Loading logs...",
1202
1302
  "empty": "No logs found."
@@ -1208,6 +1308,7 @@
1208
1308
  "cancel": "Cancel",
1209
1309
  "save": "Save"
1210
1310
  },
1311
+ "draftStatus": "Draft saved {relativeLabel} • Last saved: {absoluteLabel}",
1211
1312
  "messages": {
1212
1313
  "createSuccess": "Category created successfully",
1213
1314
  "updateSuccess": "Category updated successfully",
@@ -1275,6 +1376,7 @@
1275
1376
  "cancel": "Cancel",
1276
1377
  "save": "Save"
1277
1378
  },
1379
+ "draftStatus": "Draft saved {relativeLabel} • Last saved: {absoluteLabel}",
1278
1380
  "messages": {
1279
1381
  "createSuccess": "Cost center created successfully",
1280
1382
  "createError": "Error creating cost center",
@@ -1332,6 +1434,7 @@
1332
1434
  "cancel": "Cancel",
1333
1435
  "save": "Save"
1334
1436
  },
1437
+ "draftStatus": "Draft saved {relativeLabel} • Last saved: {absoluteLabel}",
1335
1438
  "messages": {
1336
1439
  "createSuccess": "Period closed successfully",
1337
1440
  "createError": "Error closing period"
@@ -1701,6 +1804,10 @@
1701
1804
  "positive": "Positive",
1702
1805
  "negative": "Negative",
1703
1806
  "withGrowth": "With growth of {value}%"
1807
+ },
1808
+ "messages": {
1809
+ "saveSuccess": "Scenario saved successfully",
1810
+ "saveError": "Error saving scenario"
1704
1811
  }
1705
1812
  },
1706
1813
  "OverviewResultsReportPage": {
@@ -1874,6 +1981,7 @@
1874
1981
  "cancel": "Cancel",
1875
1982
  "save": "Save"
1876
1983
  },
1984
+ "draftStatus": "Draft saved {relativeLabel} • Last saved: {absoluteLabel}",
1877
1985
  "messages": {
1878
1986
  "createSuccess": "Currency created successfully",
1879
1987
  "createError": "Error creating currency",