import type { AuthenticatorRoute } from '@aws-amplify/ui'; import { RenderNothing } from '../../../components'; import type { AuthenticatorMachineContext, AuthenticatorMachineContextKey, AuthenticatorRouteComponentKey, DefaultComponentType, DefaultPropsType, Defaults, } from '../types'; import type { UseAuthenticator, UseAuthenticatorSelector, } from '../useAuthenticator'; import { isComponentRouteKey } from '../utils'; import { MACHINE_PROP_KEYS, EVENT_HANDLER_KEY_MAP } from './constants'; import type { ConvertedMachineProps, FormEventHandlerMachineKey, FormEventHandlerPropKey, UseAuthenticatorRoute, UseAuthenticatorRouteDefault, } from './types'; // only select `route` from machine context export const routeSelector: UseAuthenticatorSelector = ({ route }) => [route]; const createSelector = (selectorKeys: AuthenticatorMachineContextKey[]): UseAuthenticatorSelector => (context) => { const dependencies = selectorKeys.map((key) => context[key]); // route should always be part of deps, so hook knows when route changes. return [...dependencies, context.route]; }; export const getRouteMachineSelector = ( route: AuthenticatorRoute ): UseAuthenticatorSelector => isComponentRouteKey(route) ? createSelector(MACHINE_PROP_KEYS[route]) : routeSelector; const isFormEventHandlerKey = ( key: AuthenticatorMachineContextKey ): key is FormEventHandlerMachineKey => ['updateBlur', 'updateForm', 'submitForm'].includes(key); const convertEventHandlerKey = ( key: FormEventHandlerMachineKey ): FormEventHandlerPropKey => EVENT_HANDLER_KEY_MAP[key]; const getConvertedMachineProps = ( route: AuthenticatorRouteComponentKey, context: AuthenticatorMachineContext ): ConvertedMachineProps => MACHINE_PROP_KEYS[route].reduce( (acc, key) => ({ ...acc, [isFormEventHandlerKey(key) ? convertEventHandlerKey(key) : key]: context[key], }), {} as ConvertedMachineProps ); export function resolveConfirmResetPasswordRoute( Component: Defaults['ConfirmResetPassword'], props: UseAuthenticator ): UseAuthenticatorRoute<'ConfirmResetPassword', FieldType> { return { Component, props: { ...Component, ...getConvertedMachineProps('confirmResetPassword', props), }, }; } export function resolveConfirmSignInRoute( Component: Defaults['ConfirmSignIn'], props: UseAuthenticator ): UseAuthenticatorRoute<'ConfirmSignIn', FieldType> { const { challengeName, ...machineProps } = getConvertedMachineProps( 'confirmSignIn', props ); return { Component, props: { ...Component, ...machineProps, challengeName } }; } export function resolveConfirmSignUpRoute( Component: Defaults['ConfirmSignUp'], props: UseAuthenticator ): UseAuthenticatorRoute<'ConfirmSignUp', FieldType> { return { Component, props: { ...Component, ...getConvertedMachineProps('confirmSignUp', props), }, }; } export function resolveConfirmVerifyUserRoute( Component: Defaults['ConfirmVerifyUser'], props: UseAuthenticator ): UseAuthenticatorRoute<'ConfirmVerifyUser', FieldType> { return { Component, props: { ...Component, ...getConvertedMachineProps('confirmVerifyUser', props), }, }; } export function resolveForceNewPasswordRoute( Component: Defaults['ForceNewPassword'], props: UseAuthenticator ): UseAuthenticatorRoute<'ForceNewPassword', FieldType> { return { Component, props: { ...Component, ...getConvertedMachineProps('forceNewPassword', props), }, }; } export function resolveForgotPasswordRoute( Component: Defaults['ForgotPassword'], props: UseAuthenticator ): UseAuthenticatorRoute<'ForgotPassword', FieldType> { return { Component, props: { ...Component, ...getConvertedMachineProps('forgotPassword', props), }, }; } export function resolveSetupTotpRoute( Component: Defaults['SetupTotp'], props: UseAuthenticator ): UseAuthenticatorRoute<'SetupTotp', FieldType> { return { Component, props: { ...Component, ...getConvertedMachineProps('setupTotp', props), }, }; } export function resolveSetupEmailRoute( Component: Defaults['SetupEmail'], props: UseAuthenticator ): UseAuthenticatorRoute<'SetupEmail', FieldType> { return { Component, props: { ...Component, ...getConvertedMachineProps('setupEmail', props), }, }; } export function resolveSelectMfaTypeRoute( Component: Defaults['SelectMfaType'], props: UseAuthenticator ): UseAuthenticatorRoute<'SelectMfaType', FieldType> { return { Component, props: { ...Component, ...getConvertedMachineProps('selectMfaType', props), }, }; } export function resolveSignInRoute( Component: Defaults['SignIn'], props: UseAuthenticator ): UseAuthenticatorRoute<'SignIn', FieldType> { // default `hideSignUp` to false const hideSignUp = false; return { Component, props: { ...Component, ...getConvertedMachineProps('signIn', props), hideSignUp, }, }; } export function resolveSignUpRoute( Component: Defaults['SignUp'], props: UseAuthenticator ): UseAuthenticatorRoute<'SignUp', FieldType> { return { Component, props: { ...Component, ...getConvertedMachineProps('signUp', props) }, }; } export function resolveVerifyUserRoute( Component: Defaults['VerifyUser'], props: UseAuthenticator ): UseAuthenticatorRoute<'VerifyUser', FieldType> { return { Component, props: { ...Component, ...getConvertedMachineProps('verifyUser', props), }, }; } export function resolveDefault< FieldType = {}, >(): UseAuthenticatorRouteDefault { return { Component: RenderNothing as DefaultComponentType, props: {} as DefaultPropsType, }; }