Files
NotII 28e292abb3 Add balance page and sidebar link for dashboard
Introduces a new balance page displaying cryptocurrency balances and withdrawal functionality. Updates the sidebar configuration to include a link to the balance page with a wallet icon.
2025-10-31 00:09:34 +00:00

169 lines
5.6 KiB
TypeScript

"use client";
import { useState } from "react";
import Dashboard from "@/components/dashboard/dashboard";
import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from "@/components/ui/card";
import { Button } from "@/components/ui/button";
import { Wallet, Bitcoin, Coins, DollarSign, ArrowUpRight } from "lucide-react";
import { toast } from "sonner";
// Mock data for balances
const mockBalances = {
bitcoin: {
symbol: "BTC",
name: "Bitcoin",
balance: 0.054321,
usdValue: 2350.45,
icon: Bitcoin,
color: "text-orange-500",
},
litecoin: {
symbol: "LTC",
name: "Litecoin",
balance: 12.345678,
usdValue: 987.65,
icon: Coins,
color: "text-blue-500",
},
monero: {
symbol: "XMR",
name: "Monero",
balance: 5.678901,
usdValue: 1123.89,
icon: DollarSign,
color: "text-orange-600",
},
};
export default function BalancePage() {
const [isWithdrawing, setIsWithdrawing] = useState<{
bitcoin: boolean;
litecoin: boolean;
monero: boolean;
}>({
bitcoin: false,
litecoin: false,
monero: false,
});
const handleWithdrawal = async (currency: "bitcoin" | "litecoin" | "monero") => {
setIsWithdrawing((prev) => ({ ...prev, [currency]: true }));
try {
// Simulate API call
await new Promise((resolve) => setTimeout(resolve, 1500));
toast.success("Withdrawal Request Submitted", {
description: `Your withdrawal request for ${mockBalances[currency].name} has been submitted successfully.`,
});
} catch (error) {
toast.error("Withdrawal Failed", {
description: `Failed to submit withdrawal request for ${mockBalances[currency].name}. Please try again.`,
});
} finally {
setIsWithdrawing((prev) => ({ ...prev, [currency]: false }));
}
};
const totalUsdValue = Object.values(mockBalances).reduce(
(sum, currency) => sum + currency.usdValue,
0
);
return (
<Dashboard>
<div className="space-y-6">
{/* Header */}
<div>
<h1 className="text-2xl font-semibold text-gray-900 dark:text-white flex items-center">
<Wallet className="mr-2 h-6 w-6" />
Balance
</h1>
<p className="mt-1 text-muted-foreground">
View your cryptocurrency balances and request withdrawals
</p>
</div>
{/* Total Balance Card */}
<Card>
<CardHeader>
<CardTitle>Total Balance</CardTitle>
<CardDescription>Combined value of all cryptocurrencies</CardDescription>
</CardHeader>
<CardContent>
<div className="text-3xl font-bold">
${totalUsdValue.toLocaleString("en-US", { minimumFractionDigits: 2, maximumFractionDigits: 2 })}
</div>
<p className="text-sm text-muted-foreground mt-2">
Equivalent in USD
</p>
</CardContent>
</Card>
{/* Currency Balance Cards */}
<div className="grid grid-cols-1 md:grid-cols-3 gap-4">
{Object.entries(mockBalances).map(([key, currency]) => {
const Icon = currency.icon;
return (
<Card key={key}>
<CardHeader>
<div className="flex items-center justify-between">
<div className="flex items-center gap-2">
<Icon className={`h-5 w-5 ${currency.color}`} />
<CardTitle className="text-lg">{currency.name}</CardTitle>
</div>
</div>
<CardDescription>{currency.symbol}</CardDescription>
</CardHeader>
<CardContent className="space-y-2">
<div>
<div className="text-2xl font-bold">
{currency.balance.toLocaleString("en-US", {
minimumFractionDigits: 6,
maximumFractionDigits: 8,
})}
</div>
<div className="text-sm text-muted-foreground">
{currency.symbol}
</div>
</div>
<div className="pt-2 border-t">
<div className="text-lg font-semibold">
${currency.usdValue.toLocaleString("en-US", {
minimumFractionDigits: 2,
maximumFractionDigits: 2,
})}
</div>
<div className="text-xs text-muted-foreground">USD Value</div>
</div>
</CardContent>
<CardFooter>
<Button
onClick={() => handleWithdrawal(key as "bitcoin" | "litecoin" | "monero")}
disabled={isWithdrawing[key as keyof typeof isWithdrawing]}
className="w-full"
variant="outline"
>
{isWithdrawing[key as keyof typeof isWithdrawing] ? (
<>
<div className="h-4 w-4 border-2 border-current border-t-transparent rounded-full animate-spin mr-2" />
Processing...
</>
) : (
<>
<ArrowUpRight className="h-4 w-4 mr-2" />
Request Withdrawal
</>
)}
</Button>
</CardFooter>
</Card>
);
})}
</div>
</div>
</Dashboard>
);
}