Some checks failed
Build Frontend / build (push) Failing after 7s
Replaces imports from 'components/ui' with 'components/common' across the app and dashboard pages, and updates model and API imports to use new paths under 'lib'. Removes redundant authentication checks from several dashboard pages. Adds new dashboard components and utility files, and reorganizes hooks and services into the 'lib' directory for improved structure.
170 lines
5.6 KiB
TypeScript
170 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/common/card";
|
|
import { Button } from "@/components/common/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>
|
|
);
|
|
}
|
|
|
|
|