import { useState, useEffect } from 'react'; import { supabase } from '@/integrations/supabase/client'; import { useAuth } from './useAuth'; import { toast } from 'sonner'; import { useInterfaceResources } from './useInterfaceResources'; export interface UserProfile { id: string; email: string; full_name: string | null; profile_image_url: string | null; function_id: string | null; privilege_id: string | null; status: 'pending' | 'active' | 'inactive' | 'rejected'; requested_at: string; created_at: string; updated_at: string; functions?: { name: string; description: string; }; privileges?: { name: string; description: string; permissions: Record; }; } export interface UserFunction { id: string; name: string; description: string | null; created_at: string; updated_at: string; } export interface UserPrivilege { id: string; name: string; description: string | null; permissions: Record; created_at: string; updated_at: string; } export interface UserDependency { table_name: string; dependency_type: string; count: number; description: string; } export function useUserManagement() { const deleteUserAndLogtoAccount = async (userId: string, email: string) => { try { const supabaseUrl = import.meta.env.VITE_SUPABASE_URL; // 1. Deleta do Logto primeiro const response = await fetch(`${supabaseUrl}/functions/v1/delete-logto-user`, { method: "POST", headers: { "Content-Type": "application/json", }, body: JSON.stringify({ email }), }); if (!response.ok) { console.error("Failed to delete from Logto", await response.text()); toast.error("Erro ao excluir do Logto. A exclusão no sistema continuará."); } // 2. Deleta do Supabase return await deleteUser(userId, true); } catch (err) { console.error(err); toast.error("Erro na comunicação com o servidor de autenticação"); return false; } }; const { user } = useAuth(); const [users, setUsers] = useState([]); const [pendingUsers, setPendingUsers] = useState([]); const [functions, setFunctions] = useState([]); const [privileges, setPrivileges] = useState([]); const [loading, setLoading] = useState(true); const { updatePrivilegeResources } = useInterfaceResources(); // Fetch all users const fetchUsers = async () => { try { const { data, error } = await supabase .from('profiles') .select(` *, functions (name, description), privileges (name, description, permissions) `) .neq('status', 'pending') .order('created_at', { ascending: false }); if (error) throw error; setUsers(data || []); } catch (error) { console.error('Error fetching users:', error); toast.error('Erro ao carregar usuários'); } }; // Fetch pending users const fetchPendingUsers = async () => { try { const { data, error } = await supabase .from('profiles') .select('*') .eq('status', 'pending') .order('requested_at', { ascending: false }); if (error) throw error; setPendingUsers(data || []); } catch (error) { console.error('Error fetching pending users:', error); toast.error('Erro ao carregar solicitações pendentes'); } }; // Fetch functions const fetchFunctions = async () => { try { const { data, error } = await supabase .from('functions') .select('*') .order('name'); if (error) throw error; setFunctions(data || []); } catch (error) { console.error('Error fetching functions:', error); toast.error('Erro ao carregar funções'); } }; // Fetch privileges const fetchPrivileges = async () => { try { const { data, error } = await supabase .from('privileges') .select('*') .order('name'); if (error) throw error; setPrivileges(data || []); } catch (error) { console.error('Error fetching privileges:', error); toast.error('Erro ao carregar privilégios'); } }; // Get user dependencies const getUserDependencies = async (userId: string): Promise => { try { const { data, error } = await supabase.rpc('get_user_dependencies', { _user_id: userId }); if (error) throw error; return data || []; } catch (error) { console.error('Error getting user dependencies:', error); return []; } }; // Replace user with UserDel const replaceUserWithDeleted = async (userId: string): Promise => { try { const { error } = await supabase.rpc('replace_user_with_deleted', { _user_id: userId }); if (error) throw error; return true; } catch (error) { console.error('Error replacing user with deleted:', error); toast.error('Erro ao substituir referências do usuário'); return false; } }; // Create new user (Admin only) const createUser = async (data: { email: string; full_name?: string; function_id?: string; privilege_id?: string; }) => { try { const { data: result, error } = await supabase.rpc('admin_create_user', { user_email: data.email, _caller_id: user?.id, user_full_name: data.full_name || null, user_function_id: data.function_id || null, user_privilege_id: data.privilege_id || null }); if (error) throw error; toast.success('Usuário criado com sucesso! Senha padrão: 1234'); fetchUsers(); return result; } catch (error: unknown) { console.error('Error creating user:', error); const err = error as Error; if (err.message?.includes('User with this email already exists')) { toast.error('Este e-mail já está em uso'); } else if (error.message?.includes('Only admins can create new users')) { toast.error('Apenas administradores podem criar usuários'); } else { toast.error('Erro ao criar usuário'); } throw error; } }; // Check if user can be deleted const canDeleteUser = async (userId: string): Promise => { try { const { data, error } = await supabase.rpc('can_delete_user', { _user_id: userId }); if (error) throw error; return data; } catch (error) { console.error('Error checking if user can be deleted:', error); return false; } }; // Delete user (Admin only) const deleteUser = async (userId: string, replaceReferences: boolean = false) => { try { // If replaceReferences is true, replace user references first if (replaceReferences) { const replaced = await replaceUserWithDeleted(userId); if (!replaced) { return false; } } // First check if user can be deleted const canDelete = await canDeleteUser(userId); if (!canDelete) { toast.error('Este usuário não pode ser excluído pois possui dados vinculados no sistema'); return false; } const { data, error } = await supabase.rpc('admin_delete_user', { _caller_id: user?.id, _user_id: userId }); if (error) throw error; toast.success('Usuário excluído com sucesso!'); fetchUsers(); fetchPendingUsers(); return true; } catch (error: unknown) { console.error('Error deleting user:', error); const err = error as Error; if (err.message?.includes('Only admins can delete users')) { toast.error('Apenas administradores podem excluir usuários'); } else if (err.message?.includes('User cannot be deleted due to existing dependencies')) { toast.error('Este usuário não pode ser excluído pois possui dados vinculados no sistema'); } else { toast.error('Erro ao excluir usuário'); } return false; } }; // Approve user const approveUser = async (userId: string) => { try { const { error } = await supabase .from('profiles') .update({ status: 'active' }) .eq('id', userId); if (error) throw error; toast.success('Usuário aprovado com sucesso!'); fetchUsers(); fetchPendingUsers(); } catch (error) { console.error('Error approving user:', error); toast.error('Erro ao aprovar usuário'); } }; // Reject user const rejectUser = async (userId: string) => { try { const { error } = await supabase .from('profiles') .update({ status: 'rejected' }) .eq('id', userId); if (error) throw error; toast.success('Usuário rejeitado'); fetchUsers(); fetchPendingUsers(); } catch (error) { console.error('Error rejecting user:', error); toast.error('Erro ao rejeitar usuário'); } }; // Update user const updateUser = async (userId: string, data: Partial) => { try { const { error } = await supabase .from('profiles') .update(data) .eq('id', userId); if (error) throw error; toast.success('Usuário atualizado com sucesso!'); fetchUsers(); } catch (error) { console.error('Error updating user:', error); toast.error('Erro ao atualizar usuário'); } }; const toggleUserStatus = async (userId: string, currentStatus: string) => { const newStatus = currentStatus === 'active' ? 'inactive' : 'active'; await updateUser(userId, { status: newStatus as UserProfile['status'] }); }; // CRUD functions for Functions table const createFunction = async (data: { name: string; description?: string }) => { try { const { error } = await supabase .from('functions') .insert(data); if (error) throw error; toast.success('Função criada com sucesso!'); fetchFunctions(); } catch (error) { console.error('Error creating function:', error); toast.error('Erro ao criar função'); } }; const updateFunction = async (id: string, data: { name: string; description?: string }) => { try { const { error } = await supabase .from('functions') .update(data) .eq('id', id); if (error) throw error; toast.success('Função atualizada com sucesso!'); fetchFunctions(); } catch (error) { console.error('Error updating function:', error); toast.error('Erro ao atualizar função'); } }; const deleteFunction = async (id: string) => { try { const { error } = await supabase .from('functions') .delete() .eq('id', id); if (error) throw error; toast.success('Função removida com sucesso!'); fetchFunctions(); } catch (error) { console.error('Error deleting function:', error); toast.error('Erro ao remover função'); } }; // CRUD functions for Privileges table - Updated to handle interface resources const createPrivilege = async (data: { name: string; description?: string; permissions?: Record }, resourceKeys: string[] = []) => { try { const { data: newPrivilege, error } = await supabase .from('privileges') .insert({ ...data, permissions: data.permissions || {} }) .select() .single(); if (error) throw error; // Update interface resources if provided if (resourceKeys.length > 0 && newPrivilege) { await updatePrivilegeResources(newPrivilege.id, resourceKeys); } toast.success('Privilégio criado com sucesso!'); fetchPrivileges(); return newPrivilege; } catch (error) { console.error('Error creating privilege:', error); toast.error('Erro ao criar privilégio'); throw error; } }; const updatePrivilege = async (id: string, data: { name: string; description?: string; permissions?: Record }) => { try { const { error } = await supabase .from('privileges') .update(data) .eq('id', id); if (error) throw error; toast.success('Privilégio atualizado com sucesso!'); fetchPrivileges(); } catch (error) { console.error('Error updating privilege:', error); toast.error('Erro ao atualizar privilégio'); } }; const deletePrivilege = async (id: string) => { try { const { error } = await supabase .from('privileges') .delete() .eq('id', id); if (error) throw error; toast.success('Privilégio removido com sucesso!'); fetchPrivileges(); } catch (error) { console.error('Error deleting privilege:', error); toast.error('Erro ao remover privilégio'); } }; useEffect(() => { if (user) { const loadData = async () => { setLoading(true); await Promise.all([ fetchUsers(), fetchPendingUsers(), fetchFunctions(), fetchPrivileges() ]); setLoading(false); }; loadData(); } }, [user]); return { users, pendingUsers, functions, privileges, loading, createUser, approveUser, rejectUser, updateUser, toggleUserStatus, deleteUser, deleteUserAndLogtoAccount, canDeleteUser, getUserDependencies, replaceUserWithDeleted, createFunction, updateFunction, deleteFunction, createPrivilege, updatePrivilege, deletePrivilege, refetchData: () => { fetchUsers(); fetchPendingUsers(); fetchFunctions(); fetchPrivileges(); } }; }