import {useCallback, useEffect, useRef, useState} from 'react'; import {useTranslation} from 'react-i18next'; import {Ban, ChevronLeft, ChevronRight, Loader2, Search, ShieldCheck, Trash2} from 'lucide-react'; import {toast} from 'sonner'; import {Badge} from '@/components/ui/badge'; import {Button} from '@/components/ui/button'; import {Card, CardContent, CardHeader, CardTitle} from '@/components/ui/card'; import { Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, } from '@/components/ui/dialog'; import {Input} from '@/components/ui/input'; import {Label} from '@/components/ui/label'; import PageContainer from '../components/PageContainer.jsx'; import {deleteUser, fetchUsers, setUserBlocked} from '../utils/admin.js'; const PAGE_SIZE = 20; const REFUSAL_KEY = { SELF_ACTION: 'ADMIN.ERROR_SELF_ACTION', TARGET_IS_ADMIN: 'ADMIN.ERROR_TARGET_IS_ADMIN', ALREADY_DELETED: 'ADMIN.ERROR_ALREADY_DELETED', }; const formatDate = (value, locale) => (value ? new Date(value).toLocaleDateString(locale) : null); /** * PLATFORM_ADMIN only: list, block and delete users. Auth checks the role; a 403 shows "no access". */ export default function AdminUsersPage() { const {t, i18n} = useTranslation(); const [query, setQuery] = useState(''); const [search, setSearch] = useState(''); const [page, setPage] = useState(0); const [result, setResult] = useState(null); const [status, setStatus] = useState('loading'); // {kind: 'block' | 'delete', user} const [pending, setPending] = useState(null); const [typedEmail, setTypedEmail] = useState(''); const [busy, setBusy] = useState(false); // Only the newest load may show its answer: a slow answer to an older search must not replace the list. const loadCount = useRef(0); const load = useCallback(async () => { const current = ++loadCount.current; try { const response = await fetchUsers(search, page, PAGE_SIZE); if (current !== loadCount.current) return; if (response.status === 401) return; if (response.status === 403) { setStatus('forbidden'); return; } if (!response.ok) { setStatus('error'); return; } const data = await response.json(); if (current !== loadCount.current) return; setResult(data); setStatus('ready'); } catch (err) { console.error('Admin users error:', err); setStatus('error'); } }, [search, page]); useEffect(() => { load(); }, [load]); const closeDialog = () => { setPending(null); setTypedEmail(''); }; const confirm = async () => { const {kind, user} = pending; setBusy(true); try { const response = kind === 'delete' ? await deleteUser(user.id) : await setUserBlocked(user.id, !user.blocked); if (response.status === 401) return; if (response.ok) { toast.success(t(kind === 'delete' ? 'ADMIN.DONE_DELETE' : user.blocked ? 'ADMIN.DONE_UNBLOCK' : 'ADMIN.DONE_BLOCK')); closeDialog(); await load(); } else { const data = await response.json().catch(() => ({})); toast.error(t(REFUSAL_KEY[data.code] ?? 'ADMIN.ERROR')); } } catch (err) { console.error('Admin action error:', err); toast.error(t('INFO.ERROR.NETWORK_FAILURE')); } finally { setBusy(false); } }; const submitSearch = (event) => { event.preventDefault(); setPage(0); setSearch(query.trim()); }; const confirmDisabled = busy || (pending?.kind === 'delete' && typedEmail.trim().toLowerCase() !== pending.user.email.toLowerCase()); return ( {t('ADMIN.TITLE')} {status === 'forbidden' &&

{t('ADMIN.NO_ACCESS')}

} {status === 'error' &&

{t('ADMIN.LOAD_ERROR')}

} {status !== 'forbidden' && (
setQuery(event.target.value)}/>
)} {status === 'loading' && } {status === 'ready' && result.content.length === 0 && (

{t('ADMIN.EMPTY')}

)} {status === 'ready' && result.content.length > 0 && (
    {result.content.map((user) => (
  • {user.email}

    {[user.displayName, t('ADMIN.REGISTERED', {date: formatDate(user.registrationDate, i18n.language)}), t('ADMIN.LAST_LOGIN', {date: formatDate(user.lastLoginDate, i18n.language) ?? t('ADMIN.NEVER')}), ].filter(Boolean).join(' ยท ')}

    {user.role !== 'USER' && {t(`ROLES.${user.role}`)}} {user.steamLinked && {t('ADMIN.STEAM')}} {user.blocked && {t('ADMIN.BLOCKED')}} {user.deletedAt && {t('ADMIN.DELETED')}}
    {user.role !== 'PLATFORM_ADMIN' && !user.deletedAt && (
    )}
  • ))}
)} {status === 'ready' && result.totalPages > 1 && (
{t('ADMIN.PAGE_OF', {current: page + 1, total: result.totalPages})}
)}
{ if (!open) closeDialog(); }}> {pending && ( {pending.kind === 'delete' ? t('ADMIN.DELETE_TITLE', {email: pending.user.email}) : pending.user.blocked ? t('ADMIN.UNBLOCK') : t('ADMIN.BLOCK_TITLE', {email: pending.user.email})} {pending.kind === 'delete' ? t('ADMIN.DELETE_TEXT') : pending.user.blocked ? pending.user.email : t('ADMIN.BLOCK_TEXT')} {pending.kind === 'delete' && (
setTypedEmail(event.target.value)}/>
)}
)}
); }