Générateur de CV sous React

Une image de Générateur de CV sous React

Un générateur de CV conçu sous React et mis en prod sur Netlify.

Le générateur a deux modes, un mode Lecture permettant de consulter le CV tel qu’il est réellement, et un mode Édition activé lorsque l’utilisateur choisit de modifier une section particulière. Il permet d’éditer les différentes valeurs en temps réel en faisant en sorte d’éviter des basculements visuels trop importants entre le mode Lecture et le mode Édition afin que l’utilisateur puisse voir ce que le résultat final va donner alors même qu’il apporte ses modifications. Une fois satisfait du résultat, il peut télécharger le CV en format PDF. Si un dépassement (overflow) est détecté dans le CV ou que le mode Édition est activé, le bouton de téléchargement de PDF est désactivé jusqu’à ce que le phénomène soit corrigé.

Le but de cet exercice était de tester mes compétences en React, notamment :

  • la gestion des states (partagés ou pas),
  • le passages de props entre composants,
  • les composants contrôlés,
  • l’affichage conditionnel,
  • la génération de listes dynamiques,
  • l’utilisation de hooks, personnalisés ou non,
  • la validation de types.

J’ai fait en sorte qu’une seule section du CV soit éditable à la fois pour éviter d’éventuels pépins non prévus au moment de la mise à jour du CV ou lors de la génération du PDF (et aussi un peu arbitrairement, pour avoir une opportunité de faire un partage de state). Chaque section modifiable du CV possède sa propre ID, et l’ID de la section en cours d’édition est gardée en state dans un composant parent, avec une valeur neutre de 0 pour le mode Lecture. L’affichage conditionnel repose surtout sur ce système d’ID.

De manière générale, si aucune section n’est focalisée (et que par conséquent l’ID en state est une valeur neutre de 0), le CV est en mode Lecture : les boutons d’activation du mode Édition et d’ajout/suppression d’items dynamiques apparaissent sur chaque section lorsque le curseur passe dessus avec une bordure délimitant la zone concernée, et le CV lui-même ressemble au PDF final.

Si une ID non-neutre est en state, le CV passe en mode Édition et les sections ne correspondant pas à cette ID ont leurs boutons désactivés et ne sont pas mis en surbrillance lors du passage de la souris afin de ne pas causer de distraction. En mode Édition, les éléments d’affichage de la section concernée sont remplacés par des champs textuels permettant à l’utilisateur de rentrer ses données. Ces champs sont des composants contrôlés, leur valeur correspond chacune à un state précis qui est mis à jour à mesure que l’utilisateur tape ses informations. Un bouton de mise à jour permettant de revenir au mode Lecture apparaît à côté de la section en question. La génération de PDF est désactivée dans le mode Édition.

Certaines sections permettent non seulement d’éditer des champs, mais aussi de créer des items pour alimenter des listes générées dynamiquement. C’est le cas de la section Expériences (qui permet de générer des cards d’expérience individuelle) et de la section Compétences (qui permet non seulement de générer des compétences, mais aussi des catégories dans lesquelles les mettre, donc des listes dans des listes). Là encore, chaque item est généré avec une ID qui est également leur clé, et une attention particulière a été accordée au fait qu’elles ne se chevauchent potentiellement pas entre différentes listes dynamiques dont l’existence est par définition optionnelle.

La card d’expérience comporte une section permettant d’entrer les dates de début et de fin d’expérience, et fait appel à une librairie externe de calendrier (react-lite-month-picker) que j’ai dû modifier un peu pour répondre à mes besoins. Chaque item comporte deux pickers, un de début d’expérience et un de fin. J’ai préféré éviter de forker la librairie, et j’ai donc privilégié l’utilisation de JavaScript pour cela. J’ai notamment dû utiliser un hook useEffect pour modifier le contenu textuel des boutons d’ouverture des calendriers et y remplacer les noms de mois (qui sont normalement complets) par leur version raccourcie. Malheureusement, je n’ai pas trop réussi à garder un rendu visuel cohérent entre le mode Lecture et le mode Édition pour les cards, notamment parce que la partie Date prend plus de place en mode Édition à cause de l’ajout d’une case à cocher permettant d’indiquer que l’expérience est encore en cours.

Comme mentionné plus tôt, j’ai également créé un hook personnalisé afin d’effectuer une vérification de l’état du CV à chaque changement de section focalisée (entre autres). Si un overflow est détecté dans le CV, la génération de PDF est désactivée.

Dans l’état actuel de choses, il était possible de sélectionner des valeurs incohérentes de début et de fin d’expérience, avec des expériences qui finissaient avant de commencer ou inversement. Le month-picker que j’ai choisi est très simple d’utilisation et n’offrait pas de fonctionnalité permettant d’éviter cela. J’ai donc également créé un hook gérant la désactivation des boutons et permettant d’éviter de telles incohérences. Le hook détecte l’ouverture d’un picker, vérifie quelle année est ouverte, la compare avec l’année enregistrée dans l’autre picker, puis désactive la navigation et les boutons appropriés afin de ne pas laisser l’utilisateur entrer des périodes de début plus lointaines que celle de fin, et inversement. Ensuite, pour s’assurer que les boutons appropriés restent désactivés lors de la navigation (ou au contraire, soient réactivés), des Event Listeners sont placés sur les flèches de navigation d’année afin de refaire la comparaison à chaque clic et de changer les attributs de manière appropriée.

Voilà, je crois que c’est à peu près tout !

Lien du repo GitHub Lien du projet live