@hed-hog/finance 0.0.228 → 0.0.229

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.
@@ -551,14 +551,16 @@ export default function ContasBancariasPage() {
551
551
  </span>
552
552
  </div>
553
553
  )}
554
- <div className="flex gap-2 pt-2">
554
+ <div className="flex flex-wrap gap-2 pt-2">
555
555
  <Button
556
556
  variant="outline"
557
557
  size="sm"
558
- className="flex-1 bg-transparent"
558
+ className="min-w-0 flex-1 basis-[calc(50%-0.25rem)] bg-transparent"
559
559
  asChild
560
560
  >
561
- <Link href="/finance/cash-and-banks/statements">
561
+ <Link
562
+ href={`/finance/cash-and-banks/statements?bank_account_id=${conta.id}`}
563
+ >
562
564
  <Eye className="mr-2 h-4 w-4" />
563
565
  {t('accountCard.statement')}
564
566
  </Link>
@@ -566,31 +568,35 @@ export default function ContasBancariasPage() {
566
568
  <Button
567
569
  variant="outline"
568
570
  size="sm"
569
- className="flex-1 bg-transparent"
571
+ className="min-w-0 flex-1 basis-[calc(50%-0.25rem)] bg-transparent"
570
572
  asChild
571
573
  >
572
- <Link href="/finance/cash-and-banks/bank-reconciliation">
574
+ <Link
575
+ href={`/finance/cash-and-banks/bank-reconciliation?bank_account_id=${conta.id}`}
576
+ >
573
577
  <RefreshCw className="mr-2 h-4 w-4" />
574
578
  {t('accountCard.reconcile')}
575
579
  </Link>
576
580
  </Button>
577
- <Button variant="outline" size="sm">
578
- <Upload className="h-4 w-4" />
579
- </Button>
580
- <Button
581
- variant="outline"
582
- size="sm"
583
- onClick={() => handleEdit(conta)}
584
- >
585
- <Pencil className="h-4 w-4" />
586
- </Button>
587
- <Button
588
- variant="outline"
589
- size="sm"
590
- onClick={() => handleDelete(conta.id)}
591
- >
592
- <Trash2 className="h-4 w-4" />
593
- </Button>
581
+ <div className="ml-auto flex shrink-0 gap-2">
582
+ <Button variant="outline" size="sm">
583
+ <Upload className="h-4 w-4" />
584
+ </Button>
585
+ <Button
586
+ variant="outline"
587
+ size="sm"
588
+ onClick={() => handleEdit(conta)}
589
+ >
590
+ <Pencil className="h-4 w-4" />
591
+ </Button>
592
+ <Button
593
+ variant="outline"
594
+ size="sm"
595
+ onClick={() => handleDelete(conta.id)}
596
+ >
597
+ <Trash2 className="h-4 w-4" />
598
+ </Button>
599
+ </div>
594
600
  </div>
595
601
  </div>
596
602
  </CardContent>
@@ -35,7 +35,8 @@ import {
35
35
  import { StatusBadge } from '@/components/ui/status-badge';
36
36
  import { Check, DollarSign, Link2, RefreshCw } from 'lucide-react';
37
37
  import { useTranslations } from 'next-intl';
38
- import { useState } from 'react';
38
+ import { usePathname, useRouter, useSearchParams } from 'next/navigation';
39
+ import { useEffect, useState } from 'react';
39
40
  import { formatarData, formatarMoeda } from '../../_lib/formatters';
40
41
  import { useFinanceData } from '../../_lib/use-finance-data';
41
42
 
@@ -101,6 +102,10 @@ function CriarAjusteDialog({ t }: { t: ReturnType<typeof useTranslations> }) {
101
102
 
102
103
  export default function ConciliacaoPage() {
103
104
  const t = useTranslations('finance.BankReconciliationPage');
105
+ const pathname = usePathname();
106
+ const router = useRouter();
107
+ const searchParams = useSearchParams();
108
+ const bankAccountIdFromUrl = searchParams.get('bank_account_id');
104
109
  const { data } = useFinanceData();
105
110
  const { extratos, titulosPagar, titulosReceber, contasBancarias, pessoas } =
106
111
  data;
@@ -138,10 +143,43 @@ export default function ConciliacaoPage() {
138
143
  ),
139
144
  ];
140
145
 
141
- const [contaFilter, setContaFilter] = useState<string>('1');
146
+ const [contaFilter, setContaFilter] = useState<string>('');
142
147
  const [selectedExtrato, setSelectedExtrato] = useState<string | null>(null);
143
148
  const [selectedTitulo, setSelectedTitulo] = useState<string | null>(null);
144
149
 
150
+ useEffect(() => {
151
+ const firstAccount = contasBancarias[0];
152
+
153
+ if (!firstAccount) {
154
+ return;
155
+ }
156
+
157
+ const hasAccountFromUrl =
158
+ !!bankAccountIdFromUrl &&
159
+ contasBancarias.some((account) => account.id === bankAccountIdFromUrl);
160
+
161
+ const nextAccountId = hasAccountFromUrl
162
+ ? (bankAccountIdFromUrl as string)
163
+ : firstAccount.id;
164
+
165
+ if (contaFilter !== nextAccountId) {
166
+ setContaFilter(nextAccountId);
167
+ }
168
+
169
+ if (bankAccountIdFromUrl !== nextAccountId) {
170
+ const params = new URLSearchParams(searchParams.toString());
171
+ params.set('bank_account_id', nextAccountId);
172
+ router.replace(`${pathname}?${params.toString()}`);
173
+ }
174
+ }, [
175
+ bankAccountIdFromUrl,
176
+ contaFilter,
177
+ contasBancarias,
178
+ pathname,
179
+ router,
180
+ searchParams,
181
+ ]);
182
+
145
183
  const extratosFiltered = extratosPendentes.filter(
146
184
  (e) => e.contaBancariaId === contaFilter
147
185
  );
@@ -171,8 +209,17 @@ export default function ConciliacaoPage() {
171
209
  />
172
210
 
173
211
  <div className="flex flex-col gap-4 sm:flex-row sm:items-center sm:justify-between">
174
- <Select value={contaFilter} onValueChange={setContaFilter}>
175
- <SelectTrigger className="w-[280px]">
212
+ <Select
213
+ value={contaFilter}
214
+ onValueChange={(value) => {
215
+ setContaFilter(value);
216
+
217
+ const params = new URLSearchParams(searchParams.toString());
218
+ params.set('bank_account_id', value);
219
+ router.replace(`${pathname}?${params.toString()}`);
220
+ }}
221
+ >
222
+ <SelectTrigger className="w-full sm:w-[280px]">
176
223
  <SelectValue placeholder={t('filters.selectAccount')} />
177
224
  </SelectTrigger>
178
225
  <SelectContent>
@@ -38,11 +38,34 @@ import {
38
38
  TableHeader,
39
39
  TableRow,
40
40
  } from '@/components/ui/table';
41
+ import { useApp, useQuery } from '@hed-hog/next-app-provider';
41
42
  import { ArrowDownRight, ArrowUpRight, Download, Upload } from 'lucide-react';
42
43
  import { useTranslations } from 'next-intl';
43
- import { useState } from 'react';
44
+ import { usePathname, useRouter, useSearchParams } from 'next/navigation';
45
+ import { useEffect, useMemo, useState } from 'react';
44
46
  import { formatarData } from '../../_lib/formatters';
45
- import { useFinanceData } from '../../_lib/use-finance-data';
47
+
48
+ type BankAccount = {
49
+ id: string;
50
+ banco: string;
51
+ descricao: string;
52
+ saldoAtual: number;
53
+ };
54
+
55
+ type Statement = {
56
+ id: string;
57
+ contaBancariaId: string;
58
+ data: string;
59
+ descricao: string;
60
+ valor: number;
61
+ tipo: 'entrada' | 'saida';
62
+ statusConciliacao:
63
+ | 'importado'
64
+ | 'pendente'
65
+ | 'conciliado'
66
+ | 'estornado'
67
+ | 'ajustado';
68
+ };
46
69
 
47
70
  function ImportarExtratoDialog({
48
71
  contasBancarias,
@@ -101,20 +124,86 @@ function ImportarExtratoDialog({
101
124
 
102
125
  export default function ExtratosPage() {
103
126
  const t = useTranslations('finance.StatementsPage');
104
- const { data } = useFinanceData();
105
- const { extratos, contasBancarias } = data;
127
+ const { request } = useApp();
128
+ const pathname = usePathname();
129
+ const router = useRouter();
130
+ const searchParams = useSearchParams();
131
+ const bankAccountIdFromUrl = searchParams.get('bank_account_id');
106
132
 
107
- const [contaFilter, setContaFilter] = useState<string>('1');
133
+ const [contaFilter, setContaFilter] = useState<string>('');
108
134
  const [search, setSearch] = useState('');
109
135
 
110
- const filteredExtratos = extratos.filter((extrato) => {
111
- const matchesConta = extrato.contaBancariaId === contaFilter;
112
- const matchesSearch = extrato.descricao
113
- .toLowerCase()
114
- .includes(search.toLowerCase());
115
- return matchesConta && matchesSearch;
136
+ const { data: contasBancarias } = useQuery<BankAccount[]>({
137
+ queryKey: ['finance-bank-accounts'],
138
+ queryFn: async () => {
139
+ const response = await request({
140
+ url: '/finance/bank-accounts',
141
+ method: 'GET',
142
+ });
143
+
144
+ return (response?.data || []) as BankAccount[];
145
+ },
146
+ initialData: [],
147
+ });
148
+
149
+ useEffect(() => {
150
+ const firstAccount = contasBancarias[0];
151
+
152
+ if (!firstAccount) {
153
+ return;
154
+ }
155
+
156
+ const hasAccountFromUrl =
157
+ !!bankAccountIdFromUrl &&
158
+ contasBancarias.some((account) => account.id === bankAccountIdFromUrl);
159
+
160
+ const nextAccountId = hasAccountFromUrl
161
+ ? (bankAccountIdFromUrl as string)
162
+ : firstAccount.id;
163
+
164
+ if (contaFilter !== nextAccountId) {
165
+ setContaFilter(nextAccountId);
166
+ }
167
+
168
+ if (bankAccountIdFromUrl !== nextAccountId) {
169
+ const params = new URLSearchParams(searchParams.toString());
170
+ params.set('bank_account_id', nextAccountId);
171
+ router.replace(`${pathname}?${params.toString()}`);
172
+ }
173
+ }, [
174
+ bankAccountIdFromUrl,
175
+ contaFilter,
176
+ contasBancarias,
177
+ pathname,
178
+ router,
179
+ searchParams,
180
+ ]);
181
+
182
+ const { data: extratos } = useQuery<Statement[]>({
183
+ queryKey: ['finance-statements', contaFilter],
184
+ queryFn: async () => {
185
+ if (!contaFilter) {
186
+ return [];
187
+ }
188
+
189
+ const response = await request({
190
+ url: `/finance/statements?bank_account_id=${contaFilter}`,
191
+ method: 'GET',
192
+ });
193
+
194
+ return (response?.data || []) as Statement[];
195
+ },
196
+ initialData: [],
116
197
  });
117
198
 
199
+ const filteredExtratos = useMemo(
200
+ () =>
201
+ extratos.filter((extrato) =>
202
+ extrato.descricao.toLowerCase().includes(search.toLowerCase())
203
+ ),
204
+ [extratos, search]
205
+ );
206
+
118
207
  const conta = contasBancarias.find((item) => item.id === contaFilter);
119
208
  const totalEntradas = filteredExtratos
120
209
  .filter((e) => e.tipo === 'entrada')
@@ -145,8 +234,17 @@ export default function ExtratosPage() {
145
234
  />
146
235
 
147
236
  <div className="flex flex-col gap-4 sm:flex-row sm:items-center">
148
- <Select value={contaFilter} onValueChange={setContaFilter}>
149
- <SelectTrigger className="w-[280px]">
237
+ <Select
238
+ value={contaFilter}
239
+ onValueChange={(value) => {
240
+ setContaFilter(value);
241
+
242
+ const params = new URLSearchParams(searchParams.toString());
243
+ params.set('bank_account_id', value);
244
+ router.replace(`${pathname}?${params.toString()}`);
245
+ }}
246
+ >
247
+ <SelectTrigger className="w-full sm:w-[280px]">
150
248
  <SelectValue placeholder={t('filters.selectAccount')} />
151
249
  </SelectTrigger>
152
250
  <SelectContent>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hed-hog/finance",
3
- "version": "0.0.228",
3
+ "version": "0.0.229",
4
4
  "main": "dist/index.js",
5
5
  "types": "dist/index.d.ts",
6
6
  "dependencies": {
@@ -10,11 +10,11 @@
10
10
  "@nestjs/jwt": "^11",
11
11
  "@nestjs/mapped-types": "*",
12
12
  "@hed-hog/api-prisma": "0.0.4",
13
- "@hed-hog/tag": "0.0.223",
14
13
  "@hed-hog/api-locale": "0.0.11",
15
14
  "@hed-hog/api-pagination": "0.0.5",
16
- "@hed-hog/api-types": "0.0.1",
15
+ "@hed-hog/tag": "0.0.223",
17
16
  "@hed-hog/api": "0.0.3",
17
+ "@hed-hog/api-types": "0.0.1",
18
18
  "@hed-hog/contact": "0.0.223"
19
19
  },
20
20
  "exports": {