Source

services/api.js

// import {getOrGenerateFcmToken} from "../notification/firebase";

/**
 * ApiService class for making API requests to the backend.
 * Handles authentication tokens and provides methods for various endpoints.
 */
class ApiService {
  constructor() {
    // this.baseURL = 'http://localhost:8000/';
    // this.baseURL = 'https://c8lwf80x-8000.inc1.devtunnels.ms/';
    // this.baseURL = 'https://memotrack.pythonanywhere.com/';
    // this.baseURL = 'https://mtbackend.pythonanywhere.com/'
    this.baseURL = process.env.BACKEND_URL || 'https://app.memotrack.net/';
  }

  /**
 * General request method to interact with the API.
 * Automatically adds Authorization header if a token exists in localStorage.
 *
 * @param {string} endpoint - The API endpoint path.
 * @param {object} [options={}] - Fetch API options (method, headers, body, etc.).
 * @returns {Promise<object|null>} - The parsed JSON response or null for 204 No Content.
 * @throws {Error} - If the HTTP response status is not OK or if the fetch fails.
 */
  async request(endpoint, options = {}) {
    const url = `${this.baseURL}${endpoint}`;
    const config = {
      headers: {
        'Content-Type': 'application/json',
        ...options.headers,
      },
      ...options,
    };

    const token = localStorage.getItem('authToken');
    if (token) {
      config.headers.Authorization = `Token ${token}`;
    }

    try {
      const response = await fetch(url, config);
      if (!response.ok) {
        throw new Error(`HTTP error! status: ${response.status}`);
      }

      if (response.status === 204) {
        return null;
      }

      return await response.json();
    } catch (error) {
      console.error('API request failed:', error);
      throw error;
    }
  }

  /**
 * Authenticates a user and retrieves an authentication token.
 *
 * @param {string} phoneNumber - The user's phone number.
 * @param {string} password - The user's password.
 * @param {string|null} [fcmToken=null] - The FCM token for push notifications.
 * @returns {Promise<object>} - The authentication data, including the token.
 */
  async login(phoneNumber, password, fcmToken=null) {
    try {
      // const fcmToken = await getOrGenerateFcmToken();

      const body = {
        phone: phoneNumber,
        password: password
      };

      if(fcmToken){
        body['fcm_token'] = fcmToken;
      }

      console.log("Sending login request with body:", body);

      const data = await this.request("/api/token-auth/", {
        method: "POST",
        headers: {
          "Content-Type": "application/json",
        },
        body: JSON.stringify(body),
      });

      console.log("Backend response:", data);
      return data;
    } catch (error) {
      console.error("Login failed:", error);
      throw error;
    }
  }

  /**
 * Logs out the current user.
 *
 * @returns {Promise<null>} - A promise that resolves when the logout request is successful.
 */
  async logout() {
    return this.request('/api/token-auth/logout/', {
      method: 'POST',
    });
  }

  async setPassword(phoneNumber, newPassword) {
    /**
 * Sets or resets the password for a given phone number.
 *
 * @param {string} phoneNumber - The user's phone number.
 * @param {string} newPassword - The new password to set.
 */
    return this.request('/api/set-password/', {
      method: 'POST',
      body: JSON.stringify({
        phone: phoneNumber,
        password: newPassword,
      })
    });
  }
  /**
 * Retrieves details for a specific hospital by its ID.
 * Typically called after a user logs in to get details about their assigned hospital.
 *
 * @param {string|number} hospitalId - The ID of the hospital.
 * @returns {Promise<object>} - The hospital details.
 */
  async getHospital(hospitalId) {
    return this.request(`/api/hospitals/${hospitalId}/`);
  }

  // Hospital-specific endpoints
  /**
 * Retrieves the list of users belonging to a specific hospital.
 *
 * @param {string|number} hospitalId - The ID of the hospital.
 * @returns {Promise<object[]>} - An array of user objects.
 */
  async getUsers(hospitalId) {
    return this.request(`/api/hospitals/${hospitalId}/users/`);
  }
  /**
 * Creates a new user within a specific hospital.
 */

  async createUser(hospitalId, userData) {
    return this.request(`/api/hospitals/${hospitalId}/users/`, {
      method: 'POST',
      body: JSON.stringify(userData),
    });
  }

  /**
 * Updates an existing user's details within a specific hospital.
 */
  async updateUser(hospitalId, userId, userData) {
    return this.request(`/api/hospitals/${hospitalId}/users/${userId}/`, {
      method: 'PATCH',
      body: JSON.stringify(userData),
    });
  }

