'use client' import { Crown, EyeOff, Pencil, Plus, Shield, ShieldCheck, Trash2, UserCheck, Users, } from 'lucide-react' import Link from 'next/link' import { useState } from 'react' import { toast } from 'sonner' import { createRank, deleteRank } from '@/actions/permissions' import { Badge } from '@/components/ui/badge' import { Button } from '@/components/ui/button' import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, } from '@/components/ui/dialog' import { Input } from '@/components/ui/input' import { Label } from '@/components/ui/label' import { useServerAction } from '@/hooks/use-server-action' interface RankSummary { id: number rank_name: string badge: string level: number prefix: string prefix_color: string hidden_rank: string userCount: number } interface Props { ranks: RankSummary[] } const RANK_ICONS: Record = { 7: , 6: , 5: , 4: , } const RANK_COLORS: Record = { 7: 'border-[var(--admin-warning-border)] bg-[var(--admin-warning-subtle)]', 6: 'border-[var(--admin-error-border)] bg-[var(--admin-error-subtle)]', 5: 'border-[var(--admin-info-border)] bg-[var(--admin-info-subtle)]', 4: 'border-[var(--admin-success-border)] bg-[var(--admin-success-subtle)]', } export function PermissionsList({ ranks: initialRanks }: Props) { const { run, isPending } = useServerAction() const [ranks, setRanks] = useState(initialRanks) const [deleteTarget, setDeleteTarget] = useState(null) const [showCreate, setShowCreate] = useState(false) const [newRankName, setNewRankName] = useState('') const [newRankLevel, setNewRankLevel] = useState('') const totalUsers = ranks.reduce((sum, r) => sum + r.userCount, 0) function handleCreate() { const level = parseInt(newRankLevel, 10) if (!newRankName.trim() || !level || level < 1) { toast.error('Name and a valid level are required') return } run(() => createRank({ rank_name: newRankName.trim(), level }), { successMessage: 'Rank created', onSuccess: () => { setShowCreate(false) setNewRankName('') setNewRankLevel('') }, }) } function handleDelete() { if (!deleteTarget) return run(() => deleteRank({ id: deleteTarget.id }), { successMessage: 'Rank deleted', onSuccess: () => { setRanks((prev) => prev.filter((r) => r.id !== deleteTarget!.id)) setDeleteTarget(null) }, }) } return (
{/* Header */}

Permissions

{ranks.length} ranks · {totalUsers.toLocaleString()} users total

{/* Rank cards */}
{ranks.map((rank) => { const prefixColor = rank.prefix_color ? rank.prefix_color.startsWith('#') ? rank.prefix_color : `#${rank.prefix_color}` : undefined return (
{/* Header */}
{RANK_ICONS[rank.id] || } {rank.rank_name || `Rank ${rank.id}`}
{rank.hidden_rank === '1' && ( )} #{rank.id}
{/* Badges row */}
Level {rank.level} {rank.badge && ( {rank.badge} )} {rank.prefix && ( {rank.prefix} )}
{/* User count */}
{rank.userCount.toLocaleString()} users
{/* Actions */}
) })}
{/* Create rank dialog */} Create New Rank Add a new permission rank. You can configure its permissions after creation.
setNewRankName(e.target.value)} placeholder="e.g. Moderator" />
setNewRankLevel(e.target.value)} placeholder="e.g. 5" min={1} />

Higher level = more base permissions in the emulator

{/* Delete confirmation dialog */} setDeleteTarget(null)}> Delete Rank #{deleteTarget?.id}? This will permanently delete "{deleteTarget?.rank_name}" and its CMS role. This cannot be undone.
) }