features/OrdersGroupsList/ordersSlice.js

/**
 * @file
 * File : ordersSlice.js
 * This file defines the orders slice for Redux state management.
 * It provides the initial state, reducers, and actions to manage orders.
 *
 * @author  Pierre-Yves Léglise <contact@axialdata.net>
 * @name ordersSlice
 */

import { createSlice } from '@reduxjs/toolkit'
import { findDefaultOrdersGroupsStatus } from '../../utils/lib/findDefaultOrdersGroupsStatus'

/**
 * The initial state for the orders slice.
 * @type {OrdersState}
 * @author  Pierre-Yves Léglise <contact@axialdata.net>
 * @typedef {Object} OrdersState  * @author  Pierre-Yves Léglise <contact@axialdata.net>
 * @property {boolean} isLoading - Indicates if the data is currently being loaded.
 * @property {string} currentOrdersGroupId - The ID of the currently selected orders group.
 * @property {string} defaultOrdersGroupStatusId - The ID of the default orders group status.
 * @property {string} error - Any error messages from failed operations.
 * @property {Array} ordersGroups - A list of orders groups.
 * @example
 * const initialState = {
 *   isLoading: false,
 *   currentOrdersGroupId: '',
 *   defaultOrdersGroupStatusId: '',
 *   error: '',
 *   ordersGroups: [],
 * }
 * @returns {OrdersState} - The initial state for the orders slice.
 */
const initialState = {
  isLoading: false,
  currentOrdersGroupId: '',
  defaultOrdersGroupStatusId: '',
  error: '',
  ordersGroups: [],
  modalMatchInvoiceIsOpen: false,
  modalSearchRefIsOpen: false,
  orderSeletedFromEditRef: null,
  matchingOrdersSelectedId: '',
}

/**
 * Redux slice for managing the state of orders and order groups.
 */
const userSlice = createSlice({
  name: 'orders',
  initialState,
  reducers: {
    /**
     * Resets the orders state to its initial state.
     * @param {OrdersState} state - The current state of the orders.
     */
    resetOrders: (state) => {
      return initialState
    },

    /**
     * Sets the loading state to true when an API call is pending.
     * @param {OrdersState} state - The current state of the orders.
     */
    ordersPending: (state) => {
      state.isLoading = true
    },

    /**
     * Sets the current orders group ID and clears any errors.
     * @param {OrdersState} state - The current state of the orders.
     * @param {Object} action - Redux action containing the payload.
     * @param {string} action.payload - The ID of the orders group to set.
     */
    setOrdersGroupId: (state, action) => {
      state.isLoading = false
      state.currentOrdersGroupId = action.payload
      state.error = ''
    },

    /**
     * Sets an error message and stops the loading state.
     * @param {OrdersState} state - The current state of the orders.
     * @param {Object} action - Redux action containing the payload.
     * @param {string} action.payload - The error message.
     */
    ordersError: (state, action) => {
      state.isLoading = false
      state.error = action.payload
    },

    /**
     * Resets the current orders group ID and stops the loading state.
     * @param {OrdersState} state - The current state of the orders.
     */
    ordersQuit: (state) => {
      state.isLoading = false
      state.currentOrdersGroupId = ''
    },

    /**
     * Sets the list of orders groups.
     * @param {OrdersState} state - The current state of the orders.
     * @param {Object} action - Redux action containing the payload.
     * @param {Array} action.payload - The list of orders groups.
     */
    setOrdersGroupsList: (state, action) => {
      state.isLoading = false
      state.ordersGroups = action.payload
    },

    /**
     * Updates the modification date of an orders group.
     * @param {OrdersState} state - The current state of the orders.
     * @param {Object} action - Redux action containing the payload.
     * @param {string} action.payload.id - The ID of the orders group to update.
     */
    updateOrdersGroupDate: (state, action) => {
      const { id } = action.payload
      const orderGroup = state.ordersGroups.find((group) => group._id === id)
      if (orderGroup) {
        orderGroup.date_modification = new Date().toISOString()
      }
    },

    /**
     * Adds a count to the orders references in an orders group.
     * @param {OrdersState} state - The current state of the orders.
     * @param {Object} action - Redux action containing the payload.
     * @param {string} action.payload.id - The ID of the orders group to update.
     * @param {number} action.payload.addRefCount - The count to add.
     */
    addOrdersToOrdersGroupCount: (state, action) => {
      const { id, addRefCount } = action.payload
      const orderGroup = state.ordersGroups.find((group) => group._id === id)
      if (orderGroup) {
        if (!orderGroup.orders_references_count) {
          orderGroup.orders_references_count = 0
        }
        orderGroup.orders_references_count += addRefCount
      }
    },

    /**
     * Removes a count from the orders references in an orders group.
     * @param {OrdersState} state - The current state of the orders.
     * @param {Object} action - Redux action containing the payload.
     * @param {string} action.payload.id - The ID of the orders group to update.
     * @param {number} action.payload.removeRefCount - The count to remove.
     */
    removeOrdersToOrdersGroupCount: (state, action) => {
      const { id, removeRefCount } = action.payload
      const orderGroup = state.ordersGroups.find((group) => group._id === id)
      if (orderGroup) {
        if (!orderGroup.orders_references_count) {
          orderGroup.orders_references_count = 0
        }
        orderGroup.orders_references_count -= removeRefCount
      }
    },

    /**
     * Sets the default orders group status ID based on provided data.
     * @param {OrdersState} state - The current state of the orders.
     * @param {Object} action - Redux action containing the payload.
     * @param {Object} action.payload.data - The data used to determine the default status.
     */
    setDefaultOrdersGroupsStatusId: (state, action) => {
      const { data } = action.payload
      state.defaultOrdersGroupStatusId = findDefaultOrdersGroupsStatus(data)
    },

    /**
     * Sets the modal match invoice is open state.
     * @param {OrdersState} state - The current state of the orders.
     * @param {Object} action - Redux action containing the payload.
     * @param {boolean} action.payload - The state of the modal match invoice.
     */
    setModalMatchInvoiceIsOpen: (state, action) => {
      state.modalMatchInvoiceIsOpen = action.payload
    },

    /**
     * Sets the matching orders selected id.
     * @param {OrdersState} state - The current state of the orders.
     * @param {Object} action - Redux action containing the payload.
     * @param {string} action.payload - The id of the matching orders.
     */
    setMatchingOrdersSelectedId: (state, action) => {
      state.matchingOrdersSelectedId = action.payload
    },

    /**
     * Sets the modal search ref is open state.
     * @param {OrdersState} state - The current state of the orders.
     * @param {Object} action - Redux action containing the payload.
     * @param {boolean} action.payload - The state of the modal search ref.
     */
    setModalSearchRefIsOpen: (state, action) => {
      state.modalSearchRefIsOpen = action.payload
    },

    /**
     * Sets the order seleted from edit ref.
     * @param {OrdersState} state - The current state of the orders.
     * @param {Object} action - Redux action containing the payload.
     * @param {Object} action.payload - The order seleted from edit ref.
     */
    setOrderSeletedFromEditRef: (state, action) => {
      state.orderSeletedFromEditRef = action.payload
    },
  },
})

