+ {/* Status Filter */}
+
+ {['pending', 'approved', 'denied'].map((s) => (
+
+ ))}
+
+
+ {/* Cards */}
+ {loading ? (
+
Loading...
+ ) : items.length === 0 ? (
+
No {status} claim requests
+ ) : (
+
+ {items.map((item) => (
+
+
+
+
+ @{item.requested_username}
+
+ {item.status}
+
+
+
+
+
Email: {item.requester_email}
+ {item.requester_name &&
Name: {item.requester_name}
}
+ {item.organization &&
Organization: {item.organization}
}
+ {item.proof_url &&
}
+
Submitted: {new Date(item.created_at).toLocaleString()}
+
+
+
+ Justification: {item.justification}
+
+
+ {item.review_notes && (
+
+ Review notes: {item.review_notes}
+
+ )}
+
+
+ {/* Actions */}
+ {item.status === 'pending' && (
+
+ {reviewingId === item.id ? (
+
+ ) : (
+
+ )}
+
+ )}
+
+
+ ))}
+
+ )}
+
+ );
+}
diff --git a/admin/src/components/Sidebar.tsx b/admin/src/components/Sidebar.tsx
index 2e7ecb6..b7137df 100644
--- a/admin/src/components/Sidebar.tsx
+++ b/admin/src/components/Sidebar.tsx
@@ -6,7 +6,7 @@ import { useAuth } from '@/lib/auth';
import { cn } from '@/lib/utils';
import {
LayoutDashboard, Users, FileText, Shield, Scale, Flag,
- Settings, Activity, LogOut, ChevronLeft, ChevronRight, Sliders, FolderTree, HardDrive,
+ Settings, Activity, LogOut, ChevronLeft, ChevronRight, Sliders, FolderTree, HardDrive, AtSign,
} from 'lucide-react';
import { useState } from 'react';
@@ -19,6 +19,7 @@ const navItems = [
{ href: '/reports', label: 'Reports', icon: Flag },
{ href: '/algorithm', label: 'Algorithm', icon: Sliders },
{ href: '/categories', label: 'Categories', icon: FolderTree },
+ { href: '/usernames', label: 'Usernames', icon: AtSign },
{ href: '/storage', label: 'Storage', icon: HardDrive },
{ href: '/system', label: 'System Health', icon: Activity },
{ href: '/settings', label: 'Settings', icon: Settings },
diff --git a/admin/src/lib/api.ts b/admin/src/lib/api.ts
index 92111ed..bb20baa 100644
--- a/admin/src/lib/api.ts
+++ b/admin/src/lib/api.ts
@@ -282,6 +282,50 @@ class ApiClient {
body: JSON.stringify({ bucket, key }),
});
}
+
+ // Reserved Usernames
+ async listReservedUsernames(params: { category?: string; search?: string; limit?: number; offset?: number } = {}) {
+ const qs = new URLSearchParams();
+ if (params.category) qs.set('category', params.category);
+ if (params.search) qs.set('search', params.search);
+ if (params.limit) qs.set('limit', String(params.limit));
+ if (params.offset) qs.set('offset', String(params.offset));
+ return this.request