Aller au contenu

Composants Frontend

Guide des composants React de Primatch : organisation, conventions et patterns.


Catégories de composants

1. UI Primitives (components/ui/)

Composants sans logique métier, purement visuels et réutilisables partout.

components/ui/
├── Button.tsx         # Bouton avec variants (primary, secondary, danger)
├── Input.tsx          # Input avec label, error, aide
├── Card.tsx           # Conteneur avec shadow/border
├── Drawer.tsx         # Bottom sheet (z-[60], au-dessus du footer nav z-50)
├── Modal.tsx          # Dialog/Overlay
├── Badge.tsx          # Label coloré (statut, type)
├── LoadingSpinner.tsx # Indicateur de chargement
└── Avatar.tsx         # Photo de profil

Règle : Les composants UI ne font aucun appel API et n'utilisent aucun hook métier.

Drawer — z-index et safe area

Drawer.tsx utilise z-[60] pour être au-dessus de la barre de navigation mobile (PlayerBottomNav, z-50). Le contenu inclut un padding bottom tenant compte de env(safe-area-inset-bottom) pour éviter l'overlap sur les appareils avec encoche/home indicator.

2. Feature Components (components/features/)

Composants spécifiques à un domaine métier.

components/features/
├── game/
│   ├── GameCard.tsx       # Carte d'aperçu d'une partie
│   ├── GameStatusBadge.tsx
│   └── ScoreForm.tsx       # Formulaire de saisie de score

3. Layout (components/layout/)

Composants structurels de la page.

components/layout/
├── Header.tsx
├── Sidebar.tsx
├── Footer.tsx
└── PageWrapper.tsx    # Wrapper standard avec title, breadcrumb

Pattern : Composant avec état de chargement

export const GameCard = ({ gameId }: { gameId: number }) => {
  const { data: game, isLoading, isError } = useGame(gameId);

  if (isLoading) return <Card><LoadingSpinner /></Card>;
  if (isError) return <Card><ErrorMessage /></Card>;
  if (!game) return null;

  return (
    <Card>
      <h3>{game.players.join(' vs ')}</h3>
      <GameStatusBadge status={game.status} />
      <time>{formatDate(game.scheduledAt)}</time>
    </Card>
  );
};

Convention de props

// ✅ Interface de props explicite et typée
interface GameCardProps {
  gameId: number;
  onScoreClick?: () => void;  // Callbacks en camelCase
  className?: string;          // Extensibilité CSS
}

export const GameCard = ({ gameId, onScoreClick, className }: GameCardProps) => {
  // ...
};