# 🧩 COMPOSANTS - BTPXPRESS FRONTEND

## 📋 Table des matières

- [Vue d'ensemble](#vue-densemble)
- [Composants Layout](#composants-layout)
- [Composants Formulaires](#composants-formulaires)
- [Composants Tableaux](#composants-tableaux)
- [Composants Graphiques](#composants-graphiques)
- [Composants Communs](#composants-communs)
- [PrimeReact](#primereact)
- [Création de composants](#création-de-composants)

---

## 🎯 Vue d'ensemble

L'application utilise **PrimeReact 10.2.1** comme bibliothèque de composants UI principale, complétée par des composants personnalisés.

### **Organisation**

```
components/
├── layout/          # Composants de mise en page
├── forms/           # Formulaires
├── tables/          # Tableaux de données
├── charts/          # Graphiques
└── common/          # Composants réutilisables
```

---

## 🏗️ Composants Layout

### **Header**

En-tête de l'application avec navigation et profil utilisateur.

**Fichier** : `components/layout/Header.tsx`

```typescript
'use client';

import { Menubar } from 'primereact/menubar';
import { Avatar } from 'primereact/avatar';
import { useAuth } from '@/hooks/useAuth';

export const Header = () => {
  const { user, logout } = useAuth();

  const items = [
    { label: 'Dashboard', icon: 'pi pi-home', url: '/dashboard' },
    { label: 'Chantiers', icon: 'pi pi-building', url: '/chantiers' },
    { label: 'Clients', icon: 'pi pi-users', url: '/clients' },
    { label: 'Matériel', icon: 'pi pi-wrench', url: '/materiels' },
  ];

  const end = (
    <div className="flex align-items-center gap-2">
      <Avatar label={user?.initials} shape="circle" />
      <span>{user?.name}</span>
    </div>
  );

  return <Menubar model={items} end={end} />;
};
```

**Props** : Aucune

**Utilisation** :
```typescript
import { Header } from '@/components/layout/Header';

<Header />
```

---

### **Sidebar**

Menu latéral de navigation.

**Fichier** : `components/layout/Sidebar.tsx`

```typescript
'use client';

import { PanelMenu } from 'primereact/panelmenu';
import { MenuItem } from 'primereact/menuitem';

export const Sidebar = () => {
  const items: MenuItem[] = [
    {
      label: 'Dashboard',
      icon: 'pi pi-home',
      url: '/dashboard',
    },
    {
      label: 'Chantiers',
      icon: 'pi pi-building',
      items: [
        { label: 'Liste', url: '/chantiers' },
        { label: 'Nouveau', url: '/chantiers/nouveau' },
        { label: 'Planning', url: '/chantiers/planning' },
      ],
    },
    {
      label: 'Clients',
      icon: 'pi pi-users',
      items: [
        { label: 'Liste', url: '/clients' },
        { label: 'Nouveau', url: '/clients/nouveau' },
      ],
    },
  ];

  return (
    <div className="sidebar">
      <PanelMenu model={items} />
    </div>
  );
};
```

---

### **Breadcrumb**

Fil d'Ariane pour la navigation.

**Fichier** : `components/layout/Breadcrumb.tsx`

```typescript
'use client';

import { BreadCrumb } from 'primereact/breadcrumb';
import { MenuItem } from 'primereact/menuitem';

interface BreadcrumbProps {
  items: MenuItem[];
}

export const AppBreadcrumb: React.FC<BreadcrumbProps> = ({ items }) => {
  const home = { icon: 'pi pi-home', url: '/dashboard' };

  return <BreadCrumb model={items} home={home} />;
};
```

**Utilisation** :
```typescript
const items = [
  { label: 'Chantiers', url: '/chantiers' },
  { label: 'Villa Moderne' },
];

<AppBreadcrumb items={items} />
```

---

## 📝 Composants Formulaires

### **ChantierForm**

Formulaire de création/modification de chantier.

**Fichier** : `components/forms/ChantierForm.tsx`

```typescript
'use client';

import { useForm, Controller } from 'react-hook-form';
import { InputText } from 'primereact/inputtext';
import { Dropdown } from 'primereact/dropdown';
import { Calendar } from 'primereact/calendar';
import { Button } from 'primereact/button';
import type { ChantierDTO } from '@/types/models/Chantier';

interface ChantierFormProps {
  chantier?: ChantierDTO;
  onSubmit: (data: ChantierDTO) => void;
  onCancel: () => void;
}

export const ChantierForm: React.FC<ChantierFormProps> = ({
  chantier,
  onSubmit,
  onCancel,
}) => {
  const { control, handleSubmit, formState: { errors } } = useForm<ChantierDTO>({
    defaultValues: chantier || {},
  });

  const statutOptions = [
    { label: 'Planifié', value: 'PLANIFIE' },
    { label: 'En cours', value: 'EN_COURS' },
    { label: 'Terminé', value: 'TERMINE' },
  ];

  return (
    <form onSubmit={handleSubmit(onSubmit)} className="p-fluid">
      <div className="field">
        <label htmlFor="nom">Nom *</label>
        <Controller
          name="nom"
          control={control}
          rules={{ required: 'Le nom est obligatoire' }}
          render={({ field }) => (
            <InputText
              id="nom"
              {...field}
              className={errors.nom ? 'p-invalid' : ''}
            />
          )}
        />
        {errors.nom && <small className="p-error">{errors.nom.message}</small>}
      </div>

      <div className="field">
        <label htmlFor="statut">Statut</label>
        <Controller
          name="statut"
          control={control}
          render={({ field }) => (
            <Dropdown
              id="statut"
              {...field}
              options={statutOptions}
              placeholder="Sélectionner un statut"
            />
          )}
        />
      </div>

      <div className="field">
        <label htmlFor="dateDebut">Date de début</label>
        <Controller
          name="dateDebut"
          control={control}
          render={({ field }) => (
            <Calendar
              id="dateDebut"
              {...field}
              dateFormat="dd/mm/yy"
              showIcon
            />
          )}
        />
      </div>

      <div className="flex gap-2 justify-content-end">
        <Button
          label="Annuler"
          icon="pi pi-times"
          className="p-button-text"
          onClick={onCancel}
          type="button"
        />
        <Button
          label="Enregistrer"
          icon="pi pi-check"
          type="submit"
        />
      </div>
    </form>
  );
};
```

---

## 📊 Composants Tableaux

### **DataTableWrapper**

Wrapper pour DataTable de PrimeReact avec fonctionnalités communes.

**Fichier** : `components/tables/DataTableWrapper.tsx`

```typescript
'use client';

import { DataTable } from 'primereact/datatable';
import { Column } from 'primereact/column';
import { Button } from 'primereact/button';

interface DataTableWrapperProps<T> {
  data: T[];
  columns: ColumnConfig[];
  onEdit?: (item: T) => void;
  onDelete?: (item: T) => void;
  loading?: boolean;
}

interface ColumnConfig {
  field: string;
  header: string;
  sortable?: boolean;
  body?: (rowData: any) => React.ReactNode;
}

export function DataTableWrapper<T>({
  data,
  columns,
  onEdit,
  onDelete,
  loading = false,
}: DataTableWrapperProps<T>) {
  const actionBodyTemplate = (rowData: T) => {
    return (
      <div className="flex gap-2">
        {onEdit && (
          <Button
            icon="pi pi-pencil"
            className="p-button-rounded p-button-text"
            onClick={() => onEdit(rowData)}
          />
        )}
        {onDelete && (
          <Button
            icon="pi pi-trash"
            className="p-button-rounded p-button-text p-button-danger"
            onClick={() => onDelete(rowData)}
          />
        )}
      </div>
    );
  };

  return (
    <DataTable
      value={data}
      paginator
      rows={10}
      loading={loading}
      emptyMessage="Aucune donnée disponible"
    >
      {columns.map((col) => (
        <Column
          key={col.field}
          field={col.field}
          header={col.header}
          sortable={col.sortable}
          body={col.body}
        />
      ))}
      {(onEdit || onDelete) && (
        <Column
          body={actionBodyTemplate}
          header="Actions"
          style={{ width: '10rem' }}
        />
      )}
    </DataTable>
  );
}
```

**Utilisation** :
```typescript
const columns = [
  { field: 'nom', header: 'Nom', sortable: true },
  { field: 'code', header: 'Code', sortable: true },
  { field: 'statut', header: 'Statut' },
];

<DataTableWrapper
  data={chantiers}
  columns={columns}
  onEdit={handleEdit}
  onDelete={handleDelete}
  loading={loading}
/>
```

---

## 📈 Composants Graphiques

### **ChartBar**

Graphique en barres avec Chart.js.

**Fichier** : `components/charts/ChartBar.tsx`

```typescript
'use client';

import { Chart } from 'primereact/chart';

interface ChartBarProps {
  data: {
    labels: string[];
    datasets: {
      label: string;
      data: number[];
      backgroundColor?: string;
    }[];
  };
  title?: string;
}

export const ChartBar: React.FC<ChartBarProps> = ({ data, title }) => {
  const options = {
    responsive: true,
    plugins: {
      legend: {
        position: 'top' as const,
      },
      title: {
        display: !!title,
        text: title,
      },
    },
  };

  return <Chart type="bar" data={data} options={options} />;
};
```

**Utilisation** :
```typescript
const data = {
  labels: ['Jan', 'Fév', 'Mar', 'Avr'],
  datasets: [
    {
      label: 'Chantiers',
      data: [12, 19, 8, 15],
      backgroundColor: 'rgba(54, 162, 235, 0.5)',
    },
  ],
};

<ChartBar data={data} title="Chantiers par mois" />
```

---

## 🔧 Composants Communs

### **LoadingSpinner**

Indicateur de chargement.

```typescript
'use client';

import { ProgressSpinner } from 'primereact/progressspinner';

export const LoadingSpinner = () => {
  return (
    <div className="flex justify-content-center align-items-center" style={{ height: '400px' }}>
      <ProgressSpinner />
    </div>
  );
};
```

### **ErrorMessage**

Message d'erreur.

```typescript
'use client';

import { Message } from 'primereact/message';

interface ErrorMessageProps {
  message: string;
}

export const ErrorMessage: React.FC<ErrorMessageProps> = ({ message }) => {
  return <Message severity="error" text={message} />;
};
```

---

## 🎨 PrimeReact

### **Composants utilisés**

| Composant | Usage |
|-----------|-------|
| **DataTable** | Tableaux de données |
| **Button** | Boutons |
| **InputText** | Champs texte |
| **Dropdown** | Listes déroulantes |
| **Calendar** | Sélecteur de date |
| **Dialog** | Modales |
| **Toast** | Notifications |
| **Chart** | Graphiques |
| **Menubar** | Menu principal |
| **PanelMenu** | Menu latéral |

### **Documentation**

https://primereact.org/

---

**Dernière mise à jour** : 2025-09-30  
**Version** : 1.0  
**Auteur** : Équipe BTPXpress

