Le bouton "Lancer l'évaluation" devient grisé automatiquement dès le passage à la dernière étape "Robustesse technique et sécurité".
Quand l'utilisateur passe à la dernière dimension (étape 6), React re-rend le composant et remplace le bouton "Suivant" par le bouton "Lancer l'évaluation". Pendant ce re-render, un événement résiduel ou un problème de timing peut déclencher automatiquement le onClick du nouveau bouton.
const isSubmittingRef = useRef(false);
const lastStepChangeRef = useRef<number>(0);Pourquoi ? Les refs ne déclenchent pas de re-render et sont plus fiables que les states pour suivre l'état de soumission.
const handleFormSubmit = useCallback((event?: React.MouseEvent) => {
// 1. Empêcher la propagation d'événements
if (event) {
event.preventDefault();
event.stopPropagation();
}
// 2. Protection temporelle : pas de soumission dans les 500ms après un changement d'étape
const timeSinceStepChange = Date.now() - lastStepChangeRef.current;
if (timeSinceStepChange < 500) {
console.warn(`⚠️ Step changed ${timeSinceStepChange}ms ago, ignoring premature submission`);
return;
}
// 3. Vérification avec ref
if (isSubmittingRef.current) {
console.warn('⚠️ Assessment already in progress (ref check)');
return;
}
// 4. Vérification avec state
if (assessmentMutation.isPending) {
console.warn('⚠️ Assessment already in progress (state check)');
return;
}
// 5. Validation du formulaire
if (!isFormValid()) {
console.warn('⚠️ Form is not valid');
return;
}
// ✅ Tout est OK, on peut soumettre
assessmentMutation.mutate(formData);
}, [assessmentMutation, formData]);const assessmentMutation = useMutation({
retry: false,
mutationFn: async (data: AssessmentFormData) => {
// Double vérification au début de la mutation
if (isSubmittingRef.current) {
throw new Error('Submission already in progress');
}
isSubmittingRef.current = true; // Marquer comme en cours
try {
// ... logique d'évaluation
} catch (error) {
isSubmittingRef.current = false; // Reset en cas d'erreur
throw error;
}
},
onSuccess: (data) => {
isSubmittingRef.current = false; // Reset en cas de succès
// ...
},
onError: (error) => {
isSubmittingRef.current = false; // Reset en cas d'erreur
// ...
}
});const handleStepChange = useCallback((newStep: number) => {
console.log(`🔄 Changing step from ${currentStep} to ${newStep}`);
lastStepChangeRef.current = Date.now(); // Enregistrer le moment du changement
setCurrentStep(newStep);
}, [currentStep]);Tous les appels à setCurrentStep ont été remplacés par handleStepChange :
- Navigation par onglets (Tabs)
- Bouton "Suivant"
- Bouton "Précédent"
- Nouvelle évaluation
const handleFormSubmit = useCallback((event?: React.MouseEvent) => {
// ...
}, [assessmentMutation, formData]);
const handleStepChange = useCallback((newStep: number) => {
// ...
}, [currentStep]);Pourquoi ? useCallback empêche la recréation de la fonction à chaque render, ce qui évite les appels intempestifs.
console.log('🔄 Assessment component rendering');
console.log('📊 Current state:', { isFormCompleted, currentStep, ... });
console.log('✅ assessmentMutation created, isPending:', assessmentMutation.isPending);
console.log('🔄 Changing step from X to Y');
console.log('✅ User clicked submit button, starting assessment...');IMPORTANT : Les modifications ne seront visibles qu'après avoir vidé le cache !
- Appuyez sur Ctrl+Shift+Delete
- Cochez "Images et fichiers en cache"
- Cliquez sur "Effacer les données"
- Appuyez sur Ctrl+F5 (rechargement forcé)
- Ou fermez complètement le navigateur et rouvrez-le
- Appuyez sur F12
- Allez dans l'onglet "Console"
- Gardez la console ouverte pendant le test
- Connectez-vous
- Allez sur "Évaluation des risques"
- Remplissez les informations de base
- Répondez aux questions des 6 premières dimensions
- Cliquez sur "Suivant" pour passer à la dernière dimension "Robustesse technique et sécurité"
- Le bouton "Lancer l'évaluation" doit apparaître
- Le bouton doit rester ACTIF (non grisé)
- Aucun log
🚀 Starting assessmentne doit apparaître - Le bouton ne doit PAS se déclencher automatiquement
- Répondez aux questions de la dernière dimension
- Cliquez manuellement sur "Lancer l'évaluation"
✅ RÉSULTAT ATTENDU :
- Vous voyez
✅ User clicked submit buttondans la console - Puis
🚀 Starting assessment for system: - Le bouton devient grisé avec le texte "Évaluation en cours..."
- L'évaluation se termine normalement
🔄 Assessment component rendering
📊 Current state: {isFormCompleted: false, currentStep: 0, ...}
✅ assessmentMutation created, isPending: false
🔄 Changing step from 5 to 6
🔄 Assessment component rendering
📊 Current state: {isFormCompleted: false, currentStep: 6, ...}
✅ assessmentMutation created, isPending: false
🚀 Starting assessment for system:(sans avoir cliqué)isPending: true(avant d'avoir cliqué)
✅ User clicked submit button, starting assessment...
📋 Form data: {...}
🚀 Starting assessment for system: [Nom du système]
📍 Stack trace: Error at mutationFn...
| Protection | Description | Efficacité |
|---|---|---|
| Délai de 500ms | Empêche la soumission dans les 500ms après un changement d'étape | ⭐⭐⭐⭐⭐ |
| Ref isSubmitting | Suivi fiable de l'état de soumission sans re-render | ⭐⭐⭐⭐⭐ |
| isPending check | Vérification de l'état de la mutation TanStack Query | ⭐⭐⭐⭐ |
| event.preventDefault() | Empêche la propagation d'événements | ⭐⭐⭐⭐ |
| event.stopPropagation() | Empêche la propagation vers les parents | ⭐⭐⭐⭐ |
| isFormValid() | Validation du formulaire avant soumission | ⭐⭐⭐⭐ |
| useCallback | Stabilisation des fonctions pour éviter les re-créations | ⭐⭐⭐⭐ |
| retry: false | Désactivation des tentatives automatiques | ⭐⭐⭐ |
| type="button" | Empêche le comportement de soumission HTML | ⭐⭐⭐ |
Vérifiez :
- Le cache est bien vidé (Ctrl+Shift+Delete)
- La page est rechargée (Ctrl+F5)
- Les logs apparaissent dans la console
Si les logs n'apparaissent pas :
- Les modifications ne sont pas chargées
- Redémarrez le serveur Docker
- Vérifiez que le build est à jour
Cherchez dans les logs :
⚠️ Step changed Xms ago→ Le délai de 500ms a bloqué la soumission (NORMAL)🚀 Starting assessmentsans✅ User clicked submit button→ Problème plus profond
Partagez :
- Tous les logs de la console
- Le moment exact où le bouton devient grisé
- Les actions effectuées juste avant
Cause probable : isPending reste à true
Solution :
- Rafraîchir la page (F5)
- Vider le cache de TanStack Query
- Redémarrer le navigateur
- ✅
client/src/pages/assessment.tsx- Protections multi-niveaux + logs
| Avant | Après |
|---|---|
| ❌ Bouton se déclenche automatiquement | ✅ Contrôle total par l'utilisateur |
| ❌ Pas de protection temporelle | ✅ Délai de 500ms après changement d'étape |
| ❌ Un seul niveau de vérification | ✅ 5 niveaux de protection |
| ❌ Fonctions recréées à chaque render | ✅ Fonctions stabilisées avec useCallback |
| ❌ Pas de logs de débogage | ✅ Logs détaillés à chaque étape |
🎉 Avec ces 5 niveaux de protection, le bouton ne devrait PLUS se déclencher automatiquement !
- Videz le cache (Ctrl+Shift+Delete)
- Rechargez la page (Ctrl+F5)
- Testez l'évaluation complète
- Vérifiez les logs dans la console
- Confirmez que le bouton ne se déclenche plus automatiquement
Si le problème persiste malgré ces corrections, partagez les logs complets de la console pour une analyse plus approfondie.