@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.
Files changed (41) hide show
  1. package/dist/finance.contract-activated.subscriber.d.ts +24 -0
  2. package/dist/finance.contract-activated.subscriber.d.ts.map +1 -0
  3. package/dist/finance.contract-activated.subscriber.js +519 -0
  4. package/dist/finance.contract-activated.subscriber.js.map +1 -0
  5. package/dist/finance.contract-activated.subscriber.spec.d.ts +2 -0
  6. package/dist/finance.contract-activated.subscriber.spec.d.ts.map +1 -0
  7. package/dist/finance.contract-activated.subscriber.spec.js +302 -0
  8. package/dist/finance.contract-activated.subscriber.spec.js.map +1 -0
  9. package/dist/finance.module.d.ts.map +1 -1
  10. package/dist/finance.module.js +6 -1
  11. package/dist/finance.module.js.map +1 -1
  12. package/hedhog/data/menu.yaml +0 -17
  13. package/hedhog/frontend/app/_components/finance-layout.tsx.ejs +108 -0
  14. package/hedhog/frontend/app/accounts-payable/approvals/page.tsx.ejs +51 -69
  15. package/hedhog/frontend/app/accounts-payable/installments/page.tsx.ejs +1312 -1138
  16. package/hedhog/frontend/app/accounts-receivable/collections-default/page.tsx.ejs +288 -268
  17. package/hedhog/frontend/app/accounts-receivable/installments/page.tsx.ejs +1175 -1016
  18. package/hedhog/frontend/app/administration/audit-logs/page.tsx.ejs +157 -173
  19. package/hedhog/frontend/app/administration/categories/page.tsx.ejs +44 -62
  20. package/hedhog/frontend/app/administration/cost-centers/page.tsx.ejs +62 -80
  21. package/hedhog/frontend/app/administration/period-close/page.tsx.ejs +151 -170
  22. package/hedhog/frontend/app/cash-and-banks/bank-accounts/page.tsx.ejs +369 -322
  23. package/hedhog/frontend/app/cash-and-banks/bank-reconciliation/page.tsx.ejs +204 -226
  24. package/hedhog/frontend/app/cash-and-banks/statements/page.tsx.ejs +122 -140
  25. package/hedhog/frontend/app/cash-and-banks/transfers/page.tsx.ejs +31 -49
  26. package/hedhog/frontend/app/page.tsx.ejs +3 -370
  27. package/hedhog/frontend/app/planning/cash-flow-forecast/page.tsx.ejs +150 -182
  28. package/hedhog/frontend/app/planning/receivables-calendar/page.tsx.ejs +52 -70
  29. package/hedhog/frontend/app/planning/scenarios/page.tsx.ejs +101 -95
  30. package/hedhog/frontend/app/reports/actual-vs-forecast/page.tsx.ejs +100 -125
  31. package/hedhog/frontend/app/reports/aging-default/page.tsx.ejs +77 -105
  32. package/hedhog/frontend/app/reports/cash-position/page.tsx.ejs +99 -134
  33. package/hedhog/frontend/app/reports/overview-results/page.tsx.ejs +147 -182
  34. package/hedhog/frontend/app/reports/top-customers/page.tsx.ejs +49 -61
  35. package/hedhog/frontend/app/reports/top-operational-expenses/page.tsx.ejs +49 -67
  36. package/hedhog/frontend/messages/en.json +176 -68
  37. package/hedhog/frontend/messages/pt.json +176 -68
  38. package/package.json +6 -5
  39. package/src/finance.contract-activated.subscriber.spec.ts +392 -0
  40. package/src/finance.contract-activated.subscriber.ts +780 -0
  41. 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-lg">
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 className="p-4" onSubmit={form.handleSubmit(handleSubmit)}>
481
- <div className="grid gap-4">
482
- <FormField
483
- control={form.control}
484
- name="banco"
485
- render={({ field }) => (
486
- <FormItem>
487
- <FormLabel>{t('fields.bank')}</FormLabel>
488
- <FormControl>
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="agencia"
497
+ name="banco"
503
498
  render={({ field }) => (
504
499
  <FormItem>
505
- <FormLabel>{t('fields.branch')}</FormLabel>
500
+ <FormLabel>{t('fields.bank')}</FormLabel>
506
501
  <FormControl>
507
502
  <Input
508
- placeholder="0000"
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="conta"
613
+ name="descricao"
521
614
  render={({ field }) => (
522
615
  <FormItem>
523
- <FormLabel>{t('fields.account')}</FormLabel>
616
+ <FormLabel>{t('fields.description')}</FormLabel>
524
617
  <FormControl>
525
618
  <Input
526
- placeholder="00000-0"
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
- </div>
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
- <FormField
574
- control={form.control}
575
- name="saldoInicial"
576
- render={({ field }) => (
577
- <FormItem>
578
- <FormLabel>{t('fields.initialBalance')}</FormLabel>
579
- <FormControl>
580
- <InputMoney
581
- ref={field.ref}
582
- name={field.name}
583
- value={field.value}
584
- onBlur={field.onBlur}
585
- onValueChange={(value) => field.onChange(value ?? 0)}
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
- </FormControl>
590
- <FormMessage />
591
- </FormItem>
592
- )}
593
- />
594
- </div>
595
-
596
- <FormField
597
- control={form.control}
598
- name="descricao"
599
- render={({ field }) => (
600
- <FormItem>
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
- <div className="flex-1 space-y-2">
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="ghost"
653
- onClick={() => void handleRemoveLogo()}
661
+ variant="outline"
662
+ onClick={handleSelectLogo}
654
663
  disabled={isUploadingLogo}
655
664
  >
656
- <Trash2 className="mr-2 h-4 w-4" />
657
- {t('fields.logoRemove')}
665
+ <Upload className="mr-2 h-4 w-4" />
666
+ {t('fields.logoAction')}
658
667
  </Button>
659
- ) : null}
660
- </div>
661
668
 
662
- <p className="text-xs text-muted-foreground">
663
- {t('fields.logoHint')}
664
- </p>
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.logoUploading', {
669
- progress: logoUploadProgress,
670
- })}
683
+ {t('fields.logoHint')}
671
684
  </p>
672
- ) : null}
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
- </div>
675
- </FormItem>
676
- </div>
695
+ </FormItem>
696
+ </FinanceSheetSection>
697
+ </FinanceSheetBody>
677
698
 
678
- <div className="flex justify-end gap-2 pt-4">
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
- <div className="grid gap-4 md:grid-cols-2">
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
- <div className="grid gap-4 md:grid-cols-2 lg:grid-cols-3">
871
- {accounts.map((conta) => {
872
- const tipo =
873
- tipoConfig[conta.tipo as keyof typeof tipoConfig] ||
874
- tipoConfig.corrente;
875
- const TipoIcon = tipo.icon;
876
- const diferenca = conta.saldoAtual - conta.saldoConciliado;
877
-
878
- return (
879
- <Card key={conta.id} className={!conta.ativo ? 'opacity-60' : ''}>
880
- <CardHeader>
881
- <div className="flex items-center justify-between">
882
- <div className="flex items-center gap-2">
883
- <BankAccountLogo account={conta} icon={TipoIcon} />
884
- <div>
885
- <div className="flex gap-4 items-center">
886
- <CardTitle className="text-base">
887
- {conta.banco}
888
- </CardTitle>
889
- {conta.descricao && (
890
- <span className="block text-muted-foreground text-xs">
891
- {conta.descricao}
892
- </span>
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
- <CardDescription className="space-y-0.5">
896
- {conta.agencia !== '-' && (
897
- <span className="block">
898
- {t('accountCard.bankAccount', {
899
- agency: conta.agencia,
900
- account: conta.conta,
901
- })}
902
- </span>
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
- <div className="flex flex-wrap gap-2 pt-2">
945
- <Button
946
- variant="outline"
947
- size="sm"
948
- className="min-w-0 flex-1 basis-[calc(50%-0.25rem)] bg-transparent"
949
- asChild
950
- >
951
- <Link
952
- href={`/finance/cash-and-banks/statements?bank_account_id=${conta.id}`}
953
- >
954
- <Eye className="mr-2 h-4 w-4" />
955
- {t('accountCard.statement')}
956
- </Link>
957
- </Button>
958
- <Button
959
- variant="outline"
960
- size="sm"
961
- className="min-w-0 flex-1 basis-[calc(50%-0.25rem)] bg-transparent"
962
- asChild
963
- >
964
- <Link
965
- href={`/finance/cash-and-banks/bank-reconciliation?bank_account_id=${conta.id}`}
966
- >
967
- <RefreshCw className="mr-2 h-4 w-4" />
968
- {t('accountCard.reconcile')}
969
- </Link>
970
- </Button>
971
- <div className="ml-auto inline-flex shrink-0 overflow-hidden rounded-md border bg-background shadow-sm">
972
- <Button
973
- variant="ghost"
974
- size="sm"
975
- className="rounded-none border-0 px-3 hover:bg-muted"
976
- onClick={() => handleEdit(conta)}
977
- aria-label={t('common.edit')}
978
- title={t('common.edit')}
979
- >
980
- <Pencil className="h-4 w-4" />
981
- </Button>
982
- <Button
983
- variant="ghost"
984
- size="sm"
985
- className="rounded-none border-0 border-l px-3 text-destructive hover:bg-destructive/10 hover:text-destructive"
986
- onClick={() => setAccountIdToDelete(conta.id)}
987
- aria-label={deleteDialogTitle}
988
- title={deleteDialogTitle}
989
- >
990
- <Trash2 className="h-4 w-4" />
991
- </Button>
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
- </div>
994
- </div>
995
- </CardContent>
996
- </Card>
997
- );
998
- })}
999
- </div>
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
  }