/** * API Client for making authenticated requests to the server * * This class provides a wrapper around the Fetch API to handle * authentication and common request patterns. * * The client uses JWT tokens for authentication, which are automatically * included in requests via the fetchAuth function provided by the auth service. * * Similar to AuthService.php, great pain and countless tears. And learning woooo!!!!!!!! */ class ApiClient { /** * Constructor * * Initialises the API client and sets up the authenticated fetch function. * Relies on the auth service being available in the global scope. */ constructor() { // Ensure auth service is available if (!auth) { console.error('Auth service not available'); } // Use the fetchAuth method from auth this.authFetch = async (url, options = {}) => { try { // For unauthenticated requests or when authentication is not required if (!options.requireAuth || !auth.isAuthenticated()) { return fetch(url, options); } // For authenticated requests delete options.requireAuth; // Remove the custom property return auth.fetchAuth(url, options); } catch (error) { console.error('Error in authFetch:', error); throw error; } }; } /** * Makes a GET request to the API * * This method handles GET requests with query parameters. * It automatically converts the params object to a query string * and handles error responses. * * @param {string} endpoint - The API endpoint * @param {Object} params - Query parameters * @returns {Promise} The response data */ async get(endpoint, params = {}) { // Build query string const queryString = Object.keys(params).length > 0 ? '?' + new URLSearchParams(params).toString() : ''; try { const response = await this.authFetch(`${endpoint}${queryString}`); if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } return await response.json(); } catch (error) { console.error(`GET request to ${endpoint} failed:`, error); throw error; } } /** * Makes a POST request to the API * * This method handles POST requests with either JSON data or FormData. * It automatically sets the appropriate headers and handles error responses. * * @param {string} endpoint - The API endpoint * @param {Object|FormData} data - The data to send * @returns {Promise} The response data */ async post(endpoint, data = {}) { try { // Prepare request options const options = { method: 'POST' }; // Handle FormData or JSON if (data instanceof FormData) { options.body = data; } else { options.headers = { 'Content-Type': 'application/json' }; options.body = JSON.stringify(data); } const response = await this.authFetch(endpoint, options); if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } return await response.json(); } catch (error) { console.error(`POST request to ${endpoint} failed:`, error); throw error; } } /** * Makes a facility-related API request * * This is a helper method that simplifies making requests to the facility controller. * It automatically creates a FormData object with the action and data parameters. * * @param {string} action - The action to perform * @param {Object} data - The data to send * @returns {Promise} The response data */ async facility(action, data = {}) { // Create FormData const formData = new FormData(); formData.append('action', action); // Add all data to FormData Object.entries(data).forEach(([key, value]) => { formData.append(key, value); }); try { // Validate auth state before making request if (!this.authFetch) { throw new Error('Auth fetch not available'); } if (action === 'status' && (!data.facilityId || !data.statusComment)) { throw new Error('Missing required data for status update'); } // Use authenticated fetch for all facility requests const response = await this.authFetch('/facilitycontroller.php', { method: 'POST', body: formData, requireAuth: true }); // Parse the response const jsonData = await response.json(); // Check if response is ok if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}, message: ${jsonData.error || 'Unknown error'}`); } return jsonData; } catch (error) { console.error('Facility API error:', error); throw error; } } /** * Creates a new facility * * This method sends a request to create a new facility with the provided data. * * @param {Object} facilityData - The facility data * @returns {Promise} The response data */ async createFacility(facilityData) { return this.facility('create', facilityData); } /** * Updates a facility * * This method sends a request to update an existing facility with the provided data. * * @param {Object} facilityData - The facility data * @returns {Promise} The response data */ async updateFacility(facilityData) { return this.facility('update', facilityData); } /** * Deletes a facility * * This method sends a request to delete a facility with the specified ID. * * @param {number|string} id - The facility ID * @returns {Promise} The response data */ async deleteFacility(id) { return this.facility('delete', { id }); } /** * Gets a facility by ID * * This method retrieves a single facility with the specified ID. * * @param {number|string} id - The facility ID * @returns {Promise} The response data */ async getFacility(id) { return this.facility('read', { id }); } /** * Gets statuses for a facility * * This method retrieves all status updates for a facility with the specified ID. * * @param {number|string} facilityId - The facility ID * @returns {Promise} The response data */ async getFacilityStatuses(facilityId) { return this.facility('getStatuses', { facilityId }); } /** * Adds a status to a facility * * This method adds a new status update to a facility. * * @param {number|string} facilityId - The facility ID * @param {string} statusComment - The status comment * @returns {Promise} The response data */ async addFacilityStatus(facilityId, statusComment) { return this.facility('status', { facilityId: facilityId, statusComment: statusComment }); } /** * Updates a facility status * * This method updates an existing status for a facility. * * @param {number|string} statusId - The status ID * @param {string} editStatus - The updated status comment * @param {number|string} facilityId - The facility ID * @returns {Promise} The response data */ async updateFacilityStatus(statusId, editStatus, facilityId) { return this.facility('editStatus', { statusId: statusId, statusComment: editStatus, facilityId: facilityId }); } /** * Deletes a facility status * * This method deletes a status update from a facility. * * @param {number|string} statusId - The status ID * @param {number|string} facilityId - The facility ID * @returns {Promise} The response data */ async deleteFacilityStatus(statusId, facilityId) { return this.facility('deleteStatus', { statusId, facilityId }); } } // initialise API client const api = new ApiClient(); // Export API client window.api = api;