feat: adicionado botão e lógica para exclusão simultânea no logto e supabase

This commit is contained in:
2026-08-18 11:57:24 +00:00
parent dd7d1c41dd
commit a4ea6787b8
2 changed files with 57 additions and 2 deletions
+29 -2
View File
@@ -20,7 +20,8 @@ import { UserProfile, UserFunction, UserPrivilege } from '@/hooks/useUserManagem
import { AvatarUpload } from '@/components/ui/avatar-upload'; import { AvatarUpload } from '@/components/ui/avatar-upload';
import { useProfileImage } from '@/hooks/useProfileImage'; import { useProfileImage } from '@/hooks/useProfileImage';
import { usePasswordManagement } from '@/hooks/usePasswordManagement'; import { usePasswordManagement } from '@/hooks/usePasswordManagement';
import { Eye, EyeOff } from 'lucide-react'; import { useUserManagement } from '@/hooks/useUserManagement';
import { Eye, EyeOff, AlertTriangle } from 'lucide-react';
interface UserModalProps { interface UserModalProps {
user: UserProfile | null; user: UserProfile | null;
@@ -35,7 +36,9 @@ interface UserModalProps {
export function UserModal({ user, functions, privileges, onSave, onCreate, onClose, readOnly = false }: UserModalProps) { export function UserModal({ user, functions, privileges, onSave, onCreate, onClose, readOnly = false }: UserModalProps) {
const { updateProfileImage, removeProfileImage, updating } = useProfileImage(); const { updateProfileImage, removeProfileImage, updating } = useProfileImage();
const { changeUserPassword, isChangingPassword } = usePasswordManagement(); const { changeUserPassword, isChangingPassword } = usePasswordManagement();
const { deleteUserAndLogtoAccount } = useUserManagement();
const [showPassword, setShowPassword] = useState(false); const [showPassword, setShowPassword] = useState(false);
const [isDeletingLogto, setIsDeletingLogto] = useState(false);
const [formData, setFormData] = useState({ const [formData, setFormData] = useState({
email: '', email: '',
full_name: '', full_name: '',
@@ -126,6 +129,18 @@ export function UserModal({ user, functions, privileges, onSave, onCreate, onClo
onClose(); onClose();
}; };
const handleDeleteLogtoAndSupabase = async () => {
if (!user || isReadOnly) return;
if (confirm(`ATENÇÃO! Esta ação irá apagar a conta do usuário ${user.email} permanentemente no LOGTO e no Supabase. O usuário perderá o acesso totalmente. Tem certeza?`)) {
setIsDeletingLogto(true);
const success = await deleteUserAndLogtoAccount(user.id, user.email);
setIsDeletingLogto(false);
if (success) {
onClose();
}
}
};
return ( return (
<Dialog open={true} onOpenChange={onClose}> <Dialog open={true} onOpenChange={onClose}>
<DialogContent className="bg-slate-800 border-slate-700 text-white max-w-md"> <DialogContent className="bg-slate-800 border-slate-700 text-white max-w-md">
@@ -297,11 +312,23 @@ export function UserModal({ user, functions, privileges, onSave, onCreate, onClo
<Button <Button
type="submit" type="submit"
className="bg-blue-600 hover:bg-blue-700" className="bg-blue-600 hover:bg-blue-700"
disabled={updating || (isCreateMode && !formData.email)} disabled={updating || (isCreateMode && !formData.email) || isDeletingLogto}
> >
{isCreateMode ? 'Criar Usuário' : 'Salvar'} {isCreateMode ? 'Criar Usuário' : 'Salvar'}
</Button> </Button>
)} )}
{!isCreateMode && !isReadOnly && (
<Button
type="button"
variant="destructive"
onClick={handleDeleteLogtoAndSupabase}
disabled={isDeletingLogto}
className="flex items-center gap-1 bg-red-600 hover:bg-red-700"
>
<AlertTriangle className="h-4 w-4" />
{isDeletingLogto ? 'Excluindo...' : 'Excluir Conta Logto'}
</Button>
)}
<Button type="button" variant="ghost" onClick={onClose}> <Button type="button" variant="ghost" onClick={onClose}>
{isReadOnly ? 'Fechar' : 'Cancelar'} {isReadOnly ? 'Fechar' : 'Cancelar'}
</Button> </Button>
+28
View File
@@ -51,6 +51,33 @@ export interface UserDependency {
} }
export function useUserManagement() { 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 { user } = useAuth();
const [users, setUsers] = useState<UserProfile[]>([]); const [users, setUsers] = useState<UserProfile[]>([]);
const [pendingUsers, setPendingUsers] = useState<UserProfile[]>([]); const [pendingUsers, setPendingUsers] = useState<UserProfile[]>([]);
@@ -458,6 +485,7 @@ export function useUserManagement() {
updateUser, updateUser,
toggleUserStatus, toggleUserStatus,
deleteUser, deleteUser,
deleteUserAndLogtoAccount,
canDeleteUser, canDeleteUser,
getUserDependencies, getUserDependencies,
replaceUserWithDeleted, replaceUserWithDeleted,