import { useState, useEffect, useCallback } from 'react'; import { MaterielBTPService, MaterielBTP, CategorieMateriel, RechercheMaterielParams } from '../services/materielBTPService'; import { ZoneClimatiqueService, ZoneClimatique, CriteresRecherche } from '../services/zoneClimatiqueService'; import { CalculsTechniquesService, ParametresCalculBriques, ResultatCalculBriques, ParametresCalculBetonArme, ResultatCalculBetonArme } from '../services/calculsTechniquesService'; import { ExportBTPService, FormatExport, OptionsExport, ResultatExport } from '../services/exportBTPService'; /** * Hook personnalisé pour l'utilisation des services BTP ultra-détaillés * Système le plus ambitieux d'Afrique pour la gestion BTP */ export interface UseBTPServicesReturn { // États de chargement loading: { materiaux: boolean; zones: boolean; calculs: boolean; export: boolean; }; // États d'erreur errors: { materiaux: string | null; zones: string | null; calculs: string | null; export: string | null; }; // Données data: { materiaux: MaterielBTP[]; zones: ZoneClimatique[]; dernierCalcul: any; dernierExport: ResultatExport | null; }; // Actions matériaux materiaux: { charger: (params?: RechercheMaterielParams) => Promise; rechercher: (criteres: RechercheMaterielParams) => Promise; obtenirParCode: (code: string) => Promise; obtenirParCategorie: (categorie: CategorieMateriel) => Promise; validerPourZone: (codeMateriel: string, zoneCode: string) => Promise; obtenirAlternatives: (codeMateriel: string, zoneCode?: string) => Promise; }; // Actions zones climatiques zones: { charger: () => Promise; rechercher: (criteres: CriteresRecherche) => Promise; obtenirParCode: (code: string) => Promise; obtenirMeilleureAdaptation: (temp: number, humidite: number, vents: number) => Promise; obtenirRecommandations: (zoneCode: string) => Promise; simulerImpact: (zoneCode: string, parametres: any) => Promise; }; // Actions calculs techniques calculs: { calculerBriques: (params: ParametresCalculBriques) => Promise; calculerBetonArme: (params: ParametresCalculBetonArme) => Promise; obtenirDosagesBeton: () => Promise; estimationRapideBriques: (surface: number, typeBrique?: string) => Promise; estimationRapideBeton: (volume: number, classeBeton?: string) => Promise; genererDevis: (calculs: any, options?: any) => Promise; }; // Actions export export: { exporterMateriaux: (options: OptionsExport & { filtres?: RechercheMaterielParams }) => Promise; exporterZones: (options: OptionsExport) => Promise; exporterCalculs: (calculs: any[], options: OptionsExport) => Promise; genererDevis: (devisData: any, format?: FormatExport) => Promise; telechargerDernier: () => void; }; // Utilitaires utils: { reinitialiser: () => void; obtenirStatistiques: () => any; validerParametres: (type: string, params: any) => any; }; } export const useBTPServices = (): UseBTPServicesReturn => { // États de chargement const [loading, setLoading] = useState({ materiaux: false, zones: false, calculs: false, export: false }); // États d'erreur const [errors, setErrors] = useState({ materiaux: null as string | null, zones: null as string | null, calculs: null as string | null, export: null as string | null }); // Données const [data, setData] = useState({ materiaux: [] as MaterielBTP[], zones: [] as ZoneClimatique[], dernierCalcul: null as any, dernierExport: null as ResultatExport | null }); // =================== FONCTIONS UTILITAIRES =================== const setLoadingState = useCallback((key: keyof typeof loading, value: boolean) => { setLoading(prev => ({ ...prev, [key]: value })); }, []); const setErrorState = useCallback((key: keyof typeof errors, error: string | null) => { setErrors(prev => ({ ...prev, [key]: error })); }, []); const handleError = useCallback((key: keyof typeof errors, error: any) => { const message = error?.message || error?.toString() || 'Une erreur est survenue'; setErrorState(key, message); console.error(`Erreur ${key}:`, error); }, [setErrorState]); // =================== ACTIONS MATÉRIAUX =================== const chargerMateriaux = useCallback(async (params?: RechercheMaterielParams) => { setLoadingState('materiaux', true); setErrorState('materiaux', null); try { const response = await MaterielBTPService.getMateriaux(params); setData(prev => ({ ...prev, materiaux: response.materiaux })); } catch (error) { handleError('materiaux', error); } finally { setLoadingState('materiaux', false); } }, [setLoadingState, setErrorState, handleError]); const rechercherMateriaux = useCallback(async (criteres: RechercheMaterielParams): Promise => { try { return await MaterielBTPService.rechercherMateriaux(criteres); } catch (error) { handleError('materiaux', error); return []; } }, [handleError]); const obtenirMaterielParCode = useCallback(async (code: string): Promise => { try { return await MaterielBTPService.getMaterielByCode(code); } catch (error) { handleError('materiaux', error); throw error; } }, [handleError]); const obtenirMateriauxParCategorie = useCallback(async (categorie: CategorieMateriel): Promise => { try { return await MaterielBTPService.getMateriauxByCategorie(categorie); } catch (error) { handleError('materiaux', error); return []; } }, [handleError]); const validerMaterielPourZone = useCallback(async (codeMateriel: string, zoneCode: string) => { try { return await MaterielBTPService.validerMaterielPourZone(codeMateriel, zoneCode); } catch (error) { handleError('materiaux', error); return { adapte: false, warnings: ['Validation impossible'], recommendations: [] }; } }, [handleError]); const obtenirAlternativesMateriel = useCallback(async (codeMateriel: string, zoneCode?: string): Promise => { try { return await MaterielBTPService.getAlternativesMateriel(codeMateriel, zoneCode); } catch (error) { handleError('materiaux', error); return []; } }, [handleError]); // =================== ACTIONS ZONES CLIMATIQUES =================== const chargerZones = useCallback(async () => { setLoadingState('zones', true); setErrorState('zones', null); try { const response = await ZoneClimatiqueService.getZonesClimatiques(); setData(prev => ({ ...prev, zones: response.zones })); } catch (error) { handleError('zones', error); } finally { setLoadingState('zones', false); } }, [setLoadingState, setErrorState, handleError]); const rechercherZones = useCallback(async (criteres: CriteresRecherche): Promise => { try { return await ZoneClimatiqueService.rechercherZones(criteres); } catch (error) { handleError('zones', error); return []; } }, [handleError]); const obtenirZoneParCode = useCallback(async (code: string): Promise => { try { return await ZoneClimatiqueService.getZoneByCode(code); } catch (error) { handleError('zones', error); throw error; } }, [handleError]); const obtenirMeilleureAdaptation = useCallback(async (temp: number, humidite: number, vents: number) => { try { return await ZoneClimatiqueService.getMeilleureAdaptation(temp, humidite, vents); } catch (error) { handleError('zones', error); return null; } }, [handleError]); const obtenirRecommandationsZone = useCallback(async (zoneCode: string) => { try { return await ZoneClimatiqueService.getRecommandationsConstruction(zoneCode); } catch (error) { handleError('zones', error); return { fondations: [], structure: [], enveloppe: [], finitions: [], equipements: [] }; } }, [handleError]); const simulerImpactClimatique = useCallback(async (zoneCode: string, parametres: any) => { try { return await ZoneClimatiqueService.simulerImpactClimatique(zoneCode, parametres); } catch (error) { handleError('zones', error); return null; } }, [handleError]); // =================== ACTIONS CALCULS TECHNIQUES =================== const calculerBriquesMur = useCallback(async (params: ParametresCalculBriques): Promise => { setLoadingState('calculs', true); setErrorState('calculs', null); try { const resultat = await CalculsTechniquesService.calculerBriquesMur(params); setData(prev => ({ ...prev, dernierCalcul: { type: 'BRIQUES', resultat, params } })); return resultat; } catch (error) { handleError('calculs', error); throw error; } finally { setLoadingState('calculs', false); } }, [setLoadingState, setErrorState, handleError]); const calculerBetonArme = useCallback(async (params: ParametresCalculBetonArme): Promise => { setLoadingState('calculs', true); setErrorState('calculs', null); try { const resultat = await CalculsTechniquesService.calculerBetonArme(params); setData(prev => ({ ...prev, dernierCalcul: { type: 'BETON', resultat, params } })); return resultat; } catch (error) { handleError('calculs', error); throw error; } finally { setLoadingState('calculs', false); } }, [setLoadingState, setErrorState, handleError]); const obtenirDosagesBeton = useCallback(async () => { try { return await CalculsTechniquesService.getDosagesBeton(); } catch (error) { handleError('calculs', error); return { dosages: {}, notes: [] }; } }, [handleError]); const estimationRapideBriques = useCallback(async (surface: number, typeBrique?: string) => { try { return await CalculsTechniquesService.estimationRapideBriques(surface, typeBrique); } catch (error) { handleError('calculs', error); return { estimationBasse: 0, estimationHaute: 0, estimationMoyenne: 0, baseCalcul: '' }; } }, [handleError]); const estimationRapideBeton = useCallback(async (volume: number, classeBeton?: string) => { try { return await CalculsTechniquesService.estimationRapideBeton(volume, classeBeton); } catch (error) { handleError('calculs', error); return { cimentSacs: 0, sableM3: 0, graviersM3: 0, eauLitres: 0, coutEstime: 0 }; } }, [handleError]); const genererDevis = useCallback(async (calculs: any, options?: any) => { try { return await CalculsTechniquesService.genererDevis(calculs, options); } catch (error) { handleError('calculs', error); return { lignesDevis: [], totalHT: 0, totalTTC: 0, delaiExecution: 0 }; } }, [handleError]); // =================== ACTIONS EXPORT =================== const exporterMateriaux = useCallback(async (options: OptionsExport & { filtres?: RechercheMaterielParams }) => { setLoadingState('export', true); setErrorState('export', null); try { const resultat = await ExportBTPService.exporterMateriaux(options); setData(prev => ({ ...prev, dernierExport: resultat })); ExportBTPService.telechargerFichier(resultat); } catch (error) { handleError('export', error); } finally { setLoadingState('export', false); } }, [setLoadingState, setErrorState, handleError]); const exporterZones = useCallback(async (options: OptionsExport) => { setLoadingState('export', true); setErrorState('export', null); try { const resultat = await ExportBTPService.exporterZonesClimatiques(options); setData(prev => ({ ...prev, dernierExport: resultat })); ExportBTPService.telechargerFichier(resultat); } catch (error) { handleError('export', error); } finally { setLoadingState('export', false); } }, [setLoadingState, setErrorState, handleError]); const exporterCalculs = useCallback(async (calculs: any[], options: OptionsExport) => { setLoadingState('export', true); setErrorState('export', null); try { const resultat = await ExportBTPService.exporterCalculs(calculs, options); setData(prev => ({ ...prev, dernierExport: resultat })); ExportBTPService.telechargerFichier(resultat); } catch (error) { handleError('export', error); } finally { setLoadingState('export', false); } }, [setLoadingState, setErrorState, handleError]); const genererDevisBTP = useCallback(async (devisData: any, format: FormatExport = 'PDF') => { setLoadingState('export', true); setErrorState('export', null); try { const resultat = await ExportBTPService.genererDevisBTP(devisData, format); setData(prev => ({ ...prev, dernierExport: resultat })); ExportBTPService.telechargerFichier(resultat); } catch (error) { handleError('export', error); } finally { setLoadingState('export', false); } }, [setLoadingState, setErrorState, handleError]); const telechargerDernierExport = useCallback(() => { if (data.dernierExport) { ExportBTPService.telechargerFichier(data.dernierExport); } }, [data.dernierExport]); // =================== UTILITAIRES =================== const reinitialiser = useCallback(() => { setData({ materiaux: [], zones: [], dernierCalcul: null, dernierExport: null }); setErrors({ materiaux: null, zones: null, calculs: null, export: null }); }, []); const obtenirStatistiques = useCallback(() => { return { nbMateriaux: data.materiaux.length, nbZones: data.zones.length, categoriesMateriaux: [...new Set(data.materiaux.map(m => m.categorie))], derniereActivite: data.dernierCalcul ? new Date(data.dernierCalcul.date || Date.now()) : null, tailleDernierExport: data.dernierExport?.size || 0 }; }, [data]); const validerParametres = useCallback((type: string, params: any) => { return CalculsTechniquesService.validerParametres(type as any, params); }, []); // =================== CHARGEMENT INITIAL =================== useEffect(() => { // Chargement automatique des données de base chargerZones(); }, [chargerZones]); // =================== RETURN =================== return { loading, errors, data, materiaux: { charger: chargerMateriaux, rechercher: rechercherMateriaux, obtenirParCode: obtenirMaterielParCode, obtenirParCategorie: obtenirMateriauxParCategorie, validerPourZone: validerMaterielPourZone, obtenirAlternatives: obtenirAlternativesMateriel }, zones: { charger: chargerZones, rechercher: rechercherZones, obtenirParCode: obtenirZoneParCode, obtenirMeilleureAdaptation, obtenirRecommandations: obtenirRecommandationsZone, simulerImpact: simulerImpactClimatique }, calculs: { calculerBriques: calculerBriquesMur, calculerBetonArme, obtenirDosagesBeton, estimationRapideBriques, estimationRapideBeton, genererDevis }, export: { exporterMateriaux, exporterZones, exporterCalculs, genererDevis: genererDevisBTP, telechargerDernier: telechargerDernierExport }, utils: { reinitialiser, obtenirStatistiques, validerParametres } }; };