const { actions, reducer } = userSlice
export const {
  ordersPending,
  setOrdersGroupId,
  ordersError,
  ordersQuit,
  setOrdersGroupsList,
  addOrdersToOrdersGroupCount,
  removeOrdersToOrdersGroupCount,
  setDefaultOrdersGroupsStatusId,
  updateOrdersGroupDate,
  setModalMatchInvoiceIsOpen,
  setMatchingOrdersSelectedId,
  setModalSearchRefIsOpen,
  setOrderSeletedFromEditRef,
  resetOrders,
} = actions
export default reducer

/**
 * Selector to get the current orders group ID.
 * @param {Object} state - The global Redux state.
 * @returns {string} - The current orders group ID.
 */
export const selectOrdersGroupId = (state) => state.orders.currentOrdersGroupId

/**
 * Selector to get the list of orders groups.
 * @param {Object} state - The global Redux state.
 * @returns {Array} - The list of orders groups.
 */
export const selectOrdersGroupsList = (state) => state.orders.ordersGroups

/**
 * Selector to get the modal match invoice is open state.
 * @param {Object} state - The global Redux state.
 * @returns {boolean} - The state of the modal match invoice.
 */
export const selectModalMatchInvoiceIsOpen = (state) =>
  state.orders.modalMatchInvoiceIsOpen

/**
 * Selector to get the matching orders selected id.
 * @param {Object} state - The global Redux state.
 * @returns {string} - The id of the matching orders.
 */
export const selectMatchingOrdersSelectedId = (state) =>
  state.orders.matchingOrdersSelectedId

/**
 * Selector to get the modal search ref is open state.
 * @param {Object} state - The global Redux state.
 * @returns {boolean} - The state of the modal search ref.
 */
export const selectModalSearchRefIsOpen = (state) =>
  state.orders.modalSearchRefIsOpen

/**
 * Selector to get the order seleted from edit ref.
 * @param {Object} state - The global Redux state.
 * @returns {Object} - The order seleted from edit ref.
 */
export const selectOrderSeletedFromEditRef = (state) =>
  state.orders.orderSeletedFromEditRef

/**
 * Selector to determine if orders are editable based on the current orders group status.
 * @param {Object} state - The global Redux state.
 * @returns {boolean} - True if orders are editable, false otherwise.
 */
export const selectOrdersAreEditable = (state) => {
  const currentOrdersGroupId = state.orders.currentOrdersGroupId
  const currentOrdersGroup = state.orders.ordersGroups.find(
    (group) => group._id === currentOrdersGroupId
  )

  if (!currentOrdersGroup || !currentOrdersGroup.status) {
    return false
  }

  const statusDescription =
    currentOrdersGroup.status.orders_group_status_description
  return statusDescription === 'A valider' || statusDescription === 'En cours'
}