feat(wallets): implement wallet management features including create, update, delete, deposit, transfer, and list movements
- Added createWallet, updateWallet, deleteWallet, depositWallet, transferWallet, and listMovements handlers. - Created corresponding routes for wallet operations. - Developed frontend components for wallet management including dialogs for creating, editing, depositing, adjusting balance, transferring, and viewing movements. - Integrated wallet management into the authenticated routes.
This commit is contained in:
@@ -0,0 +1,101 @@
|
||||
import { useWalletMovements } from "@/lib/queries";
|
||||
import type { Wallet } from "@/lib/api";
|
||||
import {
|
||||
ResponsiveDialog,
|
||||
ResponsiveDialogContent,
|
||||
ResponsiveDialogHeader,
|
||||
ResponsiveDialogTitle,
|
||||
} from "@/components/ui/responsive-dialog";
|
||||
|
||||
const amountFormatter = new Intl.NumberFormat("es-AR", {
|
||||
minimumFractionDigits: 2,
|
||||
maximumFractionDigits: 4,
|
||||
});
|
||||
|
||||
const dateFormatter = new Intl.DateTimeFormat("es-AR", {
|
||||
day: "2-digit",
|
||||
month: "2-digit",
|
||||
year: "numeric",
|
||||
hour: "2-digit",
|
||||
minute: "2-digit",
|
||||
});
|
||||
|
||||
const typeLabels: Record<string, string> = {
|
||||
DEPOSIT: "Depósito",
|
||||
WITHDRAWAL: "Extracción",
|
||||
TRANSFER_IN: "Transferencia recibida",
|
||||
TRANSFER_OUT: "Transferencia enviada",
|
||||
ADJUSTMENT: "Ajuste",
|
||||
};
|
||||
|
||||
interface WalletMovementsDialogProps {
|
||||
wallet: Wallet;
|
||||
open: boolean;
|
||||
onOpenChange: (open: boolean) => void;
|
||||
}
|
||||
|
||||
export function WalletMovementsDialog({
|
||||
wallet,
|
||||
open,
|
||||
onOpenChange,
|
||||
}: WalletMovementsDialogProps) {
|
||||
const { data: movements, isLoading } = useWalletMovements(
|
||||
open ? wallet.id : 0,
|
||||
);
|
||||
|
||||
return (
|
||||
<ResponsiveDialog open={open} onOpenChange={onOpenChange}>
|
||||
<ResponsiveDialogContent>
|
||||
<ResponsiveDialogHeader>
|
||||
<ResponsiveDialogTitle>
|
||||
Movimientos de {wallet.name}
|
||||
</ResponsiveDialogTitle>
|
||||
</ResponsiveDialogHeader>
|
||||
|
||||
{isLoading ? (
|
||||
<p className="text-sm text-muted-foreground">Cargando...</p>
|
||||
) : movements && movements.length > 0 ? (
|
||||
<div className="max-h-96 space-y-1 overflow-y-auto">
|
||||
{movements.map((m) => (
|
||||
<div
|
||||
key={m.id}
|
||||
className="flex items-center justify-between rounded-md p-2 text-sm hover:bg-muted/50"
|
||||
>
|
||||
<div className="flex flex-col">
|
||||
<span className="font-medium">{typeLabels[m.type] ?? m.type}</span>
|
||||
{m.description && (
|
||||
<span className="text-xs text-muted-foreground">
|
||||
{m.description}
|
||||
</span>
|
||||
)}
|
||||
{m.transferGroupId && (
|
||||
<span className="text-xs text-muted-foreground font-mono">
|
||||
ID: {m.transferGroupId.slice(0, 8)}...
|
||||
</span>
|
||||
)}
|
||||
<span className="text-xs text-muted-foreground">
|
||||
{dateFormatter.format(new Date(m.createdAt))}
|
||||
</span>
|
||||
</div>
|
||||
<span
|
||||
className={`tabular-nums font-medium ${
|
||||
m.amount >= 0
|
||||
? "text-emerald-600 dark:text-emerald-400"
|
||||
: "text-red-600 dark:text-red-400"
|
||||
}`}
|
||||
>
|
||||
{m.amount >= 0 ? "+" : ""}
|
||||
{amountFormatter.format(m.amount)}
|
||||
</span>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
) : (
|
||||
<p className="text-sm text-muted-foreground">
|
||||
Sin movimientos registrados.
|
||||
</p>
|
||||
)}
|
||||
</ResponsiveDialogContent>
|
||||
</ResponsiveDialog>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user