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.
169 lines
5.6 KiB
TypeScript
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>
|
|
);
|
|
}
|
|
|