Add admin dashboard pages and restructure admin route

Introduces new admin dashboard pages for alerts, bans, invites, orders, settings, status, and vendors under app/dashboard/admin/. Moves the main admin page to the new dashboard structure and adds a shared admin layout. Updates sidebar configuration and adds supporting components and hooks for admin features.
This commit is contained in:
NotII
2025-10-18 15:19:10 +01:00
parent 03a2e37502
commit bfc60012cf
16 changed files with 2074 additions and 13 deletions

View File

@@ -0,0 +1,280 @@
import React from "react";
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import { Textarea } from "@/components/ui/textarea";
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select";
import { Badge } from "@/components/ui/badge";
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table";
import { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle, AlertDialogTrigger } from "@/components/ui/alert-dialog";
import { UserX, Shield, Search, Ban, Unlock } from "lucide-react";
import { useState } from "react";
export default function AdminBanPage() {
const [banData, setBanData] = useState({
username: "",
reason: "",
duration: "",
description: ""
});
// Mock data for banned users
const bannedUsers = [
{
id: "1",
username: "spam_user",
email: "spam@example.com",
reason: "Spam",
bannedBy: "admin1",
banDate: "2024-01-15",
duration: "Permanent",
status: "active"
},
{
id: "2",
username: "fraud_vendor",
email: "fraud@example.com",
reason: "Fraud",
bannedBy: "admin1",
banDate: "2024-01-20",
duration: "30 days",
status: "active"
},
{
id: "3",
username: "policy_violator",
email: "violator@example.com",
reason: "Policy Violation",
bannedBy: "admin1",
banDate: "2024-01-25",
duration: "7 days",
status: "expired"
}
];
const handleBanUser = () => {
// Handle ban user logic
console.log("Banning user:", banData);
};
return (
<div className="space-y-6">
<div>
<h1 className="text-2xl font-semibold tracking-tight">Ban Users</h1>
<p className="text-sm text-muted-foreground mt-1">Manage user bans and suspensions</p>
</div>
{/* Stats Cards */}
<div className="grid gap-4 md:grid-cols-4">
<Card>
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
<CardTitle className="text-sm font-medium">Active Bans</CardTitle>
<Shield className="h-4 w-4 text-muted-foreground" />
</CardHeader>
<CardContent>
<div className="text-2xl font-bold">12</div>
<p className="text-xs text-muted-foreground">Currently banned</p>
</CardContent>
</Card>
<Card>
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
<CardTitle className="text-sm font-medium">Permanent Bans</CardTitle>
<UserX className="h-4 w-4 text-muted-foreground" />
</CardHeader>
<CardContent>
<div className="text-2xl font-bold">3</div>
<p className="text-xs text-muted-foreground">Permanent suspensions</p>
</CardContent>
</Card>
<Card>
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
<CardTitle className="text-sm font-medium">Temporary Bans</CardTitle>
<Ban className="h-4 w-4 text-muted-foreground" />
</CardHeader>
<CardContent>
<div className="text-2xl font-bold">9</div>
<p className="text-xs text-muted-foreground">Time-limited bans</p>
</CardContent>
</Card>
<Card>
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
<CardTitle className="text-sm font-medium">Appeals Pending</CardTitle>
<Unlock className="h-4 w-4 text-muted-foreground" />
</CardHeader>
<CardContent>
<div className="text-2xl font-bold">2</div>
<p className="text-xs text-muted-foreground">Awaiting review</p>
</CardContent>
</Card>
</div>
<div className="grid gap-6 lg:grid-cols-2">
{/* Ban User Form */}
<Card>
<CardHeader>
<CardTitle className="flex items-center">
<UserX className="h-5 w-5 mr-2" />
Ban User
</CardTitle>
<CardDescription>
Enter user details and reason for banning
</CardDescription>
</CardHeader>
<CardContent className="space-y-4">
<div className="space-y-2">
<Label htmlFor="username">Username</Label>
<Input
id="username"
placeholder="Enter username to ban"
value={banData.username}
onChange={(e) => setBanData({...banData, username: e.target.value})}
/>
</div>
<div className="space-y-2">
<Label htmlFor="reason">Reason</Label>
<Select value={banData.reason} onValueChange={(value) => setBanData({...banData, reason: value})}>
<SelectTrigger>
<SelectValue placeholder="Select ban reason" />
</SelectTrigger>
<SelectContent>
<SelectItem value="spam">Spam</SelectItem>
<SelectItem value="fraud">Fraud</SelectItem>
<SelectItem value="harassment">Harassment</SelectItem>
<SelectItem value="policy_violation">Policy Violation</SelectItem>
<SelectItem value="suspicious_activity">Suspicious Activity</SelectItem>
<SelectItem value="other">Other</SelectItem>
</SelectContent>
</Select>
</div>
<div className="space-y-2">
<Label htmlFor="duration">Duration</Label>
<Select value={banData.duration} onValueChange={(value) => setBanData({...banData, duration: value})}>
<SelectTrigger>
<SelectValue placeholder="Select ban duration" />
</SelectTrigger>
<SelectContent>
<SelectItem value="1_day">1 Day</SelectItem>
<SelectItem value="7_days">7 Days</SelectItem>
<SelectItem value="30_days">30 Days</SelectItem>
<SelectItem value="90_days">90 Days</SelectItem>
<SelectItem value="permanent">Permanent</SelectItem>
</SelectContent>
</Select>
</div>
<div className="space-y-2">
<Label htmlFor="description">Additional Details</Label>
<Textarea
id="description"
placeholder="Provide additional context for the ban..."
value={banData.description}
onChange={(e) => setBanData({...banData, description: e.target.value})}
/>
</div>
<AlertDialog>
<AlertDialogTrigger asChild>
<Button variant="destructive" className="w-full">
<Ban className="h-4 w-4 mr-2" />
Ban User
</Button>
</AlertDialogTrigger>
<AlertDialogContent>
<AlertDialogHeader>
<AlertDialogTitle>Confirm Ban</AlertDialogTitle>
<AlertDialogDescription>
Are you sure you want to ban user "{banData.username}"? This action cannot be undone.
</AlertDialogDescription>
</AlertDialogHeader>
<AlertDialogFooter>
<AlertDialogCancel>Cancel</AlertDialogCancel>
<AlertDialogAction onClick={handleBanUser}>
Confirm Ban
</AlertDialogAction>
</AlertDialogFooter>
</AlertDialogContent>
</AlertDialog>
</CardContent>
</Card>
{/* Search Banned Users */}
<Card>
<CardHeader>
<CardTitle>Search Banned Users</CardTitle>
<CardDescription>Look up existing bans and their status</CardDescription>
</CardHeader>
<CardContent className="space-y-4">
<div className="relative">
<Search className="absolute left-2 top-2.5 h-4 w-4 text-muted-foreground" />
<Input placeholder="Search by username or email..." className="pl-8" />
</div>
<Button variant="outline" className="w-full">
Search Bans
</Button>
</CardContent>
</Card>
</div>
{/* Banned Users Table */}
<Card>
<CardHeader>
<CardTitle>Recent Bans</CardTitle>
<CardDescription>View and manage current and past bans</CardDescription>
</CardHeader>
<CardContent>
<Table>
<TableHeader>
<TableRow>
<TableHead>User</TableHead>
<TableHead>Reason</TableHead>
<TableHead>Duration</TableHead>
<TableHead>Banned By</TableHead>
<TableHead>Date</TableHead>
<TableHead>Status</TableHead>
<TableHead className="text-right">Actions</TableHead>
</TableRow>
</TableHeader>
<TableBody>
{bannedUsers.map((user) => (
<TableRow key={user.id}>
<TableCell>
<div>
<div className="font-medium">{user.username}</div>
<div className="text-sm text-muted-foreground">{user.email}</div>
</div>
</TableCell>
<TableCell>{user.reason}</TableCell>
<TableCell>{user.duration}</TableCell>
<TableCell>{user.bannedBy}</TableCell>
<TableCell>{user.banDate}</TableCell>
<TableCell>
<Badge
variant={user.status === "active" ? "destructive" : "secondary"}
>
{user.status}
</Badge>
</TableCell>
<TableCell className="text-right">
<div className="flex items-center justify-end space-x-2">
{user.status === "active" && (
<Button variant="outline" size="sm">
<Unlock className="h-4 w-4" />
</Button>
)}
<Button variant="outline" size="sm">
View Details
</Button>
</div>
</TableCell>
</TableRow>
))}
</TableBody>
</Table>
</CardContent>
</Card>
</div>
);
}