import { Badge } from '@/components/ui/badge';
import { Button } from '@/components/ui/button';
import {
Dialog,
DialogContent,
DialogDescription,
DialogHeader,
DialogTitle,
} from '@/components/ui/dialog';
import { Input } from '@/components/ui/input';
import { Label } from '@/components/ui/label';
import { AdminLayout } from '@/features/admin/admin-layout';
import { ApiClientError, apiClient } from '@/lib/api-client';
import type { AdminUser, AdminUserSession } from '@repo/api-contract';
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
import { useLocation } from '@tanstack/react-router';
import {
Ban,
CheckCircle2,
Globe,
LogIn,
MapPin,
Monitor,
RefreshCw,
Search,
ShieldAlert,
Users,
} from 'lucide-react';
import { useEffect, useState } from 'react';
function SessionsDialog({
user,
onClose,
}: {
user: AdminUser;
onClose: () => void;
}) {
const queryClient = useQueryClient();
const { data, isLoading } = useQuery({
queryKey: ['admin-user-sessions', user.id],
queryFn: () => apiClient.admin.getUserSessions(user.id),
});
const revokeMutation = useMutation({
mutationFn: () => apiClient.admin.revokeAllSessions(user.id),
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ['admin-user-sessions', user.id] });
queryClient.invalidateQueries({ queryKey: ['admin-users'] });
},
});
return (
);
}
function SessionRow({ session }: { session: AdminUserSession }) {
const isExpired = new Date(session.expiresAt) < new Date();
const userAgent = session.userAgent ?? 'Desconocido';
const ip = session.ipAddress ?? '—';
const location =
session.city || session.country
? [session.city, session.country].filter(Boolean).join(', ')
: null;
return (
{userAgent}
{isExpired ? (
Expirada
) : (
Activa
)}
{ip}
{location && (
{location}
)}
{new Date(session.createdAt).toLocaleString()}
);
}
function BlockDialog({
user,
onClose,
}: {
user: AdminUser;
onClose: () => void;
}) {
const queryClient = useQueryClient();
const [reason, setReason] = useState('');
const mutation = useMutation({
mutationFn: (banReason?: string) => apiClient.admin.blockUser(user.id, { banReason }),
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ['admin-users'] });
onClose();
},
});
return (
);
}
function UnblockDialog({
user,
onClose,
}: {
user: AdminUser;
onClose: () => void;
}) {
const queryClient = useQueryClient();
const mutation = useMutation({
mutationFn: () => apiClient.admin.unblockUser(user.id),
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ['admin-users'] });
onClose();
},
});
return (
);
}
function RoleBadge({ role }: { role: string }) {
if (role === 'super_admin') {
return (
Super Admin
);
}
return (
{role}
);
}
export function UsersPage() {
const location = useLocation();
const queryClient = useQueryClient();
const [blockingUser, setBlockingUser] = useState(null);
const [unblockingUser, setUnblockingUser] = useState(null);
const [sessionsUser, setSessionsUser] = useState(null);
const [searchInput, setSearchInput] = useState('');
const [search, setSearch] = useState('');
useEffect(() => {
const timer = setTimeout(() => setSearch(searchInput), 300);
return () => clearTimeout(timer);
}, [searchInput]);
const { data, isLoading } = useQuery({
queryKey: ['admin-users', search],
queryFn: () => apiClient.admin.listUsers(search || undefined),
});
return (
Usuarios
{data?.length ?? 0} usuarios registrados en Playzer.
{blockingUser && setBlockingUser(null)} />}
{unblockingUser && (
setUnblockingUser(null)} />
)}
{sessionsUser && setSessionsUser(null)} />}
{isLoading ? (
) : data?.length === 0 ? (
No hay usuarios registrados.
) : (
|
Usuario
|
Rol
|
Complejos
|
Sesiones
|
Registro
|
Estado
|
Acción
|
{data?.map((user) => (
|
|
|
{user.complexCount}
|
|
{new Date(user.createdAt).toLocaleDateString()}
|
{user.banned ? (
Bloqueado
) : (
Activo
)}
|
{user.banned ? (
) : (
)}
|
))}
)}
);
}