Skip to content
Share
Explore

REVIEW CODE MAKER/CHECKER

1. Contexte

Ce review couvre 8 composants React du module RequestMakerChecker permettant à un Maker de soumettre des demandes (agences, droits, privilèges) et à un Checker de les valider ou rejeter.
Famille Agence : ConsultAgencyCheckerComponent, TreatAgencyControlComponent
Famille Droits/Privilèges : ListPrivDroitCheckerComponent, TreatPrivDroitComponent, ListPrivMenuComponent, TreatPrivMenuComponent

2. RequestCheckerComponent

dashboard/demandes/checker/index.js
Critique localStorage accédé au niveau module sans protection
L'accès à localStorage se fait directement dans le corps du composant, hors de tout hook ou try/catch. Si localStorage est vide ou corrompu au moment du rendu, le composant crash avant que React puisse afficher quoi que ce soit — aucun message d'erreur n'est présenté à l'utilisateur.
// Exécuté au render, hors de tout try/catch
const allPriv = JSON.parse(localStorage.getItem("user")).others;
const one = allPriv.find((one) => one.title === privilegeChecker);

// Avec protection — pattern déjà appliqué dans RequestMakerComponent
const allPriv = JSON.parse(localStorage.getItem("user"))?.others || [];
const one = allPriv.find((one) => one.title === privilegeChecker);
Idéalement, les deux composants doivent utiliser le helper centralisé getUser() défini dans la section transverse.
Critique response.data.data accédé sans vérification
Si le backend renvoie une réponse sans data (timeout, erreur serveur, structure inattendue), l'accès à response.data.data.length lève une exception non interceptée dans le .then().
// Existing implementation
api.post(...).then((response) => {
if (response.data.data.length > 0) {
setreqs(response.data.data)
}
})

// Correct implementation
api.post(...).then((response) => {
const LIST = response.data?.data;
if (Array.isArray(LIST) && LIST.length > 0) {
setreqs(LIST);
} else {
setreqs([]);
}
})
Important Vérification de privilège déclarée mais jamais utilisée
La variable one est calculée pour vérifier si l'utilisateur a le privilège Checker, mais elle n'est jamais utilisée pour conditionner l'affichage ou restreindre l'accès. Dans un contexte sensible, une vérification de droit silencieusement ignorée est particulièrement problématique.
// Calculé mais jamais utilisé dans le JSX
const one = allPriv.find((one) => one.title === privilegeChecker);

// La vérification doit conditionner quelque chose
if (!one) return <Redirect to="/unauthorized" />;
// ou conditionner l'affichage du bouton de traitement dans le tableau
Important Incohérence BRANCHE vs AGENCE dans les switch
La liste de filtres targets utilise la clé "BRANCHE" pour les agences, alors que les fonctions goToDetail et goToPageTreat attendent "AGENCE". Si l'API renvoie "BRANCHE", le switch tombe sur le default et affiche un warning au lieu de naviguer.
// targets (filtre)
{ key: "BRANCHE", label: boa_intl_static("entity_agencyRequest") }

// goToDetail / goToPageTreat (navigation)
case "AGENCE":
history.push(`${base}/agence/checker/view/...`);
À vérifier avec la valeur réellement renvoyée par l'API et harmoniser partout.
Important LIMIT hardcodé à 10000
Charger jusqu'à 10 000 demandes en une seule requête est un anti-pattern. Si le volume croît, cela provoque des lenteurs serveur, un payload réseau lourd et un rendu dégradé. La pagination côté serveur doit être activée et LIMIT doit correspondre à page_size.
// Correct Pattern
params.append('START', 1);
params.append('LIMIT', 10000);
Important reqs initialisé sans valeur
ReactDatatable reçoit records={reqs} avec undefined lors du premier rendu, avant que getAllRequests termine. Selon la version de la lib, cela peut provoquer une erreur ou un rendu inattendu.
// Existing implementation
const [reqs, setreqs] = useState()

// Correct implementation
const [reqs, setreqs] = useState([])
Mineur Convention de nommage non homogène
Plusieurs conventions coexistent et nuisent à la lisibilité :
const [reqs, setreqs] = useState() // camelCase incomplet
setSstatus(...) // double 's' par erreur
setentity(...) // minuscule au lieu de setEntity
À uniformiser en camelCase strict : setReqs, setStatus, setEntity.

