@hed-hog/finance 0.0.300 → 0.0.301
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/frontend/app/_components/finance-layout.tsx.ejs +108 -0
- package/hedhog/frontend/app/accounts-payable/approvals/page.tsx.ejs +91 -106
- package/hedhog/frontend/app/accounts-payable/installments/page.tsx.ejs +1306 -1145
- package/hedhog/frontend/app/accounts-receivable/collections-default/page.tsx.ejs +288 -268
- package/hedhog/frontend/app/accounts-receivable/installments/page.tsx.ejs +491 -351
- 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 +332 -286
- 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 +32 -49
- package/hedhog/frontend/app/planning/cash-flow-forecast/page.tsx.ejs +84 -108
- package/hedhog/frontend/app/planning/receivables-calendar/page.tsx.ejs +53 -70
- package/hedhog/frontend/app/planning/scenarios/page.tsx.ejs +98 -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 +7 -6
- 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,14 +1,9 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
|
+
import { FinancePageSection } from '@/app/(app)/(libraries)/finance/_components/finance-layout';
|
|
3
4
|
import { EmptyState, Page, PageHeader } from '@/components/entity-list';
|
|
4
5
|
import { Button } from '@/components/ui/button';
|
|
5
|
-
import {
|
|
6
|
-
Card,
|
|
7
|
-
CardContent,
|
|
8
|
-
CardDescription,
|
|
9
|
-
CardHeader,
|
|
10
|
-
CardTitle,
|
|
11
|
-
} from '@/components/ui/card';
|
|
6
|
+
import { KpiCardsGrid } from '@/components/ui/kpi-cards-grid';
|
|
12
7
|
import {
|
|
13
8
|
Dialog,
|
|
14
9
|
DialogContent,
|
|
@@ -659,6 +654,35 @@ export default function ExtratosPage() {
|
|
|
659
654
|
const totalSaidas = extratos
|
|
660
655
|
.filter((e) => e.tipo === 'saida')
|
|
661
656
|
.reduce((acc, e) => acc + e.valor, 0);
|
|
657
|
+
const summaryCards = [
|
|
658
|
+
{
|
|
659
|
+
key: 'inflows',
|
|
660
|
+
title: t('cards.inflows'),
|
|
661
|
+
value: <Money value={totalEntradas} />,
|
|
662
|
+
icon: ArrowUpRight,
|
|
663
|
+
layout: 'compact' as const,
|
|
664
|
+
valueClassName: 'text-green-600',
|
|
665
|
+
iconContainerClassName: 'bg-green-500/10 text-green-700',
|
|
666
|
+
accentClassName: 'from-green-500/20 via-emerald-500/10 to-transparent',
|
|
667
|
+
},
|
|
668
|
+
{
|
|
669
|
+
key: 'outflows',
|
|
670
|
+
title: t('cards.outflows'),
|
|
671
|
+
value: <Money value={totalSaidas} />,
|
|
672
|
+
icon: ArrowDownRight,
|
|
673
|
+
layout: 'compact' as const,
|
|
674
|
+
valueClassName: 'text-red-600',
|
|
675
|
+
iconContainerClassName: 'bg-red-500/10 text-red-700',
|
|
676
|
+
accentClassName: 'from-red-500/20 via-rose-500/10 to-transparent',
|
|
677
|
+
},
|
|
678
|
+
{
|
|
679
|
+
key: 'balance',
|
|
680
|
+
title: t('cards.accountBalance'),
|
|
681
|
+
value: <Money value={conta?.saldoAtual || 0} />,
|
|
682
|
+
description: conta?.descricao,
|
|
683
|
+
layout: 'compact' as const,
|
|
684
|
+
},
|
|
685
|
+
];
|
|
662
686
|
|
|
663
687
|
const handleExport = async () => {
|
|
664
688
|
if (!contaFilter) {
|
|
@@ -749,7 +773,7 @@ export default function ExtratosPage() {
|
|
|
749
773
|
router.replace(`${pathname}?${params.toString()}`);
|
|
750
774
|
}}
|
|
751
775
|
>
|
|
752
|
-
<SelectTrigger className="w-full sm:w-
|
|
776
|
+
<SelectTrigger className="w-full sm:w-70">
|
|
753
777
|
<SelectValue placeholder={t('filters.selectAccount')} />
|
|
754
778
|
</SelectTrigger>
|
|
755
779
|
<SelectContent>
|
|
@@ -769,141 +793,99 @@ export default function ExtratosPage() {
|
|
|
769
793
|
</div>
|
|
770
794
|
</div>
|
|
771
795
|
|
|
772
|
-
<
|
|
773
|
-
<Card>
|
|
774
|
-
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
|
|
775
|
-
<CardTitle className="text-sm font-medium">
|
|
776
|
-
{t('cards.inflows')}
|
|
777
|
-
</CardTitle>
|
|
778
|
-
<ArrowUpRight className="h-4 w-4 text-green-500" />
|
|
779
|
-
</CardHeader>
|
|
780
|
-
<CardContent>
|
|
781
|
-
<div className="text-2xl font-bold text-green-600">
|
|
782
|
-
<Money value={totalEntradas} />
|
|
783
|
-
</div>
|
|
784
|
-
</CardContent>
|
|
785
|
-
</Card>
|
|
786
|
-
<Card>
|
|
787
|
-
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
|
|
788
|
-
<CardTitle className="text-sm font-medium">
|
|
789
|
-
{t('cards.outflows')}
|
|
790
|
-
</CardTitle>
|
|
791
|
-
<ArrowDownRight className="h-4 w-4 text-red-500" />
|
|
792
|
-
</CardHeader>
|
|
793
|
-
<CardContent>
|
|
794
|
-
<div className="text-2xl font-bold text-red-600">
|
|
795
|
-
<Money value={totalSaidas} />
|
|
796
|
-
</div>
|
|
797
|
-
</CardContent>
|
|
798
|
-
</Card>
|
|
799
|
-
<Card>
|
|
800
|
-
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
|
|
801
|
-
<CardTitle className="text-sm font-medium">
|
|
802
|
-
{t('cards.accountBalance')}
|
|
803
|
-
</CardTitle>
|
|
804
|
-
</CardHeader>
|
|
805
|
-
<CardContent>
|
|
806
|
-
<div className="text-2xl font-bold">
|
|
807
|
-
<Money value={conta?.saldoAtual || 0} />
|
|
808
|
-
</div>
|
|
809
|
-
<p className="text-xs text-muted-foreground">{conta?.descricao}</p>
|
|
810
|
-
</CardContent>
|
|
811
|
-
</Card>
|
|
812
|
-
</div>
|
|
796
|
+
<KpiCardsGrid items={summaryCards} columns={3} />
|
|
813
797
|
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
798
|
+
<FinancePageSection
|
|
799
|
+
title={t('table.title')}
|
|
800
|
+
description={t('table.foundTransactions', { count: extratos.length })}
|
|
801
|
+
contentClassName="p-4 sm:p-5"
|
|
802
|
+
>
|
|
803
|
+
{extratos.length > 0 ? (
|
|
804
|
+
<div className="overflow-x-auto">
|
|
805
|
+
<Table className="min-w-190 table-fixed">
|
|
806
|
+
<TableHeader>
|
|
807
|
+
<TableRow>
|
|
808
|
+
<TableHead className="w-27.5">
|
|
809
|
+
{t('table.headers.date')}
|
|
810
|
+
</TableHead>
|
|
811
|
+
<TableHead>{t('table.headers.description')}</TableHead>
|
|
812
|
+
<TableHead className="w-32.5 text-right">
|
|
813
|
+
{t('table.headers.value')}
|
|
814
|
+
</TableHead>
|
|
815
|
+
<TableHead className="w-27.5">
|
|
816
|
+
{t('table.headers.type')}
|
|
817
|
+
</TableHead>
|
|
818
|
+
<TableHead className="w-35">
|
|
819
|
+
{t('table.headers.reconciliation')}
|
|
820
|
+
</TableHead>
|
|
821
|
+
</TableRow>
|
|
822
|
+
</TableHeader>
|
|
823
|
+
<TableBody>
|
|
824
|
+
{extratos.map((extrato) => (
|
|
825
|
+
<TableRow
|
|
826
|
+
key={extrato.id}
|
|
827
|
+
className="cursor-pointer"
|
|
828
|
+
onClick={() => setExtratoSelecionado(extrato)}
|
|
829
|
+
onKeyDown={(event) => {
|
|
830
|
+
if (event.key === 'Enter' || event.key === ' ') {
|
|
831
|
+
event.preventDefault();
|
|
832
|
+
setExtratoSelecionado(extrato);
|
|
833
|
+
}
|
|
834
|
+
}}
|
|
835
|
+
role="button"
|
|
836
|
+
tabIndex={0}
|
|
837
|
+
>
|
|
838
|
+
<TableCell>{formatarData(extrato.data)}</TableCell>
|
|
839
|
+
<TableCell className="truncate" title={extrato.descricao}>
|
|
840
|
+
{extrato.descricao}
|
|
841
|
+
</TableCell>
|
|
842
|
+
<TableCell className="text-right">
|
|
843
|
+
<span
|
|
844
|
+
className={
|
|
845
|
+
extrato.tipo === 'entrada'
|
|
846
|
+
? 'text-green-600'
|
|
847
|
+
: 'text-red-600'
|
|
852
848
|
}
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
>
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
<span
|
|
863
|
-
className={
|
|
864
|
-
extrato.tipo === 'entrada'
|
|
865
|
-
? 'text-green-600'
|
|
866
|
-
: 'text-red-600'
|
|
867
|
-
}
|
|
868
|
-
>
|
|
869
|
-
<Money value={extrato.valor} />
|
|
849
|
+
>
|
|
850
|
+
<Money value={extrato.valor} />
|
|
851
|
+
</span>
|
|
852
|
+
</TableCell>
|
|
853
|
+
<TableCell>
|
|
854
|
+
{extrato.tipo === 'entrada' ? (
|
|
855
|
+
<span className="flex items-center gap-1 text-green-600">
|
|
856
|
+
<ArrowUpRight className="h-4 w-4" />
|
|
857
|
+
{t('types.inflow')}
|
|
870
858
|
</span>
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
title={t('empty.title')}
|
|
902
|
-
description={t('empty.description')}
|
|
903
|
-
actionLabel={t('importDialog.action')}
|
|
904
|
-
onAction={() => setIsImportSheetOpen(true)}
|
|
905
|
-
/>
|
|
906
|
-
)}
|
|
859
|
+
) : (
|
|
860
|
+
<span className="flex items-center gap-1 text-red-600">
|
|
861
|
+
<ArrowDownRight className="h-4 w-4" />
|
|
862
|
+
{t('types.outflow')}
|
|
863
|
+
</span>
|
|
864
|
+
)}
|
|
865
|
+
</TableCell>
|
|
866
|
+
<TableCell>
|
|
867
|
+
<StatusBadge
|
|
868
|
+
status={extrato.statusConciliacao}
|
|
869
|
+
type="conciliacao"
|
|
870
|
+
/>
|
|
871
|
+
</TableCell>
|
|
872
|
+
</TableRow>
|
|
873
|
+
))}
|
|
874
|
+
</TableBody>
|
|
875
|
+
</Table>
|
|
876
|
+
</div>
|
|
877
|
+
) : (
|
|
878
|
+
<div className="p-2 sm:p-4">
|
|
879
|
+
<EmptyState
|
|
880
|
+
icon={<Upload className="h-12 w-12" />}
|
|
881
|
+
title={t('empty.title')}
|
|
882
|
+
description={t('empty.description')}
|
|
883
|
+
actionLabel={t('importDialog.action')}
|
|
884
|
+
onAction={() => setIsImportSheetOpen(true)}
|
|
885
|
+
/>
|
|
886
|
+
</div>
|
|
887
|
+
)}
|
|
888
|
+
</FinancePageSection>
|
|
907
889
|
|
|
908
890
|
<Dialog
|
|
909
891
|
open={!!extratoSelecionado}
|
|
@@ -1,14 +1,9 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
|
+
import { FinancePageSection } from '@/app/(app)/(libraries)/finance/_components/finance-layout';
|
|
3
4
|
import { Page, PageHeader } from '@/components/entity-list';
|
|
4
5
|
import { Button } from '@/components/ui/button';
|
|
5
|
-
import {
|
|
6
|
-
Card,
|
|
7
|
-
CardContent,
|
|
8
|
-
CardDescription,
|
|
9
|
-
CardHeader,
|
|
10
|
-
CardTitle,
|
|
11
|
-
} from '@/components/ui/card';
|
|
6
|
+
import { KpiCardsGrid } from '@/components/ui/kpi-cards-grid';
|
|
12
7
|
import { FilterBar } from '@/components/ui/filter-bar';
|
|
13
8
|
import {
|
|
14
9
|
Form,
|
|
@@ -347,6 +342,25 @@ export default function TransferenciasPage() {
|
|
|
347
342
|
};
|
|
348
343
|
|
|
349
344
|
const totalTransferido = transferencias.reduce((acc, t) => acc + t.valor, 0);
|
|
345
|
+
const summaryCards = [
|
|
346
|
+
{
|
|
347
|
+
key: 'transferred',
|
|
348
|
+
title: t('cards.totalTransferred'),
|
|
349
|
+
value: <Money value={totalTransferido} />,
|
|
350
|
+
description: t('cards.transferCount', { count: transferencias.length }),
|
|
351
|
+
icon: ArrowRight,
|
|
352
|
+
layout: 'compact' as const,
|
|
353
|
+
iconContainerClassName: 'bg-blue-500/10 text-blue-700',
|
|
354
|
+
accentClassName: 'from-blue-500/20 via-sky-500/10 to-transparent',
|
|
355
|
+
},
|
|
356
|
+
{
|
|
357
|
+
key: 'activeAccounts',
|
|
358
|
+
title: t('cards.activeAccounts'),
|
|
359
|
+
value: contasBancarias.filter((conta) => conta.ativo).length,
|
|
360
|
+
description: t('cards.available'),
|
|
361
|
+
layout: 'compact' as const,
|
|
362
|
+
},
|
|
363
|
+
];
|
|
350
364
|
|
|
351
365
|
return (
|
|
352
366
|
<Page>
|
|
@@ -369,7 +383,7 @@ export default function TransferenciasPage() {
|
|
|
369
383
|
|
|
370
384
|
<div className="flex flex-col gap-4 sm:flex-row sm:items-center">
|
|
371
385
|
<Select value={accountFilter} onValueChange={setAccountFilter}>
|
|
372
|
-
<SelectTrigger className="w-full sm:w-
|
|
386
|
+
<SelectTrigger className="w-full sm:w-70">
|
|
373
387
|
<SelectValue placeholder={t('common.select')} />
|
|
374
388
|
</SelectTrigger>
|
|
375
389
|
<SelectContent>
|
|
@@ -391,45 +405,14 @@ export default function TransferenciasPage() {
|
|
|
391
405
|
</div>
|
|
392
406
|
</div>
|
|
393
407
|
|
|
394
|
-
<
|
|
395
|
-
<Card>
|
|
396
|
-
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
|
|
397
|
-
<CardTitle className="text-sm font-medium">
|
|
398
|
-
{t('cards.totalTransferred')}
|
|
399
|
-
</CardTitle>
|
|
400
|
-
</CardHeader>
|
|
401
|
-
<CardContent>
|
|
402
|
-
<div className="text-2xl font-bold">
|
|
403
|
-
<Money value={totalTransferido} />
|
|
404
|
-
</div>
|
|
405
|
-
<p className="text-xs text-muted-foreground">
|
|
406
|
-
{t('cards.transferCount', { count: transferencias.length })}
|
|
407
|
-
</p>
|
|
408
|
-
</CardContent>
|
|
409
|
-
</Card>
|
|
410
|
-
<Card>
|
|
411
|
-
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
|
|
412
|
-
<CardTitle className="text-sm font-medium">
|
|
413
|
-
{t('cards.activeAccounts')}
|
|
414
|
-
</CardTitle>
|
|
415
|
-
</CardHeader>
|
|
416
|
-
<CardContent>
|
|
417
|
-
<div className="text-2xl font-bold">
|
|
418
|
-
{contasBancarias.filter((conta) => conta.ativo).length}
|
|
419
|
-
</div>
|
|
420
|
-
<p className="text-xs text-muted-foreground">
|
|
421
|
-
{t('cards.available')}
|
|
422
|
-
</p>
|
|
423
|
-
</CardContent>
|
|
424
|
-
</Card>
|
|
425
|
-
</div>
|
|
408
|
+
<KpiCardsGrid items={summaryCards} columns={2} />
|
|
426
409
|
|
|
427
|
-
<
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
<
|
|
410
|
+
<FinancePageSection
|
|
411
|
+
title={t('table.title')}
|
|
412
|
+
description={t('table.description')}
|
|
413
|
+
contentClassName="p-4 sm:p-5"
|
|
414
|
+
>
|
|
415
|
+
<div className="overflow-x-auto">
|
|
433
416
|
<Table>
|
|
434
417
|
<TableHeader>
|
|
435
418
|
<TableRow>
|
|
@@ -464,7 +447,7 @@ export default function TransferenciasPage() {
|
|
|
464
447
|
</div>
|
|
465
448
|
</TableCell>
|
|
466
449
|
<TableCell className="text-center">
|
|
467
|
-
<ArrowRight className="h-4 w-4 text-muted-foreground
|
|
450
|
+
<ArrowRight className="mx-auto h-4 w-4 text-muted-foreground" />
|
|
468
451
|
</TableCell>
|
|
469
452
|
<TableCell>
|
|
470
453
|
<div>
|
|
@@ -485,8 +468,8 @@ export default function TransferenciasPage() {
|
|
|
485
468
|
})}
|
|
486
469
|
</TableBody>
|
|
487
470
|
</Table>
|
|
488
|
-
</
|
|
489
|
-
</
|
|
471
|
+
</div>
|
|
472
|
+
</FinancePageSection>
|
|
490
473
|
</Page>
|
|
491
474
|
);
|
|
492
475
|
}
|
|
@@ -1,14 +1,10 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
|
+
import { FinancePageSection } from '@/app/(app)/(libraries)/finance/_components/finance-layout';
|
|
3
4
|
import { Page, PageHeader } from '@/components/entity-list';
|
|
4
5
|
import { Button } from '@/components/ui/button';
|
|
5
|
-
import {
|
|
6
|
-
|
|
7
|
-
CardContent,
|
|
8
|
-
CardDescription,
|
|
9
|
-
CardHeader,
|
|
10
|
-
CardTitle,
|
|
11
|
-
} from '@/components/ui/card';
|
|
6
|
+
import { Card, CardContent } from '@/components/ui/card';
|
|
7
|
+
import { KpiCardsGrid } from '@/components/ui/kpi-cards-grid';
|
|
12
8
|
import { Money } from '@/components/ui/money';
|
|
13
9
|
import {
|
|
14
10
|
Select,
|
|
@@ -73,6 +69,42 @@ export default function FluxoCaixaPage() {
|
|
|
73
69
|
const totalEntradas = entradasPrevistas.reduce((acc, e) => acc + e.valor, 0);
|
|
74
70
|
const totalSaidas = saidasPrevistas.reduce((acc, s) => acc + s.valor, 0);
|
|
75
71
|
const saldoFinal = kpis.saldoCaixa + totalEntradas - totalSaidas;
|
|
72
|
+
const summaryCards = [
|
|
73
|
+
{
|
|
74
|
+
key: 'currentBalance',
|
|
75
|
+
title: t('cards.currentBalance'),
|
|
76
|
+
value: <Money value={kpis.saldoCaixa} />,
|
|
77
|
+
icon: Wallet,
|
|
78
|
+
layout: 'compact' as const,
|
|
79
|
+
},
|
|
80
|
+
{
|
|
81
|
+
key: 'expectedInflows',
|
|
82
|
+
title: t('cards.expectedInflows'),
|
|
83
|
+
value: <Money value={totalEntradas} />,
|
|
84
|
+
icon: TrendingUp,
|
|
85
|
+
layout: 'compact' as const,
|
|
86
|
+
valueClassName: 'text-green-600',
|
|
87
|
+
iconContainerClassName: 'bg-green-500/10 text-green-700',
|
|
88
|
+
accentClassName: 'from-green-500/20 via-emerald-500/10 to-transparent',
|
|
89
|
+
},
|
|
90
|
+
{
|
|
91
|
+
key: 'expectedOutflows',
|
|
92
|
+
title: t('cards.expectedOutflows'),
|
|
93
|
+
value: <Money value={totalSaidas} />,
|
|
94
|
+
icon: TrendingDown,
|
|
95
|
+
layout: 'compact' as const,
|
|
96
|
+
valueClassName: 'text-red-600',
|
|
97
|
+
iconContainerClassName: 'bg-red-500/10 text-red-700',
|
|
98
|
+
accentClassName: 'from-red-500/20 via-rose-500/10 to-transparent',
|
|
99
|
+
},
|
|
100
|
+
{
|
|
101
|
+
key: 'projectedBalance',
|
|
102
|
+
title: t('cards.projectedBalance'),
|
|
103
|
+
value: <Money value={saldoFinal} />,
|
|
104
|
+
layout: 'compact' as const,
|
|
105
|
+
valueClassName: saldoFinal >= 0 ? 'text-green-600' : 'text-red-600',
|
|
106
|
+
},
|
|
107
|
+
];
|
|
76
108
|
|
|
77
109
|
return (
|
|
78
110
|
<Page>
|
|
@@ -98,7 +130,7 @@ export default function FluxoCaixaPage() {
|
|
|
98
130
|
onValueChange={setHorizonte}
|
|
99
131
|
disabled={isFetching}
|
|
100
132
|
>
|
|
101
|
-
<SelectTrigger className="w-
|
|
133
|
+
<SelectTrigger className="w-45">
|
|
102
134
|
<SelectValue placeholder={t('filters.horizon')} />
|
|
103
135
|
</SelectTrigger>
|
|
104
136
|
<SelectContent>
|
|
@@ -116,7 +148,7 @@ export default function FluxoCaixaPage() {
|
|
|
116
148
|
}
|
|
117
149
|
disabled={isFetching}
|
|
118
150
|
>
|
|
119
|
-
<SelectTrigger className="w-
|
|
151
|
+
<SelectTrigger className="w-45">
|
|
120
152
|
<SelectValue placeholder={t('filters.scenario')} />
|
|
121
153
|
</SelectTrigger>
|
|
122
154
|
<SelectContent>
|
|
@@ -137,106 +169,50 @@ export default function FluxoCaixaPage() {
|
|
|
137
169
|
) : null}
|
|
138
170
|
</div>
|
|
139
171
|
|
|
140
|
-
<
|
|
141
|
-
<Card>
|
|
142
|
-
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
|
|
143
|
-
<CardTitle className="text-sm font-medium">
|
|
144
|
-
{t('cards.currentBalance')}
|
|
145
|
-
</CardTitle>
|
|
146
|
-
<Wallet className="h-4 w-4 text-muted-foreground" />
|
|
147
|
-
</CardHeader>
|
|
148
|
-
<CardContent>
|
|
149
|
-
<div className="text-2xl font-bold">
|
|
150
|
-
<Money value={kpis.saldoCaixa} />
|
|
151
|
-
</div>
|
|
152
|
-
</CardContent>
|
|
153
|
-
</Card>
|
|
154
|
-
<Card>
|
|
155
|
-
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
|
|
156
|
-
<CardTitle className="text-sm font-medium">
|
|
157
|
-
{t('cards.expectedInflows')}
|
|
158
|
-
</CardTitle>
|
|
159
|
-
<TrendingUp className="h-4 w-4 text-green-500" />
|
|
160
|
-
</CardHeader>
|
|
161
|
-
<CardContent>
|
|
162
|
-
<div className="text-2xl font-bold text-green-600">
|
|
163
|
-
<Money value={totalEntradas} />
|
|
164
|
-
</div>
|
|
165
|
-
</CardContent>
|
|
166
|
-
</Card>
|
|
167
|
-
<Card>
|
|
168
|
-
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
|
|
169
|
-
<CardTitle className="text-sm font-medium">
|
|
170
|
-
{t('cards.expectedOutflows')}
|
|
171
|
-
</CardTitle>
|
|
172
|
-
<TrendingDown className="h-4 w-4 text-red-500" />
|
|
173
|
-
</CardHeader>
|
|
174
|
-
<CardContent>
|
|
175
|
-
<div className="text-2xl font-bold text-red-600">
|
|
176
|
-
<Money value={totalSaidas} />
|
|
177
|
-
</div>
|
|
178
|
-
</CardContent>
|
|
179
|
-
</Card>
|
|
180
|
-
<Card>
|
|
181
|
-
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
|
|
182
|
-
<CardTitle className="text-sm font-medium">
|
|
183
|
-
{t('cards.projectedBalance')}
|
|
184
|
-
</CardTitle>
|
|
185
|
-
</CardHeader>
|
|
186
|
-
<CardContent>
|
|
187
|
-
<div
|
|
188
|
-
className={`text-2xl font-bold ${saldoFinal >= 0 ? 'text-green-600' : 'text-red-600'}`}
|
|
189
|
-
>
|
|
190
|
-
<Money value={saldoFinal} />
|
|
191
|
-
</div>
|
|
192
|
-
</CardContent>
|
|
193
|
-
</Card>
|
|
194
|
-
</div>
|
|
172
|
+
<KpiCardsGrid items={summaryCards} columns={4} />
|
|
195
173
|
|
|
196
|
-
<
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
<
|
|
202
|
-
<
|
|
203
|
-
<
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
</CardContent>
|
|
239
|
-
</Card>
|
|
174
|
+
<FinancePageSection
|
|
175
|
+
title={t('projection.title')}
|
|
176
|
+
description={t('projection.description')}
|
|
177
|
+
contentClassName="p-4 sm:p-5"
|
|
178
|
+
>
|
|
179
|
+
<ResponsiveContainer width="100%" height={350}>
|
|
180
|
+
<AreaChart data={chartData}>
|
|
181
|
+
<CartesianGrid strokeDasharray="3 3" className="stroke-muted" />
|
|
182
|
+
<XAxis dataKey="data" tick={{ fontSize: 12 }} />
|
|
183
|
+
<YAxis
|
|
184
|
+
tick={{ fontSize: 12 }}
|
|
185
|
+
tickFormatter={(value) => `${(value / 1000).toFixed(0)}k`}
|
|
186
|
+
/>
|
|
187
|
+
<Tooltip
|
|
188
|
+
formatter={(value: number) => formatarMoeda(value)}
|
|
189
|
+
contentStyle={{
|
|
190
|
+
backgroundColor: 'hsl(var(--background))',
|
|
191
|
+
border: '1px solid hsl(var(--border))',
|
|
192
|
+
borderRadius: '8px',
|
|
193
|
+
}}
|
|
194
|
+
/>
|
|
195
|
+
<Legend />
|
|
196
|
+
<Area
|
|
197
|
+
type="monotone"
|
|
198
|
+
dataKey="saldoPrevisto"
|
|
199
|
+
name={t('projection.predictedBalance')}
|
|
200
|
+
stroke="hsl(var(--primary))"
|
|
201
|
+
fill="hsl(var(--primary))"
|
|
202
|
+
fillOpacity={0.2}
|
|
203
|
+
/>
|
|
204
|
+
<Area
|
|
205
|
+
type="monotone"
|
|
206
|
+
dataKey="saldoRealizado"
|
|
207
|
+
name={t('projection.actualBalance')}
|
|
208
|
+
stroke="hsl(var(--chart-2))"
|
|
209
|
+
fill="hsl(var(--chart-2))"
|
|
210
|
+
fillOpacity={0.2}
|
|
211
|
+
connectNulls
|
|
212
|
+
/>
|
|
213
|
+
</AreaChart>
|
|
214
|
+
</ResponsiveContainer>
|
|
215
|
+
</FinancePageSection>
|
|
240
216
|
|
|
241
217
|
<Tabs defaultValue="entradas">
|
|
242
218
|
<TabsList>
|