teamdigitale/italia-app

View on GitHub
ts/store/reducers/persistedPreferences.ts

Summary

Maintainability
C
1 day
Test Coverage
/**
 * A reducer for persisted preferences.
 */
import * as O from "fp-ts/lib/Option";
import * as pot from "@pagopa/ts-commons/lib/pot";
import { Calendar } from "react-native-calendar-events";
import { createSelector } from "reselect";
import { isActionOf } from "typesafe-actions";
import { Locales } from "../../../locales/locales";
import { setMixpanelEnabled } from "../actions/mixpanel";
import {
  continueWithRootOrJailbreak,
  customEmailChannelSetEnabled,
  preferenceFingerprintIsEnabledSaveSuccess,
  preferencesPagoPaTestEnvironmentSetEnabled,
  preferredCalendarRemoveSuccess,
  preferredCalendarSaveSuccess,
  preferredLanguageSaveSuccess,
  serviceAlertDisplayedOnceSuccess,
  preferencesPnTestEnvironmentSetEnabled,
  preferencesIdPayTestSetEnabled,
  preferencesDesignSystemSetEnabled
} from "../actions/persistedPreferences";
import { Action } from "../actions/types";
import { differentProfileLoggedIn } from "../actions/crossSessions";
import { GlobalState } from "./types";

export type PersistedPreferencesState = Readonly<{
  isFingerprintEnabled?: boolean;
  preferredCalendar?: Calendar;
  preferredLanguage?: Locales;
  wasServiceAlertDisplayedOnce?: boolean;
  isPagoPATestEnabled: boolean;
  // TODO: create transformer for Option objects and use Option instead of pot
  //       https://www.pivotaltracker.com/story/show/170998374
  isCustomEmailChannelEnabled: pot.Pot<boolean, undefined>;
  continueWithRootOrJailbreak?: boolean;
  isMixpanelEnabled: boolean | null;
  isPnTestEnabled: boolean;
  isIdPayTestEnabled?: boolean;
  // 'isDesignSystemEnabled' has been introduced without a migration
  // (PR https://github.com/pagopa/io-app/pull/4427) so there are cases
  // where its value is `undefined` (when the user updates the app without
  // changing the variable value later). Typescript cannot detect this so
  // be sure to handle such case when reading and using this value
  isDesignSystemEnabled: boolean;
}>;

export const initialPreferencesState: PersistedPreferencesState = {
  isFingerprintEnabled: undefined,
  preferredCalendar: undefined,
  preferredLanguage: undefined,
  wasServiceAlertDisplayedOnce: false,
  isPagoPATestEnabled: false,
  isCustomEmailChannelEnabled: pot.none,
  continueWithRootOrJailbreak: false,
  isMixpanelEnabled: null,
  isPnTestEnabled: false,
  isIdPayTestEnabled: false,
  isDesignSystemEnabled: false
};

export default function preferencesReducer(
  state: PersistedPreferencesState = initialPreferencesState,
  action: Action
): PersistedPreferencesState {
  if (isActionOf(preferenceFingerprintIsEnabledSaveSuccess, action)) {
    return {
      ...state,
      isFingerprintEnabled: action.payload.isFingerprintEnabled
    };
  }
  if (isActionOf(preferredCalendarSaveSuccess, action)) {
    return {
      ...state,
      preferredCalendar: action.payload.preferredCalendar
    };
  }
  if (isActionOf(preferredCalendarRemoveSuccess, action)) {
    return {
      ...state,
      preferredCalendar: initialPreferencesState.preferredCalendar
    };
  }
  if (isActionOf(preferredLanguageSaveSuccess, action)) {
    return {
      ...state,
      preferredLanguage: action.payload.preferredLanguage
    };
  }
  if (isActionOf(serviceAlertDisplayedOnceSuccess, action)) {
    return {
      ...state,
      wasServiceAlertDisplayedOnce: action.payload.wasServiceAlertDisplayedOnce
    };
  }
  if (isActionOf(preferencesPagoPaTestEnvironmentSetEnabled, action)) {
    return {
      ...state,
      isPagoPATestEnabled: action.payload.isPagoPATestEnabled
    };
  }

  if (isActionOf(customEmailChannelSetEnabled, action)) {
    return {
      ...state,
      isCustomEmailChannelEnabled: pot.some(action.payload)
    };
  }

  if (isActionOf(continueWithRootOrJailbreak, action)) {
    return {
      ...state,
      continueWithRootOrJailbreak: action.payload
    };
  }

  if (isActionOf(setMixpanelEnabled, action)) {
    return {
      ...state,
      isMixpanelEnabled: action.payload
    };
  }

  if (isActionOf(preferencesPnTestEnvironmentSetEnabled, action)) {
    return {
      ...state,
      isPnTestEnabled: action.payload.isPnTestEnabled
    };
  }

  if (isActionOf(preferencesDesignSystemSetEnabled, action)) {
    return {
      ...state,
      isDesignSystemEnabled: action.payload.isDesignSystemEnabled
    };
  }

  // when the current user is different from the previous logged one
  // reset the mixpanel opt-in preference
  if (isActionOf(differentProfileLoggedIn, action)) {
    return {
      ...state,
      isMixpanelEnabled: null,
      isFingerprintEnabled: undefined
    };
  }

  if (isActionOf(preferencesIdPayTestSetEnabled, action)) {
    return {
      ...state,
      isIdPayTestEnabled: action.payload.isIdPayTestEnabled
    };
  }

  return state;
}

// Selectors
export const isPagoPATestEnabledSelector = (state: GlobalState) =>
  state.persistedPreferences.isPagoPATestEnabled;

export const wasServiceAlertDisplayedOnceSelector = (state: GlobalState) =>
  state.persistedPreferences.wasServiceAlertDisplayedOnce;

export const isCustomEmailChannelEnabledSelector = (state: GlobalState) =>
  state.persistedPreferences.isCustomEmailChannelEnabled;

export const preferredCalendarSelector = (state: GlobalState) =>
  state.persistedPreferences.preferredCalendar;

export const isFingerprintEnabledSelector = (state: GlobalState) =>
  state.persistedPreferences.isFingerprintEnabled;

export const persistedPreferencesSelector = (state: GlobalState) =>
  state.persistedPreferences;

export const continueWithRootOrJailbreakSelector = (state: GlobalState) =>
  state.persistedPreferences.continueWithRootOrJailbreak;

export const isMixpanelEnabled = (state: GlobalState): boolean | null =>
  state.persistedPreferences.isMixpanelEnabled;

export const isPnTestEnabledSelector = (state: GlobalState) =>
  state.persistedPreferences.isPnTestEnabled;

export const isIdPayTestEnabledSelector = (state: GlobalState) =>
  !!state.persistedPreferences?.isIdPayTestEnabled;

// 'isDesignSystemEnabled' has been introduced without a migration
// (PR https://github.com/pagopa/io-app/pull/4427) so there are cases
// where its value is `undefined` (when the user updates the app without
// changing the variable value later). Typescript cannot detect this so
// we must make sure that the signature's return type is respected
export const isDesignSystemEnabledSelector = (state: GlobalState) =>
  state.persistedPreferences.isDesignSystemEnabled ?? false;

// returns the preferred language as an Option from the persisted store
export const preferredLanguageSelector = createSelector<
  GlobalState,
  PersistedPreferencesState,
  O.Option<Locales>
>(persistedPreferencesSelector, pps => O.fromNullable(pps.preferredLanguage));