features/auth/authSlice.js

/**
 * @file
 * File: authSlice.js
 * This file defines the Redux slice for managing authentication state.
 * It handles actions related to user authentication, including login, logout, and user profile updates.
 *
 * @author Pierre-Yves Léglise <contact@axialdata.net>
 * @name authSlice
 */

import { createSlice } from '@reduxjs/toolkit'

// Initial state for authentication slice
const initialState = {
  userId: null,
  userName: null,
  firstName: null,
  lastName: null,
  roles: null,
  email: null,
  language: 'EN_en',
  isLoading: false,
  isProcessed: false,
  isAuth: false,
  isRemember: true,
  accessToken: null,
  emailValid: false,
  mfaEnabled: false,
  mfaActive: false,
  picture: null,
  pictureIsValid: false,
  error: '',
}

/**
 * Redux slice for authentication state management.
 * It contains reducers to handle various authentication-related actions.
 */
const authSlice = createSlice({
  name: 'auth',
  initialState,
  reducers: {
    /**
     * Sets the state to loading when a login request is initiated.
     */
    logingPending: (state) => {
      state.isLoading = true
    },

    /**
     * Sets the state to processed after a login request completes.
     */
    logingEnded: (state) => {
      state.isLoading = false
      state.isProcessed = true
    },

    /**
     * Updates the state with user information and authentication status on successful login.
     * @param {Object} state - Current state.
     * @param {Object} action - Action containing the user data.
     */
    logingSuccess: (state, action) => {
      state.isLoading = false
      state.isProcessed = true
      state.isAuth = true
      state.userId = action.payload.userId
      state.userName = action.payload.userName
      state.firstName = action.payload.firstName
      state.lastName = action.payload.lastName
      state.email = action.payload.email
      state.roles = action.payload.roles
      state.language = action.payload.language
      state.emailValid = action.payload.emailValid
      state.accessToken = action.payload.accessToken
      state.mfaActive = action.payload.mfaActive
      state.mfaEnabled = action.payload.mfaEnabled
      state.picture = action.payload.picture
      state.pictureIsValid = action.payload.pictureIsValid
      state.error = ''
    },

    /**
     * Updates the state for MFA (Multi-Factor Authentication) before OTP (One-Time Password) validation.
     * @param {Object} state - Current state.
     * @param {Object} action - Action containing the MFA and user data.
     */
    loginBeforeOtp: (state, action) => {
      state.isLoading = false
      state.isProcessed = true
      state.mfaActive = action.payload.mfaActive
      state.mfaEnabled = action.payload.mfaEnabled
      state.accessToken = action.payload.accessToken
      state.userId = action.payload.userId
      state.language = action.payload.language
      state.isRemember = false
      state.error = ''
    },

    /**
     * Handles login errors by updating the state with the error message.
     * @param {Object} state - Current state.
     * @param {string} action - Error message.
     */
    logingError: (state, action) => {
      state.isLoading = false
      state.isProcessed = true
      state.error = action.payload
    },

    /**
     * Updates the remember-me option for the login process.
     * @param {Object} state - Current state.
     * @param {Object} action - Action containing the remember option.
     */
    logingRemember: (state, action) => {
      state.isLoading = false
      state.isProcessed = true
      state.isRemember = action.payload.isRemember
      state.error = ''
    },

    /**
     * Updates the authentication state with new user information.
     * @param {Object} state - Current state.
     * @param {Object} action - Action containing the updated user data.
     */
    logingUpdate: (state, action) => {
      state.isLoading = false
      state.isProcessed = true
      state.userId = action.payload.userId
      state.firstName = action.payload.firstName
      state.lastName = action.payload.lastName
      state.userName = action.payload.userName
      state.language = action.payload.language
      state.email = action.payload.email
      state.roles = action.payload.roles
      state.emailValid = action.payload.emailValid
      state.mfaActive = action.payload.mfaActive
      state.mfaEnabled = action.payload.mfaEnabled
      state.picture = action.payload.picture
      state.pictureIsValid = action.payload.pictureIsValid
      state.error = ''
    },

    /**
     * Resets the authentication state upon user logout.
     */
    logingOut: (state) => {
      state.userId = null
      state.userName = null
      state.firstName = null
      state.lastName = null
      state.roles = null
      state.email = null
      state.language = initialState.language
      state.isLoading = false
      state.isProcessed = true
      state.isAuth = false
      state.accessToken = null
      state.emailValid = false
      state.mfaActive = false
      state.mfaEnabled = false
      state.picture = null
      state.pictureIsValid = false
      state.error = ''
    },

    /**
     * Updates the user's profile picture in the state.
     * @param {Object} state - Current state.
     * @param {Object} action - Action containing the new profile picture data.
     */
    updateAuthPicture: (state, action) => {
      state.picture = action.payload.picture
      state.pictureIsValid = true
    },
  },
})

const { actions, reducer } = authSlice

// Exporting the actions for use in components
export const {
  logingPending,
  logingSuccess,
  loginBeforeOtp,
  logingError,
  logingOut,
  logingRemember,
  logingUpdate,
  logingEnded,
  updateAuthPicture,
} = actions

export default reducer

// Selectors for accessing specific pieces of the authentication state
export const selectCurrentIsAuth = (state) => state.auth.isAuth
export const selectCurrentUserId = (state) => state.auth.userId
export const selectCurrentToken = (state) => state.auth.accessToken
export const selectAuthUserRole = (state) => state.auth.roles