@hed-hog/finance 0.0.300 → 0.0.302
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.
- package/dist/finance.contract-activated.subscriber.d.ts +24 -0
- package/dist/finance.contract-activated.subscriber.d.ts.map +1 -0
- package/dist/finance.contract-activated.subscriber.js +519 -0
- package/dist/finance.contract-activated.subscriber.js.map +1 -0
- package/dist/finance.contract-activated.subscriber.spec.d.ts +2 -0
- package/dist/finance.contract-activated.subscriber.spec.d.ts.map +1 -0
- package/dist/finance.contract-activated.subscriber.spec.js +302 -0
- package/dist/finance.contract-activated.subscriber.spec.js.map +1 -0
- package/dist/finance.module.d.ts.map +1 -1
- package/dist/finance.module.js +6 -1
- package/dist/finance.module.js.map +1 -1
- package/hedhog/data/menu.yaml +0 -17
- package/hedhog/frontend/app/_components/finance-layout.tsx.ejs +108 -0
- package/hedhog/frontend/app/accounts-payable/approvals/page.tsx.ejs +51 -69
- package/hedhog/frontend/app/accounts-payable/installments/page.tsx.ejs +1312 -1138
- package/hedhog/frontend/app/accounts-receivable/collections-default/page.tsx.ejs +288 -268
- package/hedhog/frontend/app/accounts-receivable/installments/page.tsx.ejs +1175 -1016
- package/hedhog/frontend/app/administration/audit-logs/page.tsx.ejs +157 -173
- package/hedhog/frontend/app/administration/categories/page.tsx.ejs +44 -62
- package/hedhog/frontend/app/administration/cost-centers/page.tsx.ejs +62 -80
- package/hedhog/frontend/app/administration/period-close/page.tsx.ejs +151 -170
- package/hedhog/frontend/app/cash-and-banks/bank-accounts/page.tsx.ejs +369 -322
- package/hedhog/frontend/app/cash-and-banks/bank-reconciliation/page.tsx.ejs +204 -226
- package/hedhog/frontend/app/cash-and-banks/statements/page.tsx.ejs +122 -140
- package/hedhog/frontend/app/cash-and-banks/transfers/page.tsx.ejs +31 -49
- package/hedhog/frontend/app/page.tsx.ejs +3 -370
- package/hedhog/frontend/app/planning/cash-flow-forecast/page.tsx.ejs +150 -182
- package/hedhog/frontend/app/planning/receivables-calendar/page.tsx.ejs +52 -70
- package/hedhog/frontend/app/planning/scenarios/page.tsx.ejs +101 -95
- package/hedhog/frontend/app/reports/actual-vs-forecast/page.tsx.ejs +100 -125
- package/hedhog/frontend/app/reports/aging-default/page.tsx.ejs +77 -105
- package/hedhog/frontend/app/reports/cash-position/page.tsx.ejs +99 -134
- package/hedhog/frontend/app/reports/overview-results/page.tsx.ejs +147 -182
- package/hedhog/frontend/app/reports/top-customers/page.tsx.ejs +49 -61
- package/hedhog/frontend/app/reports/top-operational-expenses/page.tsx.ejs +49 -67
- package/hedhog/frontend/messages/en.json +176 -68
- package/hedhog/frontend/messages/pt.json +176 -68
- package/package.json +6 -5
- package/src/finance.contract-activated.subscriber.spec.ts +392 -0
- package/src/finance.contract-activated.subscriber.ts +780 -0
- package/src/finance.module.ts +6 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
|
-
import { Page, PageHeader } from '@/components/entity-list';
|
|
3
|
+
import { EmptyState, Page, PageHeader } from '@/components/entity-list';
|
|
4
4
|
import {
|
|
5
5
|
AlertDialog,
|
|
6
6
|
AlertDialogAction,
|
|
@@ -20,6 +20,7 @@ import {
|
|
|
20
20
|
CardHeader,
|
|
21
21
|
CardTitle,
|
|
22
22
|
} from '@/components/ui/card';
|
|
23
|
+
import { KpiCardsGrid } from '@/components/ui/kpi-cards-grid';
|
|
23
24
|
import {
|
|
24
25
|
Form,
|
|
25
26
|
FormControl,
|
|
@@ -45,6 +46,11 @@ import {
|
|
|
45
46
|
SheetHeader,
|
|
46
47
|
SheetTitle,
|
|
47
48
|
} from '@/components/ui/sheet';
|
|
49
|
+
import {
|
|
50
|
+
FinancePageSection,
|
|
51
|
+
FinanceSheetBody,
|
|
52
|
+
FinanceSheetSection,
|
|
53
|
+
} from '../../_components/finance-layout';
|
|
48
54
|
import { useApp, useQuery } from '@hed-hog/next-app-provider';
|
|
49
55
|
import { zodResolver } from '@hookform/resolvers/zod';
|
|
50
56
|
import {
|
|
@@ -469,7 +475,7 @@ function NovaContaSheet({
|
|
|
469
475
|
}
|
|
470
476
|
}}
|
|
471
477
|
>
|
|
472
|
-
<SheetContent className="w-full sm:max-w-
|
|
478
|
+
<SheetContent className="flex h-full w-full flex-col sm:max-w-2xl">
|
|
473
479
|
<SheetHeader>
|
|
474
480
|
<SheetTitle>
|
|
475
481
|
{editingAccount ? t('common.edit') : t('newAccount.title')}
|
|
@@ -477,37 +483,25 @@ function NovaContaSheet({
|
|
|
477
483
|
<SheetDescription>{t('newAccount.description')}</SheetDescription>
|
|
478
484
|
</SheetHeader>
|
|
479
485
|
<Form {...form}>
|
|
480
|
-
<form
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
<Input
|
|
490
|
-
placeholder={t('fields.bankPlaceholder')}
|
|
491
|
-
{...field}
|
|
492
|
-
/>
|
|
493
|
-
</FormControl>
|
|
494
|
-
<FormMessage />
|
|
495
|
-
</FormItem>
|
|
496
|
-
)}
|
|
497
|
-
/>
|
|
498
|
-
|
|
499
|
-
<div className="grid grid-cols-2 gap-4">
|
|
486
|
+
<form
|
|
487
|
+
className="flex h-full flex-col"
|
|
488
|
+
onSubmit={form.handleSubmit(handleSubmit)}
|
|
489
|
+
>
|
|
490
|
+
<FinanceSheetBody>
|
|
491
|
+
<FinanceSheetSection
|
|
492
|
+
title={t('sections.accountData.title')}
|
|
493
|
+
description={t('sections.accountData.description')}
|
|
494
|
+
>
|
|
500
495
|
<FormField
|
|
501
496
|
control={form.control}
|
|
502
|
-
name="
|
|
497
|
+
name="banco"
|
|
503
498
|
render={({ field }) => (
|
|
504
499
|
<FormItem>
|
|
505
|
-
<FormLabel>{t('fields.
|
|
500
|
+
<FormLabel>{t('fields.bank')}</FormLabel>
|
|
506
501
|
<FormControl>
|
|
507
502
|
<Input
|
|
508
|
-
placeholder=
|
|
503
|
+
placeholder={t('fields.bankPlaceholder')}
|
|
509
504
|
{...field}
|
|
510
|
-
value={field.value || ''}
|
|
511
505
|
/>
|
|
512
506
|
</FormControl>
|
|
513
507
|
<FormMessage />
|
|
@@ -515,15 +509,114 @@ function NovaContaSheet({
|
|
|
515
509
|
)}
|
|
516
510
|
/>
|
|
517
511
|
|
|
512
|
+
<div className="grid gap-4 md:grid-cols-2">
|
|
513
|
+
<FormField
|
|
514
|
+
control={form.control}
|
|
515
|
+
name="agencia"
|
|
516
|
+
render={({ field }) => (
|
|
517
|
+
<FormItem>
|
|
518
|
+
<FormLabel>{t('fields.branch')}</FormLabel>
|
|
519
|
+
<FormControl>
|
|
520
|
+
<Input
|
|
521
|
+
placeholder="0000"
|
|
522
|
+
{...field}
|
|
523
|
+
value={field.value || ''}
|
|
524
|
+
/>
|
|
525
|
+
</FormControl>
|
|
526
|
+
<FormMessage />
|
|
527
|
+
</FormItem>
|
|
528
|
+
)}
|
|
529
|
+
/>
|
|
530
|
+
|
|
531
|
+
<FormField
|
|
532
|
+
control={form.control}
|
|
533
|
+
name="conta"
|
|
534
|
+
render={({ field }) => (
|
|
535
|
+
<FormItem>
|
|
536
|
+
<FormLabel>{t('fields.account')}</FormLabel>
|
|
537
|
+
<FormControl>
|
|
538
|
+
<Input
|
|
539
|
+
placeholder="00000-0"
|
|
540
|
+
{...field}
|
|
541
|
+
value={field.value || ''}
|
|
542
|
+
/>
|
|
543
|
+
</FormControl>
|
|
544
|
+
<FormMessage />
|
|
545
|
+
</FormItem>
|
|
546
|
+
)}
|
|
547
|
+
/>
|
|
548
|
+
</div>
|
|
549
|
+
|
|
550
|
+
<div className="grid gap-4 md:grid-cols-2">
|
|
551
|
+
<FormField
|
|
552
|
+
control={form.control}
|
|
553
|
+
name="tipo"
|
|
554
|
+
render={({ field }) => (
|
|
555
|
+
<FormItem>
|
|
556
|
+
<FormLabel>{t('fields.type')}</FormLabel>
|
|
557
|
+
<Select
|
|
558
|
+
value={field.value}
|
|
559
|
+
onValueChange={field.onChange}
|
|
560
|
+
>
|
|
561
|
+
<FormControl>
|
|
562
|
+
<SelectTrigger className="w-full">
|
|
563
|
+
<SelectValue placeholder={t('common.select')} />
|
|
564
|
+
</SelectTrigger>
|
|
565
|
+
</FormControl>
|
|
566
|
+
<SelectContent>
|
|
567
|
+
<SelectItem value="corrente">
|
|
568
|
+
{t('types.corrente')}
|
|
569
|
+
</SelectItem>
|
|
570
|
+
<SelectItem value="poupanca">
|
|
571
|
+
{t('types.poupanca')}
|
|
572
|
+
</SelectItem>
|
|
573
|
+
<SelectItem value="investimento">
|
|
574
|
+
{t('types.investimento')}
|
|
575
|
+
</SelectItem>
|
|
576
|
+
<SelectItem value="caixa">
|
|
577
|
+
{t('types.caixa')}
|
|
578
|
+
</SelectItem>
|
|
579
|
+
</SelectContent>
|
|
580
|
+
</Select>
|
|
581
|
+
<FormMessage />
|
|
582
|
+
</FormItem>
|
|
583
|
+
)}
|
|
584
|
+
/>
|
|
585
|
+
|
|
586
|
+
<FormField
|
|
587
|
+
control={form.control}
|
|
588
|
+
name="saldoInicial"
|
|
589
|
+
render={({ field }) => (
|
|
590
|
+
<FormItem>
|
|
591
|
+
<FormLabel>{t('fields.initialBalance')}</FormLabel>
|
|
592
|
+
<FormControl>
|
|
593
|
+
<InputMoney
|
|
594
|
+
ref={field.ref}
|
|
595
|
+
name={field.name}
|
|
596
|
+
value={field.value}
|
|
597
|
+
onBlur={field.onBlur}
|
|
598
|
+
onValueChange={(value) =>
|
|
599
|
+
field.onChange(value ?? 0)
|
|
600
|
+
}
|
|
601
|
+
placeholder="0,00"
|
|
602
|
+
disabled={!!editingAccount}
|
|
603
|
+
/>
|
|
604
|
+
</FormControl>
|
|
605
|
+
<FormMessage />
|
|
606
|
+
</FormItem>
|
|
607
|
+
)}
|
|
608
|
+
/>
|
|
609
|
+
</div>
|
|
610
|
+
|
|
518
611
|
<FormField
|
|
519
612
|
control={form.control}
|
|
520
|
-
name="
|
|
613
|
+
name="descricao"
|
|
521
614
|
render={({ field }) => (
|
|
522
615
|
<FormItem>
|
|
523
|
-
<FormLabel>{t('fields.
|
|
616
|
+
<FormLabel>{t('fields.description')}</FormLabel>
|
|
524
617
|
<FormControl>
|
|
525
618
|
<Input
|
|
526
|
-
placeholder=
|
|
619
|
+
placeholder={t('fields.descriptionPlaceholder')}
|
|
527
620
|
{...field}
|
|
528
621
|
value={field.value || ''}
|
|
529
622
|
/>
|
|
@@ -532,150 +625,78 @@ function NovaContaSheet({
|
|
|
532
625
|
</FormItem>
|
|
533
626
|
)}
|
|
534
627
|
/>
|
|
535
|
-
</
|
|
536
|
-
|
|
537
|
-
<div className="grid grid-cols-2 gap-4">
|
|
538
|
-
<FormField
|
|
539
|
-
control={form.control}
|
|
540
|
-
name="tipo"
|
|
541
|
-
render={({ field }) => (
|
|
542
|
-
<FormItem>
|
|
543
|
-
<FormLabel>{t('fields.type')}</FormLabel>
|
|
544
|
-
<Select
|
|
545
|
-
value={field.value}
|
|
546
|
-
onValueChange={field.onChange}
|
|
547
|
-
>
|
|
548
|
-
<FormControl>
|
|
549
|
-
<SelectTrigger className="w-full">
|
|
550
|
-
<SelectValue placeholder={t('common.select')} />
|
|
551
|
-
</SelectTrigger>
|
|
552
|
-
</FormControl>
|
|
553
|
-
<SelectContent>
|
|
554
|
-
<SelectItem value="corrente">
|
|
555
|
-
{t('types.corrente')}
|
|
556
|
-
</SelectItem>
|
|
557
|
-
<SelectItem value="poupanca">
|
|
558
|
-
{t('types.poupanca')}
|
|
559
|
-
</SelectItem>
|
|
560
|
-
<SelectItem value="investimento">
|
|
561
|
-
{t('types.investimento')}
|
|
562
|
-
</SelectItem>
|
|
563
|
-
<SelectItem value="caixa">
|
|
564
|
-
{t('types.caixa')}
|
|
565
|
-
</SelectItem>
|
|
566
|
-
</SelectContent>
|
|
567
|
-
</Select>
|
|
568
|
-
<FormMessage />
|
|
569
|
-
</FormItem>
|
|
570
|
-
)}
|
|
571
|
-
/>
|
|
628
|
+
</FinanceSheetSection>
|
|
572
629
|
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
placeholder="0,00"
|
|
587
|
-
disabled={!!editingAccount}
|
|
630
|
+
<FinanceSheetSection
|
|
631
|
+
title={t('sections.logo.title')}
|
|
632
|
+
description={t('sections.logo.description')}
|
|
633
|
+
>
|
|
634
|
+
<FormItem>
|
|
635
|
+
<FormLabel>{t('fields.logo')}</FormLabel>
|
|
636
|
+
<div className="flex flex-col gap-4 rounded-xl border border-dashed border-border/70 bg-muted/20 p-4 sm:flex-row sm:items-start">
|
|
637
|
+
<div className="flex h-20 w-20 shrink-0 items-center justify-center overflow-hidden rounded-lg bg-muted">
|
|
638
|
+
{logoPreviewUrl ? (
|
|
639
|
+
<img
|
|
640
|
+
src={logoPreviewUrl}
|
|
641
|
+
alt={t('fields.logo')}
|
|
642
|
+
className="h-full w-full object-cover"
|
|
588
643
|
/>
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
<FormLabel>{t('fields.description')}</FormLabel>
|
|
602
|
-
<FormControl>
|
|
603
|
-
<Input
|
|
604
|
-
placeholder={t('fields.descriptionPlaceholder')}
|
|
605
|
-
{...field}
|
|
606
|
-
value={field.value || ''}
|
|
607
|
-
/>
|
|
608
|
-
</FormControl>
|
|
609
|
-
<FormMessage />
|
|
610
|
-
</FormItem>
|
|
611
|
-
)}
|
|
612
|
-
/>
|
|
613
|
-
|
|
614
|
-
<FormItem>
|
|
615
|
-
<FormLabel>{t('fields.logo')}</FormLabel>
|
|
616
|
-
<div className="flex items-start gap-4 rounded-lg border p-3">
|
|
617
|
-
<div className="flex h-20 w-20 shrink-0 items-center justify-center overflow-hidden rounded-lg bg-muted">
|
|
618
|
-
{logoPreviewUrl ? (
|
|
619
|
-
<img
|
|
620
|
-
src={logoPreviewUrl}
|
|
621
|
-
alt={t('fields.logo')}
|
|
622
|
-
className="h-full w-full object-cover"
|
|
644
|
+
) : (
|
|
645
|
+
<Landmark className="h-8 w-8 text-muted-foreground" />
|
|
646
|
+
)}
|
|
647
|
+
</div>
|
|
648
|
+
|
|
649
|
+
<div className="flex-1 space-y-2">
|
|
650
|
+
<input
|
|
651
|
+
ref={logoInputRef}
|
|
652
|
+
type="file"
|
|
653
|
+
accept="image/*"
|
|
654
|
+
className="hidden"
|
|
655
|
+
onChange={handleLogoUpload}
|
|
623
656
|
/>
|
|
624
|
-
) : (
|
|
625
|
-
<Landmark className="h-8 w-8 text-muted-foreground" />
|
|
626
|
-
)}
|
|
627
|
-
</div>
|
|
628
657
|
|
|
629
|
-
|
|
630
|
-
<input
|
|
631
|
-
ref={logoInputRef}
|
|
632
|
-
type="file"
|
|
633
|
-
accept="image/*"
|
|
634
|
-
className="hidden"
|
|
635
|
-
onChange={handleLogoUpload}
|
|
636
|
-
/>
|
|
637
|
-
|
|
638
|
-
<div className="flex flex-wrap gap-2">
|
|
639
|
-
<Button
|
|
640
|
-
type="button"
|
|
641
|
-
variant="outline"
|
|
642
|
-
onClick={handleSelectLogo}
|
|
643
|
-
disabled={isUploadingLogo}
|
|
644
|
-
>
|
|
645
|
-
<Upload className="mr-2 h-4 w-4" />
|
|
646
|
-
{t('fields.logoAction')}
|
|
647
|
-
</Button>
|
|
648
|
-
|
|
649
|
-
{logoFileId ? (
|
|
658
|
+
<div className="flex flex-wrap gap-2">
|
|
650
659
|
<Button
|
|
651
660
|
type="button"
|
|
652
|
-
variant="
|
|
653
|
-
onClick={
|
|
661
|
+
variant="outline"
|
|
662
|
+
onClick={handleSelectLogo}
|
|
654
663
|
disabled={isUploadingLogo}
|
|
655
664
|
>
|
|
656
|
-
<
|
|
657
|
-
{t('fields.
|
|
665
|
+
<Upload className="mr-2 h-4 w-4" />
|
|
666
|
+
{t('fields.logoAction')}
|
|
658
667
|
</Button>
|
|
659
|
-
) : null}
|
|
660
|
-
</div>
|
|
661
668
|
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
669
|
+
{logoFileId ? (
|
|
670
|
+
<Button
|
|
671
|
+
type="button"
|
|
672
|
+
variant="ghost"
|
|
673
|
+
onClick={() => void handleRemoveLogo()}
|
|
674
|
+
disabled={isUploadingLogo}
|
|
675
|
+
>
|
|
676
|
+
<Trash2 className="mr-2 h-4 w-4" />
|
|
677
|
+
{t('fields.logoRemove')}
|
|
678
|
+
</Button>
|
|
679
|
+
) : null}
|
|
680
|
+
</div>
|
|
665
681
|
|
|
666
|
-
{isUploadingLogo ? (
|
|
667
682
|
<p className="text-xs text-muted-foreground">
|
|
668
|
-
{t('fields.
|
|
669
|
-
progress: logoUploadProgress,
|
|
670
|
-
})}
|
|
683
|
+
{t('fields.logoHint')}
|
|
671
684
|
</p>
|
|
672
|
-
|
|
685
|
+
|
|
686
|
+
{isUploadingLogo ? (
|
|
687
|
+
<p className="text-xs text-muted-foreground">
|
|
688
|
+
{t('fields.logoUploading', {
|
|
689
|
+
progress: logoUploadProgress,
|
|
690
|
+
})}
|
|
691
|
+
</p>
|
|
692
|
+
) : null}
|
|
693
|
+
</div>
|
|
673
694
|
</div>
|
|
674
|
-
</
|
|
675
|
-
</
|
|
676
|
-
</
|
|
695
|
+
</FormItem>
|
|
696
|
+
</FinanceSheetSection>
|
|
697
|
+
</FinanceSheetBody>
|
|
677
698
|
|
|
678
|
-
<div className="flex justify-end gap-2
|
|
699
|
+
<div className="flex justify-end gap-2 border-t px-4 py-4 sm:px-6">
|
|
679
700
|
<Button type="button" variant="outline" onClick={handleCancel}>
|
|
680
701
|
{t('common.cancel')}
|
|
681
702
|
</Button>
|
|
@@ -748,6 +769,44 @@ export default function ContasBancariasPage() {
|
|
|
748
769
|
const saldoConciliadoTotal = accounts
|
|
749
770
|
.filter((c) => c.ativo)
|
|
750
771
|
.reduce((acc, c) => acc + c.saldoConciliado, 0);
|
|
772
|
+
const activeAccountsCount = accounts.filter((c) => c.ativo).length;
|
|
773
|
+
const inactiveAccountsCount = accounts.length - activeAccountsCount;
|
|
774
|
+
const summaryCards = [
|
|
775
|
+
{
|
|
776
|
+
key: 'balance',
|
|
777
|
+
title: t('cards.totalBalance'),
|
|
778
|
+
value: <Money value={saldoTotal} />,
|
|
779
|
+
description: t('cards.activeAccounts', {
|
|
780
|
+
count: activeAccountsCount,
|
|
781
|
+
}),
|
|
782
|
+
icon: Landmark,
|
|
783
|
+
layout: 'compact' as const,
|
|
784
|
+
},
|
|
785
|
+
{
|
|
786
|
+
key: 'reconciled',
|
|
787
|
+
title: t('cards.reconciledBalance'),
|
|
788
|
+
value: <Money value={saldoConciliadoTotal} />,
|
|
789
|
+
description: `${t('cards.difference')}: ${new Intl.NumberFormat(
|
|
790
|
+
currentLocaleCode === 'pt' ? 'pt-BR' : 'en-US',
|
|
791
|
+
{
|
|
792
|
+
style: 'currency',
|
|
793
|
+
currency: 'BRL',
|
|
794
|
+
}
|
|
795
|
+
).format(saldoTotal - saldoConciliadoTotal)}`,
|
|
796
|
+
icon: RefreshCw,
|
|
797
|
+
layout: 'compact' as const,
|
|
798
|
+
},
|
|
799
|
+
{
|
|
800
|
+
key: 'accounts',
|
|
801
|
+
title: t('cards.accountsOverview'),
|
|
802
|
+
value: activeAccountsCount,
|
|
803
|
+
description: t('cards.inactiveAccounts', {
|
|
804
|
+
count: inactiveAccountsCount,
|
|
805
|
+
}),
|
|
806
|
+
icon: Building2,
|
|
807
|
+
layout: 'compact' as const,
|
|
808
|
+
},
|
|
809
|
+
];
|
|
751
810
|
|
|
752
811
|
const handleCreate = () => {
|
|
753
812
|
setEditingAccount(null);
|
|
@@ -829,174 +888,162 @@ export default function ContasBancariasPage() {
|
|
|
829
888
|
</AlertDialogContent>
|
|
830
889
|
</AlertDialog>
|
|
831
890
|
|
|
832
|
-
<
|
|
833
|
-
<Card>
|
|
834
|
-
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
|
|
835
|
-
<CardTitle className="text-sm font-medium">
|
|
836
|
-
{t('cards.totalBalance')}
|
|
837
|
-
</CardTitle>
|
|
838
|
-
<Landmark className="h-4 w-4 text-muted-foreground" />
|
|
839
|
-
</CardHeader>
|
|
840
|
-
<CardContent>
|
|
841
|
-
<div className="text-2xl font-bold">
|
|
842
|
-
<Money value={saldoTotal} />
|
|
843
|
-
</div>
|
|
844
|
-
<p className="text-xs text-muted-foreground">
|
|
845
|
-
{t('cards.activeAccounts', {
|
|
846
|
-
count: accounts.filter((c) => c.ativo).length,
|
|
847
|
-
})}
|
|
848
|
-
</p>
|
|
849
|
-
</CardContent>
|
|
850
|
-
</Card>
|
|
851
|
-
<Card>
|
|
852
|
-
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
|
|
853
|
-
<CardTitle className="text-sm font-medium">
|
|
854
|
-
{t('cards.reconciledBalance')}
|
|
855
|
-
</CardTitle>
|
|
856
|
-
<RefreshCw className="h-4 w-4 text-muted-foreground" />
|
|
857
|
-
</CardHeader>
|
|
858
|
-
<CardContent>
|
|
859
|
-
<div className="text-2xl font-bold">
|
|
860
|
-
<Money value={saldoConciliadoTotal} />
|
|
861
|
-
</div>
|
|
862
|
-
<p className="text-xs text-muted-foreground">
|
|
863
|
-
{t('cards.difference')}:{' '}
|
|
864
|
-
<Money value={saldoTotal - saldoConciliadoTotal} />
|
|
865
|
-
</p>
|
|
866
|
-
</CardContent>
|
|
867
|
-
</Card>
|
|
868
|
-
</div>
|
|
891
|
+
<KpiCardsGrid items={summaryCards} columns={3} />
|
|
869
892
|
|
|
870
|
-
<
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
893
|
+
<FinancePageSection
|
|
894
|
+
contentClassName="p-0"
|
|
895
|
+
className="border-none shadow-none"
|
|
896
|
+
>
|
|
897
|
+
{accounts.length > 0 ? (
|
|
898
|
+
<div className="grid gap-4 md:grid-cols-2 xl:grid-cols-3">
|
|
899
|
+
{accounts.map((conta) => {
|
|
900
|
+
const tipo =
|
|
901
|
+
tipoConfig[conta.tipo as keyof typeof tipoConfig] ||
|
|
902
|
+
tipoConfig.corrente;
|
|
903
|
+
const TipoIcon = tipo.icon;
|
|
904
|
+
const diferenca = conta.saldoAtual - conta.saldoConciliado;
|
|
905
|
+
|
|
906
|
+
return (
|
|
907
|
+
<Card
|
|
908
|
+
key={conta.id}
|
|
909
|
+
className={!conta.ativo ? 'border-border/60 opacity-70' : ''}
|
|
910
|
+
>
|
|
911
|
+
<CardHeader className="space-y-4">
|
|
912
|
+
<div className="flex items-start justify-between gap-3">
|
|
913
|
+
<div className="flex min-w-0 items-center gap-3">
|
|
914
|
+
<BankAccountLogo account={conta} icon={TipoIcon} />
|
|
915
|
+
<div className="min-w-0">
|
|
916
|
+
<div className="flex flex-wrap items-center gap-2">
|
|
917
|
+
<CardTitle className="text-base">
|
|
918
|
+
{conta.banco}
|
|
919
|
+
</CardTitle>
|
|
920
|
+
{conta.descricao ? (
|
|
921
|
+
<span className="text-xs text-muted-foreground">
|
|
922
|
+
{conta.descricao}
|
|
923
|
+
</span>
|
|
924
|
+
) : null}
|
|
925
|
+
</div>
|
|
926
|
+
<CardDescription className="space-y-0.5">
|
|
927
|
+
{conta.agencia !== '-' ? (
|
|
928
|
+
<span className="block">
|
|
929
|
+
{t('accountCard.bankAccount', {
|
|
930
|
+
agency: conta.agencia,
|
|
931
|
+
account: conta.conta,
|
|
932
|
+
})}
|
|
933
|
+
</span>
|
|
934
|
+
) : null}
|
|
935
|
+
<span className="block">{tipo.label}</span>
|
|
936
|
+
</CardDescription>
|
|
937
|
+
</div>
|
|
894
938
|
</div>
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
)}
|
|
904
|
-
</CardDescription>
|
|
905
|
-
</div>
|
|
906
|
-
</div>
|
|
907
|
-
{!conta.ativo && (
|
|
908
|
-
<Badge variant="outline" className="text-muted-foreground">
|
|
909
|
-
{t('status.inactive')}
|
|
910
|
-
</Badge>
|
|
911
|
-
)}
|
|
912
|
-
</div>
|
|
913
|
-
</CardHeader>
|
|
914
|
-
<CardContent>
|
|
915
|
-
<div className="space-y-3">
|
|
916
|
-
<div>
|
|
917
|
-
<p className="text-sm text-muted-foreground">
|
|
918
|
-
{t('accountCard.currentBalance')}
|
|
919
|
-
</p>
|
|
920
|
-
<p className="text-2xl font-bold">
|
|
921
|
-
<Money value={conta.saldoAtual} />
|
|
922
|
-
</p>
|
|
923
|
-
</div>
|
|
924
|
-
<div className="flex items-center justify-between text-sm">
|
|
925
|
-
<span className="text-muted-foreground">
|
|
926
|
-
{t('accountCard.reconciledBalance')}
|
|
927
|
-
</span>
|
|
928
|
-
<Money value={conta.saldoConciliado} />
|
|
929
|
-
</div>
|
|
930
|
-
{diferenca !== 0 && (
|
|
931
|
-
<div className="flex items-center justify-between text-sm">
|
|
932
|
-
<span className="text-muted-foreground">
|
|
933
|
-
{t('accountCard.difference')}
|
|
934
|
-
</span>
|
|
935
|
-
<span
|
|
936
|
-
className={
|
|
937
|
-
diferenca > 0 ? 'text-green-600' : 'text-red-600'
|
|
938
|
-
}
|
|
939
|
-
>
|
|
940
|
-
<Money value={diferenca} showSign />
|
|
941
|
-
</span>
|
|
939
|
+
{!conta.ativo ? (
|
|
940
|
+
<Badge
|
|
941
|
+
variant="outline"
|
|
942
|
+
className="text-muted-foreground"
|
|
943
|
+
>
|
|
944
|
+
{t('status.inactive')}
|
|
945
|
+
</Badge>
|
|
946
|
+
) : null}
|
|
942
947
|
</div>
|
|
943
|
-
|
|
944
|
-
<
|
|
945
|
-
<
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
>
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
948
|
+
</CardHeader>
|
|
949
|
+
<CardContent>
|
|
950
|
+
<div className="space-y-3">
|
|
951
|
+
<div>
|
|
952
|
+
<p className="text-sm text-muted-foreground">
|
|
953
|
+
{t('accountCard.currentBalance')}
|
|
954
|
+
</p>
|
|
955
|
+
<p className="text-2xl font-bold">
|
|
956
|
+
<Money value={conta.saldoAtual} />
|
|
957
|
+
</p>
|
|
958
|
+
</div>
|
|
959
|
+
<div className="flex items-center justify-between text-sm">
|
|
960
|
+
<span className="text-muted-foreground">
|
|
961
|
+
{t('accountCard.reconciledBalance')}
|
|
962
|
+
</span>
|
|
963
|
+
<Money value={conta.saldoConciliado} />
|
|
964
|
+
</div>
|
|
965
|
+
{diferenca !== 0 ? (
|
|
966
|
+
<div className="flex items-center justify-between text-sm">
|
|
967
|
+
<span className="text-muted-foreground">
|
|
968
|
+
{t('accountCard.difference')}
|
|
969
|
+
</span>
|
|
970
|
+
<span
|
|
971
|
+
className={
|
|
972
|
+
diferenca > 0 ? 'text-green-600' : 'text-red-600'
|
|
973
|
+
}
|
|
974
|
+
>
|
|
975
|
+
<Money value={diferenca} showSign />
|
|
976
|
+
</span>
|
|
977
|
+
</div>
|
|
978
|
+
) : null}
|
|
979
|
+
<div className="flex flex-wrap gap-2 pt-2">
|
|
980
|
+
<Button
|
|
981
|
+
variant="outline"
|
|
982
|
+
size="sm"
|
|
983
|
+
className="min-w-0 flex-1 basis-[calc(50%-0.25rem)] bg-transparent"
|
|
984
|
+
asChild
|
|
985
|
+
>
|
|
986
|
+
<Link
|
|
987
|
+
href={`/finance/cash-and-banks/statements?bank_account_id=${conta.id}`}
|
|
988
|
+
>
|
|
989
|
+
<Eye className="mr-2 h-4 w-4" />
|
|
990
|
+
{t('accountCard.statement')}
|
|
991
|
+
</Link>
|
|
992
|
+
</Button>
|
|
993
|
+
<Button
|
|
994
|
+
variant="outline"
|
|
995
|
+
size="sm"
|
|
996
|
+
className="min-w-0 flex-1 basis-[calc(50%-0.25rem)] bg-transparent"
|
|
997
|
+
asChild
|
|
998
|
+
>
|
|
999
|
+
<Link
|
|
1000
|
+
href={`/finance/cash-and-banks/bank-reconciliation?bank_account_id=${conta.id}`}
|
|
1001
|
+
>
|
|
1002
|
+
<RefreshCw className="mr-2 h-4 w-4" />
|
|
1003
|
+
{t('accountCard.reconcile')}
|
|
1004
|
+
</Link>
|
|
1005
|
+
</Button>
|
|
1006
|
+
<div className="ml-auto inline-flex shrink-0 overflow-hidden rounded-md border bg-background shadow-sm">
|
|
1007
|
+
<Button
|
|
1008
|
+
variant="ghost"
|
|
1009
|
+
size="sm"
|
|
1010
|
+
className="rounded-none border-0 px-3 hover:bg-muted"
|
|
1011
|
+
onClick={() => handleEdit(conta)}
|
|
1012
|
+
aria-label={t('common.edit')}
|
|
1013
|
+
title={t('common.edit')}
|
|
1014
|
+
>
|
|
1015
|
+
<Pencil className="h-4 w-4" />
|
|
1016
|
+
</Button>
|
|
1017
|
+
<Button
|
|
1018
|
+
variant="ghost"
|
|
1019
|
+
size="sm"
|
|
1020
|
+
className="rounded-none border-0 border-l px-3 text-destructive hover:bg-destructive/10 hover:text-destructive"
|
|
1021
|
+
onClick={() => setAccountIdToDelete(conta.id)}
|
|
1022
|
+
aria-label={deleteDialogTitle}
|
|
1023
|
+
title={deleteDialogTitle}
|
|
1024
|
+
>
|
|
1025
|
+
<Trash2 className="h-4 w-4" />
|
|
1026
|
+
</Button>
|
|
1027
|
+
</div>
|
|
1028
|
+
</div>
|
|
992
1029
|
</div>
|
|
993
|
-
</
|
|
994
|
-
</
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1030
|
+
</CardContent>
|
|
1031
|
+
</Card>
|
|
1032
|
+
);
|
|
1033
|
+
})}
|
|
1034
|
+
</div>
|
|
1035
|
+
) : (
|
|
1036
|
+
<div className="p-6 sm:p-8">
|
|
1037
|
+
<EmptyState
|
|
1038
|
+
icon={<Landmark className="h-12 w-12" />}
|
|
1039
|
+
title={t('empty.title')}
|
|
1040
|
+
description={t('empty.description')}
|
|
1041
|
+
actionLabel={t('newAccount.action')}
|
|
1042
|
+
onAction={handleCreate}
|
|
1043
|
+
/>
|
|
1044
|
+
</div>
|
|
1045
|
+
)}
|
|
1046
|
+
</FinancePageSection>
|
|
1000
1047
|
</Page>
|
|
1001
1048
|
);
|
|
1002
1049
|
}
|