mirror of
https://github.com/felipegcoutinho/openmonetis.git
synced 2026-05-09 19:01:47 +00:00
refactor: atualiza transacoes dashboard e relatorios
This commit is contained in:
@@ -3,16 +3,16 @@ import { RiAddLine } from "@remixicon/react";
|
||||
import { useEffect, useMemo, useState, useTransition } from "react";
|
||||
import { toast } from "sonner";
|
||||
import {
|
||||
createLancamentoAction,
|
||||
updateLancamentoAction,
|
||||
createTransactionAction,
|
||||
updateTransactionAction,
|
||||
} from "@/features/transactions/actions";
|
||||
import {
|
||||
filterSecondaryPagadorOptions,
|
||||
groupAndSortCategorias,
|
||||
} from "@/features/transactions/categoria-helpers";
|
||||
filterSecondaryPayerOptions,
|
||||
groupAndSortCategories,
|
||||
} from "@/features/transactions/category-helpers";
|
||||
import {
|
||||
applyFieldDependencies,
|
||||
buildLancamentoInitialState,
|
||||
buildTransactionInitialState,
|
||||
deriveCreditCardPeriod,
|
||||
} from "@/features/transactions/form-helpers";
|
||||
import { Button } from "@/shared/components/ui/button";
|
||||
@@ -36,41 +36,41 @@ import { BoletoFieldsSection } from "./boleto-fields-section";
|
||||
import { CategorySection } from "./category-section";
|
||||
import { ConditionSection } from "./condition-section";
|
||||
import { NoteSection } from "./note-section";
|
||||
import { PagadorSection } from "./pagador-section";
|
||||
import { PayerSection } from "./payer-section";
|
||||
import { PaymentMethodSection } from "./payment-method-section";
|
||||
import { SplitAndSettlementSection } from "./split-settlement-section";
|
||||
import type {
|
||||
FormState,
|
||||
LancamentoDialogProps,
|
||||
TransactionDialogProps,
|
||||
} from "./transaction-dialog-types";
|
||||
|
||||
export function LancamentoDialog({
|
||||
export function TransactionDialog({
|
||||
mode,
|
||||
trigger,
|
||||
open,
|
||||
onOpenChange,
|
||||
pagadorOptions,
|
||||
splitPagadorOptions,
|
||||
defaultPagadorId,
|
||||
contaOptions,
|
||||
cartaoOptions,
|
||||
categoriaOptions,
|
||||
payerOptions,
|
||||
splitPayerOptions,
|
||||
defaultPayerId,
|
||||
accountOptions,
|
||||
cardOptions,
|
||||
categoryOptions,
|
||||
estabelecimentos,
|
||||
lancamento,
|
||||
transaction,
|
||||
defaultPeriod,
|
||||
defaultCartaoId,
|
||||
defaultCardId,
|
||||
defaultPaymentMethod,
|
||||
defaultPurchaseDate,
|
||||
defaultName,
|
||||
defaultAmount,
|
||||
lockCartaoSelection,
|
||||
lockCardSelection,
|
||||
lockPaymentMethod,
|
||||
isImporting = false,
|
||||
defaultTransactionType,
|
||||
forceShowTransactionType = false,
|
||||
onSuccess,
|
||||
onBulkEditRequest,
|
||||
}: LancamentoDialogProps) {
|
||||
}: TransactionDialogProps) {
|
||||
const [dialogOpen, setDialogOpen] = useControlledState(
|
||||
open,
|
||||
false,
|
||||
@@ -78,8 +78,8 @@ export function LancamentoDialog({
|
||||
);
|
||||
|
||||
const [formState, setFormState] = useState<FormState>(() =>
|
||||
buildLancamentoInitialState(lancamento, defaultPagadorId, defaultPeriod, {
|
||||
defaultCartaoId,
|
||||
buildTransactionInitialState(transaction, defaultPayerId, defaultPeriod, {
|
||||
defaultCardId,
|
||||
defaultPaymentMethod,
|
||||
defaultPurchaseDate,
|
||||
defaultName,
|
||||
@@ -93,12 +93,12 @@ export function LancamentoDialog({
|
||||
|
||||
useEffect(() => {
|
||||
if (dialogOpen) {
|
||||
const initial = buildLancamentoInitialState(
|
||||
lancamento,
|
||||
defaultPagadorId,
|
||||
const initial = buildTransactionInitialState(
|
||||
transaction,
|
||||
defaultPayerId,
|
||||
defaultPeriod,
|
||||
{
|
||||
defaultCartaoId,
|
||||
defaultCardId,
|
||||
defaultPaymentMethod,
|
||||
defaultPurchaseDate,
|
||||
defaultName,
|
||||
@@ -108,15 +108,13 @@ export function LancamentoDialog({
|
||||
},
|
||||
);
|
||||
|
||||
// Derive credit card period on open when cartaoId is pre-filled
|
||||
// Derive credit card period on open when cardId is pre-filled
|
||||
if (
|
||||
initial.paymentMethod === "Cartão de crédito" &&
|
||||
initial.cartaoId &&
|
||||
initial.cardId &&
|
||||
initial.purchaseDate
|
||||
) {
|
||||
const card = cartaoOptions.find(
|
||||
(opt) => opt.value === initial.cartaoId,
|
||||
);
|
||||
const card = cardOptions.find((opt) => opt.value === initial.cardId);
|
||||
if (card?.closingDay) {
|
||||
initial.period = deriveCreditCardPeriod(
|
||||
initial.purchaseDate,
|
||||
@@ -131,45 +129,45 @@ export function LancamentoDialog({
|
||||
}
|
||||
}, [
|
||||
dialogOpen,
|
||||
lancamento,
|
||||
defaultPagadorId,
|
||||
transaction,
|
||||
defaultPayerId,
|
||||
defaultPeriod,
|
||||
defaultCartaoId,
|
||||
defaultCardId,
|
||||
defaultPaymentMethod,
|
||||
defaultPurchaseDate,
|
||||
defaultName,
|
||||
defaultAmount,
|
||||
defaultTransactionType,
|
||||
isImporting,
|
||||
cartaoOptions,
|
||||
cardOptions,
|
||||
]);
|
||||
|
||||
const primaryPagador = formState.pagadorId;
|
||||
const primaryPayerId = formState.payerId;
|
||||
|
||||
const secondaryPagadorOptions = useMemo(
|
||||
() => filterSecondaryPagadorOptions(splitPagadorOptions, primaryPagador),
|
||||
[splitPagadorOptions, primaryPagador],
|
||||
const secondaryPayerOptions = useMemo(
|
||||
() => filterSecondaryPayerOptions(splitPayerOptions, primaryPayerId),
|
||||
[splitPayerOptions, primaryPayerId],
|
||||
);
|
||||
|
||||
const categoriaGroups = useMemo(() => {
|
||||
const filtered = categoriaOptions.filter(
|
||||
const categoryGroups = useMemo(() => {
|
||||
const filtered = categoryOptions.filter(
|
||||
(option) =>
|
||||
option.group?.toLowerCase() === formState.transactionType.toLowerCase(),
|
||||
);
|
||||
return groupAndSortCategorias(filtered);
|
||||
}, [categoriaOptions, formState.transactionType]);
|
||||
return groupAndSortCategories(filtered);
|
||||
}, [categoryOptions, formState.transactionType]);
|
||||
|
||||
type CreateLancamentoInput = Parameters<typeof createLancamentoAction>[0];
|
||||
type UpdateLancamentoInput = Parameters<typeof updateLancamentoAction>[0];
|
||||
type CreateTransactionInput = Parameters<typeof createTransactionAction>[0];
|
||||
type UpdateTransactionInput = Parameters<typeof updateTransactionAction>[0];
|
||||
|
||||
const totalAmount = useMemo(() => {
|
||||
const parsed = Number.parseFloat(formState.amount);
|
||||
return Number.isNaN(parsed) ? 0 : Math.abs(parsed);
|
||||
}, [formState.amount]);
|
||||
|
||||
function getCardInfo(cartaoId: string | undefined) {
|
||||
if (!cartaoId) return null;
|
||||
const card = cartaoOptions.find((opt) => opt.value === cartaoId);
|
||||
function getCardInfo(cardId: string | undefined) {
|
||||
if (!cardId) return null;
|
||||
const card = cardOptions.find((opt) => opt.value === cardId);
|
||||
if (!card) return null;
|
||||
return {
|
||||
closingDay: card.closingDay ?? null,
|
||||
@@ -182,9 +180,9 @@ export function LancamentoDialog({
|
||||
value: FormState[Key],
|
||||
) {
|
||||
setFormState((prev) => {
|
||||
const effectiveCartaoId =
|
||||
key === "cartaoId" ? (value as string) : prev.cartaoId;
|
||||
const cardInfo = getCardInfo(effectiveCartaoId);
|
||||
const effectiveCardId =
|
||||
key === "cardId" ? (value as string) : prev.cardId;
|
||||
const cardInfo = getCardInfo(effectiveCardId);
|
||||
|
||||
const dependencies = applyFieldDependencies(key, value, prev, cardInfo);
|
||||
|
||||
@@ -214,7 +212,7 @@ export function LancamentoDialog({
|
||||
return;
|
||||
}
|
||||
|
||||
if (formState.isSplit && !formState.pagadorId) {
|
||||
if (formState.isSplit && !formState.payerId) {
|
||||
const message =
|
||||
"Selecione o pagador principal para dividir o lançamento.";
|
||||
setErrorMessage(message);
|
||||
@@ -222,7 +220,7 @@ export function LancamentoDialog({
|
||||
return;
|
||||
}
|
||||
|
||||
if (formState.isSplit && !formState.secondaryPagadorId) {
|
||||
if (formState.isSplit && !formState.secondaryPayerId) {
|
||||
const message =
|
||||
"Selecione o pagador secundário para dividir o lançamento.";
|
||||
setErrorMessage(message);
|
||||
@@ -240,7 +238,7 @@ export function LancamentoDialog({
|
||||
|
||||
const sanitizedAmount = Math.abs(amountValue);
|
||||
|
||||
if (!formState.categoriaId) {
|
||||
if (!formState.categoryId) {
|
||||
const message = "Selecione uma categoria.";
|
||||
setErrorMessage(message);
|
||||
toast.error(message);
|
||||
@@ -248,32 +246,32 @@ export function LancamentoDialog({
|
||||
}
|
||||
|
||||
if (formState.paymentMethod === "Cartão de crédito") {
|
||||
if (!formState.cartaoId) {
|
||||
if (!formState.cardId) {
|
||||
const message = "Selecione o cartão.";
|
||||
setErrorMessage(message);
|
||||
toast.error(message);
|
||||
return;
|
||||
}
|
||||
} else if (!formState.contaId) {
|
||||
} else if (!formState.accountId) {
|
||||
const message = "Selecione a conta.";
|
||||
setErrorMessage(message);
|
||||
toast.error(message);
|
||||
return;
|
||||
}
|
||||
|
||||
const payload: CreateLancamentoInput = {
|
||||
const payload: CreateTransactionInput = {
|
||||
purchaseDate: formState.purchaseDate,
|
||||
period: formState.period,
|
||||
name: formState.name.trim(),
|
||||
transactionType:
|
||||
formState.transactionType as CreateLancamentoInput["transactionType"],
|
||||
formState.transactionType as CreateTransactionInput["transactionType"],
|
||||
amount: sanitizedAmount,
|
||||
condition: formState.condition as CreateLancamentoInput["condition"],
|
||||
condition: formState.condition as CreateTransactionInput["condition"],
|
||||
paymentMethod:
|
||||
formState.paymentMethod as CreateLancamentoInput["paymentMethod"],
|
||||
pagadorId: formState.pagadorId ?? null,
|
||||
secondaryPagadorId: formState.isSplit
|
||||
? formState.secondaryPagadorId
|
||||
formState.paymentMethod as CreateTransactionInput["paymentMethod"],
|
||||
payerId: formState.payerId ?? null,
|
||||
secondaryPayerId: formState.isSplit
|
||||
? formState.secondaryPayerId
|
||||
: undefined,
|
||||
isSplit: formState.isSplit,
|
||||
primarySplitAmount: formState.isSplit
|
||||
@@ -282,9 +280,9 @@ export function LancamentoDialog({
|
||||
secondarySplitAmount: formState.isSplit
|
||||
? Number.parseFloat(formState.secondarySplitAmount) || undefined
|
||||
: undefined,
|
||||
contaId: formState.contaId ?? null,
|
||||
cartaoId: formState.cartaoId ?? null,
|
||||
categoriaId: formState.categoriaId ?? null,
|
||||
accountId: formState.accountId ?? null,
|
||||
cardId: formState.cardId ?? null,
|
||||
categoryId: formState.categoryId ?? null,
|
||||
note: formState.note.trim() || null,
|
||||
isSettled:
|
||||
formState.paymentMethod === "Cartão de crédito"
|
||||
@@ -309,7 +307,7 @@ export function LancamentoDialog({
|
||||
|
||||
startTransition(async () => {
|
||||
if (mode === "create") {
|
||||
const result = await createLancamentoAction(payload);
|
||||
const result = await createTransactionAction(payload);
|
||||
|
||||
if (result.success) {
|
||||
toast.success(result.message);
|
||||
@@ -324,18 +322,18 @@ export function LancamentoDialog({
|
||||
}
|
||||
|
||||
// Update mode
|
||||
const hasSeriesId = Boolean(lancamento?.seriesId);
|
||||
const hasSeriesId = Boolean(transaction?.seriesId);
|
||||
|
||||
if (hasSeriesId && onBulkEditRequest) {
|
||||
// Para lançamentos em série, abre o diálogo de bulk action
|
||||
onBulkEditRequest({
|
||||
id: lancamento?.id ?? "",
|
||||
id: transaction?.id ?? "",
|
||||
name: formState.name.trim(),
|
||||
categoriaId: formState.categoriaId,
|
||||
categoryId: formState.categoryId,
|
||||
note: formState.note.trim() || "",
|
||||
pagadorId: formState.pagadorId,
|
||||
contaId: formState.contaId,
|
||||
cartaoId: formState.cartaoId,
|
||||
payerId: formState.payerId,
|
||||
accountId: formState.accountId,
|
||||
cardId: formState.cardId,
|
||||
amount: sanitizedAmount,
|
||||
dueDate:
|
||||
formState.paymentMethod === "Boleto"
|
||||
@@ -350,12 +348,12 @@ export function LancamentoDialog({
|
||||
}
|
||||
|
||||
// Atualização normal para lançamentos únicos ou todos os campos
|
||||
const updatePayload: UpdateLancamentoInput = {
|
||||
id: lancamento?.id ?? "",
|
||||
const updatePayload: UpdateTransactionInput = {
|
||||
id: transaction?.id ?? "",
|
||||
...payload,
|
||||
};
|
||||
|
||||
const result = await updateLancamentoAction(updatePayload);
|
||||
const result = await updateTransactionAction(updatePayload);
|
||||
|
||||
if (result.success) {
|
||||
toast.success(result.message);
|
||||
@@ -369,15 +367,15 @@ export function LancamentoDialog({
|
||||
});
|
||||
};
|
||||
|
||||
const isCopyMode = mode === "create" && Boolean(lancamento) && !isImporting;
|
||||
const isImportMode = mode === "create" && Boolean(lancamento) && isImporting;
|
||||
const isCopyMode = mode === "create" && Boolean(transaction) && !isImporting;
|
||||
const isImportMode = mode === "create" && Boolean(transaction) && isImporting;
|
||||
const isNewWithType =
|
||||
mode === "create" && !lancamento && defaultTransactionType;
|
||||
mode === "create" && !transaction && defaultTransactionType;
|
||||
|
||||
const title =
|
||||
mode === "create"
|
||||
? isImportMode
|
||||
? "Importar para Minha Conta"
|
||||
? "Importar para Minha FinancialAccount"
|
||||
: isCopyMode
|
||||
? "Copiar lançamento"
|
||||
: isNewWithType
|
||||
@@ -405,7 +403,7 @@ export function LancamentoDialog({
|
||||
const showSettledToggle = formState.paymentMethod !== "Cartão de crédito";
|
||||
const isUpdateMode = mode === "update";
|
||||
const disablePaymentMethod = Boolean(lockPaymentMethod && mode === "create");
|
||||
const disableCartaoSelect = Boolean(lockCartaoSelection && mode === "create");
|
||||
const disableCardSelect = Boolean(lockCardSelection && mode === "create");
|
||||
|
||||
return (
|
||||
<Dialog open={dialogOpen} onOpenChange={setDialogOpen}>
|
||||
@@ -430,8 +428,8 @@ export function LancamentoDialog({
|
||||
<CategorySection
|
||||
formState={formState}
|
||||
onFieldChange={handleFieldChange}
|
||||
categoriaOptions={categoriaOptions}
|
||||
categoriaGroups={categoriaGroups}
|
||||
categoryOptions={categoryOptions}
|
||||
categoryGroups={categoryGroups}
|
||||
isUpdateMode={isUpdateMode}
|
||||
hideTransactionType={
|
||||
Boolean(isNewWithType) && !forceShowTransactionType
|
||||
@@ -446,22 +444,22 @@ export function LancamentoDialog({
|
||||
/>
|
||||
) : null}
|
||||
|
||||
<PagadorSection
|
||||
<PayerSection
|
||||
formState={formState}
|
||||
onFieldChange={handleFieldChange}
|
||||
pagadorOptions={pagadorOptions}
|
||||
secondaryPagadorOptions={secondaryPagadorOptions}
|
||||
payerOptions={payerOptions}
|
||||
secondaryPayerOptions={secondaryPayerOptions}
|
||||
totalAmount={totalAmount}
|
||||
/>
|
||||
|
||||
<PaymentMethodSection
|
||||
formState={formState}
|
||||
onFieldChange={handleFieldChange}
|
||||
contaOptions={contaOptions}
|
||||
cartaoOptions={cartaoOptions}
|
||||
accountOptions={accountOptions}
|
||||
cardOptions={cardOptions}
|
||||
isUpdateMode={isUpdateMode}
|
||||
disablePaymentMethod={disablePaymentMethod}
|
||||
disableCartaoSelect={disableCartaoSelect}
|
||||
disableCardSelect={disableCardSelect}
|
||||
/>
|
||||
|
||||
{showDueDate ? (
|
||||
|
||||
Reference in New Issue
Block a user