  /**
 * Deletes a user from a specific hospital.
 */
  async deleteUser(hospitalId, userId) {
    return this.request(`/api/hospitals/${hospitalId}/users/${userId}/`, {
      method: 'DELETE',
    });
  }

  async getRoles(hospitalId) {
    return await this.request(`/api/hospitals/${hospitalId}/roles/`);
  }
  

  /**
 * Creates a new role within a specific hospital.
 */
  async createRole(hospitalId, roleData) {
    return this.request(`/api/hospitals/${hospitalId}/roles/`, {
      method: 'POST',
      body: JSON.stringify(roleData),
    });
  }
  
  async updateRole(hospitalId, roleId, roleData) {
    /**
 * Updates an existing role's details within a specific hospital.
 */
    return this.request(`/api/hospitals/${hospitalId}/roles/${roleId}/`, {
      method: 'PATCH',
      body: JSON.stringify(roleData),
    });
  }

  async deleteRole(hospitalId, roleId) {
    /**
 * Deletes a role from a specific hospital.
 */
    return this.request(`/api/hospitals/${hospitalId}/roles/${roleId}/`, {
      method: 'DELETE',
    });
  }

  async getBlocks(hospitalId) {
    return this.request(`/api/hospitals/${hospitalId}/blocks/`);
  }
  async getBlock(hospitalId, blockId) {
    return this.request(`/api/hospitals/${hospitalId}/blocks/${blockId}/`);
  }
  /**
 * Retrieves the list of blocks within a specific hospital.
 */

  async createBlock(hospitalId, blockData) {
    return this.request(`/api/hospitals/${hospitalId}/blocks/`, {
      method: 'POST',
      body: JSON.stringify(blockData),
    });
  }

  /**
 * Updates an existing block's details within a specific hospital.
 */
  async updateBlock(hospitalId, blockId, blockData) {
    return this.request(`/api/hospitals/${hospitalId}/blocks/${blockId}/`, {
      method: 'PATCH',
      body: JSON.stringify(blockData),
    });
  }

  async deleteBlock(hospitalId, blockId) {
    /**
 * Deletes a block from a specific hospital.
 */
    return this.request(`/api/hospitals/${hospitalId}/blocks/${blockId}/`, {
      method: 'DELETE',
    });
  }

  async getShifts(hospitalId) {
    return this.request(`/api/hospitals/${hospitalId}/shifts/`);
  }

  /**
 * Creates a new shift within a specific hospital.
 */
  async createShift(hospitalId, shiftData) {
    return this.request(`/api/hospitals/${hospitalId}/shifts/`, {
      method: 'POST',
      body: JSON.stringify(shiftData),
    });
  }

  async updateShift(hospitalId, shiftId, shiftData) {
    /**
 * Updates an existing shift's details within a specific hospital.
 */
    return this.request(`/api/hospitals/${hospitalId}/shifts/${shiftId}/`, {
      method: 'PATCH',
      body: JSON.stringify(shiftData),
    });
  }

  async deleteShift(hospitalId, shiftId) {
    /**
 * Deletes a shift from a specific hospital.
 */
    return this.request(`/api/hospitals/${hospitalId}/shifts/${shiftId}/`, {
      method: 'DELETE',
    });
  }

  // ================= Approver Hierarchies =================
  async getApproverHierarchies(hospitalId) {
    /**
 * Retrieves the list of approver hierarchies for a specific hospital.
 */
    return this.request(`/api/hospitals/${hospitalId}/hierarchies/`);
  }

  async createApproverHierarchy(hospitalId, data) {
    /**
 * Creates a new approver hierarchy for a specific hospital.
 */
    return this.request(`/api/hospitals/${hospitalId}/hierarchies/`, {
      method: 'POST',
      body: JSON.stringify(data),
    });
  }

  async updateApproverHierarchy(hospitalId, id, data) {
    /**
 * Updates an existing approver hierarchy for a specific hospital.
 */
    return this.request(`/api/hospitals/${hospitalId}/hierarchies/${id}/`, {
      method: 'PATCH',
      body: JSON.stringify(data),
    });
  }

  async deleteApproverHierarchy(hospitalId, id) {
    /**
 * Deletes an approver hierarchy from a specific hospital.
 */
    return this.request(`/api/hospitals/${hospitalId}/hierarchies/${id}/`, {
      method: 'DELETE',
    });
  }

