const BASE_URL = import.meta.env.VITE_API_BASE_URL || ''; const CUSTOM_API_BASE_URL = import.meta.env.VITE_CUSTOM_API_BASE_URL || ''; // Le moteur de requête unifié et intelligent const apiCall = async (endpoint, param2 = 'GET', param3 = null) => { let method = 'GET'; let body = null; // DÉTECTION DE SIGNATURE (Le bouclier anti-crash) if (typeof param2 === 'string') { // Cas 1 : On a bien envoyé (URL, "POST", {données}) method = param2.toUpperCase(); body = param3; } else if (typeof param2 === 'object' && param2 !== null) { // Cas 2 : L'ancienne méthode a envoyé (URL, {données}) // On redirige l'objet vers le body, et on force en POST body = param2; method = (typeof param3 === 'string') ? param3.toUpperCase() : 'POST'; } // 1. Récupération du sésame const token = localStorage.getItem('token'); // 2. Préparation de l'enveloppe const headers = { 'Content-Type': 'application/json', 'Accept': 'application/json' }; if (token) { headers['Authorization'] = `Bearer ${token}`; } // 3. Configuration finale garantie sans objets égarés const options = { method: method, headers: headers, credentials: 'include' }; if (body) { options.body = JSON.stringify(body); } try { const response = await fetch(endpoint, options); if (response.status === 401 || response.status === 403) { throw new Error("Accès refusé. Session expirée ou non valide."); } const data = await response.json(); // Gestion des erreurs internes de l'API if (data.error) { throw new Error(data.error.message || "Erreur renvoyée par le serveur de facturation."); } return data.result || data; } catch (error) { console.error(`[API FAIL] ${method} ${endpoint} :`, error); throw error; } }; // ========================================== // ROUTES FOSSBILLING NATIVES (BACKTICKS INTÉGRÉS) // ========================================== export const loginClient = (email, password) => apiCall(`${BASE_URL}/api/guest/client/login`, { email, password }); // Récupère la liste des services/commandes du client export const getClientOrders = () => apiCall(`${BASE_URL}/api/client/order/get_list`); // Récupère les détails techniques du service rattaché à une commande export const getOrderService = (order_id) => apiCall(`${BASE_URL}/api/client/order/service`, { id: order_id }); // Récupère le catalogue public des produits FOSSBilling export const getProductList = () => apiCall(`${BASE_URL}/api/guest/product/get_list`); // Vide le panier (Action PUBLIQUE : on passe par l'API Guest) export const resetCart = async () => { try { // Changement : api/guest/ au lieu de api/client/ const cart = await apiCall(`${BASE_URL}/api/guest/cart/get`, 'GET'); if (cart && cart.items && cart.items.length > 0) { for (const item of cart.items) { // Changement : api/guest/ await apiCall(`${BASE_URL}/api/guest/cart/remove_item`, 'POST', { id: item.id }); } } } catch (err) { console.warn("Nettoyage du panier ignoré :", err); } }; // Ajoute un produit au panier avec ses options étalées à la racine export const addToCart = (productId, period, additionalData = {}) => apiCall(`${BASE_URL}/api/guest/cart/add_item`, 'POST', { id: productId, period: period, ...additionalData // Les 3 petits points "étalent" le contenu de l'objet }); // Valide le panier (Action PRIVÉE : on reste sur l'API Client pour générer la facture) export const checkoutCart = () => apiCall(`${BASE_URL}/api/client/cart/checkout`, 'POST'); // Récupère les informations du client connecté export const getClientProfile = () => apiCall(`${BASE_URL}/api/client/profile/get`, 'GET'); // ========================================== // ROUTES PERSONNALISÉES (CUSTOM API) // ========================================== export const registerUnifiedClient = async (email, username, password, firstName, lastName) => { try { // Utilisation des backticks ici aussi ! const response = await fetch(`${CUSTOM_API_BASE_URL}/custom_api/signup.php`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ email: email, username: username, password: password, first_name: firstName, last_name: lastName }) }); const data = await response.json(); if (data.error) throw new Error(data.error.message); return data.result; } catch (err) { console.error("Erreur lors de l'inscription unifiée :", err); throw new Error("Échec de l'inscription. Veuillez réessayer plus tard."); } } // Récupère la liste de toutes les commandes actives du client export const getMyServices = () => apiCall(`${BASE_URL}/api/client/order/get_list`, 'GET'); // Récupère les détails secrets d'un service (dont le mot de passe HestiaCP/VPS) export const getServiceDetails = (orderId) => apiCall(`${BASE_URL}/api/client/order/get`, 'POST', { id: orderId }); // Récupère les secrets spécifiques du service physique attaché à une commande export const getHostingServiceDetails = (orderId) => apiCall(`${BASE_URL}/api/client/order/service`, 'POST', { id: orderId }); // Force la réinitialisation du mot de passe sur le serveur distant (HestiaCP) export const resetHostingPassword = (orderId, newPassword) => apiCall(`${BASE_URL}/api/client/servicehosting/change_password`, 'POST', { order_id: orderId, password: newPassword, password_confirm: newPassword }); // Déclenche le sas de connexion SSO via le navigateur (Ne pas utiliser apiCall ici) export const launchSSOGateway = (username, password) => { const form = document.createElement('form'); form.method = 'POST'; // Tu peux utiliser ta BASE_URL si elle pointe vers web.gise.be // Sinon, on garde l'URL absolue vers ton API personnalisée form.action = `${CUSTOM_API_BASE_URL}/custom_api/sso.php`; form.target = '_blank'; const userField = document.createElement('input'); userField.type = 'hidden'; userField.name = 'user'; userField.value = username; form.appendChild(userField); const passField = document.createElement('input'); passField.type = 'hidden'; passField.name = 'password'; passField.value = password; form.appendChild(passField); document.body.appendChild(form); form.submit(); document.body.removeChild(form); };