Source

contexts/AuthContext.js

  import React, { createContext, useContext, useState, useEffect } from 'react';
  import ApiService from '../services/api';

  const AuthContext = createContext();

  export const useAuth = () => {
    const context = useContext(AuthContext);
    if (!context) {
      throw new Error('useAuth must be used within an AuthProvider');
    }
    return context;
  };

  const AuthProvider = ({ children }) => {
    /**
     * @typedef {object} User - Represents the authenticated user.
     * @property {number} id - The user's ID.
     * @property {string} username - The user's username.
     * @property {boolean} is_superuser - True if the user is a superuser.
     * @property {boolean} is_staff - True if the user is a staff member.
     * @property {boolean} is_creator - True if the user has creator permissions.
     * @property {boolean} is_approver - True if the user has approver permissions.
     * @property {boolean} is_responder - True if the user has responder permissions.
     * @property {boolean} is_raiser - True if the user has raiser permissions.
     * @property {number} hospital_id - The ID of the hospital the user belongs to.
     */

    /** @type {[User | null, React.Dispatch<React.SetStateAction<User | null>>]} */
    const [user, setUser] = useState(null);
    /** @type {[object | null, React.Dispatch<React.SetStateAction<object | null>>]} */
    const [hospital, setHospital] = useState(null);
    const [loading, setLoading] = useState(true);
    const [apiService] = useState(new ApiService());

    // Initialize authentication state on component mount
    useEffect(() => {
      initializeAuth();
    }, []);

    const initializeAuth = async () => {
      try {
        const token = localStorage.getItem('authToken');
        const storedUser = JSON.parse(localStorage.getItem('user') || 'null');
        const storedHospital = JSON.parse(localStorage.getItem('hospital') || 'null');

        if (token && storedUser && storedHospital) {
          setUser(storedUser);
          setHospital(storedHospital);
        }
      } catch (error) {
        console.error('Failed to initialize auth:', error);
        logout();
      } finally {
        setLoading(false);
      }
    };

    /**
     * Handles user login.
     * @param {string} phoneNumber - The user's phone number.
     * @param {string} password - The user's password.
     * @param {string} fcmToken - The Firebase Cloud Messaging token for the device.
     * @returns {Promise<{success: boolean, error?: string}>} - An object indicating the success of the login and an optional error message.
     */

    const login = async (phoneNumber, password,fcmToken) => {
      try {
        // Login API returns: { token, user: {..., hospital_id: 123}, hospital: {...} }
        const response = await apiService.login(phoneNumber, password,fcmToken);
        const { token, user: userData, hospital: hospitalData } = response;

        // Store auth data
        console.log(response);
        localStorage.setItem('authToken', token);
        localStorage.setItem('user', JSON.stringify(userData));
        localStorage.setItem('hospital', JSON.stringify(hospitalData));

        setUser(userData);
        setHospital(hospitalData);

        return { success: true };
      } catch (error) {
        return { success: false, error: error.message };
      }
    };

    /**
     * Handles user logout.
     */
    const logout = async () => {
      await apiService.logout();
      localStorage.removeItem('authToken');
      localStorage.removeItem('user');
      localStorage.removeItem('hospital');
      setUser(null);
      setHospital(null);
    };

    /**
     * Updates the authenticated user, hospital, and token.
     * @param {User | null} newUser - The new user data.
     * @param {object | null} newHospital - The new hospital data.
     * @param {string | null} newToken - The new authentication token.
     */
    const updateAuth = (newUser, newHospital, newToken) => {
      setUser(newUser);
      setHospital(newHospital);
      localStorage.setItem('user', JSON.stringify(newUser));
      localStorage.setItem('hospital', JSON.stringify(newHospital));
      localStorage.setItem('authToken', newToken);
    };

    /**
     * Sets a new password for the user.
     * @param {string} phoneNumber - The user's phone number.
     * @param {string} newPassword - The new password.
     */
    const setPasswordfunc = async (phoneNumber, newPassword) => {
      return await apiService.setPassword(phoneNumber, newPassword);
    };

    const value = {
      user,
    hospital,
    loading,
    login,
    logout,
    updateAuth,
    setPasswordfunc,

    /**
     * @type {ApiService} - An instance of the ApiService for making API calls.
     */


    apiService,
    isAuthenticated: !!user,
    isSuperuser: user?.is_superuser || user?.is_staff || (user?.is_creator && user?.is_approver && user?.is_responder) || false,
    isApprover: user?.is_approver || false,
    isResponder: user?.is_responder || false,
    isCreator: user?.is_creator || false,
    isRaiser: user?.is_raiser || false,

  };

  return <AuthContext.Provider value={value}>{children}</AuthContext.Provider>;
};

export { AuthContext, AuthProvider };