Files
btpxpress-frontend/services/api.ts

995 lines
37 KiB
TypeScript

/**
* Services API pour BTP Xpress
*/
import axios, { AxiosInstance, AxiosResponse } from 'axios';
import { API_CONFIG } from '../config/api';
import keycloak from '../lib/keycloak';
import { CacheService, CacheKeys } from './cacheService';
import {
Client,
Chantier,
Devis,
Facture,
DashboardStats,
ChantierRecent,
FactureEnRetard,
DevisEnAttente,
FilterOptions,
SearchResult,
Employe,
Equipe,
Materiel,
MaintenanceMateriel,
PlanningEvent,
PlanningCalendrierView,
PlanningConflict,
PlanningStats
} from '../types/btp';
import { UserInfo } from '../types/auth';
class ApiService {
private api: AxiosInstance;
private serverStatusListeners: ((isOnline: boolean) => void)[] = [];
constructor() {
this.api = axios.create({
baseURL: API_CONFIG.baseURL,
timeout: API_CONFIG.timeout,
headers: API_CONFIG.headers,
});
// Interceptor pour les requêtes
this.api.interceptors.request.use(
async (config) => {
console.log('🔐 API Request:', config.url);
// Vérifier si Keycloak est initialisé et l'utilisateur authentifié
if (keycloak && keycloak.authenticated && keycloak.token) {
try {
// Rafraîchir le token si nécessaire (70 secondes avant expiration)
await keycloak.updateToken(70);
// Ajouter le token Bearer à l'en-tête Authorization
config.headers['Authorization'] = `Bearer ${keycloak.token}`;
console.log('✅ Token ajouté à la requête');
} catch (error) {
console.error('❌ Erreur lors de la mise à jour du token Keycloak:', error);
// En cas d'erreur, rediriger vers la page de connexion
keycloak.login();
throw error;
}
} else {
console.warn('⚠️ Keycloak non authentifié, requête sans token');
}
// Ajouter des en-têtes par défaut
config.headers['X-Requested-With'] = 'XMLHttpRequest';
return config;
},
(error) => {
return Promise.reject(error);
}
);
// Interceptor pour les réponses
this.api.interceptors.response.use(
(response: AxiosResponse) => response,
async (error) => {
// Ne pas logger les 404 sur les endpoints de chantiers par client (pas encore implémentés)
const is404OnChantiersByClient = error.response?.status === 404 &&
error.config?.url?.includes('/chantiers/client/');
if (!is404OnChantiersByClient) {
// Utiliser console.warn au lieu de console.error pour éviter les erreurs React DevTools
console.warn('API Error:', error.response?.status, error.response?.data || error.message);
}
// Gérer les erreurs de connexion réseau
if (!error.response) {
// Erreur réseau (serveur indisponible, pas de connexion, etc.)
if (error.code === 'ECONNABORTED') {
error.userMessage = 'Délai d\'attente dépassé. Le serveur backend met trop de temps à répondre.';
error.statusCode = 'TIMEOUT';
} else if (error.code === 'ERR_NETWORK') {
error.userMessage = 'Impossible de joindre le serveur backend. Vérifiez votre connexion internet et que le serveur backend est démarré (mvn quarkus:dev).';
error.statusCode = 'NETWORK_ERROR';
} else {
error.userMessage = 'Serveur backend indisponible. Vérifiez que le serveur backend est démarré (mvn quarkus:dev) et accessible sur le port 8080.';
error.statusCode = 'SERVER_UNAVAILABLE';
}
// Émettre un événement global pour notifier l'application
this.notifyServerStatus(false);
return Promise.reject(error);
}
// Serveur répond, donc il est disponible
this.notifyServerStatus(true);
if (error.response?.status === 401) {
// Gestion des erreurs d'authentification (token expiré ou absent)
if (typeof window !== 'undefined') {
const currentUrl = window.location.href;
const hasAuthCode = currentUrl.includes('code=') && currentUrl.includes('/dashboard');
if (!hasAuthCode) {
console.log('🔄 Token expiré ou absent, redirection vers Keycloak...');
// Essayer de rafraîchir le token Keycloak
if (keycloak && keycloak.authenticated) {
try {
await keycloak.updateToken(-1); // Force refresh
// Retry the original request
return this.api.request(error.config);
} catch (refreshError) {
console.error('❌ Impossible de rafraîchir le token, reconnexion requise');
// Sauvegarder la page actuelle pour y revenir après reconnexion
const currentPath = window.location.pathname + window.location.search;
sessionStorage.setItem('returnUrl', currentPath);
// Rediriger vers Keycloak pour authentification
keycloak.login();
}
} else {
// Pas authentifié, rediriger vers Keycloak
console.log('❌ Non authentifié, redirection vers Keycloak...');
if (keycloak) {
keycloak.login();
}
}
} else {
console.log('🔄 API Service: Erreur 401 ignorée car authentification en cours...');
}
}
}
// Créer une erreur plus propre pour l'affichage
const errorMessage = error.response?.data?.message ||
error.response?.data?.error ||
error.message ||
'Une erreur est survenue';
const enhancedError = {
...error,
userMessage: errorMessage,
statusCode: error.response?.status
};
return Promise.reject(enhancedError);
}
);
}
// === GESTION STATUT SERVEUR ===
private notifyServerStatus(isOnline: boolean) {
this.serverStatusListeners.forEach(listener => {
try {
listener(isOnline);
} catch (error) {
console.error('Erreur dans listener de statut serveur:', error);
}
});
}
public onServerStatusChange(callback: (isOnline: boolean) => void) {
this.serverStatusListeners.push(callback);
return () => {
const index = this.serverStatusListeners.indexOf(callback);
if (index > -1) {
this.serverStatusListeners.splice(index, 1);
}
};
}
public async checkServerHealth(urgentCheck: boolean = false): Promise<boolean> {
const timeout = urgentCheck ? 3000 : 8000; // Timeout plus long pour checks de routine
try {
// Endpoint dédié health check ultra-léger
await this.api.get('/api/v1/health', {
timeout,
headers: { 'Cache-Control': 'no-cache' },
params: { _t: Date.now() } // Cache busting
});
this.notifyServerStatus(true);
return true;
} catch (error) {
// Fallback sur endpoint Quarkus standard puis clients
try {
await this.api.get('/q/health', { timeout: timeout * 0.8 });
this.notifyServerStatus(true);
return true;
} catch (secondError) {
try {
await this.api.get('/api/v1/clients', {
timeout: timeout * 0.6,
params: { size: 1 }
});
this.notifyServerStatus(true);
return true;
} catch (thirdError) {
this.notifyServerStatus(false);
return false;
}
}
}
}
// === CLIENTS ===
async getClients(): Promise<Client[]> {
return CacheService.getOrSet(
CacheKeys.CLIENTS,
async () => {
const response = await this.api.get<Client[]>('/api/v1/clients');
return Array.isArray(response.data) ? response.data : [];
},
5 * 60 * 1000 // 5 minutes
);
}
async getClient(id: string): Promise<Client> {
const response = await this.api.get<Client>(`/api/v1/clients/${id}`);
return response.data;
}
async createClient(client: Partial<Client>): Promise<Client> {
const response = await this.api.post<Client>('/api/v1/clients', client);
return response.data;
}
async updateClient(id: string, client: Partial<Client>): Promise<Client> {
const response = await this.api.put<Client>(`/api/v1/clients/${id}`, client);
return response.data;
}
async deleteClient(id: string): Promise<void> {
await this.api.delete(`/api/v1/clients/${id}`);
}
async searchClients(params: {
nom?: string;
entreprise?: string;
ville?: string;
email?: string;
}): Promise<Client[]> {
const response = await this.api.get<Client[]>('/api/v1/clients/search', { params });
return response.data;
}
async searchClientsByNom(nom: string): Promise<Client[]> {
const response = await this.api.get<Client[]>('/api/v1/clients/search', { params: { nom } });
return response.data;
}
async searchClientsByEntreprise(entreprise: string): Promise<Client[]> {
const response = await this.api.get<Client[]>('/api/v1/clients/search', { params: { entreprise } });
return response.data;
}
async searchClientsByVille(ville: string): Promise<Client[]> {
const response = await this.api.get<Client[]>('/api/v1/clients/search', { params: { ville } });
return response.data;
}
async searchClientsByEmail(email: string): Promise<Client[]> {
const response = await this.api.get<Client[]>('/api/v1/clients/search', { params: { email } });
return response.data;
}
async getClientsCount(): Promise<number> {
const response = await this.api.get<number>('/api/v1/clients/count');
return response.data;
}
// === CHANTIERS ===
async getChantiers(): Promise<Chantier[]> {
const response = await this.api.get<Chantier[]>('/api/v1/chantiers');
return Array.isArray(response.data) ? response.data : [];
}
async getChantiersActifs(): Promise<Chantier[]> {
const response = await this.api.get<Chantier[]>('/api/v1/chantiers/actifs');
return Array.isArray(response.data) ? response.data : [];
}
async getChantier(id: string): Promise<Chantier> {
const response = await this.api.get<Chantier>(`/api/v1/chantiers/${id}`);
return response.data;
}
async createChantier(chantier: Partial<Chantier>): Promise<Chantier> {
const response = await this.api.post<Chantier>('/api/v1/chantiers', chantier);
return response.data;
}
async updateChantier(id: string, chantier: Partial<Chantier>): Promise<Chantier> {
const response = await this.api.put<Chantier>(`/api/v1/chantiers/${id}`, chantier);
return response.data;
}
async deleteChantier(id: string, permanent: boolean = false): Promise<void> {
await this.api.delete(`/api/v1/chantiers/${id}`, {
params: { permanent }
});
}
async getChantiersByClient(clientId: string): Promise<Chantier[]> {
try {
const response = await this.api.get<Chantier[]>(`/api/v1/chantiers/client/${clientId}`);
return response.data;
} catch (error: any) {
// Si l'endpoint n'existe pas encore côté backend (404)
if (error.response?.status === 404) {
console.debug(`Endpoint /api/v1/chantiers/client/${clientId} non implémenté, retour d'une liste vide`);
// Retourner une liste vide en attendant l'implémentation backend
return [];
}
// Relancer l'erreur pour les autres cas
throw error;
}
}
async getChantiersRecents(): Promise<ChantierRecent[]> {
const response = await this.api.get<ChantierRecent[]>('/api/v1/chantiers/recent');
return response.data;
}
// === DEVIS ===
async getDevis(): Promise<Devis[]> {
return CacheService.getOrSet(
CacheKeys.DEVIS,
async () => {
const response = await this.api.get<Devis[]>('/api/v1/devis');
return Array.isArray(response.data) ? response.data : [];
},
3 * 60 * 1000 // 3 minutes (plus court car données plus volatiles)
);
}
async getDevisById(id: string): Promise<Devis> {
const response = await this.api.get<Devis>(`/api/v1/devis/${id}`);
return response.data;
}
async getDevisEnAttente(): Promise<DevisEnAttente[]> {
const response = await this.api.get<DevisEnAttente[]>('/api/v1/devis/en-attente');
return response.data;
}
async createDevis(devis: Partial<Devis>): Promise<Devis> {
const response = await this.api.post<Devis>('/api/v1/devis', devis);
// Invalider le cache des devis
CacheService.delete(CacheKeys.DEVIS);
CacheService.invalidatePattern('devis_.*');
return response.data;
}
async updateDevis(id: string, devis: Partial<Devis>): Promise<Devis> {
const response = await this.api.put<Devis>(`/api/v1/devis/${id}`, devis);
// Invalider le cache des devis
CacheService.delete(CacheKeys.DEVIS);
CacheService.delete(CacheKeys.devisById(id));
CacheService.invalidatePattern('devis_.*');
return response.data;
}
async deleteDevis(id: string): Promise<void> {
await this.api.delete(`/api/v1/devis/${id}`);
// Invalider le cache des devis
CacheService.delete(CacheKeys.DEVIS);
CacheService.delete(CacheKeys.devisById(id));
CacheService.invalidatePattern('devis_.*');
}
// === FACTURES ===
async getFactures(): Promise<Facture[]> {
return CacheService.getOrSet(
CacheKeys.FACTURES,
async () => {
const response = await this.api.get<Facture[]>('/api/v1/factures');
return Array.isArray(response.data) ? response.data : [];
},
3 * 60 * 1000 // 3 minutes
);
}
async getFacture(id: string): Promise<Facture> {
const response = await this.api.get<Facture>(`/api/v1/factures/${id}`);
return response.data;
}
async getFacturesEnRetard(): Promise<FactureEnRetard[]> {
const response = await this.api.get<FactureEnRetard[]>('/api/v1/factures/en-retard');
return response.data;
}
async createFacture(facture: Partial<Facture>): Promise<Facture> {
const response = await this.api.post<Facture>('/api/v1/factures', facture);
// Invalider le cache des factures
CacheService.delete(CacheKeys.FACTURES);
CacheService.invalidatePattern('factures_.*');
return response.data;
}
async updateFacture(id: string, facture: Partial<Facture>): Promise<Facture> {
const response = await this.api.put<Facture>(`/api/v1/factures/${id}`, facture);
// Invalider le cache des factures
CacheService.delete(CacheKeys.FACTURES);
CacheService.delete(CacheKeys.factureById(id));
CacheService.invalidatePattern('factures_.*');
return response.data;
}
async deleteFacture(id: string): Promise<void> {
await this.api.delete(`/api/v1/factures/${id}`);
// Invalider le cache des factures
CacheService.delete(CacheKeys.FACTURES);
CacheService.delete(CacheKeys.factureById(id));
CacheService.invalidatePattern('factures_.*');
}
// === DASHBOARD ===
async getDashboardStats(): Promise<DashboardStats> {
const response = await this.api.get<DashboardStats>('/api/v1/dashboard/stats');
return response.data;
}
// === HEALTH ===
async getHealth(): Promise<{ status: string; timestamp: string }> {
const response = await this.api.get('/api/v1/health');
return response.data;
}
async getVersion(): Promise<{ version: string; environment: string }> {
const response = await this.api.get('/api/v1/version');
return response.data;
}
// === AUTH ===
async getCurrentUser(): Promise<UserInfo> {
const response = await this.api.get('/api/v1/auth/user');
return response.data;
}
async getAuthStatus(): Promise<{ authenticated: boolean; principal: string | null; hasJWT: boolean; timestamp: number }> {
const response = await this.api.get('/api/v1/auth/status');
return response.data;
}
// === BUDGETS ===
async getBudgets(params?: { search?: string; statut?: string; tendance?: string }) {
const response = await this.api.get('/api/v1/budgets', { params });
return response.data;
}
async getBudget(id: string) {
const response = await this.api.get(`/api/v1/budgets/${id}`);
return response.data;
}
async getBudgetByChantier(chantierId: string) {
const response = await this.api.get(`/api/v1/budgets/chantier/${chantierId}`);
return response.data;
}
async getBudgetsEnDepassement() {
const response = await this.api.get('/api/v1/budgets/depassement');
return response.data;
}
async getBudgetsNecessitantAttention() {
const response = await this.api.get('/api/v1/budgets/attention');
return response.data;
}
async createBudget(budget: any) {
const response = await this.api.post('/api/v1/budgets', budget);
return response.data;
}
async updateBudget(id: string, budget: any) {
const response = await this.api.put(`/api/v1/budgets/${id}`, budget);
return response.data;
}
async deleteBudget(id: string) {
const response = await this.api.delete(`/api/v1/budgets/${id}`);
return response.data;
}
async updateBudgetDepenses(id: string, depense: number) {
const response = await this.api.put(`/api/v1/budgets/${id}/depenses`, { depense });
return response.data;
}
async updateBudgetAvancement(id: string, avancement: number) {
const response = await this.api.put(`/api/v1/budgets/${id}/avancement`, { avancement });
return response.data;
}
async ajouterAlerteBudget(id: string, description: string) {
const response = await this.api.post(`/api/v1/budgets/${id}/alertes`, { description });
return response.data;
}
async supprimerAlertesBudget(id: string) {
const response = await this.api.delete(`/api/v1/budgets/${id}/alertes`);
return response.data;
}
// === EMPLOYÉS ===
async getEmployes(): Promise<Employe[]> {
const response = await this.api.get<Employe[]>('/api/v1/employes');
return Array.isArray(response.data) ? response.data : [];
}
async getEmploye(id: string): Promise<Employe> {
const response = await this.api.get<Employe>(`/api/v1/employes/${id}`);
return response.data;
}
async createEmploye(employe: Partial<Employe>): Promise<Employe> {
const response = await this.api.post<Employe>('/api/v1/employes', employe);
return response.data;
}
async updateEmploye(id: string, employe: Partial<Employe>): Promise<Employe> {
const response = await this.api.put<Employe>(`/api/v1/employes/${id}`, employe);
return response.data;
}
async deleteEmploye(id: string): Promise<void> {
await this.api.delete(`/api/v1/employes/${id}`);
}
async searchEmployes(params: {
nom?: string;
poste?: string;
specialite?: string;
statut?: string;
}): Promise<Employe[]> {
const response = await this.api.get<Employe[]>('/api/v1/employes/search', { params });
return response.data;
}
async getEmployesDisponibles(dateDebut?: string, dateFin?: string): Promise<Employe[]> {
const response = await this.api.get<Employe[]>('/api/v1/employes/disponibles', {
params: { dateDebut, dateFin }
});
return response.data;
}
async getEmployesByEquipe(equipeId: string): Promise<Employe[]> {
const response = await this.api.get<Employe[]>(`/api/v1/employes/by-equipe/${equipeId}`);
return response.data;
}
async getEmployesCount(): Promise<number> {
const response = await this.api.get<number>('/api/v1/employes/count');
return response.data;
}
async getEmployesStats(): Promise<any> {
const response = await this.api.get('/api/v1/employes/stats');
return response.data;
}
// === ÉQUIPES ===
async getEquipes(): Promise<Equipe[]> {
const response = await this.api.get<Equipe[]>('/api/v1/equipes');
return Array.isArray(response.data) ? response.data : [];
}
async getEquipe(id: string): Promise<Equipe> {
const response = await this.api.get<Equipe>(`/api/v1/equipes/${id}`);
return response.data;
}
async createEquipe(equipe: Partial<Equipe>): Promise<Equipe> {
const response = await this.api.post<Equipe>('/api/v1/equipes', equipe);
return response.data;
}
async updateEquipe(id: string, equipe: Partial<Equipe>): Promise<Equipe> {
const response = await this.api.put<Equipe>(`/api/v1/equipes/${id}`, equipe);
return response.data;
}
async deleteEquipe(id: string): Promise<void> {
await this.api.delete(`/api/v1/equipes/${id}`);
}
async searchEquipes(params: {
nom?: string;
specialite?: string;
statut?: string;
}): Promise<Equipe[]> {
const response = await this.api.get<Equipe[]>('/api/v1/equipes/search', { params });
return response.data;
}
async getEquipesDisponibles(dateDebut?: string, dateFin?: string): Promise<Equipe[]> {
const response = await this.api.get<Equipe[]>('/api/v1/equipes/disponibles', {
params: { dateDebut, dateFin }
});
return response.data;
}
async getMembresEquipe(equipeId: string): Promise<Employe[]> {
const response = await this.api.get<Employe[]>(`/api/v1/equipes/${equipeId}/membres`);
return response.data;
}
async ajouterMembreEquipe(equipeId: string, employeId: string): Promise<void> {
await this.api.post(`/api/v1/equipes/${equipeId}/membres/${employeId}`);
}
async retirerMembreEquipe(equipeId: string, employeId: string): Promise<void> {
await this.api.delete(`/api/v1/equipes/${equipeId}/membres/${employeId}`);
}
async getEquipesCount(): Promise<number> {
const response = await this.api.get<number>('/api/v1/equipes/count');
return response.data;
}
async getEquipesStats(): Promise<any> {
const response = await this.api.get('/api/v1/equipes/stats');
return response.data;
}
// === MATÉRIELS ===
async getMateriels(): Promise<Materiel[]> {
const response = await this.api.get<Materiel[]>('/api/v1/materiels');
return Array.isArray(response.data) ? response.data : [];
}
async getMateriel(id: string): Promise<Materiel> {
const response = await this.api.get<Materiel>(`/api/v1/materiels/${id}`);
return response.data;
}
async createMateriel(materiel: Partial<Materiel>): Promise<Materiel> {
const response = await this.api.post<Materiel>('/api/v1/materiels', materiel);
return response.data;
}
async updateMateriel(id: string, materiel: Partial<Materiel>): Promise<Materiel> {
const response = await this.api.put<Materiel>(`/api/v1/materiels/${id}`, materiel);
return response.data;
}
async deleteMateriel(id: string): Promise<void> {
await this.api.delete(`/api/v1/materiels/${id}`);
}
async searchMateriels(params: {
nom?: string;
type?: string;
marque?: string;
statut?: string;
localisation?: string;
}): Promise<Materiel[]> {
const response = await this.api.get<Materiel[]>('/api/v1/materiels/search', { params });
return response.data;
}
async getMaterielsDisponibles(dateDebut?: string, dateFin?: string, type?: string): Promise<Materiel[]> {
const response = await this.api.get<Materiel[]>('/api/v1/materiels/disponibles', {
params: { dateDebut, dateFin, type }
});
return response.data;
}
async getMaterielsMaintenancePrevue(jours: number = 30): Promise<Materiel[]> {
const response = await this.api.get<Materiel[]>('/api/v1/materiels/maintenance-prevue', {
params: { jours }
});
return response.data;
}
async getMaterielsByType(type: string): Promise<Materiel[]> {
const response = await this.api.get<Materiel[]>(`/api/v1/materiels/by-type/${type}`);
return response.data;
}
async reserverMateriel(id: string, dateDebut: string, dateFin: string): Promise<void> {
await this.api.post(`/api/v1/materiels/${id}/reserve`, null, {
params: { dateDebut, dateFin }
});
}
async libererMateriel(id: string): Promise<void> {
await this.api.post(`/api/v1/materiels/${id}/liberer`);
}
async getMaterielsCount(): Promise<number> {
const response = await this.api.get<number>('/api/v1/materiels/count');
return response.data;
}
async getMaterielsStats(): Promise<any> {
const response = await this.api.get('/api/v1/materiels/stats');
return response.data;
}
async getValeurTotaleMateriels(): Promise<number> {
const response = await this.api.get<number>('/api/v1/materiels/valeur-totale');
return response.data;
}
// === MAINTENANCES ===
async getMaintenances(): Promise<MaintenanceMateriel[]> {
const response = await this.api.get<MaintenanceMateriel[]>('/api/v1/maintenances');
return Array.isArray(response.data) ? response.data : [];
}
async getMaintenance(id: string): Promise<MaintenanceMateriel> {
const response = await this.api.get<MaintenanceMateriel>(`/api/v1/maintenances/${id}`);
return response.data;
}
async createMaintenance(maintenance: Partial<MaintenanceMateriel>): Promise<MaintenanceMateriel> {
const response = await this.api.post<MaintenanceMateriel>('/api/v1/maintenances', maintenance);
return response.data;
}
async updateMaintenance(id: string, maintenance: Partial<MaintenanceMateriel>): Promise<MaintenanceMateriel> {
const response = await this.api.put<MaintenanceMateriel>(`/api/v1/maintenances/${id}`, maintenance);
return response.data;
}
async deleteMaintenance(id: string): Promise<void> {
await this.api.delete(`/api/v1/maintenances/${id}`);
}
async getMaintenancesByMateriel(materielId: string): Promise<MaintenanceMateriel[]> {
const response = await this.api.get<MaintenanceMateriel[]>(`/api/v1/maintenances/by-materiel/${materielId}`);
return response.data;
}
// === PLANNING ===
async getPlanningEvents(params?: {
dateDebut?: string;
dateFin?: string;
type?: string;
statut?: string;
}): Promise<PlanningEvent[]> {
const response = await this.api.get<PlanningEvent[]>('/api/v1/planning/events', { params });
return Array.isArray(response.data) ? response.data : [];
}
async getPlanningEvent(id: string): Promise<PlanningEvent> {
const response = await this.api.get<PlanningEvent>(`/api/v1/planning/events/${id}`);
return response.data;
}
async createPlanningEvent(event: Partial<PlanningEvent>): Promise<PlanningEvent> {
const response = await this.api.post<PlanningEvent>('/api/v1/planning/events', event);
return response.data;
}
async updatePlanningEvent(id: string, event: Partial<PlanningEvent>): Promise<PlanningEvent> {
const response = await this.api.put<PlanningEvent>(`/api/v1/planning/events/${id}`, event);
return response.data;
}
async deletePlanningEvent(id: string): Promise<void> {
await this.api.delete(`/api/v1/planning/events/${id}`);
}
async getCalendrierView(annee: number, mois: number): Promise<PlanningCalendrierView> {
const response = await this.api.get<PlanningCalendrierView>('/api/v1/planning/calendrier', {
params: { annee, mois }
});
return response.data;
}
async detecterConflitsPlanification(dateDebut?: string, dateFin?: string): Promise<PlanningConflict[]> {
const response = await this.api.get<PlanningConflict[]>('/api/v1/planning/conflits', {
params: { dateDebut, dateFin }
});
return response.data;
}
async getPlanningEmploye(employeId: string, dateDebut?: string, dateFin?: string): Promise<PlanningEvent[]> {
const response = await this.api.get<PlanningEvent[]>(`/api/v1/planning/employe/${employeId}`, {
params: { dateDebut, dateFin }
});
return response.data;
}
async getPlanningEquipe(equipeId: string, dateDebut?: string, dateFin?: string): Promise<PlanningEvent[]> {
const response = await this.api.get<PlanningEvent[]>(`/api/v1/planning/equipe/${equipeId}`, {
params: { dateDebut, dateFin }
});
return response.data;
}
async getPlanningMateriel(materielId: string, dateDebut?: string, dateFin?: string): Promise<PlanningEvent[]> {
const response = await this.api.get<PlanningEvent[]>(`/api/v1/planning/materiel/${materielId}`, {
params: { dateDebut, dateFin }
});
return response.data;
}
async assignEmployesToEvent(eventId: string, employeIds: string[]): Promise<void> {
await this.api.post(`/api/v1/planning/events/${eventId}/assign-employes`, employeIds);
}
async assignMaterielsToEvent(eventId: string, materielIds: string[]): Promise<void> {
await this.api.post(`/api/v1/planning/events/${eventId}/assign-materiels`, materielIds);
}
async getPlanningStats(): Promise<PlanningStats> {
const response = await this.api.get<PlanningStats>('/api/v1/planning/stats');
return response.data;
}
async getTauxOccupation(dateDebut?: string, dateFin?: string): Promise<any> {
const response = await this.api.get('/api/v1/planning/occupation', {
params: { dateDebut, dateFin }
});
return response.data;
}
// === TEST ===
async testCreateChantier(chantier: any): Promise<string> {
const response = await this.api.post('/api/v1/test/chantier', chantier);
return response.data;
}
}
// Instance singleton
export const apiService = new ApiService();
// Services spécialisés
export const clientService = {
getAll: () => apiService.getClients(),
getById: (id: string) => apiService.getClient(id),
create: (client: Partial<Client>) => apiService.createClient(client),
update: (id: string, client: Partial<Client>) => apiService.updateClient(id, client),
delete: (id: string) => apiService.deleteClient(id),
search: (params: any) => apiService.searchClients(params),
searchByNom: (nom: string) => apiService.searchClientsByNom(nom),
searchByEntreprise: (entreprise: string) => apiService.searchClientsByEntreprise(entreprise),
searchByVille: (ville: string) => apiService.searchClientsByVille(ville),
searchByEmail: (email: string) => apiService.searchClientsByEmail(email),
count: () => apiService.getClientsCount(),
};
export const chantierService = {
getAll: () => apiService.getChantiers(),
getAllActive: () => apiService.getChantiersActifs(),
getById: (id: string) => apiService.getChantier(id),
create: (chantier: Partial<Chantier>) => apiService.createChantier(chantier),
update: (id: string, chantier: Partial<Chantier>) => apiService.updateChantier(id, chantier),
delete: (id: string, permanent: boolean = false) => apiService.deleteChantier(id, permanent),
getByClient: (clientId: string) => apiService.getChantiersByClient(clientId),
getRecents: () => apiService.getChantiersRecents(),
};
export const devisService = {
getAll: () => apiService.getDevis(),
getById: (id: string) => apiService.getDevisById(id),
getEnAttente: () => apiService.getDevisEnAttente(),
create: (devis: Partial<Devis>) => apiService.createDevis(devis),
update: (id: string, devis: Partial<Devis>) => apiService.updateDevis(id, devis),
delete: (id: string) => apiService.deleteDevis(id),
};
export const factureService = {
getAll: () => apiService.getFactures(),
getById: (id: string) => apiService.getFacture(id),
getEnRetard: () => apiService.getFacturesEnRetard(),
create: (facture: Partial<Facture>) => apiService.createFacture(facture),
update: (id: string, facture: Partial<Facture>) => apiService.updateFacture(id, facture),
delete: (id: string) => apiService.deleteFacture(id),
};
export const dashboardService = {
getStats: () => apiService.getDashboardStats(),
};
export const employeService = {
getAll: () => apiService.getEmployes(),
getById: (id: string) => apiService.getEmploye(id),
create: (employe: Partial<Employe>) => apiService.createEmploye(employe),
update: (id: string, employe: Partial<Employe>) => apiService.updateEmploye(id, employe),
delete: (id: string) => apiService.deleteEmploye(id),
search: (params: any) => apiService.searchEmployes(params),
getDisponibles: (dateDebut?: string, dateFin?: string) => apiService.getEmployesDisponibles(dateDebut, dateFin),
getByEquipe: (equipeId: string) => apiService.getEmployesByEquipe(equipeId),
count: () => apiService.getEmployesCount(),
getStats: () => apiService.getEmployesStats(),
};
export const equipeService = {
getAll: () => apiService.getEquipes(),
getById: (id: string) => apiService.getEquipe(id),
create: (equipe: Partial<Equipe>) => apiService.createEquipe(equipe),
update: (id: string, equipe: Partial<Equipe>) => apiService.updateEquipe(id, equipe),
delete: (id: string) => apiService.deleteEquipe(id),
search: (params: any) => apiService.searchEquipes(params),
getDisponibles: (dateDebut?: string, dateFin?: string) => apiService.getEquipesDisponibles(dateDebut, dateFin),
getMembres: (equipeId: string) => apiService.getMembresEquipe(equipeId),
ajouterMembre: (equipeId: string, employeId: string) => apiService.ajouterMembreEquipe(equipeId, employeId),
retirerMembre: (equipeId: string, employeId: string) => apiService.retirerMembreEquipe(equipeId, employeId),
count: () => apiService.getEquipesCount(),
getStats: () => apiService.getEquipesStats(),
};
export const materielService = {
getAll: () => apiService.getMateriels(),
getById: (id: string) => apiService.getMateriel(id),
create: (materiel: Partial<Materiel>) => apiService.createMateriel(materiel),
update: (id: string, materiel: Partial<Materiel>) => apiService.updateMateriel(id, materiel),
delete: (id: string) => apiService.deleteMateriel(id),
search: (params: any) => apiService.searchMateriels(params),
getDisponibles: (dateDebut?: string, dateFin?: string, type?: string) => apiService.getMaterielsDisponibles(dateDebut, dateFin, type),
getMaintenancePrevue: (jours?: number) => apiService.getMaterielsMaintenancePrevue(jours),
getByType: (type: string) => apiService.getMaterielsByType(type),
reserver: (id: string, dateDebut: string, dateFin: string) => apiService.reserverMateriel(id, dateDebut, dateFin),
liberer: (id: string) => apiService.libererMateriel(id),
count: () => apiService.getMaterielsCount(),
getStats: () => apiService.getMaterielsStats(),
getValeurTotale: () => apiService.getValeurTotaleMateriels(),
};
export const budgetService = {
getAll: (params?: { search?: string; statut?: string; tendance?: string }) => apiService.getBudgets(params),
getById: (id: string) => apiService.getBudget(id),
getByChantier: (chantierId: string) => apiService.getBudgetByChantier(chantierId),
getEnDepassement: () => apiService.getBudgetsEnDepassement(),
getNecessitantAttention: () => apiService.getBudgetsNecessitantAttention(),
create: (budget: any) => apiService.createBudget(budget),
update: (id: string, budget: any) => apiService.updateBudget(id, budget),
delete: (id: string) => apiService.deleteBudget(id),
updateDepenses: (id: string, depense: number) => apiService.updateBudgetDepenses(id, depense),
updateAvancement: (id: string, avancement: number) => apiService.updateBudgetAvancement(id, avancement),
ajouterAlerte: (id: string, description: string) => apiService.ajouterAlerteBudget(id, description),
supprimerAlertes: (id: string) => apiService.supprimerAlertesBudget(id),
};
export const maintenanceService = {
getAll: () => apiService.getMaintenances(),
getById: (id: string) => apiService.getMaintenance(id),
create: (maintenance: Partial<MaintenanceMateriel>) => apiService.createMaintenance(maintenance),
update: (id: string, maintenance: Partial<MaintenanceMateriel>) => apiService.updateMaintenance(id, maintenance),
delete: (id: string) => apiService.deleteMaintenance(id),
getByMateriel: (materielId: string) => apiService.getMaintenancesByMateriel(materielId),
};
export const planningService = {
getEvents: (params?: any) => apiService.getPlanningEvents(params),
getEvent: (id: string) => apiService.getPlanningEvent(id),
createEvent: (event: Partial<PlanningEvent>) => apiService.createPlanningEvent(event),
updateEvent: (id: string, event: Partial<PlanningEvent>) => apiService.updatePlanningEvent(id, event),
deleteEvent: (id: string) => apiService.deletePlanningEvent(id),
getCalendrierView: (annee: number, mois: number) => apiService.getCalendrierView(annee, mois),
detecterConflits: (dateDebut?: string, dateFin?: string) => apiService.detecterConflitsPlanification(dateDebut, dateFin),
getPlanningEmploye: (employeId: string, dateDebut?: string, dateFin?: string) => apiService.getPlanningEmploye(employeId, dateDebut, dateFin),
getPlanningEquipe: (equipeId: string, dateDebut?: string, dateFin?: string) => apiService.getPlanningEquipe(equipeId, dateDebut, dateFin),
getPlanningMateriel: (materielId: string, dateDebut?: string, dateFin?: string) => apiService.getPlanningMateriel(materielId, dateDebut, dateFin),
assignEmployes: (eventId: string, employeIds: string[]) => apiService.assignEmployesToEvent(eventId, employeIds),
assignMateriels: (eventId: string, materielIds: string[]) => apiService.assignMaterielsToEvent(eventId, materielIds),
getStats: () => apiService.getPlanningStats(),
getTauxOccupation: (dateDebut?: string, dateFin?: string) => apiService.getTauxOccupation(dateDebut, dateFin),
};
// Service pour les types de chantier
// TODO: Implement proper methods in ApiService class
export const typeChantierService = {
getAll: () => Promise.resolve([]),
getByCategorie: () => Promise.resolve([]),
getById: (id: string) => Promise.resolve(null),
getByCode: (code: string) => Promise.resolve(null),
create: (typeChantier: any) => Promise.resolve(typeChantier),
update: (id: string, typeChantier: any) => Promise.resolve(typeChantier),
delete: (id: string) => Promise.resolve(true),
reactivate: (id: string) => Promise.resolve(true),
getStatistiques: () => Promise.resolve({}),
};
export default apiService;