'use client'; import { useEffect, useMemo, useState } from 'react'; import Link from 'next/link'; import { apiUrl } from '@/lib/constants'; interface ClipboardSummary { id: string; createdAt: string; lastActivity: string; hasPassword: boolean; entryCount: number; fileCount: number; ttl: number | null; } export default function AdminDashboard() { const [token, setToken] = useState(''); const [inputToken, setInputToken] = useState(''); const [clipboards, setClipboards] = useState([]); const [loading, setLoading] = useState(false); const [error, setError] = useState(''); useEffect(() => { const saved = localStorage.getItem('adminToken'); if (saved) { setToken(saved); setInputToken(saved); } }, []); useEffect(() => { if (token) { fetchClipboards(); } // eslint-disable-next-line react-hooks/exhaustive-deps }, [token]); const fetchClipboards = async () => { setLoading(true); setError(''); try { const response = await fetch(`${apiUrl}/admin/clipboards`, { headers: { 'x-admin-token': token }, }); if (response.status === 401) { setError('Invalid token. Please log in again.'); return; } if (!response.ok) { throw new Error('Failed to fetch clipboards'); } const data = await response.json(); setClipboards(data); } catch (err) { setError(err instanceof Error ? err.message : 'Unknown error'); } finally { setLoading(false); } }; const handleLogin = () => { if (!inputToken) { setError('Please enter an admin token'); return; } localStorage.setItem('adminToken', inputToken); setToken(inputToken); setError(''); }; const handleDelete = async (roomCode: string) => { if (!confirm(`Delete clipboard ${roomCode}? This cannot be undone.`)) { return; } try { const response = await fetch(`${apiUrl}/admin/clipboards/${roomCode}`, { method: 'DELETE', headers: { 'x-admin-token': token }, }); if (!response.ok) { throw new Error('Failed to delete clipboard'); } await fetchClipboards(); } catch (err) { setError(err instanceof Error ? err.message : 'Unknown error'); } }; const tokenValid = useMemo(() => Boolean(token), [token]); return (

Admin Dashboard

Manage clipboards and inspect activity

Back to Home
setInputToken(e.target.value)} className="input w-full" placeholder="Enter admin token" />
{error &&

{error}

}
{tokenValid && (

Clipboards

{loading ? (

Loading clipboards...

) : (
{clipboards.length === 0 && ( )} {clipboards.map((clipboard) => ( ))}
ID Entries Files Password TTL Last Activity Actions
No clipboards found.
{clipboard.id} {clipboard.entryCount} {clipboard.fileCount} {clipboard.hasPassword ? 'Yes' : 'No'} {formatTTL(clipboard.ttl)} {new Date(clipboard.lastActivity).toLocaleString()}
View
)}
)}
); } function formatTTL(ttl: number | null): string { if (ttl === null) return 'None'; if (ttl < 60) return `${ttl}s`; if (ttl < 3600) return `${Math.round(ttl / 60)}m`; const hours = Math.round(ttl / 3600); return `${hours}h`; }