feat: add force delete functionality for users and improve deletion confirmation flow

This commit is contained in:
2025-10-17 23:37:28 +02:00
parent db76597b6e
commit 024e1de04b
2 changed files with 75 additions and 6 deletions

View File

@@ -72,6 +72,8 @@ export default function AdminPage() {
const [currentPassword, setCurrentPassword] = useState('');
const [changeNewPassword, setChangeNewPassword] = useState('');
const [confirmPassword, setConfirmPassword] = useState('');
const [forceDelete, setForceDelete] = useState(false);
const [showForceModal, setShowForceModal] = useState(false);
useEffect(() => {
if (status === 'loading') return;
@@ -231,10 +233,41 @@ export default function AdminPage() {
const handleDeleteUser = async () => {
if (!selectedUser) return;
await fetch(`/api/users/${selectedUser.id}`, { method: 'DELETE' });
setDialogOpen(false);
setSelectedUser(null);
fetchHours();
const res = await fetch(`/api/users/${selectedUser.id}`, {
method: 'DELETE',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ force: forceDelete }),
});
if (res.ok) {
setDialogOpen(false);
setSelectedUser(null);
fetchHours();
toast.success('Utilisateur supprimé');
} else if (res.status === 400) {
setDialogOpen(false);
setShowForceModal(true);
} else {
const data = await res.json();
toast.error(data.error || 'Erreur lors de la suppression');
}
};
const handleForceDelete = async () => {
if (!selectedUser) return;
const res = await fetch(`/api/users/${selectedUser.id}`, {
method: 'DELETE',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ force: true }),
});
if (res.ok) {
setShowForceModal(false);
setSelectedUser(null);
fetchHours();
toast.success('Utilisateur supprimé');
} else {
const data = await res.json();
toast.error(data.error || 'Erreur lors de la suppression');
}
};
const handleChangePassword = async (e: React.FormEvent) => {
@@ -370,7 +403,7 @@ export default function AdminPage() {
Valider
</Button>
<Button
onClick={() => handleDelete(hour.id)}
onClick={() => handleValidate(hour.id, 'REJECTED')}
variant="destructive"
disabled={hour.userId === session?.user?.id}
>
@@ -413,6 +446,7 @@ export default function AdminPage() {
id: userId,
name: userMap[userId]?.name,
});
setForceDelete(false);
setDialogOpen(true);
}}
variant="destructive"
@@ -570,6 +604,15 @@ export default function AdminPage() {
</DialogHeader>
<DialogDescription>
Êtes-vous sûr de vouloir supprimer cet utilisateur ?
<div className="flex items-center space-x-2 mt-2">
<input
type="checkbox"
id="force"
checked={forceDelete}
onChange={(e) => setForceDelete(e.target.checked)}
/>
<Label htmlFor="force">Forcer la suppression même si l'utilisateur a des heures</Label>
</div>
</DialogDescription>
<DialogFooter>
<Button onClick={() => setDialogOpen(false)}>Annuler</Button>
@@ -580,6 +623,24 @@ export default function AdminPage() {
</DialogContent>
</Dialog>
)}
{selectedUser && showForceModal && (
<Dialog open={showForceModal} onOpenChange={setShowForceModal}>
<DialogContent>
<DialogHeader>
<DialogTitle>Confirmation de suppression forcée</DialogTitle>
</DialogHeader>
<DialogDescription>
Cette action supprimera l'utilisateur sans tenir compte de ses heures. Êtes-vous sûr ?
</DialogDescription>
<DialogFooter>
<Button onClick={() => setShowForceModal(false)}>Annuler</Button>
<Button onClick={handleForceDelete} variant="destructive">
Supprimer
</Button>
</DialogFooter>
</DialogContent>
</Dialog>
)}
<div>
<Button onClick={() => handleExport('csv')} className="mr-2">
Exporter CSV

View File

@@ -13,6 +13,8 @@ export async function DELETE(
}
const { id } = await params;
const body = await request.json().catch(() => ({}));
const { force = false } = body;
const user = await prisma.user.findUnique({
where: { id },
@@ -26,13 +28,19 @@ export async function DELETE(
);
}
if (user.hours.length > 0) {
if (user.hours.length > 0 && !force) {
return NextResponse.json(
{ error: 'Impossible de supprimer un utilisateur avec des heures' },
{ status: 400 },
);
}
if (force && user.hours.length > 0) {
await prisma.hour.deleteMany({
where: { userId: id },
});
}
await prisma.user.delete({
where: { id },
});