Source: app/reducers/authenticationReducer.js

/* global WP_DEFINE_IS_NODE */
import {
  SET_AUTH_TOKENS,
  SET_INITIAL_USER_STATE,
  CHANGE_INITIAL_USER_STATE,
  SET_USER_PERMISSION_STATE,
} from '../actions/authenticationActions';
import { getAccountType } from '../util/userPermissionStateUtil';

/**
 * Object that maps JWT clauses to their corresponding property names in an account entity
 * from the API. This is used to have a consistent API to get account information from the
 * userAccountSelector
 */
export const JWT_CLAUSE_MAP = {
  sub: 'id',
  preferred_username: 'userName',
  name: 'name',
  role: 'roles',
  zoneinfo: 'timeZoneId',
  group_id: 'groupId',
  account_state: 'accountState',
  member_type: 'memberType',
};

export const JWT_CLAUSE_MAP_ID_TOKEN = {
  email: 'email',
  ua: 'ua',
  mps: 'mps',
};

const authenticationReducer = (
  authState = {
    /**
     * The JWT access token (if the user is logged in)
     * This will be removed in the initial state sent to the client, because the client
     * will get its own access token using the implicit auth flow
     */
    accessToken: null,
    /**
     * The JWT identity token (if the user is logged in)
     * This will be removed in the initial state sent to the client, because the client
     * will get its own access token using the implicit auth flow
     */
    idToken: null,
    /**
     * An object containing the decoded clauses in the JWT access token (if the user is logged in).
     * This information will be available as initial state to the client. This is to make sure
     * the clauses in the token are immediately available on the client, without having to wait
     * for the implicit auth flow to complete. For that reason, some technical clauses that are
     * specifically meant for the server token are not included in this object (like nbf, issuer,
     * exp)
     *
     * __PLEASE NOTE: __ As we want a single source of truth for account information, it is best
     * not to use this state directly. Instead, use the userAccountSelector available in the
     * `reducers` folder.
     */
    userInfo: null,
  },
  action,
) => {
  switch (action.type) {
    case SET_AUTH_TOKENS: {
      const { idToken, accessToken, decodedAccessToken, decodedIdToken } = action.payload;
      const userInfo = authState.userInfo || {};

      Object.keys(JWT_CLAUSE_MAP).forEach(
        clause => (userInfo[clause] = decodedAccessToken[clause]),
      );
      Object.keys(JWT_CLAUSE_MAP_ID_TOKEN).forEach(
        clause => (userInfo[clause] = decodedIdToken[clause]),
      );

      return {
        ...authState,
        accessToken,
        idToken,
        userInfo,
        userPermissionState: {
          // eslint-disable-next-line no-underscore-dangle
          ...authState.userPermissionState,
          accountState: userInfo.account_state,
        },
      };
    }
    case SET_INITIAL_USER_STATE:
    case CHANGE_INITIAL_USER_STATE: {
      const prevUserInfo = authState.userInfo || {};
      return {
        ...authState,
        userInfo: {
          ...prevUserInfo,
          initialUserState: action.payload,
        },
      };
    }
    case SET_USER_PERMISSION_STATE: {
      const { accountState, roles, userId } = action.payload;
      return {
        ...authState,
        userPermissionState: {
          userId,
          accountState,
          roles,
          subscriptionType: getAccountType(accountState),
        },
      };
    }
    default:
      return authState;
  }
};

export default authenticationReducer;