209 lines
7.1 KiB
TypeScript
209 lines
7.1 KiB
TypeScript
import { Metadata } from "next";
|
|
import Link from "next/link";
|
|
import { notFound } from "next/navigation";
|
|
import { getUser } from "@/lib/auth";
|
|
import { Button } from "@/components/ui/button";
|
|
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
|
|
import { LogoutButton } from "@/components/auth/logout-button";
|
|
import { Input } from "@/components/ui/input";
|
|
import { prisma } from "@/lib/prisma";
|
|
|
|
export const metadata: Metadata = {
|
|
title: "Token Holders - Stones Database",
|
|
description: "Track holders of ERC20 tokens",
|
|
};
|
|
|
|
export default async function TokenHoldersPage() {
|
|
const user = await getUser();
|
|
|
|
if (!user) {
|
|
notFound();
|
|
}
|
|
|
|
// Mock token data (this would be replaced with real data from the database)
|
|
const tokens = [
|
|
{
|
|
id: "stones",
|
|
name: "Stones",
|
|
symbol: "STONES",
|
|
description: "The native token of the Stones ecosystem",
|
|
imageUrl: "https://placekitten.com/203/203",
|
|
holders: 1245,
|
|
marketCap: "$4.5M",
|
|
},
|
|
{
|
|
id: "eth",
|
|
name: "Ethereum",
|
|
symbol: "ETH",
|
|
description: "Native cryptocurrency of the Ethereum blockchain",
|
|
imageUrl: "https://placekitten.com/204/204",
|
|
holders: 52000000,
|
|
marketCap: "$367B",
|
|
},
|
|
{
|
|
id: "dai",
|
|
name: "Dai Stablecoin",
|
|
symbol: "DAI",
|
|
description: "Decentralized stablecoin pegged to the US Dollar",
|
|
imageUrl: "https://placekitten.com/205/205",
|
|
holders: 684000,
|
|
marketCap: "$5.2B",
|
|
},
|
|
];
|
|
|
|
return (
|
|
<div className="flex min-h-screen flex-col">
|
|
<header className="sticky top-0 z-50 w-full border-b bg-background/95 backdrop-blur supports-[backdrop-filter]:bg-background/60">
|
|
<div className="container flex h-14 items-center justify-between">
|
|
<div className="mr-4 flex">
|
|
<Link href="/" className="mr-6 flex items-center space-x-2">
|
|
<span className="font-bold">Stones Database</span>
|
|
</Link>
|
|
</div>
|
|
<nav className="flex items-center space-x-4">
|
|
<Link href="/contacts" className="text-sm font-medium">
|
|
Contacts
|
|
</Link>
|
|
<Link href="/dashboard" className="text-sm font-medium">
|
|
Dashboard
|
|
</Link>
|
|
{user && (
|
|
<div className="flex items-center gap-4">
|
|
<span className="text-sm text-muted-foreground">
|
|
Hello, {user.name}
|
|
</span>
|
|
<LogoutButton />
|
|
</div>
|
|
)}
|
|
</nav>
|
|
</div>
|
|
</header>
|
|
<main className="flex-1 container py-6">
|
|
<div className="flex items-center justify-between mb-6">
|
|
<div>
|
|
<Link href="/dashboard">
|
|
<p className="text-sm text-blue-500 hover:text-blue-700 mb-2">
|
|
← Back to Dashboard
|
|
</p>
|
|
</Link>
|
|
<h1 className="text-3xl font-bold">Token Holders</h1>
|
|
<p className="text-gray-500 mt-1">Track holders of ERC20 tokens</p>
|
|
</div>
|
|
<div className="flex gap-2">
|
|
<Button variant="outline">
|
|
Add New Token
|
|
</Button>
|
|
<Button>
|
|
Sync Token Data
|
|
</Button>
|
|
</div>
|
|
</div>
|
|
|
|
<div className="mb-6">
|
|
<Card>
|
|
<CardHeader>
|
|
<CardTitle>Search Tokens</CardTitle>
|
|
</CardHeader>
|
|
<CardContent>
|
|
<div className="flex gap-4">
|
|
<Input placeholder="Search by token name, symbol, or contract address" className="max-w-xl" />
|
|
<Button>Search</Button>
|
|
</div>
|
|
</CardContent>
|
|
</Card>
|
|
</div>
|
|
|
|
<div className="grid gap-6 md:grid-cols-3">
|
|
{tokens.map((token) => (
|
|
<Card key={token.id}>
|
|
<div className="p-4 flex items-center gap-4">
|
|
<img
|
|
src={token.imageUrl}
|
|
alt={token.name}
|
|
className="w-16 h-16 rounded-full"
|
|
/>
|
|
<div>
|
|
<h3 className="font-bold">{token.name}</h3>
|
|
<p className="text-sm text-gray-500">{token.symbol}</p>
|
|
</div>
|
|
</div>
|
|
<CardContent className="pt-0 space-y-4">
|
|
<p className="text-sm text-gray-500">{token.description}</p>
|
|
<div className="grid grid-cols-2 gap-4">
|
|
<div>
|
|
<p className="text-sm text-gray-500">Holders</p>
|
|
<p className="font-medium">{token.holders.toLocaleString()}</p>
|
|
</div>
|
|
<div>
|
|
<p className="text-sm text-gray-500">Market Cap</p>
|
|
<p className="font-medium">{token.marketCap}</p>
|
|
</div>
|
|
</div>
|
|
<div className="flex justify-end">
|
|
<Link href={`/token-holders/${token.id}`}>
|
|
<Button variant="secondary">
|
|
View Holders
|
|
</Button>
|
|
</Link>
|
|
</div>
|
|
</CardContent>
|
|
</Card>
|
|
))}
|
|
</div>
|
|
|
|
<div className="mt-8">
|
|
<Card>
|
|
<CardHeader>
|
|
<CardTitle>Add Token</CardTitle>
|
|
</CardHeader>
|
|
<CardContent>
|
|
<form className="space-y-4">
|
|
<div className="grid grid-cols-1 gap-4 sm:grid-cols-2">
|
|
<div className="space-y-2">
|
|
<label htmlFor="token-name" className="text-sm font-medium">
|
|
Token Name
|
|
</label>
|
|
<Input
|
|
id="token-name"
|
|
placeholder="Enter token name"
|
|
/>
|
|
</div>
|
|
<div className="space-y-2">
|
|
<label htmlFor="token-symbol" className="text-sm font-medium">
|
|
Token Symbol
|
|
</label>
|
|
<Input
|
|
id="token-symbol"
|
|
placeholder="e.g., ETH"
|
|
/>
|
|
</div>
|
|
</div>
|
|
<div className="space-y-2">
|
|
<label htmlFor="contract-address" className="text-sm font-medium">
|
|
Contract Address
|
|
</label>
|
|
<Input
|
|
id="contract-address"
|
|
placeholder="0x..."
|
|
/>
|
|
</div>
|
|
<div className="flex justify-end">
|
|
<Button type="submit">
|
|
Add Token
|
|
</Button>
|
|
</div>
|
|
</form>
|
|
</CardContent>
|
|
</Card>
|
|
</div>
|
|
</main>
|
|
<footer className="w-full border-t py-6">
|
|
<div className="container flex flex-col items-center justify-between gap-4 md:flex-row">
|
|
<p className="text-center text-sm leading-loose text-muted-foreground md:text-left">
|
|
© 2025 BoilerHaus. All rights reserved.
|
|
</p>
|
|
</div>
|
|
</footer>
|
|
</div>
|
|
);
|
|
}
|