Enhances accessibility and usability for touch devices and Chromebooks by updating global styles, adding ARIA attributes, and optimizing component layouts. Introduces a new useIsTouchDevice hook, improves focus states, and increases viewport scalability. ChatDetail now supports better keyboard navigation and larger touch targets.
283 lines
11 KiB
TypeScript
283 lines
11 KiB
TypeScript
"use client";
|
|
|
|
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>
|
|
);
|
|
}
|