feat: melhora os dialogs e detalhes de lançamentos

This commit is contained in:
Felipe Coutinho
2026-03-16 01:14:40 +00:00
parent 69df314db7
commit f4e7108119
7 changed files with 350 additions and 437 deletions

View File

@@ -7,17 +7,15 @@ import {
formatPeriod, formatPeriod,
} from "@/features/transactions/formatting-helpers"; } from "@/features/transactions/formatting-helpers";
import { TransactionTypeBadge } from "@/shared/components/transaction-type-badge"; import { TransactionTypeBadge } from "@/shared/components/transaction-type-badge";
import { Badge } from "@/shared/components/ui/badge";
import { Button } from "@/shared/components/ui/button"; import { Button } from "@/shared/components/ui/button";
import {
CardContent,
CardDescription,
CardHeader,
} from "@/shared/components/ui/card";
import { import {
Dialog, Dialog,
DialogClose, DialogClose,
DialogContent, DialogContent,
DialogDescription,
DialogFooter, DialogFooter,
DialogHeader,
DialogTitle, DialogTitle,
} from "@/shared/components/ui/dialog"; } from "@/shared/components/ui/dialog";
import { Separator } from "@/shared/components/ui/separator"; import { Separator } from "@/shared/components/ui/separator";
@@ -30,12 +28,14 @@ interface TransactionDetailsDialogProps {
open: boolean; open: boolean;
onOpenChange: (open: boolean) => void; onOpenChange: (open: boolean) => void;
transaction: TransactionItem | null; transaction: TransactionItem | null;
onEdit?: (transaction: TransactionItem) => void;
} }
export function TransactionDetailsDialog({ export function TransactionDetailsDialog({
open, open,
onOpenChange, onOpenChange,
transaction, transaction,
onEdit,
}: TransactionDetailsDialogProps) { }: TransactionDetailsDialogProps) {
if (!transaction) return null; if (!transaction) return null;
@@ -54,139 +54,163 @@ export function TransactionDetailsDialog({
? valorParcela * (totalParcelas - parcelaAtual) ? valorParcela * (totalParcelas - parcelaAtual)
: 0; : 0;
const isBoleto = transaction.paymentMethod === "Boleto";
const handleEdit = () => {
onOpenChange(false);
onEdit?.(transaction);
};
return ( return (
<Dialog open={open} onOpenChange={onOpenChange}> <Dialog open={open} onOpenChange={onOpenChange}>
<DialogContent className="p-0 sm:max-w-xl sm:border-0 sm:p-2"> <DialogContent className="sm:max-w-xl">
<div className="gap-2 space-y-4 py-4"> <DialogHeader>
<CardHeader className="flex flex-row items-start border-b sm:border-b-0"> <DialogTitle>{transaction.name}</DialogTitle>
<div> <DialogDescription>
<DialogTitle className="group flex items-center gap-2 text-lg"> {formatDate(transaction.purchaseDate)}
#{transaction.id} </DialogDescription>
</DialogTitle> </DialogHeader>
<CardDescription>
{formatDate(transaction.purchaseDate)}
</CardDescription>
</div>
</CardHeader>
<CardContent className="text-sm"> <div className="max-h-[60vh] overflow-y-auto text-sm">
<div className="grid gap-3"> <div className="grid gap-3">
<ul className="grid gap-3"> <ul className="grid gap-3">
<DetailRow label="Descrição" value={transaction.name} /> <DetailRow
label="Período"
value={formatPeriod(transaction.period)}
/>
<DetailRow <li className="flex items-center justify-between">
label="Período" <span className="text-muted-foreground">
value={formatPeriod(transaction.period)} Forma de Pagamento
</span>
<span className="flex items-center gap-1.5">
{getPaymentMethodIcon(transaction.paymentMethod)}
<span>{transaction.paymentMethod}</span>
</span>
</li>
<DetailRow
label={transaction.cartaoName ? "Cartão" : "Conta"}
value={transaction.cartaoName ?? transaction.contaName ?? "—"}
/>
<DetailRow
label="Categoria"
value={transaction.categoriaName ?? "—"}
/>
<li className="flex items-center justify-between">
<span className="text-muted-foreground">Tipo de Transação</span>
<TransactionTypeBadge
kind={
transaction.categoriaName === "Saldo inicial"
? "Saldo inicial"
: transaction.transactionType
}
/> />
</li>
<DetailRow
label="Condição"
value={formatCondition(transaction.condition)}
/>
<li className="flex items-center justify-between">
<span className="text-muted-foreground">Responsável</span>
<span>{transaction.pagadorName}</span>
</li>
<li className="flex items-center justify-between">
<span className="text-muted-foreground">Status</span>
<Badge
variant="secondary"
className={
transaction.isSettled
? "text-success bg-success/10"
: "text-muted-foreground"
}
>
{transaction.isSettled ? "Pago" : "Pendente"}
</Badge>
</li>
{isBoleto && transaction.dueDate && (
<DetailRow
label="Vencimento"
value={formatDate(transaction.dueDate)}
/>
)}
{transaction.isDivided && (
<li className="flex items-center justify-between"> <li className="flex items-center justify-between">
<span className="text-muted-foreground"> <span className="text-muted-foreground">Divisão</span>
Forma de Pagamento <Badge variant="outline">Dividido</Badge>
</span>
<span className="flex items-center gap-1.5">
{getPaymentMethodIcon(transaction.paymentMethod)}
<span className="capitalize">
{transaction.paymentMethod}
</span>
</span>
</li> </li>
)}
<DetailRow {transaction.note && (
label={transaction.cartaoName ? "Cartão" : "Conta"} <li className="flex flex-col gap-1">
value={transaction.cartaoName ?? transaction.contaName ?? "—"} <span className="text-muted-foreground">Notas</span>
/> <span className="text-foreground">{transaction.note}</span>
</li>
)}
</ul>
<DetailRow <ul className="mb-2 grid gap-3">
label="Categoria" {isInstallment && (
value={transaction.categoriaName ?? "—"} <li className="mt-4">
/> <InstallmentTimeline
purchaseDate={parseLocalDateString(
<li className="flex items-center justify-between"> transaction.purchaseDate,
<span className="text-muted-foreground"> )}
Tipo de Transação currentInstallment={parcelaAtual}
</span> totalInstallments={totalParcelas}
<TransactionTypeBadge period={transaction.period}
kind={
transaction.categoriaName === "Saldo inicial"
? "Saldo inicial"
: transaction.transactionType
}
/> />
</li> </li>
)}
<DetailRow
label={isInstallment ? "Valor da Parcela" : "Valor"}
value={currencyFormatter.format(valorParcela)}
/>
{isInstallment && (
<DetailRow <DetailRow
label="Condição" label="Valor Restante"
value={formatCondition(transaction.condition)} value={currencyFormatter.format(valorRestante)}
/> />
)}
<li className="flex items-center justify-between"> {transaction.recurrenceCount && (
<span className="text-muted-foreground">Responsável</span>
<span className="flex items-center gap-2 capitalize">
<span>{transaction.pagadorName}</span>
</span>
</li>
<DetailRow <DetailRow
label="Status" label="Quantidade de Recorrências"
value={transaction.isSettled ? "Pago" : "Pendente"} value={`${transaction.recurrenceCount} meses`}
/> />
)}
{transaction.note && ( {!isInstallment && <Separator className="my-2" />}
<DetailRow label="Notas" value={transaction.note} />
)}
</ul>
<ul className="mb-6 grid gap-3"> <li className="flex items-center justify-between font-semibold">
{isInstallment && ( <span className="text-muted-foreground">Total da Compra</span>
<li className="mt-4"> <span className="text-lg">
<InstallmentTimeline {currencyFormatter.format(valorTotal)}
purchaseDate={parseLocalDateString( </span>
transaction.purchaseDate, </li>
)} </ul>
currentInstallment={parcelaAtual} </div>
totalInstallments={totalParcelas}
period={transaction.period}
/>
</li>
)}
<DetailRow
label={isInstallment ? "Valor da Parcela" : "Valor"}
value={currencyFormatter.format(valorParcela)}
/>
{isInstallment && (
<DetailRow
label="Valor Restante"
value={currencyFormatter.format(valorRestante)}
/>
)}
{transaction.recurrenceCount && (
<DetailRow
label="Quantidade de Recorrências"
value={`${transaction.recurrenceCount} meses`}
/>
)}
{!isInstallment && <Separator className="my-2" />}
<li className="flex items-center justify-between font-semibold">
<span className="text-muted-foreground">Total da Compra</span>
<span className="text-lg">
{currencyFormatter.format(valorTotal)}
</span>
</li>
</ul>
</div>
<DialogFooter>
<DialogClose asChild>
<Button type="button">Entendi</Button>
</DialogClose>
</DialogFooter>
</CardContent>
</div> </div>
<DialogFooter>
{onEdit && !transaction.readonly && (
<Button variant="outline" onClick={handleEdit}>
Editar
</Button>
)}
<DialogClose asChild>
<Button type="button">Fechar</Button>
</DialogClose>
</DialogFooter>
</DialogContent> </DialogContent>
</Dialog> </Dialog>
); );
@@ -201,7 +225,7 @@ function DetailRow({ label, value }: DetailRowProps) {
return ( return (
<li className="flex items-center justify-between"> <li className="flex items-center justify-between">
<span className="text-muted-foreground">{label}</span> <span className="text-muted-foreground">{label}</span>
<span className="capitalize">{value}</span> <span>{value}</span>
</li> </li>
); );
} }

View File

@@ -16,14 +16,14 @@ export function BasicFieldsSection({
return ( return (
<div className="space-y-3"> <div className="space-y-3">
<div className="space-y-1"> <div className="space-y-1">
<Label htmlFor="name">Estabelecimento</Label> <Label htmlFor="name">Descrição</Label>
<EstabelecimentoInput <EstabelecimentoInput
id="name" id="name"
value={formState.name} value={formState.name}
onChange={(value) => onFieldChange("name", value)} onChange={(value) => onFieldChange("name", value)}
estabelecimentos={estabelecimentos} estabelecimentos={estabelecimentos}
placeholder="Ex.: Restaurante do Zé" placeholder="Ex.: Restaurante do Zé"
maxLength={20} maxLength={60}
required required
/> />
</div> </div>

View File

@@ -44,7 +44,7 @@ export function PayerSection({
> >
<SelectTrigger <SelectTrigger
id="payer" id="payer"
className={formState.isSplit ? "w-[55%]" : "w-full"} className={formState.isSplit ? "min-w-0 flex-1" : "w-full"}
> >
<SelectValue placeholder="Selecione"> <SelectValue placeholder="Selecione">
{formState.payerId && {formState.payerId &&

View File

@@ -44,7 +44,7 @@ function InlinePeriodPicker({
<PopoverTrigger asChild> <PopoverTrigger asChild>
<button <button
type="button" type="button"
className="text-xs text-primary underline-offset-2 hover:underline cursor-pointer lowercase" className="cursor-pointer text-xs text-primary underline-offset-2 hover:underline lowercase"
> >
{displayPeriod(period)} {displayPeriod(period)}
</button> </button>
@@ -82,7 +82,6 @@ export function PaymentMethodSection({
"Transferência bancária", "Transferência bancária",
].includes(formState.paymentMethod); ].includes(formState.paymentMethod);
// Filtrar contas apenas do tipo "Pré-Pago | VR/VA" quando forma de pagamento for "Pré-Pago | VR/VA"
const filteredContaOptions = const filteredContaOptions =
formState.paymentMethod === "Pré-Pago | VR/VA" formState.paymentMethod === "Pré-Pago | VR/VA"
? accountOptions.filter( ? accountOptions.filter(
@@ -90,270 +89,159 @@ export function PaymentMethodSection({
) )
: accountOptions; : accountOptions;
const hasSecondaryColumn = isCartaoSelected || showContaSelect;
return ( return (
<> <div className="flex w-full flex-col gap-2 md:flex-row">
{!isUpdateMode ? ( {!isUpdateMode ? (
<div className="flex w-full flex-col gap-2 md:flex-row"> <div
<div className={cn(
className={cn( "w-full space-y-1",
"space-y-1 w-full", hasSecondaryColumn ? "md:w-1/2" : "md:w-full",
isCartaoSelected || showContaSelect ? "md:w-1/2" : "md:w-full", )}
)} >
<Label htmlFor="paymentMethod">Forma de pagamento</Label>
<Select
value={formState.paymentMethod}
onValueChange={(value) => onFieldChange("paymentMethod", value)}
disabled={disablePaymentMethod}
> >
<Label htmlFor="paymentMethod">Forma de pagamento</Label> <SelectTrigger
<Select id="paymentMethod"
value={formState.paymentMethod} className="w-full"
onValueChange={(value) => onFieldChange("paymentMethod", value)}
disabled={disablePaymentMethod} disabled={disablePaymentMethod}
> >
<SelectTrigger <SelectValue placeholder="Selecione" className="w-full">
id="paymentMethod" {formState.paymentMethod && (
className="w-full" <PaymentMethodSelectContent label={formState.paymentMethod} />
disabled={disablePaymentMethod} )}
> </SelectValue>
<SelectValue placeholder="Selecione" className="w-full"> </SelectTrigger>
{formState.paymentMethod && ( <SelectContent>
<PaymentMethodSelectContent {PAYMENT_METHODS.map((method) => (
label={formState.paymentMethod} <SelectItem key={method} value={method}>
<PaymentMethodSelectContent label={method} />
</SelectItem>
))}
</SelectContent>
</Select>
</div>
) : null}
{isCartaoSelected ? (
<div
className={cn(
"w-full space-y-1",
!isUpdateMode ? "md:w-1/2" : "md:w-full",
)}
>
<Label htmlFor="cartao">Cartão</Label>
<Select
value={formState.cardId}
onValueChange={(value) => onFieldChange("cardId", value)}
disabled={disableCardSelect}
>
<SelectTrigger
id="cartao"
className="w-full"
disabled={disableCardSelect}
>
<SelectValue placeholder="Selecione">
{formState.cardId &&
(() => {
const selectedOption = cardOptions.find(
(opt) => opt.value === formState.cardId,
);
return selectedOption ? (
<AccountCardSelectContent
label={selectedOption.label}
logo={selectedOption.logo}
isCartao={true}
/>
) : null;
})()}
</SelectValue>
</SelectTrigger>
<SelectContent>
{cardOptions.length === 0 ? (
<div className="px-2 py-6 text-center">
<p className="text-sm text-muted-foreground">
Nenhum cartão cadastrado
</p>
</div>
) : (
cardOptions.map((option) => (
<SelectItem key={option.value} value={option.value}>
<AccountCardSelectContent
label={option.label}
logo={option.logo}
isCartao={true}
/> />
)}
</SelectValue>
</SelectTrigger>
<SelectContent>
{PAYMENT_METHODS.map((method) => (
<SelectItem key={method} value={method}>
<PaymentMethodSelectContent label={method} />
</SelectItem> </SelectItem>
))} ))
</SelectContent>
</Select>
</div>
{isCartaoSelected ? (
<div className="space-y-1 w-full md:w-1/2">
<Label htmlFor="cartao">Cartão</Label>
<Select
value={formState.cardId}
onValueChange={(value) => onFieldChange("cardId", value)}
disabled={disableCardSelect}
>
<SelectTrigger
id="cartao"
className="w-full"
disabled={disableCardSelect}
>
<SelectValue placeholder="Selecione">
{formState.cardId &&
(() => {
const selectedOption = cardOptions.find(
(opt) => opt.value === formState.cardId,
);
return selectedOption ? (
<AccountCardSelectContent
label={selectedOption.label}
logo={selectedOption.logo}
isCartao={true}
/>
) : null;
})()}
</SelectValue>
</SelectTrigger>
<SelectContent>
{cardOptions.length === 0 ? (
<div className="px-2 py-6 text-center">
<p className="text-sm text-muted-foreground">
Nenhum cartão cadastrado
</p>
</div>
) : (
cardOptions.map((option) => (
<SelectItem key={option.value} value={option.value}>
<AccountCardSelectContent
label={option.label}
logo={option.logo}
isCartao={true}
/>
</SelectItem>
))
)}
</SelectContent>
</Select>
{formState.cardId ? (
<InlinePeriodPicker
period={formState.period}
onPeriodChange={(value) => onFieldChange("period", value)}
/>
) : null}
</div>
) : null}
{!isCartaoSelected && showContaSelect ? (
<div
className={cn(
"space-y-1 w-full",
!isUpdateMode ? "md:w-1/2" : "md:w-full",
)} )}
> </SelectContent>
<Label htmlFor="conta">Conta</Label> </Select>
<Select {formState.cardId ? (
value={formState.accountId} <InlinePeriodPicker
onValueChange={(value) => onFieldChange("accountId", value)} period={formState.period}
> onPeriodChange={(value) => onFieldChange("period", value)}
<SelectTrigger id="conta" className="w-full"> />
<SelectValue placeholder="Selecione">
{formState.accountId &&
(() => {
const selectedOption = filteredContaOptions.find(
(opt) => opt.value === formState.accountId,
);
return selectedOption ? (
<AccountCardSelectContent
label={selectedOption.label}
logo={selectedOption.logo}
isCartao={false}
/>
) : null;
})()}
</SelectValue>
</SelectTrigger>
<SelectContent>
{filteredContaOptions.length === 0 ? (
<div className="px-2 py-6 text-center">
<p className="text-sm text-muted-foreground">
Nenhuma conta cadastrada
</p>
</div>
) : (
filteredContaOptions.map((option) => (
<SelectItem key={option.value} value={option.value}>
<AccountCardSelectContent
label={option.label}
logo={option.logo}
isCartao={false}
/>
</SelectItem>
))
)}
</SelectContent>
</Select>
</div>
) : null} ) : null}
</div> </div>
) : null} ) : null}
{isUpdateMode ? ( {!isCartaoSelected && showContaSelect ? (
<div className="flex w-full flex-col gap-2 md:flex-row"> <div
{isCartaoSelected ? ( className={cn(
<div "w-full space-y-1",
className={cn( !isUpdateMode ? "md:w-1/2" : "md:w-full",
"space-y-1 w-full", )}
!isUpdateMode ? "md:w-1/2" : "md:w-full", >
<Label htmlFor="conta">Conta</Label>
<Select
value={formState.accountId}
onValueChange={(value) => onFieldChange("accountId", value)}
>
<SelectTrigger id="conta" className="w-full">
<SelectValue placeholder="Selecione">
{formState.accountId &&
(() => {
const selectedOption = filteredContaOptions.find(
(opt) => opt.value === formState.accountId,
);
return selectedOption ? (
<AccountCardSelectContent
label={selectedOption.label}
logo={selectedOption.logo}
isCartao={false}
/>
) : null;
})()}
</SelectValue>
</SelectTrigger>
<SelectContent>
{filteredContaOptions.length === 0 ? (
<div className="px-2 py-6 text-center">
<p className="text-sm text-muted-foreground">
Nenhuma conta cadastrada
</p>
</div>
) : (
filteredContaOptions.map((option) => (
<SelectItem key={option.value} value={option.value}>
<AccountCardSelectContent
label={option.label}
logo={option.logo}
isCartao={false}
/>
</SelectItem>
))
)} )}
> </SelectContent>
<Label htmlFor="cartaoUpdate">Cartão</Label> </Select>
<Select
value={formState.cardId}
onValueChange={(value) => onFieldChange("cardId", value)}
>
<SelectTrigger id="cartaoUpdate" className="w-full">
<SelectValue placeholder="Selecione">
{formState.cardId &&
(() => {
const selectedOption = cardOptions.find(
(opt) => opt.value === formState.cardId,
);
return selectedOption ? (
<AccountCardSelectContent
label={selectedOption.label}
logo={selectedOption.logo}
isCartao={true}
/>
) : null;
})()}
</SelectValue>
</SelectTrigger>
<SelectContent>
{cardOptions.length === 0 ? (
<div className="px-2 py-6 text-center">
<p className="text-sm text-muted-foreground">
Nenhum cartão cadastrado
</p>
</div>
) : (
cardOptions.map((option) => (
<SelectItem key={option.value} value={option.value}>
<AccountCardSelectContent
label={option.label}
logo={option.logo}
isCartao={true}
/>
</SelectItem>
))
)}
</SelectContent>
</Select>
{formState.cardId ? (
<InlinePeriodPicker
period={formState.period}
onPeriodChange={(value) => onFieldChange("period", value)}
/>
) : null}
</div>
) : null}
{!isCartaoSelected && showContaSelect ? (
<div
className={cn(
"space-y-1 w-full",
!isUpdateMode ? "md:w-1/2" : "md:w-full",
)}
>
<Label htmlFor="contaUpdate">Conta</Label>
<Select
value={formState.accountId}
onValueChange={(value) => onFieldChange("accountId", value)}
>
<SelectTrigger id="contaUpdate" className="w-full">
<SelectValue placeholder="Selecione">
{formState.accountId &&
(() => {
const selectedOption = filteredContaOptions.find(
(opt) => opt.value === formState.accountId,
);
return selectedOption ? (
<AccountCardSelectContent
label={selectedOption.label}
logo={selectedOption.logo}
isCartao={false}
/>
) : null;
})()}
</SelectValue>
</SelectTrigger>
<SelectContent>
{filteredContaOptions.length === 0 ? (
<div className="px-2 py-6 text-center">
<p className="text-sm text-muted-foreground">
Nenhuma conta cadastrada
</p>
</div>
) : (
filteredContaOptions.map((option) => (
<SelectItem key={option.value} value={option.value}>
<AccountCardSelectContent
label={option.label}
logo={option.logo}
isCartao={false}
/>
</SelectItem>
))
)}
</SelectContent>
</Select>
</div>
) : null}
</div> </div>
) : null} ) : null}
</> </div>
); );
} }

View File

@@ -21,7 +21,7 @@ export function SplitAndSettlementSection({
<div> <div>
<p className="text-sm text-foreground">Dividir lançamento</p> <p className="text-sm text-foreground">Dividir lançamento</p>
<p className="text-xs text-muted-foreground"> <p className="text-xs text-muted-foreground">
Selecione para atribuir parte do valor a outro pagador. Atribuir parte do valor a outro pagador.
</p> </p>
</div> </div>
<Checkbox <Checkbox
@@ -40,7 +40,7 @@ export function SplitAndSettlementSection({
<div> <div>
<p className="text-sm text-foreground">Marcar como pago</p> <p className="text-sm text-foreground">Marcar como pago</p>
<p className="text-xs text-muted-foreground"> <p className="text-xs text-muted-foreground">
Indica que o lançamento foi pago ou recebido. Indica que o valor foi pago.
</p> </p>
</div> </div>
<Checkbox <Checkbox

View File

@@ -418,92 +418,92 @@ export function TransactionDialog({
</DialogHeader> </DialogHeader>
<form <form
className="space-y-3 -mx-6 max-h-[80vh] overflow-y-auto px-6 pb-1" className="flex flex-col gap-0"
onSubmit={handleSubmit} onSubmit={handleSubmit}
noValidate noValidate
> >
<BasicFieldsSection <div className="space-y-3 -mx-6 max-h-[70vh] overflow-y-auto px-6 pb-1">
formState={formState} <BasicFieldsSection
onFieldChange={handleFieldChange} formState={formState}
estabelecimentos={estabelecimentos} onFieldChange={handleFieldChange}
/> estabelecimentos={estabelecimentos}
/>
<CategorySection <CategorySection
formState={formState} formState={formState}
onFieldChange={handleFieldChange} onFieldChange={handleFieldChange}
categoryOptions={categoryOptions} categoryOptions={categoryOptions}
categoryGroups={categoryGroups} categoryGroups={categoryGroups}
isUpdateMode={isUpdateMode} isUpdateMode={isUpdateMode}
hideTransactionType={ hideTransactionType={
Boolean(isNewWithType) && !forceShowTransactionType Boolean(isNewWithType) && !forceShowTransactionType
} }
/> />
{!isUpdateMode ? (
<SplitAndSettlementSection <SplitAndSettlementSection
formState={formState} formState={formState}
onFieldChange={handleFieldChange} onFieldChange={handleFieldChange}
showSettledToggle={showSettledToggle} showSettledToggle={showSettledToggle}
/> />
) : null}
<PayerSection <PayerSection
formState={formState}
onFieldChange={handleFieldChange}
payerOptions={payerOptions}
secondaryPayerOptions={secondaryPayerOptions}
totalAmount={totalAmount}
/>
<PaymentMethodSection
formState={formState}
onFieldChange={handleFieldChange}
accountOptions={accountOptions}
cardOptions={cardOptions}
isUpdateMode={isUpdateMode}
disablePaymentMethod={disablePaymentMethod}
disableCardSelect={disableCardSelect}
/>
{showDueDate ? (
<BoletoFieldsSection
formState={formState} formState={formState}
onFieldChange={handleFieldChange} onFieldChange={handleFieldChange}
showPaymentDate={showPaymentDate} payerOptions={payerOptions}
secondaryPayerOptions={secondaryPayerOptions}
totalAmount={totalAmount}
/> />
) : null}
<Collapsible <PaymentMethodSection
defaultOpen={ formState={formState}
formState.condition !== "À vista" || formState.note.length > 0 onFieldChange={handleFieldChange}
} accountOptions={accountOptions}
> cardOptions={cardOptions}
<CollapsibleTrigger className="flex w-full items-center gap-1 text-xs text-muted-foreground hover:text-foreground transition-colors cursor-pointer [&[data-state=open]>svg]:rotate-180 mt-4"> isUpdateMode={isUpdateMode}
<RiArrowDropDownLine className="text-primary size-4 transition-transform duration-200" /> disablePaymentMethod={disablePaymentMethod}
Condições e anotações disableCardSelect={disableCardSelect}
</CollapsibleTrigger> />
<CollapsibleContent className="space-y-3 pt-3">
{!isUpdateMode ? (
<ConditionSection
formState={formState}
onFieldChange={handleFieldChange}
showInstallments={showInstallments}
showRecurrence={showRecurrence}
/>
) : null}
{showDueDate ? (
<BoletoFieldsSection
formState={formState}
onFieldChange={handleFieldChange}
showPaymentDate={showPaymentDate}
/>
) : null}
{isUpdateMode ? (
<NoteSection <NoteSection
formState={formState} formState={formState}
onFieldChange={handleFieldChange} onFieldChange={handleFieldChange}
/> />
</CollapsibleContent> ) : (
</Collapsible> <Collapsible defaultOpen={formState.condition !== "À vista"}>
<CollapsibleTrigger className="flex w-full items-center gap-1 text-xs text-muted-foreground hover:text-foreground transition-colors cursor-pointer [&[data-state=open]>svg]:rotate-180 mt-4">
<RiArrowDropDownLine className="text-primary size-4 transition-transform duration-200" />
Condições e anotações
</CollapsibleTrigger>
<CollapsibleContent className="space-y-3 pt-3">
<ConditionSection
formState={formState}
onFieldChange={handleFieldChange}
showInstallments={showInstallments}
showRecurrence={showRecurrence}
/>
<NoteSection
formState={formState}
onFieldChange={handleFieldChange}
/>
</CollapsibleContent>
</Collapsible>
)}
</div>
{errorMessage ? ( {errorMessage ? (
<p className="text-sm text-destructive">{errorMessage}</p> <p className="mt-3 text-sm text-destructive">{errorMessage}</p>
) : null} ) : null}
<DialogFooter> <DialogFooter className="mt-4">
<Button <Button
type="button" type="button"
variant="outline" variant="outline"

View File

@@ -506,6 +506,7 @@ export function TransactionsPage({
} }
}} }}
transaction={detailsOpen ? selectedTransaction : null} transaction={detailsOpen ? selectedTransaction : null}
onEdit={handleEdit}
/> />
<ConfirmActionDialog <ConfirmActionDialog