feat(lancamentos): aprimora parcelamentos e protecoes

This commit is contained in:
Felipe Coutinho
2026-05-21 13:47:14 +00:00
parent b6659ef66e
commit 4e8f9cc5fa
16 changed files with 275 additions and 66 deletions

View File

@@ -130,7 +130,7 @@ export function InstallmentAnalysisPage({
return (
<div className="flex flex-col gap-4">
{/* Card de resumo principal */}
<Card className="border-none bg-primary/10 dark:bg-primary/10">
<Card className="border-none bg-primary/10 shadow-none">
<CardContent className="flex flex-col items-start justify-center gap-2 py-2">
<p className="text-sm text-muted-foreground">
Se você pagar tudo que está selecionado:

View File

@@ -64,8 +64,8 @@ export function InstallmentGroupCard({
const hasSelection = selectedInstallments.size > 0;
const progress =
group.totalInstallments > 0
? (group.paidInstallments / group.totalInstallments) * 100
group.trackedInstallments > 0
? (group.paidInstallments / group.trackedInstallments) * 100
: 0;
const selectedAmount = group.pendingInstallments
@@ -83,6 +83,10 @@ export function InstallmentGroupCard({
);
const cardLogoSrc = resolveLogoSrc(group.cartaoLogo);
const cardName = group.cartaoName ?? "Compra parcelada";
const untrackedLabel =
group.untrackedInstallments === 1
? "1 parcela anterior fora do acompanhamento"
: `${group.untrackedInstallments} parcelas anteriores fora do acompanhamento`;
return (
<>
@@ -153,7 +157,7 @@ export function InstallmentGroupCard({
<div className="grid grid-cols-2 gap-4 p-4 rounded-lg bg-primary/5 mb-4">
<div className="space-y-1">
<p className="text-xs text-muted-foreground font-medium">
Valor total
Valor acompanhado
</p>
<MoneyValues
amount={totalAmount}
@@ -180,8 +184,8 @@ export function InstallmentGroupCard({
<div className="flex items-center gap-1 text-muted-foreground">
<RiCheckboxCircleFill className="size-3.5 text-success" />
<span>
{group.paidInstallments} de {group.totalInstallments} parcelas
pagas
{group.paidInstallments} de {group.trackedInstallments}{" "}
parcelas acompanhadas pagas
</span>
</div>
{unpaidCount > 0 && (
@@ -198,6 +202,9 @@ export function InstallmentGroupCard({
className="h-2.5 bg-muted"
indicatorClassName="bg-success"
/>
{group.untrackedInstallments > 0 && (
<p className="text-xs text-muted-foreground">{untrackedLabel}</p>
)}
</div>
{/* Valor selecionado */}

View File

@@ -51,6 +51,9 @@ export type InstallmentGroup = {
cartaoDueDay: string | null;
cartaoLogo: string | null;
totalInstallments: number;
trackedStartInstallment: number;
trackedInstallments: number;
untrackedInstallments: number;
paidInstallments: number;
pendingInstallments: InstallmentDetail[];
totalPendingAmount: number;
@@ -153,6 +156,12 @@ export async function fetchInstallmentAnalysis(
cartaoDueDay: row.cartaoDueDay,
cartaoLogo: row.cartaoLogo,
totalInstallments: row.installmentCount ?? 0,
trackedStartInstallment: installmentDetail.currentInstallment,
trackedInstallments: 1,
untrackedInstallments: Math.max(
0,
installmentDetail.currentInstallment - 1,
),
paidInstallments: 0,
pendingInstallments: [installmentDetail],
totalPendingAmount: amount,
@@ -168,7 +177,13 @@ export async function fetchInstallmentAnalysis(
const paidCount = group.pendingInstallments.filter(
(i) => i.isSettled,
).length;
const trackedStartInstallment = Math.min(
...group.pendingInstallments.map((i) => i.currentInstallment),
);
group.paidInstallments = paidCount;
group.trackedStartInstallment = trackedStartInstallment;
group.trackedInstallments = group.pendingInstallments.length;
group.untrackedInstallments = Math.max(0, trackedStartInstallment - 1);
return group;
})
// Filtrar apenas séries que têm pelo menos uma parcela em aberto (não paga)