- Fixed LoginPage.js to use correct API endpoint (localhost:8000) - Fixed prop naming (onLoginSuccess → onLogin) - Fixed data structure mapping (voter.email → email, etc) - Removed duplicate src/ folder structure - Updated DashboardPage.js with proper API endpoints - Added lucide-react dependency - Fixed docker-compose and Dockerfile.backend for proper execution - Cleaned up console logs - System fully working with Docker deployment
409 lines
7.9 KiB
Markdown
409 lines
7.9 KiB
Markdown
# 🧩 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
|
|
|
|
```javascript
|
|
Header.propTypes = {
|
|
voter: PropTypes.object, // Données de l'utilisateur connecté
|
|
onLogout: PropTypes.func.isRequired, // Callback de déconnexion
|
|
}
|
|
```
|
|
|
|
### Utilisation
|
|
|
|
```jsx
|
|
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
|
|
|
|
---
|
|
|
|
## Footer
|
|
|
|
Pied de page avec liens et informations.
|
|
|
|
### Utilisation
|
|
|
|
```jsx
|
|
import Footer from './components/Footer';
|
|
|
|
<Footer />
|
|
```
|
|
|
|
### Sections
|
|
|
|
- À propos
|
|
- Liens rapides
|
|
- Légal
|
|
- Contact
|
|
|
|
---
|
|
|
|
## VoteCard
|
|
|
|
Affiche un vote sous forme de carte.
|
|
|
|
### Props
|
|
|
|
```javascript
|
|
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
|
|
|
|
```jsx
|
|
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
|
|
|
|
```javascript
|
|
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
|
|
|
|
```jsx
|
|
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
|
|
|
|
```javascript
|
|
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
|
|
|
|
```jsx
|
|
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
|
|
|
|
```javascript
|
|
LoadingSpinner.propTypes = {
|
|
fullscreen: PropTypes.bool, // Mode plein écran avec overlay
|
|
}
|
|
```
|
|
|
|
### Utilisation
|
|
|
|
```jsx
|
|
import LoadingSpinner from './components/LoadingSpinner';
|
|
|
|
// Inline
|
|
<LoadingSpinner />
|
|
|
|
// Plein écran
|
|
<LoadingSpinner fullscreen={true} />
|
|
```
|
|
|
|
---
|
|
|
|
## Patterns de Composants
|
|
|
|
### Pattern 1: Formulaire avec Validation
|
|
|
|
```jsx
|
|
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
|
|
|
|
```jsx
|
|
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
|
|
|
|
```jsx
|
|
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
|
|
|
|
```html
|
|
<!-- 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`:
|
|
|
|
```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
|
|
|
|
```jsx
|
|
<button
|
|
aria-label="Fermer le menu"
|
|
onClick={close}
|
|
>
|
|
✕
|
|
</button>
|
|
```
|
|
|
|
---
|
|
|
|
## Performance
|
|
|
|
### Code Splitting
|
|
|
|
Utilisez `React.lazy()` pour charger les pages à la demande:
|
|
|
|
```jsx
|
|
const DashboardPage = React.lazy(() => import('./pages/DashboardPage'));
|
|
|
|
<Suspense fallback={<LoadingSpinner />}>
|
|
<DashboardPage />
|
|
</Suspense>
|
|
```
|
|
|
|
### Memoization
|
|
|
|
Pour les composants coûteux:
|
|
|
|
```jsx
|
|
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](https://react.dev).
|