diff --git a/components/lancamentos/dialogs/mass-add-dialog.tsx b/components/lancamentos/dialogs/mass-add-dialog.tsx index 5b61787..ab62ac6 100644 --- a/components/lancamentos/dialogs/mass-add-dialog.tsx +++ b/components/lancamentos/dialogs/mass-add-dialog.tsx @@ -1,5 +1,6 @@ "use client"; +import { PeriodPicker } from "@/components/period-picker"; import { Button } from "@/components/ui/button"; import { CurrencyInput } from "@/components/ui/currency-input"; import { DatePicker } from "@/components/ui/date-picker"; @@ -23,7 +24,6 @@ import { } from "@/components/ui/select"; import { Separator } from "@/components/ui/separator"; import { Spinner } from "@/components/ui/spinner"; -import { PeriodPicker } from "@/components/period-picker"; import { groupAndSortCategorias } from "@/lib/lancamentos/categoria-helpers"; import { LANCAMENTO_PAYMENT_METHODS } from "@/lib/lancamentos/constants"; import { getTodayDateString } from "@/lib/utils/date"; @@ -33,7 +33,6 @@ import { toast } from "sonner"; import type { SelectOption } from "../../types"; import { CategoriaSelectContent, - ConditionSelectContent, ContaCartaoSelectContent, PagadorSelectContent, PaymentMethodSelectContent, @@ -52,6 +51,7 @@ interface MassAddDialogProps { estabelecimentos: string[]; selectedPeriod: string; defaultPagadorId?: string | null; + defaultCartaoId?: string | null; } export interface MassAddFormData { @@ -92,18 +92,32 @@ export function MassAddDialog({ estabelecimentos, selectedPeriod, defaultPagadorId, + defaultCartaoId, }: MassAddDialogProps) { const [loading, setLoading] = useState(false); // Fixed fields state (sempre ativos, sem checkboxes) const [transactionType, setTransactionType] = useState("Despesa"); const [paymentMethod, setPaymentMethod] = useState( - LANCAMENTO_PAYMENT_METHODS[0] + LANCAMENTO_PAYMENT_METHODS[0], ); - const [condition, setCondition] = useState("À vista"); const [period, setPeriod] = useState(selectedPeriod); - const [contaId, setContaId] = useState(); - const [cartaoId, setCartaoId] = useState(); + // Formato: "conta:uuid" ou "cartao:uuid" + const [contaCartaoId, setContaCartaoId] = useState( + defaultCartaoId ? `cartao:${defaultCartaoId}` : undefined, + ); + + // Quando defaultCartaoId está definido, exibe apenas o cartão específico + const isLockedToCartao = !!defaultCartaoId; + + // Deriva contaId e cartaoId do valor selecionado + const isCartaoSelected = contaCartaoId?.startsWith("cartao:"); + const contaId = contaCartaoId?.startsWith("conta:") + ? contaCartaoId.replace("conta:", "") + : undefined; + const cartaoId = contaCartaoId?.startsWith("cartao:") + ? contaCartaoId.replace("cartao:", "") + : undefined; // Transaction rows const [transactions, setTransactions] = useState([ @@ -120,7 +134,7 @@ export function MassAddDialog({ // Categorias agrupadas e filtradas por tipo de transação const groupedCategorias = useMemo(() => { const filtered = categoriaOptions.filter( - (option) => option.group?.toLowerCase() === transactionType.toLowerCase() + (option) => option.group?.toLowerCase() === transactionType.toLowerCase(), ); return groupAndSortCategorias(filtered); }, [categoriaOptions, transactionType]); @@ -150,33 +164,28 @@ export function MassAddDialog({ const updateTransaction = ( id: string, field: keyof TransactionRow, - value: string | undefined + value: string | undefined, ) => { setTransactions( - transactions.map((t) => (t.id === id ? { ...t, [field]: value } : t)) + transactions.map((t) => (t.id === id ? { ...t, [field]: value } : t)), ); }; const handleSubmit = async () => { // Validate conta/cartao selection - if (paymentMethod === "Cartão de crédito" && !cartaoId) { - toast.error("Selecione um cartão para continuar"); - return; - } - - if (paymentMethod !== "Cartão de crédito" && !contaId) { - toast.error("Selecione uma conta para continuar"); + if (!contaCartaoId) { + toast.error("Selecione uma conta ou cartão para continuar"); return; } // Validate transactions const invalidTransactions = transactions.filter( - (t) => !t.name.trim() || !t.amount.trim() || !t.purchaseDate + (t) => !t.name.trim() || !t.amount.trim() || !t.purchaseDate, ); if (invalidTransactions.length > 0) { toast.error( - "Preencha todos os campos obrigatórios das transações (data, estabelecimento e valor)" + "Preencha todos os campos obrigatórios das transações (data, estabelecimento e valor)", ); return; } @@ -185,11 +194,11 @@ export function MassAddDialog({ const formData: MassAddFormData = { fixedFields: { transactionType, - paymentMethod, - condition, + paymentMethod: isCartaoSelected ? "Cartão de crédito" : paymentMethod, + condition: "À vista", period, - contaId: paymentMethod !== "Cartão de crédito" ? contaId : undefined, - cartaoId: paymentMethod === "Cartão de crédito" ? cartaoId : undefined, + contaId: contaId, + cartaoId: cartaoId, }, transactions: transactions.map((t) => ({ purchaseDate: t.purchaseDate, @@ -207,10 +216,10 @@ export function MassAddDialog({ // Reset form setTransactionType("Despesa"); setPaymentMethod(LANCAMENTO_PAYMENT_METHODS[0]); - setCondition("À vista"); setPeriod(selectedPeriod); - setContaId(undefined); - setCartaoId(undefined); + setContaCartaoId( + defaultCartaoId ? `cartao:${defaultCartaoId}` : undefined, + ); setTransactions([ { id: crypto.randomUUID(), @@ -235,6 +244,8 @@ export function MassAddDialog({ Adicionar múltiplos lançamentos Configure os valores padrão e adicione várias transações de uma vez. + Todos os lançamentos adicionados aqui são{" "} + sempre à vista. @@ -242,7 +253,7 @@ export function MassAddDialog({ {/* Fixed Fields Section */}

Valores Padrão

-
+
{/* Transaction Type */}
@@ -300,25 +311,6 @@ export function MassAddDialog({
- {/* Condition */} -
- - -
- {/* Period */}
@@ -332,16 +324,20 @@ export function MassAddDialog({ {/* Conta/Cartao */}
- {paymentMethod === "Cartão de crédito" ? ( - + + + {contaCartaoId && + (() => { + if (isCartaoSelected) { const selectedOption = cartaoOptions.find( - (opt) => opt.value === cartaoId + (opt) => opt.value === cartaoId, ); return selectedOption ? ( ) : null; - })()} - - - - {cartaoOptions.map((option) => ( - - - - ))} - - - ) : ( - - )} + } + })()} + + + + {cartaoOptions.length > 0 && ( + + {!isLockedToCartao && ( + Cartões + )} + {cartaoOptions + .filter( + (option) => + !isLockedToCartao || + option.value === defaultCartaoId, + ) + .map((option) => ( + + + + ))} + + )} + {!isLockedToCartao && contaOptions.length > 0 && ( + + Contas + {contaOptions.map((option) => ( + + + + ))} + + )} + +
@@ -405,18 +414,7 @@ export function MassAddDialog({ {/* Transactions Section */}
-
-

Transações

- -
+

Lançamentos

{transactions.map((transaction, index) => ( @@ -439,7 +437,7 @@ export function MassAddDialog({ updateTransaction( transaction.id, "purchaseDate", - value + value, ) } placeholder="Data" @@ -505,7 +503,7 @@ export function MassAddDialog({ {transaction.pagadorId && (() => { const selectedOption = pagadorOptions.find( - (opt) => opt.value === transaction.pagadorId + (opt) => opt.value === transaction.pagadorId, ); return selectedOption ? ( @@ -576,10 +574,21 @@ export function MassAddDialog({ type="button" variant="ghost" size="icon" + className="size-7 shrink-0" + onClick={addTransaction} + > + + Adicionar transação + +
diff --git a/components/lancamentos/page/lancamentos-page.tsx b/components/lancamentos/page/lancamentos-page.tsx index 17295b4..fe939cf 100644 --- a/components/lancamentos/page/lancamentos-page.tsx +++ b/components/lancamentos/page/lancamentos-page.tsx @@ -14,12 +14,18 @@ import { toast } from "sonner"; import { AnticipateInstallmentsDialog } from "../dialogs/anticipate-installments-dialog/anticipate-installments-dialog"; import { AnticipationHistoryDialog } from "../dialogs/anticipate-installments-dialog/anticipation-history-dialog"; -import { BulkActionDialog, type BulkActionScope } from "../dialogs/bulk-action-dialog"; +import { + BulkActionDialog, + type BulkActionScope, +} from "../dialogs/bulk-action-dialog"; import { BulkImportDialog } from "../dialogs/bulk-import-dialog"; import { LancamentoDetailsDialog } from "../dialogs/lancamento-details-dialog"; import { LancamentoDialog } from "../dialogs/lancamento-dialog/lancamento-dialog"; import { LancamentosTable } from "../table/lancamentos-table"; -import { MassAddDialog, type MassAddFormData } from "../dialogs/mass-add-dialog"; +import { + MassAddDialog, + type MassAddFormData, +} from "../dialogs/mass-add-dialog"; import type { ContaCartaoFilterOption, LancamentoFilterOption, @@ -97,7 +103,7 @@ export function LancamentosPage({ useState(null); const [detailsOpen, setDetailsOpen] = useState(false); const [settlementLoadingId, setSettlementLoadingId] = useState( - null + null, ); const [bulkEditOpen, setBulkEditOpen] = useState(false); const [bulkDeleteOpen, setBulkDeleteOpen] = useState(false); @@ -125,17 +131,26 @@ export function LancamentosPage({ const [selectedForAnticipation, setSelectedForAnticipation] = useState(null); const [bulkImportOpen, setBulkImportOpen] = useState(false); - const [lancamentosToImport, setLancamentosToImport] = useState([]); + const [lancamentosToImport, setLancamentosToImport] = useState< + LancamentoItem[] + >([]); const handleToggleSettlement = useCallback(async (item: LancamentoItem) => { if (item.paymentMethod === "Cartão de crédito") { toast.info( - "Pagamentos com cartão são conciliados automaticamente. Ajuste pelo cartão." + "Pagamentos com cartão são conciliados automaticamente. Ajuste pelo cartão.", ); return; } - const supportedMethods = ["Pix", "Boleto", "Dinheiro", "Cartão de débito", "Pré-Pago | VR/VA", "Transferência bancária"]; + const supportedMethods = [ + "Pix", + "Boleto", + "Dinheiro", + "Cartão de débito", + "Pré-Pago | VR/VA", + "Transferência bancária", + ]; if (!supportedMethods.includes(item.paymentMethod)) { return; } @@ -203,7 +218,7 @@ export function LancamentosPage({ setBulkDeleteOpen(false); setPendingDeleteData(null); }, - [pendingDeleteData] + [pendingDeleteData], ); const handleBulkEditRequest = useCallback( @@ -230,7 +245,7 @@ export function LancamentosPage({ setEditOpen(false); setBulkEditOpen(true); }, - [selectedLancamento] + [selectedLancamento], ); const handleBulkEdit = useCallback( @@ -262,7 +277,7 @@ export function LancamentosPage({ setBulkEditOpen(false); setPendingEditData(null); }, - [pendingEditData] + [pendingEditData], ); const handleMassAddSubmit = useCallback(async (data: MassAddFormData) => { @@ -299,7 +314,12 @@ export function LancamentosPage({ setPendingMultipleDeleteData([]); }, [pendingMultipleDeleteData]); - const handleCreate = useCallback(() => { + const [transactionTypeForCreate, setTransactionTypeForCreate] = useState< + "Despesa" | "Receita" | null + >(null); + + const handleCreate = useCallback((type: "Despesa" | "Receita") => { + setTransactionTypeForCreate(type); setCreateOpen(true); }, []); @@ -393,6 +413,7 @@ export function LancamentosPage({ defaultPaymentMethod={defaultPaymentMethod} lockCartaoSelection={lockCartaoSelection} lockPaymentMethod={lockPaymentMethod} + defaultTransactionType={transactionTypeForCreate ?? undefined} /> ) : null} @@ -541,6 +562,7 @@ export function LancamentosPage({ estabelecimentos={estabelecimentos} selectedPeriod={selectedPeriod} defaultPagadorId={defaultPagadorId} + defaultCartaoId={defaultCartaoId} /> ) : null}