# 🛠️ GUIDE DE DÉVELOPPEMENT - BTPXPRESS FRONTEND

## 📋 Table des matières

- [Prérequis](#prérequis)
- [Installation](#installation)
- [Configuration](#configuration)
- [Structure du projet](#structure-du-projet)
- [Conventions de code](#conventions-de-code)
- [Workflow de développement](#workflow-de-développement)
- [Composants](#composants)
- [Services API](#services-api)
- [Gestion de l'état](#gestion-de-létat)
- [Routing](#routing)
- [Styling](#styling)
- [Debugging](#debugging)
- [Bonnes pratiques](#bonnes-pratiques)

---

## 🔧 Prérequis

### **Logiciels requis**

| Logiciel | Version | Vérification |
|----------|---------|--------------|
| **Node.js** | 20.x LTS | `node --version` |
| **npm** | 10.x | `npm --version` |
| **VS Code** | Latest | Recommandé |

### **Extensions VS Code recommandées**

- **ES7+ React/Redux/React-Native snippets**
- **Prettier - Code formatter**
- **ESLint**
- **TypeScript Vue Plugin (Volar)**
- **Tailwind CSS IntelliSense**
- **Auto Rename Tag**
- **Path Intellisense**

---

## 📦 Installation

### **1. Cloner et installer**

```bash
cd btpxpress/btpxpress-client
npm install
```

### **2. Configurer les variables d'environnement**

Créer `.env.local` :

```bash
NEXT_PUBLIC_API_URL=http://localhost:8080/api/v1
NEXT_PUBLIC_KEYCLOAK_URL=http://localhost:8180
NEXT_PUBLIC_KEYCLOAK_REALM=btpxpress
NEXT_PUBLIC_KEYCLOAK_CLIENT_ID=btpxpress-frontend
```

### **3. Lancer le serveur de développement**

```bash
npm run dev
```

Ouvrir http://localhost:3000

---

## ⚙️ Configuration

### **next.config.js**

```javascript
/** @type {import('next').NextConfig} */
const nextConfig = {
  reactStrictMode: true,
  swcMinify: true,
  images: {
    domains: ['localhost'],
  },
  env: {
    API_URL: process.env.NEXT_PUBLIC_API_URL,
  },
}

module.exports = nextConfig
```

### **tsconfig.json**

```json
{
  "compilerOptions": {
    "target": "ES2020",
    "lib": ["dom", "dom.iterable", "esnext"],
    "allowJs": true,
    "skipLibCheck": true,
    "strict": true,
    "forceConsistentCasingInFileNames": true,
    "noEmit": true,
    "esModuleInterop": true,
    "module": "esnext",
    "moduleResolution": "bundler",
    "resolveJsonModule": true,
    "isolatedModules": true,
    "jsx": "preserve",
    "incremental": true,
    "paths": {
      "@/*": ["./*"],
      "@/components/*": ["./components/*"],
      "@/services/*": ["./services/*"],
      "@/types/*": ["./types/*"],
      "@/hooks/*": ["./hooks/*"]
    }
  },
  "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"],
  "exclude": ["node_modules"]
}
```

---

## 📁 Structure du projet

```
btpxpress-client/
├── app/                          # App Router (Next.js 15)
│   ├── (auth)/                   # Groupe de routes authentifiées
│   │   ├── layout.tsx            # Layout avec sidebar
│   │   ├── dashboard/
│   │   │   └── page.tsx          # /dashboard
│   │   ├── chantiers/
│   │   │   ├── page.tsx          # /chantiers (liste)
│   │   │   ├── [id]/
│   │   │   │   └── page.tsx      # /chantiers/[id] (détails)
│   │   │   └── nouveau/
│   │   │       └── page.tsx      # /chantiers/nouveau
│   │   └── ...
│   ├── login/
│   │   └── page.tsx              # /login
│   ├── layout.tsx                # Layout racine
│   ├── page.tsx                  # / (accueil)
│   └── globals.css               # Styles globaux
├── components/
│   ├── layout/
│   │   ├── Header.tsx
│   │   ├── Sidebar.tsx
│   │   └── Footer.tsx
│   ├── forms/
│   │   ├── ChantierForm.tsx
│   │   └── ClientForm.tsx
│   ├── tables/
│   │   └── DataTableWrapper.tsx
│   └── common/
│       ├── LoadingSpinner.tsx
│       └── ErrorMessage.tsx
├── services/
│   ├── api/
│   │   ├── chantierService.ts
│   │   ├── clientService.ts
│   │   └── apiClient.ts
│   ├── auth/
│   │   └── keycloakService.ts
│   └── utils/
│       └── formatters.ts
├── types/
│   ├── models/
│   │   ├── Chantier.ts
│   │   └── Client.ts
│   └── api/
│       └── responses.ts
├── hooks/
│   ├── useAuth.ts
│   ├── useChantiers.ts
│   └── useToast.ts
├── contexts/
│   ├── AuthContext.tsx
│   └── ThemeContext.tsx
└── public/
    ├── images/
    └── icons/
```

---

## 📝 Conventions de code

### **Nommage**

| Élément | Convention | Exemple |
|---------|------------|---------|
| **Composants** | PascalCase | `ChantierForm.tsx` |
| **Fichiers** | PascalCase (composants), camelCase (autres) | `Header.tsx`, `apiClient.ts` |
| **Variables** | camelCase | `const userName = ...` |
| **Constantes** | UPPER_SNAKE_CASE | `const API_URL = ...` |
| **Types/Interfaces** | PascalCase | `interface ChantierDTO` |
| **Hooks** | camelCase avec `use` | `useAuth()` |

### **Structure d'un composant**

```typescript
'use client'; // Si nécessaire (composant client)

import React from 'react';
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,
}) => {
  // Hooks
  const [loading, setLoading] = React.useState(false);

  // Handlers
  const handleSubmit = async (e: React.FormEvent) => {
    e.preventDefault();
    setLoading(true);
    // ...
  };

  // Render
  return (
    <form onSubmit={handleSubmit}>
      {/* JSX */}
    </form>
  );
};
```

---

## 🔄 Workflow de développement

### **1. Créer une branche**

```bash
git checkout -b feature/nom-de-la-fonctionnalite
```

### **2. Développer**

1. Créer le type TypeScript (`types/models/`)
2. Créer le service API (`services/api/`)
3. Créer le composant (`components/`)
4. Créer la page (`app/`)
5. Tester

### **3. Tester localement**

```bash
npm run dev
npm run lint
npm test
```

### **4. Commit et Push**

```bash
git add .
git commit -m "feat: ajout de la fonctionnalité X"
git push origin feature/nom-de-la-fonctionnalite
```

---

## 🧩 Composants

### **Composant fonctionnel avec TypeScript**

```typescript
import React from 'react';

interface Props {
  title: string;
  count: number;
  onIncrement: () => void;
}

export const Counter: React.FC<Props> = ({ title, count, onIncrement }) => {
  return (
    <div>
      <h2>{title}</h2>
      <p>Count: {count}</p>
      <button onClick={onIncrement}>Increment</button>
    </div>
  );
};
```

### **Composant avec PrimeReact**

```typescript
'use client';

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

export const ChantierTable = ({ chantiers }) => {
  const actionBodyTemplate = (rowData) => {
    return (
      <Button
        icon="pi pi-pencil"
        className="p-button-rounded p-button-text"
        onClick={() => handleEdit(rowData)}
      />
    );
  };

  return (
    <DataTable value={chantiers} paginator rows={10}>
      <Column field="nom" header="Nom" sortable />
      <Column field="code" header="Code" sortable />
      <Column field="statut" header="Statut" />
      <Column body={actionBodyTemplate} header="Actions" />
    </DataTable>
  );
};
```

---

## 🔌 Services API

### **Client API de base**

```typescript
// services/api/apiClient.ts
import axios from 'axios';

const apiClient = axios.create({
  baseURL: process.env.NEXT_PUBLIC_API_URL,
  headers: {
    'Content-Type': 'application/json',
  },
});

// Intercepteur pour ajouter le token
apiClient.interceptors.request.use((config) => {
  const token = localStorage.getItem('token');
  if (token) {
    config.headers.Authorization = `Bearer ${token}`;
  }
  return config;
});

export default apiClient;
```

### **Service spécifique**

```typescript
// services/api/chantierService.ts
import apiClient from './apiClient';
import type { ChantierDTO } from '@/types/models/Chantier';

export const chantierService = {
  getAll: async (): Promise<ChantierDTO[]> => {
    const response = await apiClient.get('/chantiers');
    return response.data;
  },

  getById: async (id: string): Promise<ChantierDTO> => {
    const response = await apiClient.get(`/chantiers/${id}`);
    return response.data;
  },

  create: async (data: ChantierDTO): Promise<ChantierDTO> => {
    const response = await apiClient.post('/chantiers', data);
    return response.data;
  },

  update: async (id: string, data: ChantierDTO): Promise<ChantierDTO> => {
    const response = await apiClient.put(`/chantiers/${id}`, data);
    return response.data;
  },

  delete: async (id: string): Promise<void> => {
    await apiClient.delete(`/chantiers/${id}`);
  },
};
```

---

## 🎨 Styling

### **PrimeReact Theme**

```typescript
// app/layout.tsx
import 'primereact/resources/themes/lara-light-blue/theme.css';
import 'primereact/resources/primereact.min.css';
import 'primeicons/primeicons.css';
```

### **CSS Modules**

```typescript
// components/Header.module.css
.header {
  background-color: #fff;
  padding: 1rem;
}

// components/Header.tsx
import styles from './Header.module.css';

export const Header = () => {
  return <header className={styles.header}>...</header>;
};
```

---

## 🐛 Debugging

### **React DevTools**

Installer l'extension Chrome/Firefox : React Developer Tools

### **Console logs**

```typescript
console.log('Debug:', data);
console.error('Error:', error);
console.table(array);
```

### **Debugger**

```typescript
const handleClick = () => {
  debugger; // Point d'arrêt
  // ...
};
```

---

## ✅ Bonnes pratiques

### **1. Typage strict**

```typescript
// ❌ Mauvais
const data: any = ...

// ✅ Bon
const data: ChantierDTO = ...
```

### **2. Gestion des erreurs**

```typescript
try {
  const data = await chantierService.getAll();
  setChantiers(data);
} catch (error) {
  console.error('Erreur:', error);
  toast.current?.show({
    severity: 'error',
    summary: 'Erreur',
    detail: 'Impossible de charger les chantiers',
  });
}
```

### **3. Loading states**

```typescript
const [loading, setLoading] = useState(false);

const loadData = async () => {
  setLoading(true);
  try {
    const data = await service.getData();
    setData(data);
  } finally {
    setLoading(false);
  }
};
```

---

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