3. RequestMakerComponent

dashboard/demandes/maker/index.js
Point fort Protection partielle du localStorage
Contrairement à RequestCheckerComponent, l'accès à others est déjà protégé avec optional chaining et fallback. C'est la bonne direction.
// Déjà appliqué
const allPriv = JSON.parse(localStorage.getItem("user"))?.others || [];
Reste à appliquer le même pattern sur les accès dans getAllRequests (.country et .token).
Critique response.data.data accédé sans vérification
Même problème que RequestCheckerComponent — voir correction ci-dessus.
Important EXIST_CHECKER calculé mais jamais utilisé
La variable EXIST_CHECKER est calculée correctement mais n'est jamais référencée dans le JSX. La vérification de droit est silencieuse.
// Calculé mais jamais utilisé
const EXIST_CHECKER = one !== null && one !== undefined && one.title.length > 0;

// Doit conditionner quelque chose dans le rendu ou la navigation
Important LIMIT hardcodé à 10000
Même problème que RequestCheckerComponent.
Important reqs initialisé sans valeur
Même problème que RequestCheckerComponent.
Mineur Import commenté laissé en production
// À supprimer
//import setStatus from "downshift/dist/src/set-a11y-status";
Mineur Convention de nommage non homogène
Mêmes problèmes que RequestCheckerComponent : setreqs, setSstatus, setentity.

4. Problèmes transverses

Ces problèmes sont présents dans tous les composants sans exception.
Critique localStorage sans protection try/catch
Tous les composants accèdent à localStorage sans try/catch. Pattern répété 3 à 4 fois par composant. Un localStorage vide ou corrompu (session expirée, navigation privée) provoque un crash silencieux.
// Partout dans les composants(Existing implementation)
JSON.parse(localStorage.getItem("user")).token
JSON.parse(localStorage.getItem("user")).country
À centraliser dans un helper partagé :
// Helper à créer une seule fois(Correct implementation)
const getUser = () => {
try {
return JSON.parse(localStorage.getItem("user")) ?? {};
} catch {
return {};
}
};
const user = getUser();
params.append('STR_UTITOKEN', user.token ?? '');
params.append('LG_SOCID', user.country ?? '');
Critique Comparaison ==au lieu de ===
Plusieurs composants utilisent la comparaison faible sur le statut API et les types de demandes. En JavaScript, == autorise des coercitions de type imprévues (1 == "1" est true). Dans un contexte sensible, toutes les comparaisons doivent être strictes.
// Existing implementation
if (data.code_statut == "1")
demande.type_demande == "CREATION" || demande.type_demande == "SUPPRESSION"
// Correct implementation
if (data.code_statut === "1")
demande.type_demande === "CREATION" || demande.type_demande === "SUPPRESSION"
Important useEffect sans dépendance id
Tous les composants lancent getDemande() dans un useEffectavec un tableau vide []. L'id vient de useParams() et doit figurer dans les dépendances. Sans ça, une navigation entre deux demandes sans démontage du composant n'entraîne pas de rechargement et l'utilisateur voit des données périmées.
// Existing implementation
useEffect(() => { getDemande(); }, [])
// Correct implementation
useEffect(() => { getDemande(); }, [id])
Mineur NotificationManager.success() sur les appels GET
Un simple chargement de données (getDemande, getPrivilegesList) déclenche inutilement une notification de succès. Les notifications de succès doivent être réservées aux actions utilisateur : validation, rejet, création.
Mineur Imports inutilisés
Plusieurs composants importent des dépendances jamais référencées : resetIdCounter (downshift), Component, Redirect, Link, fade, ThemeProvider, withStyles, createMuiTheme. À supprimer pour alléger le bundle et éviter toute confusion.

5. ConsultAgencyCheckerComponent

