@hed-hog/finance 0.0.245 → 0.0.249

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.
@@ -9,6 +9,14 @@ import {
9
9
  CardHeader,
10
10
  CardTitle,
11
11
  } from '@/components/ui/card';
12
+ import {
13
+ Dialog,
14
+ DialogContent,
15
+ DialogDescription,
16
+ DialogFooter,
17
+ DialogHeader,
18
+ DialogTitle,
19
+ } from '@/components/ui/dialog';
12
20
  import { FilterBar } from '@/components/ui/filter-bar';
13
21
  import {
14
22
  Form,
@@ -166,7 +174,7 @@ function ImportarExtratoSheet({
166
174
  <FormLabel>{t('importDialog.bankAccount')}</FormLabel>
167
175
  <Select value={field.value} onValueChange={field.onChange}>
168
176
  <FormControl>
169
- <SelectTrigger>
177
+ <SelectTrigger className="w-full">
170
178
  <SelectValue
171
179
  placeholder={t('importDialog.selectAccount')}
172
180
  />
@@ -238,8 +246,10 @@ export default function ExtratosPage() {
238
246
 
239
247
  const [contaFilter, setContaFilter] = useState<string>('');
240
248
  const [search, setSearch] = useState('');
249
+ const [extratoSelecionado, setExtratoSelecionado] =
250
+ useState<Statement | null>(null);
241
251
 
242
- const { data: contasBancarias } = useQuery<BankAccount[]>({
252
+ const { data: contasBancarias = [] } = useQuery<BankAccount[]>({
243
253
  queryKey: ['finance-bank-accounts'],
244
254
  queryFn: async () => {
245
255
  const response = await request({
@@ -249,7 +259,6 @@ export default function ExtratosPage() {
249
259
 
250
260
  return (response?.data || []) as BankAccount[];
251
261
  },
252
- initialData: [],
253
262
  });
254
263
 
255
264
  useEffect(() => {
@@ -285,7 +294,9 @@ export default function ExtratosPage() {
285
294
  searchParams,
286
295
  ]);
287
296
 
288
- const { data: extratos, refetch: refetchExtratos } = useQuery<Statement[]>({
297
+ const { data: extratos = [], refetch: refetchExtratos } = useQuery<
298
+ Statement[]
299
+ >({
289
300
  queryKey: ['finance-statements', contaFilter],
290
301
  queryFn: async () => {
291
302
  if (!contaFilter) {
@@ -299,7 +310,6 @@ export default function ExtratosPage() {
299
310
 
300
311
  return (response?.data || []) as Statement[];
301
312
  },
302
- initialData: [],
303
313
  });
304
314
 
305
315
  const filteredExtratos = useMemo(
@@ -311,6 +321,11 @@ export default function ExtratosPage() {
311
321
  );
312
322
 
313
323
  const conta = contasBancarias.find((item) => item.id === contaFilter);
324
+ const contaExtratoSelecionado = extratoSelecionado
325
+ ? contasBancarias.find(
326
+ (item) => item.id === extratoSelecionado.contaBancariaId
327
+ )
328
+ : undefined;
314
329
  const totalEntradas = filteredExtratos
315
330
  .filter((e) => e.tipo === 'entrada')
316
331
  .reduce((acc, e) => acc + e.valor, 0);
@@ -466,60 +481,182 @@ export default function ExtratosPage() {
466
481
  </CardDescription>
467
482
  </CardHeader>
468
483
  <CardContent>
469
- <Table>
470
- <TableHeader>
471
- <TableRow>
472
- <TableHead>{t('table.headers.date')}</TableHead>
473
- <TableHead>{t('table.headers.description')}</TableHead>
474
- <TableHead className="text-right">
475
- {t('table.headers.value')}
476
- </TableHead>
477
- <TableHead>{t('table.headers.type')}</TableHead>
478
- <TableHead>{t('table.headers.reconciliation')}</TableHead>
479
- </TableRow>
480
- </TableHeader>
481
- <TableBody>
482
- {filteredExtratos.map((extrato) => (
483
- <TableRow key={extrato.id}>
484
- <TableCell>{formatarData(extrato.data)}</TableCell>
485
- <TableCell>{extrato.descricao}</TableCell>
486
- <TableCell className="text-right">
487
- <span
488
- className={
489
- extrato.tipo === 'entrada'
490
- ? 'text-green-600'
491
- : 'text-red-600'
484
+ <div className="overflow-x-auto">
485
+ <Table className="min-w-[760px] table-fixed">
486
+ <TableHeader>
487
+ <TableRow>
488
+ <TableHead className="w-[110px]">
489
+ {t('table.headers.date')}
490
+ </TableHead>
491
+ <TableHead>{t('table.headers.description')}</TableHead>
492
+ <TableHead className="w-[130px] text-right">
493
+ {t('table.headers.value')}
494
+ </TableHead>
495
+ <TableHead className="w-[110px]">
496
+ {t('table.headers.type')}
497
+ </TableHead>
498
+ <TableHead className="w-[140px]">
499
+ {t('table.headers.reconciliation')}
500
+ </TableHead>
501
+ </TableRow>
502
+ </TableHeader>
503
+ <TableBody>
504
+ {filteredExtratos.map((extrato) => (
505
+ <TableRow
506
+ key={extrato.id}
507
+ className="cursor-pointer"
508
+ onClick={() => setExtratoSelecionado(extrato)}
509
+ onKeyDown={(event) => {
510
+ if (event.key === 'Enter' || event.key === ' ') {
511
+ event.preventDefault();
512
+ setExtratoSelecionado(extrato);
492
513
  }
493
- >
494
- {extrato.tipo === 'saida' && '-'}
495
- <Money value={extrato.valor} />
496
- </span>
497
- </TableCell>
498
- <TableCell>
499
- {extrato.tipo === 'entrada' ? (
500
- <span className="flex items-center gap-1 text-green-600">
501
- <ArrowUpRight className="h-4 w-4" />
502
- {t('types.inflow')}
514
+ }}
515
+ role="button"
516
+ tabIndex={0}
517
+ >
518
+ <TableCell>{formatarData(extrato.data)}</TableCell>
519
+ <TableCell className="truncate" title={extrato.descricao}>
520
+ {extrato.descricao}
521
+ </TableCell>
522
+ <TableCell className="text-right">
523
+ <span
524
+ className={
525
+ extrato.tipo === 'entrada'
526
+ ? 'text-green-600'
527
+ : 'text-red-600'
528
+ }
529
+ >
530
+ <Money value={extrato.valor} />
503
531
  </span>
504
- ) : (
505
- <span className="flex items-center gap-1 text-red-600">
506
- <ArrowDownRight className="h-4 w-4" />
507
- {t('types.outflow')}
508
- </span>
509
- )}
510
- </TableCell>
511
- <TableCell>
512
- <StatusBadge
513
- status={extrato.statusConciliacao}
514
- type="conciliacao"
515
- />
516
- </TableCell>
517
- </TableRow>
518
- ))}
519
- </TableBody>
520
- </Table>
532
+ </TableCell>
533
+ <TableCell>
534
+ {extrato.tipo === 'entrada' ? (
535
+ <span className="flex items-center gap-1 text-green-600">
536
+ <ArrowUpRight className="h-4 w-4" />
537
+ {t('types.inflow')}
538
+ </span>
539
+ ) : (
540
+ <span className="flex items-center gap-1 text-red-600">
541
+ <ArrowDownRight className="h-4 w-4" />
542
+ {t('types.outflow')}
543
+ </span>
544
+ )}
545
+ </TableCell>
546
+ <TableCell>
547
+ <StatusBadge
548
+ status={extrato.statusConciliacao}
549
+ type="conciliacao"
550
+ />
551
+ </TableCell>
552
+ </TableRow>
553
+ ))}
554
+ </TableBody>
555
+ </Table>
556
+ </div>
521
557
  </CardContent>
522
558
  </Card>
559
+
560
+ <Dialog
561
+ open={!!extratoSelecionado}
562
+ onOpenChange={(open) => {
563
+ if (!open) {
564
+ setExtratoSelecionado(null);
565
+ }
566
+ }}
567
+ >
568
+ <DialogContent className="sm:max-w-lg">
569
+ <DialogHeader>
570
+ <DialogTitle>{t('table.title')}</DialogTitle>
571
+ <DialogDescription>{t('header.description')}</DialogDescription>
572
+ </DialogHeader>
573
+
574
+ {extratoSelecionado ? (
575
+ <div className="space-y-4 rounded-md border p-4">
576
+ <div className="text-center">
577
+ <p className="text-sm text-muted-foreground">
578
+ {t('table.headers.reconciliation')}
579
+ </p>
580
+ <div className="mt-1 flex justify-center">
581
+ <StatusBadge
582
+ status={extratoSelecionado.statusConciliacao}
583
+ type="conciliacao"
584
+ />
585
+ </div>
586
+ </div>
587
+
588
+ <div className="grid grid-cols-1 gap-3 sm:grid-cols-2">
589
+ <div>
590
+ <p className="text-xs text-muted-foreground">
591
+ {t('table.headers.date')}
592
+ </p>
593
+ <p className="font-medium">
594
+ {formatarData(extratoSelecionado.data)}
595
+ </p>
596
+ </div>
597
+ <div>
598
+ <p className="text-xs text-muted-foreground">
599
+ {t('table.headers.type')}
600
+ </p>
601
+ <p className="font-medium">
602
+ {extratoSelecionado.tipo === 'entrada'
603
+ ? t('types.inflow')
604
+ : t('types.outflow')}
605
+ </p>
606
+ </div>
607
+ <div className="sm:col-span-2">
608
+ <p className="text-xs text-muted-foreground">
609
+ {t('table.headers.description')}
610
+ </p>
611
+ <p className="font-medium wrap-break-word">
612
+ {extratoSelecionado.descricao}
613
+ </p>
614
+ </div>
615
+ <div>
616
+ <p className="text-xs text-muted-foreground">
617
+ {t('table.headers.value')}
618
+ </p>
619
+ <p
620
+ className={`font-medium ${
621
+ extratoSelecionado.tipo === 'entrada'
622
+ ? 'text-green-600'
623
+ : 'text-red-600'
624
+ }`}
625
+ >
626
+ <Money value={extratoSelecionado.valor} />
627
+ </p>
628
+ </div>
629
+ <div>
630
+ <p className="text-xs text-muted-foreground">
631
+ {t('importDialog.bankAccount')}
632
+ </p>
633
+ <p className="font-medium">
634
+ {contaExtratoSelecionado
635
+ ? `${contaExtratoSelecionado.banco} - ${contaExtratoSelecionado.descricao}`
636
+ : '-'}
637
+ </p>
638
+ </div>
639
+ <div className="sm:col-span-2">
640
+ <p className="text-xs text-muted-foreground">ID</p>
641
+ <p className="font-mono text-xs break-all">
642
+ {extratoSelecionado.id}
643
+ </p>
644
+ </div>
645
+ </div>
646
+ </div>
647
+ ) : null}
648
+
649
+ <DialogFooter>
650
+ <Button
651
+ type="button"
652
+ variant="outline"
653
+ onClick={() => setExtratoSelecionado(null)}
654
+ >
655
+ {t('common.cancel')}
656
+ </Button>
657
+ </DialogFooter>
658
+ </DialogContent>
659
+ </Dialog>
523
660
  </Page>
524
661
  );
525
662
  }
@@ -58,10 +58,34 @@ SELECT
58
58
  NOW()
59
59
  FROM ordered_missing;
60
60
 
61
+ -- Sincroniza o campo setting.value com os valores atuais da setting_list
62
+ WITH target AS (
63
+ SELECT id
64
+ FROM setting
65
+ WHERE slug = 'storage-accept-mimetype'
66
+ ),
67
+ rebuilt AS (
68
+ SELECT
69
+ t.id,
70
+ COALESCE(
71
+ jsonb_agg(to_jsonb(sl.value) ORDER BY sl."order", sl.id)::text,
72
+ '[]'
73
+ ) AS value_array
74
+ FROM target t
75
+ LEFT JOIN setting_list sl ON sl.setting_id = t.id
76
+ GROUP BY t.id
77
+ )
78
+ UPDATE setting s
79
+ SET value = r.value_array,
80
+ updated_at = NOW()
81
+ FROM rebuilt r
82
+ WHERE s.id = r.id;
83
+
61
84
  -- Verificação
62
85
  SELECT
63
86
  s.id,
64
87
  s.slug,
88
+ s.value,
65
89
  sl."order",
66
90
  sl.value
67
91
  FROM setting s
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hed-hog/finance",
3
- "version": "0.0.245",
3
+ "version": "0.0.249",
4
4
  "main": "dist/index.js",
5
5
  "types": "dist/index.d.ts",
6
6
  "dependencies": {
@@ -9,14 +9,14 @@
9
9
  "@nestjs/core": "^11",
10
10
  "@nestjs/jwt": "^11",
11
11
  "@nestjs/mapped-types": "*",
12
+ "@hed-hog/tag": "0.0.249",
12
13
  "@hed-hog/api-pagination": "0.0.5",
14
+ "@hed-hog/contact": "0.0.249",
13
15
  "@hed-hog/api-prisma": "0.0.4",
14
- "@hed-hog/tag": "0.0.240",
15
- "@hed-hog/api-locale": "0.0.11",
16
- "@hed-hog/api": "0.0.3",
17
- "@hed-hog/contact": "0.0.240",
18
16
  "@hed-hog/api-types": "0.0.1",
19
- "@hed-hog/core": "0.0.240"
17
+ "@hed-hog/api": "0.0.3",
18
+ "@hed-hog/api-locale": "0.0.11",
19
+ "@hed-hog/core": "0.0.249"
20
20
  },
21
21
  "exports": {
22
22
  ".": {