feat(finance): refina fluxos de transacoes e pagadores

This commit is contained in:
Felipe Coutinho
2026-03-09 17:13:44 +00:00
parent 69da27276c
commit ada1377640
58 changed files with 1288 additions and 1559 deletions

View File

@@ -1,6 +1,5 @@
"use client";
import { useCallback, useMemo } from "react";
import { Label } from "@/components/ui/label";
import {
Select,
@@ -10,73 +9,48 @@ import {
SelectValue,
} from "@/components/ui/select";
import { LANCAMENTO_CONDITIONS } from "@/lib/lancamentos/constants";
import { formatCurrency } from "@/lib/utils/currency";
import { cn } from "@/lib/utils/ui";
import { ConditionSelectContent } from "../../select-items";
import type { ConditionSectionProps } from "./lancamento-dialog-types";
function formatCurrency(value: number): string {
return value.toLocaleString("pt-BR", {
minimumFractionDigits: 2,
maximumFractionDigits: 2,
});
}
export function ConditionSection({
formState,
onFieldChange,
showInstallments,
showRecurrence,
}: ConditionSectionProps) {
const amount = useMemo(() => {
const value = Number(formState.amount);
return Number.isNaN(value) || value <= 0 ? null : value;
}, [formState.amount]);
const parsedAmount = Number(formState.amount);
const amount =
Number.isNaN(parsedAmount) || parsedAmount <= 0 ? null : parsedAmount;
const getInstallmentLabel = useCallback(
(count: number) => {
if (amount) {
const installmentValue = amount / count;
return `${count}x de R$ ${formatCurrency(installmentValue)}`;
}
return `${count}x`;
},
[amount],
);
const getInstallmentLabel = (count: number) => {
if (amount) {
const installmentValue = amount / count;
return `${count}x de R$ ${formatCurrency(installmentValue)}`;
}
const _getRecurrenceLabel = (count: number) => {
return `${count} meses`;
return `${count}x`;
};
const installmentSummary = useMemo(() => {
if (!showInstallments || !formState.installmentCount || !amount) {
return null;
}
const installmentCount = Number(formState.installmentCount);
const installmentSummary =
showInstallments &&
formState.installmentCount &&
amount &&
!Number.isNaN(installmentCount) &&
installmentCount > 0
? getInstallmentLabel(installmentCount)
: null;
const count = Number(formState.installmentCount);
if (Number.isNaN(count) || count <= 0) {
return null;
}
return getInstallmentLabel(count);
}, [
showInstallments,
formState.installmentCount,
amount,
getInstallmentLabel,
]);
const recurrenceSummary = useMemo(() => {
if (!showRecurrence || !formState.recurrenceCount) {
return null;
}
const count = Number(formState.recurrenceCount);
if (Number.isNaN(count) || count <= 0) {
return null;
}
return `Por ${count} meses`;
}, [showRecurrence, formState.recurrenceCount]);
const recurrenceCount = Number(formState.recurrenceCount);
const recurrenceSummary =
showRecurrence &&
formState.recurrenceCount &&
!Number.isNaN(recurrenceCount) &&
recurrenceCount > 0
? `Por ${recurrenceCount} meses`
: null;
return (
<div className="flex w-full flex-col gap-2 md:flex-row">

View File

@@ -1,6 +1,5 @@
"use client";
import { useCallback } from "react";
import { CurrencyInput } from "@/components/ui/currency-input";
import { Label } from "@/components/ui/label";
import {
@@ -20,25 +19,19 @@ export function PagadorSection({
secondaryPagadorOptions,
totalAmount,
}: PagadorSectionProps) {
const handlePrimaryAmountChange = useCallback(
(value: string) => {
onFieldChange("primarySplitAmount", value);
const numericValue = Number.parseFloat(value) || 0;
const remaining = Math.max(0, totalAmount - numericValue);
onFieldChange("secondarySplitAmount", remaining.toFixed(2));
},
[totalAmount, onFieldChange],
);
const handlePrimaryAmountChange = (value: string) => {
onFieldChange("primarySplitAmount", value);
const numericValue = Number.parseFloat(value) || 0;
const remaining = Math.max(0, totalAmount - numericValue);
onFieldChange("secondarySplitAmount", remaining.toFixed(2));
};
const handleSecondaryAmountChange = useCallback(
(value: string) => {
onFieldChange("secondarySplitAmount", value);
const numericValue = Number.parseFloat(value) || 0;
const remaining = Math.max(0, totalAmount - numericValue);
onFieldChange("primarySplitAmount", remaining.toFixed(2));
},
[totalAmount, onFieldChange],
);
const handleSecondaryAmountChange = (value: string) => {
onFieldChange("secondarySplitAmount", value);
const numericValue = Number.parseFloat(value) || 0;
const remaining = Math.max(0, totalAmount - numericValue);
onFieldChange("primarySplitAmount", remaining.toFixed(2));
};
return (
<div className="flex w-full flex-col gap-2 md:flex-row">

View File

@@ -16,7 +16,7 @@ import {
SelectValue,
} from "@/components/ui/select";
import { LANCAMENTO_PAYMENT_METHODS } from "@/lib/lancamentos/constants";
import { displayPeriod } from "@/lib/utils/period";
import { dateToPeriod, displayPeriod, periodToDate } from "@/lib/utils/period";
import { cn } from "@/lib/utils/ui";
import {
ContaCartaoSelectContent,
@@ -24,17 +24,6 @@ import {
} from "../../select-items";
import type { PaymentMethodSectionProps } from "./lancamento-dialog-types";
function periodToDate(period: string): Date {
const [year, month] = period.split("-").map(Number);
return new Date(year, month - 1, 1);
}
function dateToPeriod(date: Date): string {
const year = date.getFullYear();
const month = String(date.getMonth() + 1).padStart(2, "0");
return `${year}-${month}`;
}
function InlinePeriodPicker({
period,
onPeriodChange,