Files
btpxpress-frontend/services/phaseTemplateService.ts
2025-10-13 05:29:32 +02:00

328 lines
11 KiB
TypeScript

/**
* Service pour la gestion des templates de phases BTP via l'API backend
* Remplace l'utilisation des données statiques par des appels API
*/
import { TypeChantier, PhaseTemplate, ChantierTemplate, TYPE_CHANTIER_LABELS, CATEGORIES_CHANTIER } from '../types/chantier-templates';
import { PhaseChantier } from '../types/btp-extended';
class PhaseTemplateService {
private apiBaseUrl = process.env.NEXT_PUBLIC_API_URL || 'http://localhost:8080/api/v1';
/**
* Récupérer la liste des types de chantiers disponibles depuis l'API
*/
async getAvailableChantierTypes(): Promise<{ value: TypeChantier; label: string; categorie: string }[]> {
try {
const response = await fetch(`${this.apiBaseUrl}/phase-templates/types-chantier`, {
headers: {
'Authorization': `Bearer ${localStorage.getItem('token')}`,
'Content-Type': 'application/json'
}
});
if (!response.ok) {
throw new Error('Erreur lors de la récupération des types de chantiers');
}
const typesFromAPI = await response.json();
// Mapper les types de l'API vers le format attendu par le frontend
const mappedTypes = typesFromAPI.map((type: any) => {
// Trouver la catégorie correspondante
let categorie = 'Autre';
for (const [cat, config] of Object.entries(CATEGORIES_CHANTIER)) {
if (config.types.includes(type as TypeChantier)) {
categorie = config.label;
break;
}
}
return {
value: type as TypeChantier,
label: TYPE_CHANTIER_LABELS[type as TypeChantier] || type,
categorie: categorie
};
});
return mappedTypes;
} catch (error) {
console.error('Erreur lors de la récupération des types de chantiers:', error);
// Fallback vers les données locales si l'API est indisponible
return this.getLocalChantierTypes();
}
}
/**
* Récupérer les templates de phases pour un type de chantier
*/
async getTemplatesByType(typeChantier: TypeChantier): Promise<PhaseTemplate[]> {
try {
const response = await fetch(`${this.apiBaseUrl}/phase-templates/by-type/${typeChantier}`, {
headers: {
'Authorization': `Bearer ${localStorage.getItem('token')}`,
'Content-Type': 'application/json'
}
});
if (!response.ok) {
throw new Error('Erreur lors de la récupération des templates');
}
const templates = await response.json();
return templates;
} catch (error) {
console.error('Erreur lors de la récupération des templates:', error);
throw error;
}
}
/**
* Récupérer un template par son ID avec ses sous-phases
*/
async getTemplateById(id: string): Promise<PhaseTemplate | null> {
try {
const response = await fetch(`${this.apiBaseUrl}/phase-templates/${id}`, {
headers: {
'Authorization': `Bearer ${localStorage.getItem('token')}`,
'Content-Type': 'application/json'
}
});
if (response.status === 404) {
return null;
}
if (!response.ok) {
throw new Error('Erreur lors de la récupération du template');
}
const template = await response.json();
return template;
} catch (error) {
console.error('Erreur lors de la récupération du template:', error);
throw error;
}
}
/**
* Prévisualiser les phases qui seraient générées pour un type de chantier
*/
async previewPhases(typeChantier: TypeChantier): Promise<PhaseTemplate[]> {
try {
const response = await fetch(`${this.apiBaseUrl}/phase-templates/previsualisation/${typeChantier}`, {
headers: {
'Authorization': `Bearer ${localStorage.getItem('token')}`,
'Content-Type': 'application/json'
}
});
if (!response.ok) {
throw new Error('Erreur lors de la prévisualisation des phases');
}
const phases = await response.json();
return phases;
} catch (error) {
console.error('Erreur lors de la prévisualisation des phases:', error);
throw error;
}
}
/**
* Calculer la durée totale estimée pour un type de chantier
*/
async calculateDureeTotale(typeChantier: TypeChantier): Promise<number> {
try {
const response = await fetch(`${this.apiBaseUrl}/phase-templates/duree-estimee/${typeChantier}`, {
headers: {
'Authorization': `Bearer ${localStorage.getItem('token')}`,
'Content-Type': 'application/json'
}
});
if (!response.ok) {
throw new Error('Erreur lors du calcul de la durée');
}
const duree = await response.json();
return duree;
} catch (error) {
console.error('Erreur lors du calcul de la durée:', error);
throw error;
}
}
/**
* Analyser la complexité d'un type de chantier
*/
async analyzeComplexity(typeChantier: TypeChantier): Promise<{
typeChantier: TypeChantier;
nombrePhases: number;
nombrePhasesCritiques: number;
dureeTotal: number;
niveauComplexite: string;
}> {
try {
const response = await fetch(`${this.apiBaseUrl}/phase-templates/complexite/${typeChantier}`, {
headers: {
'Authorization': `Bearer ${localStorage.getItem('token')}`,
'Content-Type': 'application/json'
}
});
if (!response.ok) {
throw new Error('Erreur lors de l\'analyse de complexité');
}
const complexite = await response.json();
return complexite;
} catch (error) {
console.error('Erreur lors de l\'analyse de complexité:', error);
throw error;
}
}
/**
* Générer automatiquement les phases pour un chantier
*/
async generatePhases(
chantierId: string,
dateDebutChantier: Date,
inclureSousPhases: boolean = true
): Promise<PhaseChantier[]> {
try {
const response = await fetch(`${this.apiBaseUrl}/phase-templates/generer-phases`, {
method: 'POST',
headers: {
'Authorization': `Bearer ${localStorage.getItem('token')}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
chantierId: chantierId,
dateDebutChantier: dateDebutChantier.toISOString().split('T')[0],
inclureSousPhases: inclureSousPhases
})
});
if (!response.ok) {
const error = await response.text();
throw new Error(error || 'Erreur lors de la génération des phases');
}
const phasesGenerees = await response.json();
return phasesGenerees;
} catch (error) {
console.error('Erreur lors de la génération des phases:', error);
throw error;
}
}
/**
* Créer un nouveau template de phase
*/
async createTemplate(template: Partial<PhaseTemplate>): Promise<PhaseTemplate> {
try {
const response = await fetch(`${this.apiBaseUrl}/phase-templates`, {
method: 'POST',
headers: {
'Authorization': `Bearer ${localStorage.getItem('token')}`,
'Content-Type': 'application/json'
},
body: JSON.stringify(template)
});
if (!response.ok) {
const error = await response.text();
throw new Error(error || 'Erreur lors de la création du template');
}
const nouveauTemplate = await response.json();
return nouveauTemplate;
} catch (error) {
console.error('Erreur lors de la création du template:', error);
throw error;
}
}
/**
* Mettre à jour un template de phase
*/
async updateTemplate(id: string, template: Partial<PhaseTemplate>): Promise<PhaseTemplate> {
try {
const response = await fetch(`${this.apiBaseUrl}/phase-templates/${id}`, {
method: 'PUT',
headers: {
'Authorization': `Bearer ${localStorage.getItem('token')}`,
'Content-Type': 'application/json'
},
body: JSON.stringify(template)
});
if (!response.ok) {
const error = await response.text();
throw new Error(error || 'Erreur lors de la mise à jour du template');
}
const templateMisAJour = await response.json();
return templateMisAJour;
} catch (error) {
console.error('Erreur lors de la mise à jour du template:', error);
throw error;
}
}
/**
* Supprimer (désactiver) un template de phase
*/
async deleteTemplate(id: string): Promise<void> {
try {
const response = await fetch(`${this.apiBaseUrl}/phase-templates/${id}`, {
method: 'DELETE',
headers: {
'Authorization': `Bearer ${localStorage.getItem('token')}`
}
});
if (!response.ok) {
const error = await response.text();
throw new Error(error || 'Erreur lors de la suppression du template');
}
} catch (error) {
console.error('Erreur lors de la suppression du template:', error);
throw error;
}
}
/**
* Fallback: Récupérer les types de chantiers depuis les données locales
*/
private getLocalChantierTypes(): { value: TypeChantier; label: string; categorie: string }[] {
const types: { value: TypeChantier; label: string; categorie: string }[] = [];
for (const [categorie, config] of Object.entries(CATEGORIES_CHANTIER)) {
for (const type of config.types) {
types.push({
value: type,
label: TYPE_CHANTIER_LABELS[type],
categorie: config.label
});
}
}
return types;
}
}
export default new PhaseTemplateService();