CIA/e-voting-system/.claude/COMPONENTS_DOC.md
E-Voting Developer 3efdabdbbd fix: Implement vote check endpoint in frontend API proxy
- Created `/frontend/app/api/votes/check/route.ts` to handle GET requests for checking if a user has voted in a specific election.
- Added error handling for unauthorized access and missing election ID.
- Forwarded requests to the backend API and returned appropriate responses.
- Updated `/frontend/app/api/votes/history/route.ts` to fetch user's voting history with error handling.
- Ensured both endpoints utilize the authorization token for secure access.
2025-11-10 02:56:47 +01:00

7.9 KiB

🧩 Documentation des Composants

Vue d'ensemble

Tous les composants sont dans src/components/ et réutilisables dans l'ensemble de l'application.


Header

Barre de navigation principale de l'application.

Props

Header.propTypes = {
  voter: PropTypes.object,                    // Données de l'utilisateur connecté
  onLogout: PropTypes.func.isRequired,        // Callback de déconnexion
}

Utilisation

import Header from './components/Header';

<Header voter={voter} onLogout={handleLogout} />

Fonctionnalités

  • Logo cliquable
  • Navigation responsive (menu hamburger sur mobile)
  • Liens différents selon la connexion
  • Profil utilisateur
  • Bouton de déconnexion

Pied de page avec liens et informations.

Utilisation

import Footer from './components/Footer';

<Footer />

Sections

  • À propos
  • Liens rapides
  • Légal
  • Contact

VoteCard

Affiche un vote sous forme de carte.

Props

VoteCard.propTypes = {
  vote: PropTypes.object.isRequired,          // Objet vote
  onVote: PropTypes.func,                     // Callback pour voter
  userVote: PropTypes.string,                 // Le vote de l'utilisateur (si votant)
  showResult: PropTypes.bool,                 // Afficher les résultats
}

Utilisation

import VoteCard from './components/VoteCard';

<VoteCard 
  vote={vote}
  onVote={handleVote}
  userVote="Oui"
  showResult={true}
/>

États

  • Actif: Bouton "VOTER MAINTENANT"
  • Déjà voté: Bouton désactivé "DÉJÀ VOTÉ" avec checkmark
  • Fermé: Bouton "Voir les Détails"
  • Futur: Bouton "M'alerter"

Affichage des Résultats

Si showResult={true} et le vote est fermé:

  • Graphique en barres avec pourcentages
  • Nombre total de votes

Alert

Notifications avec différents types.

Props

Alert.propTypes = {
  type: PropTypes.oneOf(['success', 'error', 'warning', 'info']),
  title: PropTypes.string,                    // Titre optionnel
  message: PropTypes.string.isRequired,       // Message d'alerte
  icon: PropTypes.elementType,                // Icône personnalisée
  onClose: PropTypes.func,                    // Callback de fermeture
}

Utilisation

import Alert from './components/Alert';

// Simple
<Alert type="success" message="Succès!" />

// Avec titre et fermeture
<Alert 
  type="error" 
  title="Erreur"
  message="Une erreur s'est produite"
  onClose={() => setError('')}
/>

Types

Type Couleur Utilisation
success Vert Confirmations, réussite
error Rouge Erreurs
warning Orange Avertissements, actions irréversibles
info Bleu Informations générales

Modal

Boîte de dialogue modale.

Props

Modal.propTypes = {
  isOpen: PropTypes.bool.isRequired,           // Afficher/Masquer la modale
  title: PropTypes.string,                     // Titre optionnel
  children: PropTypes.node.isRequired,         // Contenu
  onClose: PropTypes.func.isRequired,          // Fermeture
  onConfirm: PropTypes.func,                   // Action de confirmation
  confirmText: PropTypes.string,               // Texte du bouton confirm (défaut: "Confirmer")
  cancelText: PropTypes.string,                // Texte du bouton cancel (défaut: "Annuler")
  type: PropTypes.oneOf(['default', 'danger']), // Type d'alerte
}

Utilisation

import Modal from './components/Modal';

<Modal
  isOpen={showModal}
  title="Confirmer votre vote"
  onClose={() => setShowModal(false)}
  onConfirm={handleVote}
  confirmText="Confirmer"
  cancelText="Annuler"
>
  <p>Êtes-vous sûr de votre choix?</p>
