Initial commit
This commit is contained in:
491
hooks/useBTPServices.ts
Normal file
491
hooks/useBTPServices.ts
Normal file
@@ -0,0 +1,491 @@
|
||||
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<void>;
|
||||
rechercher: (criteres: RechercheMaterielParams) => Promise<MaterielBTP[]>;
|
||||
obtenirParCode: (code: string) => Promise<MaterielBTP>;
|
||||
obtenirParCategorie: (categorie: CategorieMateriel) => Promise<MaterielBTP[]>;
|
||||
validerPourZone: (codeMateriel: string, zoneCode: string) => Promise<any>;
|
||||
obtenirAlternatives: (codeMateriel: string, zoneCode?: string) => Promise<MaterielBTP[]>;
|
||||
};
|
||||
|
||||
// Actions zones climatiques
|
||||
zones: {
|
||||
charger: () => Promise<void>;
|
||||
rechercher: (criteres: CriteresRecherche) => Promise<ZoneClimatique[]>;
|
||||
obtenirParCode: (code: string) => Promise<ZoneClimatique>;
|
||||
obtenirMeilleureAdaptation: (temp: number, humidite: number, vents: number) => Promise<ZoneClimatique | null>;
|
||||
obtenirRecommandations: (zoneCode: string) => Promise<any>;
|
||||
simulerImpact: (zoneCode: string, parametres: any) => Promise<any>;
|
||||
};
|
||||
|
||||
// Actions calculs techniques
|
||||
calculs: {
|
||||
calculerBriques: (params: ParametresCalculBriques) => Promise<ResultatCalculBriques>;
|
||||
calculerBetonArme: (params: ParametresCalculBetonArme) => Promise<ResultatCalculBetonArme>;
|
||||
obtenirDosagesBeton: () => Promise<any>;
|
||||
estimationRapideBriques: (surface: number, typeBrique?: string) => Promise<any>;
|
||||
estimationRapideBeton: (volume: number, classeBeton?: string) => Promise<any>;
|
||||
genererDevis: (calculs: any, options?: any) => Promise<any>;
|
||||
};
|
||||
|
||||
// Actions export
|
||||
export: {
|
||||
exporterMateriaux: (options: OptionsExport & { filtres?: RechercheMaterielParams }) => Promise<void>;
|
||||
exporterZones: (options: OptionsExport) => Promise<void>;
|
||||
exporterCalculs: (calculs: any[], options: OptionsExport) => Promise<void>;
|
||||
genererDevis: (devisData: any, format?: FormatExport) => Promise<void>;
|
||||
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<MaterielBTP[]> => {
|
||||
try {
|
||||
return await MaterielBTPService.rechercherMateriaux(criteres);
|
||||
} catch (error) {
|
||||
handleError('materiaux', error);
|
||||
return [];
|
||||
}
|
||||
}, [handleError]);
|
||||
|
||||
const obtenirMaterielParCode = useCallback(async (code: string): Promise<MaterielBTP> => {
|
||||
try {
|
||||
return await MaterielBTPService.getMaterielByCode(code);
|
||||
} catch (error) {
|
||||
handleError('materiaux', error);
|
||||
throw error;
|
||||
}
|
||||
}, [handleError]);
|
||||
|
||||
const obtenirMateriauxParCategorie = useCallback(async (categorie: CategorieMateriel): Promise<MaterielBTP[]> => {
|
||||
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<MaterielBTP[]> => {
|
||||
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<ZoneClimatique[]> => {
|
||||
try {
|
||||
return await ZoneClimatiqueService.rechercherZones(criteres);
|
||||
} catch (error) {
|
||||
handleError('zones', error);
|
||||
return [];
|
||||
}
|
||||
}, [handleError]);
|
||||
|
||||
const obtenirZoneParCode = useCallback(async (code: string): Promise<ZoneClimatique> => {
|
||||
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<ResultatCalculBriques> => {
|
||||
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<ResultatCalculBetonArme> => {
|
||||
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
|
||||
}
|
||||
};
|
||||
};
|
||||
Reference in New Issue
Block a user