  // ================= Memo =================
  async createMemo(hospitalId, memoData) {
    /**
 * Creates a new memo for a specific hospital.
 */
    return this.request(`/api/${hospitalId}/create-memo/`, {
      method: 'POST',
      body: JSON.stringify(memoData),
    });
  }

  async updateMemo(hospitalId, memoId, memoData) {
    console.log(memoData);
    /**
 * Updates an existing memo for a specific hospital.
 */
    return this.request(`/api/${hospitalId}/memos/${memoId}/`, {
      method: 'PATCH',
      body: JSON.stringify(memoData),
    });
  }

  async getMemo(hospitalId, memoId) {
    /**
 * Retrieves details of a specific memo for a given hospital.
 */
    return this.request(`/api/${hospitalId}/memos/${memoId}/`);
  }

  async getUserMemos(hospitalId) {
    /**
 * Retrieves all memos associated with the current user for a specific hospital.
 */
    return this.request(`/api/${hospitalId}/memos/`);
  }

  async approveMemo(hospitalId, memoId, data) {
    return this.request(`/api/${hospitalId}/memos/${memoId}/approve/`, {
      method: 'POST',
      body: JSON.stringify(data),
    });
  }

  /**
 * Rejects a memo for a specific hospital.
 */
  async rejectMemo(hospitalId, memoId, data) {
    return this.request(`/api/${hospitalId}/memos/${memoId}/reject/`, {
      method: 'POST',
      body: JSON.stringify(data),
    });
  }

  // =============== Worker Status =================
  async addWorkerStatus(hospitalId, memoId, data) {
    /**
 * Adds a work status event to a specific memo.
 */
    return this.request(`/api/${hospitalId}/memos/${memoId}/work-status/`, {
      method: 'POST',
      body: JSON.stringify(data),
    });
  }

  async deleteWorkerStatus(hospitalId, memoId, eventId, metadata = {}) {
    /**
 * Deletes a specific work status event from a memo.
 */
    return this.request(`/api/${hospitalId}/memos/${memoId}/work-status/`, {
      method: 'DELETE',
      body: JSON.stringify({
        event_type: 'worker_status_delete',
        payload: { event_id: eventId },
        metadata,
      }),
    });
  }

  
  async getWards(hospitalId) {
    return this.request(`/api/hospitals/${hospitalId}/wards/`);
    /**
 * Retrieves the list of all wards within a specific hospital.
 */
  }

  async getWardsByBlock(hospitalId,blockId) {
    return this.request(`/api/hospitals/${hospitalId}/wards/?block=${blockId}`);
    /**
 * Retrieves the list of wards for a specific block within a hospital.
 */
  }

  async switchWard(wardId) {
    return this.request('/api/switch-ward/', {
      method: 'POST',
      body: JSON.stringify({ ward_id: wardId }),  
    });
  }

  async refreshUser() {
    /**
 * Refreshes the current user's details and permissions.
 */
    return this.request('/api/refresh-user/', {
      method: 'POST',
    });
  }

  async createWard(hospitalId, wardData) {
    return this.request(`/api/hospitals/${hospitalId}/wards/`, {
      method: 'POST',
      body: JSON.stringify(wardData),
    });
  }
  /**
 * Creates a new ward within a specific hospital.
 */

  async updateWard(hospitalId, wardId, wardData) {
    return this.request(`/api/hospitals/${hospitalId}/wards/${wardId}/`, {
      method: 'PATCH',
      body: JSON.stringify(wardData),
    });
  }

  /**
 * Updates an existing ward's details within a specific hospital.
 */
  async deleteWard(hospitalId, wardId) {
    return this.request(`/api/hospitals/${hospitalId}/wards/${wardId}/`, {
      method: 'DELETE',
    });
  }

  async restoreWard(hospitalId, wardId) {
    return this.request(`/api/hospitals/${hospitalId}/wards/${wardId}/restore/`, {
      /**
 * Restores a soft-deleted ward within a specific hospital.
 */
      method: 'POST',
    });
  }

  // helpers for otp verifications

  async refreshOTP(hospitalId,memoId){
    return this.request(`/api/${hospitalId}/memos/${memoId}/refresh-otp/`,{
      method:'POST',
    });
  }

  /**
 * Retrieves memos for the dashboard view, optionally filtered by query parameters.
 */
  async getDashboardMemos(hospitalId,queryParams = ''){
    return this.request( `/api/${hospitalId}/dashboard-memos/?${queryParams}`,{
      method:'GET'
    });
  }

}


export default ApiService;