</Modal>

LoadingSpinner

Indicateur de chargement.

Props

LoadingSpinner.propTypes = {
  fullscreen: PropTypes.bool,  // Mode plein écran avec overlay
}

Utilisation

import LoadingSpinner from './components/LoadingSpinner';

// Inline
<LoadingSpinner />

// Plein écran
<LoadingSpinner fullscreen={true} />

Patterns de Composants

Pattern 1: Formulaire avec Validation

import { useForm } from '../hooks/useApi';

function MyForm() {
  const { values, errors, handleChange, handleSubmit } = useForm(
    { email: '', password: '' },
    async (values) => {
      // Submit logic
    }
  );

  return (
    <form onSubmit={handleSubmit}>
      <input 
        name="email" 
        value={values.email} 
        onChange={handleChange}
      />
      {errors.email && <span>{errors.email}</span>}
      <button type="submit">Envoyer</button>
    </form>
  );
}

Pattern 2: Chargement de Données

import { useApi } from '../hooks/useApi';

function MyComponent() {
  const { data, loading, error } = useApi('/api/endpoint');

  if (loading) return <LoadingSpinner />;
  if (error) return <Alert type="error" message={error} />;

  return <div>{data}</div>;
}

Pattern 3: Modal de Confirmation

function MyComponentWithConfirmation() {
  const [showModal, setShowModal] = useState(false);

  const handleDelete = async () => {
    // Delete logic
    setShowModal(false);
  };

  return (
    <>
      <button onClick={() => setShowModal(true)}>Supprimer</button>
      
      <Modal
        isOpen={showModal}
        title="Confirmer la suppression"
        onClose={() => setShowModal(false)}
        onConfirm={handleDelete}
        type="danger"
      >
        <p>Cette action est irréversible.</p>
      </Modal>
    </>
  );
}

Styling des Composants

Tous les composants utilisent des classes CSS dans le fichier styles/components.css.

Classes Disponibles

<!-- Boutons -->
<button class="btn btn-primary">Primaire</button>
<button class="btn btn-secondary">Secondaire</button>
<button class="btn btn-success">Succès</button>
<button class="btn btn-danger">Danger</button>
<button class="btn btn-warning">Warning</button>
<button class="btn btn-ghost">Ghost</button>

<!-- Tailles -->
<button class="btn btn-sm">Petit</button>
<button class="btn btn-lg">Grand</button>

<!-- Autre -->
<button class="btn btn-block">Pleine largeur</button>

Personnalisation

Modifiez les styles dans src/styles/components.css:

.btn-primary {
  background-color: var(--primary-blue);
  /* ... */
}

Accessibilité

Tous les composants respectent les standards WCAG 2.1:

  • Navigation au clavier (Tab, Enter, Escape)
  • Contraste de couleur minimum AA
  • Textes alternatifs pour les icônes
  • Labels associés aux inputs
  • Sémantique HTML correcte
  • Focus visible
  • Aria attributes

Exemple

<button 
  aria-label="Fermer le menu"
  onClick={close}
>
  
</button>

Performance

Code Splitting

Utilisez React.lazy() pour charger les pages à la demande:

const DashboardPage = React.lazy(() => import('./pages/DashboardPage'));

<Suspense fallback={<LoadingSpinner />}>
  <DashboardPage />
</Suspense>

Memoization

Pour les composants coûteux:

import { memo } from 'react';

const VoteCard = memo(({ vote, onVote }) => {
  // Component
});

Troubleshooting

Le composant ne s'affiche pas

  1. Vérifiez que les props requises sont passées
  2. Vérifiez les erreurs dans la console
  3. Vérifiez les imports

Les styles ne s'appliquent pas

  1. Vérifiez que le CSS est importé dans index.js
  2. Vérifiez la spécificité des classes CSS
  3. Utilisez DevTools pour inspecter les styles

Le composant est lent

  1. Utilisez React.memo() si le composant dépend de props simples
  2. Utilisez useMemo() pour les calculs coûteux
  3. Vérifiez les rendus inutiles avec DevTools

Améliorations Futures

  • Ajouter des animations avec Framer Motion
  • Ajouter un thème sombre
  • Composants Storybook
  • Tests unitaires pour tous les composants
  • Gérer l'internationalization (i18n)

Pour toute question, consultez la documentation officielle React.