checker/agence/consultation/index.js
Composant de consultation pure — tous les champs sont en readOnly. Les problèmes transverses s'appliquent. Points spécifiques :
Mineur Dead code — onSubmit / useForm / register
Le composant est en lecture seule mais embarque onSubmit, handleSubmit et useForm qui ne sont jamais utilisés côté JSX. register n'est appliqué que sur un seul champ de manière incohérente. Tout ce bloc est à supprimer.
Important Gestion d'erreur réseau trop générique
Le bloc catch affiche error.toString() directement, ce qui expose l'objet d'erreur brut à l'utilisateur. À distinguer selon le type d'erreur :
// Existing implementation catch error
.catch(error => {
NotificationManager.error(error.toString());
});
// Correct implementation
.catch(error => {
if (error.response) {
NotificationManager.error(error.response.data?.desc_statut || "Erreur serveur");
} else if (error.request) {
NotificationManager.error("Erreur réseau, veuillez réessayer");
} else {
NotificationManager.error("Une erreur inattendue s'est produite");
}
});
Important Optional chaining non systématique
Certains accès à response.data.data sont protégés par ?. et d'autres non, créant une incohérence et des risques de crash si la réponse API est partielle.
// Mixte dans le même composant(Existing implementation)
response.data.data.ACTION_DEMANDE // pas protégé
response.data.data?.TYPE_DEMANDE // protégé
response.data.data.DATA_JSON_NEW.STR_AGEBP // double risque
// Systématique(Correct implementation)
response.data?.data?.DATA_JSON_NEW?.STR_AGEBP

6. TreatAgencyControlComponent

checker/agence/traitement/index.js
Composant le plus critique de la famille Agence — il permet la validation ou le rejet d'une demande. Plusieurs bugs bloquants en production.
Critique try/catch ne capture pas les erreurs Promise
La fonction handleConfirmAction est déclarée async mais mélange .then() et try/catch. Le bloc catch ne capturera jamais les erreurs rejetées par la Promise. De plus, data référencé dans le catch n'existe pas dans ce scope → ReferenceError garanti.
// Pattern actuel
try {
api.post(endpoint, params, config).then(function (response) {
// ...
})
} catch (error) {
NotificationManager.error(data.desc_statut); // data = undefined ici !
}
// async/await pur(Correct Pattern)
try {
const response = await api.post(endpoint, params, config);
const data = response.data;
if (data.code_statut === "1") {
NotificationManager.success(
action === "VALIDATE"
?
:
);
setTimeout(() => {
window.location.replace('/dashboard/demandes/checker');
}, 2000);
} else {
NotificationManager.error(data.desc_statut);
}
} catch (error) {
setLoading(true);
NotificationManager.error("Une erreur est survenue lors du traitement");
}
Critique Double soumission possible — pas de guard
Aucun verrou ne protège handleConfirmAction contre les doubles clics. Dans un flux sensible, un double clic peut envoyer deux requêtes validateDemande au backend.
// Correction
const [isSubmitting, setIsSubmitting] = useState(false);
const handleConfirmAction = async () => {
if (!motifChecker.trim() || isSubmitting) return;
setIsSubmitting(true);
try {
// ... appel API
} finally {
setLoading(true);
setIsSubmitting(false);
}
};
// Sur le bouton
<Button disabled={!motifChecker.trim() || isSubmitting}>
Important Endpoint rejet sans slash initial
// Asymétrie
action === "VALIDATE"
? "/demandes/validateDemande" // slash présent
: "demandes/rejetDemande"; // slash absent
Selon la configuration baseURL d'axios, l'un des deux endpoints peut être mal résolu. À harmoniser.
Important Champs éditables sans vérification du statut
Dans la vue MODIFICATION, les champs "nouvelles valeurs" restent éditables même si la demande est déjà VALIDEE ou REJETEE. L'édition doit être conditionnée au statut.
// Correct
const isEditable = demande.statusReq === "EN_ATTENTE";
<TextField
InputProps={{
classes,
readOnly: !isEditable,
disableUnderline: true
}}
/>
Important Boutons Valider/Rejeter accessibles sur demande déjà traitée
// Correct
<button
onClick={() => handleActionClick("VALIDATE")}
disabled={demande.statusReq !== "EN_ATTENTE"}
>

7. ListPrivDroitCheckerComponent

checker/droits/consultation/index.js
Point fort Logique added/removed bien conçue
La logique de filtrage des privilèges modifiés (added/removed via filter) est claire et correcte. L'usage de === sur code_statut dans getDemande est également bon.
Critique localStorage sans try/catch (x4)
Want to print your doc?
This is not the way.
Try clicking the ··· in the right corner or using a keyboard shortcut (
CtrlP
) instead.