import { useState, useEffect, useCallback } from 'react' import { useNavigate } from 'react-router-dom' import { UserCheck, UserX, Shield, ArrowRightLeft, ExternalLink } from 'lucide-react' import { DataTable, Pagination, SearchInput, PageHeader, StatusBadge, ActionMenu } from '@/components/admin' import type { Column } from '@/components/admin' import { Modal } from '@/components/common/Modal' import { adminApi } from '@/api/admin' import { toast } from '@/lib/toast' import { cn } from '@/lib/utils' interface AdminUser { id: string email: string name: string role: string is_super_admin: boolean is_active: boolean account_id: string | null account_role: string | null created_at: string last_login: string | null } export function UsersPage() { const navigate = useNavigate() const [users, setUsers] = useState([]) const [loading, setLoading] = useState(true) const [search, setSearch] = useState('') const [page, setPage] = useState(1) const [total, setTotal] = useState(0) const pageSize = 20 // Role change modal const [roleModalUser, setRoleModalUser] = useState(null) const [newRole, setNewRole] = useState('') // Move account modal const [moveModalUser, setMoveModalUser] = useState(null) const [displayCode, setDisplayCode] = useState('') const fetchUsers = useCallback(async () => { setLoading(true) try { const data = await adminApi.listUsers({ page, size: pageSize, search: search || undefined }) setUsers(data.items || data) setTotal(data.total || (data.items ? data.items.length : data.length)) } catch { toast.error('Failed to load users') } finally { setLoading(false) } }, [page, search]) useEffect(() => { fetchUsers() }, [fetchUsers]) const handleRoleChange = async () => { if (!roleModalUser || !newRole) return try { await adminApi.updateUserRole(roleModalUser.id, newRole) toast.success('Role updated') setRoleModalUser(null) fetchUsers() } catch { toast.error('Failed to update role') } } const handleToggleActive = async (user: AdminUser) => { try { if (user.is_active) { await adminApi.deactivateUser(user.id) toast.success('User deactivated') } else { await adminApi.activateUser(user.id) toast.success('User activated') } fetchUsers() } catch { toast.error('Failed to update user status') } } const handleMoveAccount = async () => { if (!moveModalUser || !displayCode) return try { await adminApi.moveUserAccount(moveModalUser.id, displayCode) toast.success('User moved to account') setMoveModalUser(null) setDisplayCode('') fetchUsers() } catch { toast.error('Failed to move user') } } const columns: Column[] = [ { key: 'name', header: 'Name', sortable: true, render: (u) => (
{u.name}
{u.email}
), }, { key: 'role', header: 'Role', render: (u) => (
{u.role} {u.is_super_admin && ( Super Admin )}
), }, { key: 'status', header: 'Status', render: (u) => ( {u.is_active ? 'Active' : 'Inactive'} ), }, { key: 'created_at', header: 'Joined', sortable: true, render: (u) => ( {new Date(u.created_at).toLocaleDateString()} ), }, { key: 'actions', header: '', className: 'w-12', render: (u) => ( , onClick: () => navigate(`/admin/users/${u.id}`), }, { label: 'Change Role', icon: , onClick: () => { setRoleModalUser(u); setNewRole(u.role) }, }, { label: u.is_active ? 'Deactivate' : 'Activate', icon: u.is_active ? : , onClick: () => handleToggleActive(u), destructive: u.is_active, }, { label: 'Move Account', icon: , onClick: () => { setMoveModalUser(u); setDisplayCode('') }, }, ]} /> ), }, ] return (
{ setSearch(v); setPage(1) }} placeholder="Search by name or email..." className="max-w-sm" /> u.id} isLoading={loading} /> {/* Role Change Modal */} setRoleModalUser(null)} title="Change Role" size="sm" footer={
} >

Changing role for {roleModalUser?.name}

{/* Move Account Modal */} setMoveModalUser(null)} title="Move User to Account" size="sm" footer={
} >

Moving {moveModalUser?.name} to a new account.

setDisplayCode(e.target.value)} placeholder="e.g. ABC-1234" className={cn( 'w-full rounded-md border border-white/10 bg-black/50 px-3 py-2 text-sm text-white', 'placeholder:text-white/40 focus:outline-none focus:border-white/30 focus:ring-2 focus:ring-white/20' )} />
) } export default UsersPage