Add admin challenge acceptance functionality: Implement adminAcceptChallenge method in ChallengeService, allowing admins to accept pending challenges. Update ChallengeManagement component to include a button for accepting challenges, enhancing admin capabilities and user feedback handling.
All checks were successful
Deploy with Docker Compose / deploy (push) Successful in 4m48s

This commit is contained in:
Julien Froidefond
2025-12-17 08:14:58 +01:00
parent 7c0b3bc848
commit ba3b2c17b9
3 changed files with 96 additions and 0 deletions

View File

@@ -234,3 +234,37 @@ export async function reactivateChallenge(challengeId: string) {
};
}
}
export async function adminAcceptChallenge(challengeId: string) {
try {
await checkAdminAccess();
const challenge = await challengeService.adminAcceptChallenge(challengeId);
revalidatePath("/admin");
revalidatePath("/challenges");
return {
success: true,
message: "Défi accepté avec succès",
data: challenge,
};
} catch (error) {
console.error("Admin accept challenge error:", error);
if (error instanceof ValidationError) {
return { success: false, error: error.message };
}
if (error instanceof NotFoundError) {
return { success: false, error: error.message };
}
if (error instanceof Error && error.message.includes("Accès refusé")) {
return { success: false, error: error.message };
}
return {
success: false,
error: "Une erreur est survenue lors de l'acceptation du défi",
};
}
}

View File

@@ -8,6 +8,7 @@ import {
deleteChallenge,
adminCancelChallenge,
reactivateChallenge,
adminAcceptChallenge,
} from "@/actions/admin/challenges";
import {
Button,
@@ -226,6 +227,29 @@ export default function ChallengeManagement() {
});
};
const handleAdminAccept = async (challengeId: string) => {
if (
!confirm(
"Êtes-vous sûr de vouloir accepter ce défi à la place de l'utilisateur ?"
)
) {
return;
}
startTransition(async () => {
const result = await adminAcceptChallenge(challengeId);
if (result.success) {
setSuccessMessage("Défi accepté avec succès");
fetchChallenges();
setTimeout(() => setSuccessMessage(null), 5000);
} else {
setErrorMessage(result.error || "Erreur lors de l'acceptation");
setTimeout(() => setErrorMessage(null), 5000);
}
});
};
if (loading) {
return (
<div className="text-center text-pixel-gold py-8">Chargement...</div>
@@ -376,6 +400,16 @@ export default function ChallengeManagement() {
>
Modifier
</Button>
{challenge.status === "PENDING" && (
<Button
onClick={() => handleAdminAccept(challenge.id)}
variant="primary"
size="sm"
disabled={isPending}
>
Accepter le défi
</Button>
)}
{challenge.status === "ACCEPTED" && (
<Button
onClick={() => setSelectedChallenge(challenge)}

View File

@@ -120,6 +120,34 @@ export class ChallengeService {
});
}
/**
* Accepte un défi en tant qu'admin (bypass les vérifications utilisateur)
*/
async adminAcceptChallenge(challengeId: string): Promise<Challenge> {
const challenge = await prisma.challenge.findUnique({
where: { id: challengeId },
});
if (!challenge) {
throw new NotFoundError("Défi");
}
// Vérifier que le défi est en attente
if (challenge.status !== "PENDING") {
throw new ValidationError(
"Ce défi ne peut plus être accepté (statut: " + challenge.status + ")"
);
}
return prisma.challenge.update({
where: { id: challengeId },
data: {
status: "ACCEPTED",
acceptedAt: new Date(),
},
});
}
/**
* Annule un défi (par le challenger ou le challenged)
*/