Files
openmonetis/src/features/dashboard/expenses/installment-expenses-helpers.ts
2026-05-28 10:59:36 -03:00

134 lines
3.2 KiB
TypeScript

import type { InstallmentExpense } from "@/features/dashboard/expenses/installment-expenses-queries";
import { calculateLastInstallmentDate } from "@/shared/lib/installments/utils";
import { capitalize } from "@/shared/utils/string";
type InstallmentExpenseDisplay = {
compactLabel: string | null;
isLast: boolean;
remainingLabel: "Próx." | "Aberto";
remainingInstallments: number;
remainingAmount: number;
endDate: string | null;
progress: number;
};
const buildInstallmentCompactLabel = (
currentInstallment: number | null,
installmentCount: number | null,
) => {
if (currentInstallment && installmentCount) {
return `${currentInstallment} de ${installmentCount}`;
}
return null;
};
const isInstallmentLast = (
currentInstallment: number | null,
installmentCount: number | null,
) => {
if (!currentInstallment || !installmentCount) {
return false;
}
return currentInstallment === installmentCount && installmentCount > 1;
};
const calculateInstallmentRemainingCount = (
currentInstallment: number | null,
installmentCount: number | null,
isSettled: boolean | null,
) => {
if (!currentInstallment || !installmentCount) {
return 0;
}
const includeCurrentInstallment = isSettled !== true;
const currentOffset = includeCurrentInstallment ? 1 : 0;
return Math.max(0, installmentCount - currentInstallment + currentOffset);
};
const calculateInstallmentRemainingAmount = (
amount: number,
currentInstallment: number | null,
installmentCount: number | null,
isSettled: boolean | null,
) =>
amount *
calculateInstallmentRemainingCount(
currentInstallment,
installmentCount,
isSettled,
);
const formatInstallmentEndDate = (
period: string,
currentInstallment: number | null,
installmentCount: number | null,
) => {
if (!currentInstallment || !installmentCount) {
return null;
}
const lastDate = calculateLastInstallmentDate(
period,
currentInstallment,
installmentCount,
);
const month = new Intl.DateTimeFormat("pt-BR", {
month: "short",
timeZone: "UTC",
}).format(lastDate);
return `${capitalize(month)} de ${lastDate.getFullYear()}`;
};
const buildInstallmentProgress = (
currentInstallment: number | null,
installmentCount: number | null,
) => {
if (!currentInstallment || !installmentCount || installmentCount <= 0) {
return 0;
}
return Math.min(
100,
Math.max(0, (currentInstallment / installmentCount) * 100),
);
};
export const buildInstallmentExpenseDisplay = (
expense: InstallmentExpense,
): InstallmentExpenseDisplay => {
const { amount, currentInstallment, installmentCount, isSettled, period } =
expense;
return {
compactLabel: buildInstallmentCompactLabel(
currentInstallment,
installmentCount,
),
isLast: isInstallmentLast(currentInstallment, installmentCount),
remainingLabel: isSettled === true ? "Próx." : "Aberto",
remainingInstallments: calculateInstallmentRemainingCount(
currentInstallment,
installmentCount,
isSettled,
),
remainingAmount: calculateInstallmentRemainingAmount(
amount,
currentInstallment,
installmentCount,
isSettled,
),
endDate: formatInstallmentEndDate(
period,
currentInstallment,
installmentCount,
),
progress: buildInstallmentProgress(currentInstallment, installmentCount),
};
};