import { DeviceModelId } from "@ledgerhq/types-devices"; import { PostOnboardingActionId, PostOnboardingState } from "@ledgerhq/types-live"; import { handleActions } from "redux-actions"; import type { ReducerMap } from "redux-actions"; import { createSelector, Selector } from "reselect"; export const initialState: PostOnboardingState = { deviceModelId: null, walletEntryPointDismissed: false, entryPointFirstDisplayedDate: null, walletEntryPointEligibleForPortfolio: null, actionsToComplete: [], actionsCompleted: {}, lastActionCompleted: null, postOnboardingInProgress: false, }; type PartialNewStatePayload = { newState: Partial }; type InitPayload = { deviceModelId: DeviceModelId; actionsIds: PostOnboardingActionId[]; }; type SetActionCompletedPayload = { actionId: PostOnboardingActionId; }; export type Payload = | undefined | PartialNewStatePayload | InitPayload | SetActionCompletedPayload | boolean; const handlers: ReducerMap = { POST_ONBOARDING_IMPORT_STATE: (_, { payload }): PostOnboardingState => ({ ...initialState, ...(payload as PartialNewStatePayload).newState, }), POST_ONBOARDING_INIT: (_, { payload }) => { const { deviceModelId, actionsIds } = payload as InitPayload; return { deviceModelId, walletEntryPointDismissed: false, entryPointFirstDisplayedDate: new Date(), walletEntryPointEligibleForPortfolio: null, actionsToComplete: actionsIds, actionsCompleted: Object.fromEntries(actionsIds.map(id => [id, false])), lastActionCompleted: null, postOnboardingInProgress: true, }; }, POST_ONBOARDING_SET_ACTION_COMPLETED: (state, { payload }) => { const { actionId } = payload as SetActionCompletedPayload; const actionsCompleted = { ...state.actionsCompleted, [actionId]: true }; return { ...state, actionsCompleted, lastActionCompleted: actionId, }; }, POST_ONBOARDING_CLEAR_LAST_ACTION_COMPLETED: state => ({ ...state, lastActionCompleted: null, }), POST_ONBOARDING_HIDE_WALLET_ENTRY_POINT: state => ({ ...state, walletEntryPointDismissed: true, entryPointFirstDisplayedDate: null, }), POST_ONBOARDING_SET_WALLET_ENTRY_POINT_ELIGIBILITY: (state, { payload }) => { if (typeof payload !== "boolean") return state; return { ...state, walletEntryPointEligibleForPortfolio: payload, }; }, POST_ONBOARDING_SET_FINISHED: state => ({ ...state, postOnboardingInProgress: false, }), }; export default handleActions(handlers, initialState); /** * remove this function once we can safely assume no user has a LL holding in * storage a ref to the old identifier "nanoFTS" which was changed in this PR * https://github.com/LedgerHQ/ledger-live/pull/2144 * */ function sanitizeDeviceModelId(deviceModelId: DeviceModelId | null): DeviceModelId | null { if (deviceModelId === null) return null; // Nb workaround to prevent crash for dev/qa that have nanoFTS references. // to be removed in a while. // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore if (deviceModelId === "nanoFTS") return DeviceModelId.stax; return deviceModelId; } export const postOnboardingSelector: Selector< { postOnboarding: PostOnboardingState }, PostOnboardingState > = createSelector( (state: { postOnboarding: PostOnboardingState }) => state.postOnboarding, postOnboarding => ({ ...postOnboarding, deviceModelId: sanitizeDeviceModelId(postOnboarding.deviceModelId), }), ); export const hubStateSelector = createSelector(postOnboardingSelector, postOnboarding => { const { deviceModelId, actionsToComplete, actionsCompleted, lastActionCompleted, postOnboardingInProgress, } = postOnboarding; return { deviceModelId: sanitizeDeviceModelId(deviceModelId), actionsToComplete, actionsCompleted, lastActionCompleted, postOnboardingInProgress, }; }); export const postOnboardingDeviceModelIdSelector = createSelector( postOnboardingSelector, postOnboarding => sanitizeDeviceModelId(postOnboarding.deviceModelId), ); export const walletPostOnboardingEntryPointDismissedSelector = createSelector( postOnboardingSelector, postOnboarding => postOnboarding.walletEntryPointDismissed, ); export const entryPointFirstDisplayedDateSelector = createSelector( postOnboardingSelector, postOnboarding => postOnboarding.entryPointFirstDisplayedDate, ); export const walletEntryPointEligibleForPortfolioSelector = createSelector( postOnboardingSelector, postOnboarding => postOnboarding.walletEntryPointEligibleForPortfolio, );