import { useEffect, useMemo, useState, type FormEvent } from 'react'; import { AtSign, Check, Copy, Edit3, KeyRound, Loader2, Mail, Plus, Search, Shield, Trash2, User as UserIcon, X } from 'lucide-react'; import { createUser, deleteUser as deleteManagedUser, fetchUsers, updateUser } from '../dataService'; import type { ManagedUser } from '../types'; type StatusFilter = 'all' | 'active' | 'inactive'; type PasswordMode = 'auto' | 'manual'; type Notice = { tone: 'success' | 'warning' | 'error'; text: string; temporaryPassword?: string; }; const statusOptions: Array<{ key: StatusFilter; label: string }> = [ { key: 'all', label: 'Todos' }, { key: 'active', label: 'Ativos' }, { key: 'inactive', label: 'Inativos' } ]; const formatDateTime = (value: string) => { const date = new Date(value); if (!value || Number.isNaN(date.getTime())) return '-'; return new Intl.DateTimeFormat('pt-BR', { day: '2-digit', month: 'short', year: 'numeric', hour: '2-digit', minute: '2-digit' }).format(date); }; const getInitials = (name: string) => { const parts = name.trim().split(/\s+/).filter(Boolean); if (!parts.length) return '?'; return parts.slice(0, 2).map((part) => part[0]).join('').toUpperCase(); }; const AdminUsers = () => { const [users, setUsers] = useState([]); const [searchTerm, setSearchTerm] = useState(''); const [statusFilter, setStatusFilter] = useState('all'); const [isLoading, setIsLoading] = useState(true); const [isModalOpen, setIsModalOpen] = useState(false); const [isSubmitting, setIsSubmitting] = useState(false); const [editingUser, setEditingUser] = useState(null); const [userToDelete, setUserToDelete] = useState(null); const [passwordMode, setPasswordMode] = useState('auto'); const [isActive, setIsActive] = useState(true); const [name, setName] = useState(''); const [email, setEmail] = useState(''); const [password, setPassword] = useState(''); const [notice, setNotice] = useState(null); const [copyLabel, setCopyLabel] = useState('Copiar'); const activeCount = useMemo(() => users.filter((user) => user.isActive).length, [users]); const inactiveCount = users.length - activeCount; const filteredUsers = useMemo(() => { const query = searchTerm.trim().toLowerCase(); return users.filter((user) => { const matchesStatus = statusFilter === 'all' || (statusFilter === 'active' && user.isActive) || (statusFilter === 'inactive' && !user.isActive); const matchesQuery = !query || user.name.toLowerCase().includes(query) || user.email.toLowerCase().includes(query); return matchesStatus && matchesQuery; }); }, [searchTerm, statusFilter, users]); const loadUsers = async () => { setIsLoading(true); try { setUsers(await fetchUsers()); } finally { setIsLoading(false); } }; useEffect(() => { // User management needs an initial API load when the admin page opens. // eslint-disable-next-line react-hooks/set-state-in-effect void loadUsers(); }, []); const resetForm = () => { setName(''); setEmail(''); setPassword(''); setPasswordMode('auto'); setIsActive(true); setEditingUser(null); setNotice(null); setCopyLabel('Copiar'); }; const closeModal = () => { if (isSubmitting) return; setIsModalOpen(false); resetForm(); }; const openCreateModal = () => { resetForm(); setIsModalOpen(true); }; const openEditModal = (user: ManagedUser) => { setEditingUser(user); setName(user.name); setEmail(user.email); setIsActive(user.isActive); setPassword(''); setPasswordMode('auto'); setNotice(null); setCopyLabel('Copiar'); setIsModalOpen(true); }; const handleCreateUser = async (event: FormEvent) => { event.preventDefault(); setIsSubmitting(true); setNotice(null); setCopyLabel('Copiar'); try { const result = await createUser({ name, email, password: passwordMode === 'manual' ? password : undefined }); setUsers((currentUsers) => [result.user, ...currentUsers]); if (result.temporaryPassword) { setNotice({ tone: 'success', text: 'Acesso criado. Copie a senha gerada antes de fechar.', temporaryPassword: result.temporaryPassword }); setName(''); setEmail(''); setPassword(''); setPasswordMode('auto'); } else { setNotice({ tone: 'success', text: 'Acesso criado com a senha definida.' }); window.setTimeout(() => { setIsModalOpen(false); resetForm(); }, 900); } } catch (error) { setNotice({ tone: 'error', text: error instanceof Error ? error.message : 'Não foi possível criar o acesso.' }); } finally { setIsSubmitting(false); } }; const handleUpdateUser = async (event: FormEvent) => { event.preventDefault(); if (!editingUser) return; setIsSubmitting(true); setNotice(null); try { const updatedUser = await updateUser(editingUser.id, { name, email, isActive, password: passwordMode === 'manual' ? password : undefined }); setUsers((currentUsers) => currentUsers.map((user) => user.id === updatedUser.id ? updatedUser : user)); setNotice({ tone: 'success', text: 'Usuário atualizado.' }); window.setTimeout(() => { setIsModalOpen(false); resetForm(); }, 700); } catch (error) { setNotice({ tone: 'error', text: error instanceof Error ? error.message : 'Não foi possível editar o usuário.' }); } finally { setIsSubmitting(false); } }; const handleDeleteUser = async () => { if (!userToDelete) return; setIsSubmitting(true); try { await deleteManagedUser(userToDelete.id); setUsers((currentUsers) => currentUsers.filter((user) => user.id !== userToDelete.id)); setUserToDelete(null); } catch (error) { setNotice({ tone: 'error', text: error instanceof Error ? error.message : 'Não foi possível excluir o usuário.' }); } finally { setIsSubmitting(false); } }; const copyTemporaryPassword = async () => { if (!notice?.temporaryPassword) return; try { await navigator.clipboard.writeText(notice.temporaryPassword); setCopyLabel('Copiado'); window.setTimeout(() => setCopyLabel('Copiar'), 1600); } catch { setCopyLabel('Falhou'); } }; const noticeClass = notice?.tone === 'error' ? 'border-red-500/30 bg-red-500/10 text-red-300' : notice?.tone === 'warning' ? 'border-amber-500/30 bg-amber-500/10 text-amber-200' : 'border-emerald-500/30 bg-emerald-500/10 text-emerald-300'; return (
Super admin

Usuários

Controle quem acessa o painel.

Total

{users.length}

Ativos

{activeCount}

Inativos

{inactiveCount}

setSearchTerm(event.target.value)} className="min-w-0 flex-1 bg-transparent text-sm text-dark-text outline-none placeholder:text-dark-muted" placeholder="Buscar nome ou e-mail" />
{statusOptions.map((option) => ( ))}
{isLoading ? (
) : users.length === 0 ? (

Nenhum usuário cadastrado

Crie o primeiro acesso para liberar o painel a outra pessoa.

) : filteredUsers.length === 0 ? (

Nenhum resultado

Ajuste a busca ou limpe os filtros.

) : (
{filteredUsers.map((user) => ( ))}
Usuário E-mail Status Criado em Ações
{getInitials(user.name)}

{user.name}

{user.email}
{user.isActive ? 'Ativo' : 'Inativo'} {formatDateTime(user.createdAt)}
)}
{isModalOpen && (

{editingUser ? 'Editar usuário' : 'Novo usuário'}

{editingUser ? 'Atualize dados, status e senha de acesso.' : 'Crie um acesso individual para o painel.'}

{editingUser ? 'Senha' : 'Senha inicial'}
{passwordMode === 'manual' && (
setPassword(event.target.value)} className="min-w-0 flex-1 bg-transparent text-dark-text outline-none placeholder:text-dark-muted" placeholder="Mínimo de 6 caracteres" minLength={6} required />
)}
{editingUser && ( )} {notice && (
{notice.tone === 'error' ? : }

{notice.text}

{notice.temporaryPassword && (
{notice.temporaryPassword}
)}
)}
)} {userToDelete && (

Excluir usuário

Esta ação remove o acesso imediatamente.

{userToDelete.name}

{userToDelete.email}

{notice?.tone === 'error' && (
{notice.text}
)}
)}
); }; export default AdminUsers;