From ce9dfe2fff2992183de84ff0afbc4d2606cbc2ba Mon Sep 17 00:00:00 2001 From: Abdullah Shahbaz Date: Sat, 3 Feb 2024 15:49:28 +0500 Subject: [PATCH] restructured project config for using in react package --- .../react/src/contexts/FlowHandlerContext.ts | 9 +++-- .../src/contexts/FlowHandlerProvider.tsx | 14 ++++--- .../base/authentication/login/Start.tsx | 4 +- .../base/authentication/signup/Start.tsx | 6 +-- packages/react/src/screens/core/SignUp.tsx | 9 ----- .../shared-ui/src/flowHandler/flowHandler.ts | 38 +++++++++++++------ .../src/flowHandler/flowHandlerConfig.ts | 10 +++++ playground/react/.env | 2 +- 8 files changed, 56 insertions(+), 36 deletions(-) diff --git a/packages/react/src/contexts/FlowHandlerContext.ts b/packages/react/src/contexts/FlowHandlerContext.ts index 75201599..664fee8d 100644 --- a/packages/react/src/contexts/FlowHandlerContext.ts +++ b/packages/react/src/contexts/FlowHandlerContext.ts @@ -6,8 +6,7 @@ import type { UserState, VerificationMethods, } from '@corbado/shared-ui'; -import { ScreenNames } from '@corbado/shared-ui'; -import type { ProjectConfig } from '@corbado/types'; +import { ScreenNames } from '@corbado/shared-ui' import { createContext } from 'react'; export interface FlowHandlerContextProps { @@ -17,7 +16,8 @@ export interface FlowHandlerContextProps { currentUserState: UserState; currentVerificationMethod: VerificationMethods | undefined; initialized: boolean; - projectConfig: ProjectConfig | undefined; + userNameRequired: boolean; + allowUserRegistration: boolean; navigateBack: () => ScreenNames; emitEvent: (event?: FlowHandlerEvents, eventOptions?: FlowHandlerEventOptions) => Promise | undefined; changeFlow: () => void; @@ -30,7 +30,8 @@ export const initialContext: FlowHandlerContextProps = { currentUserState: {}, currentVerificationMethod: undefined, initialized: false, - projectConfig: undefined, + userNameRequired: true, + allowUserRegistration: true, navigateBack: () => ScreenNames.Start, emitEvent: () => Promise.reject(), changeFlow: () => void 0, diff --git a/packages/react/src/contexts/FlowHandlerProvider.tsx b/packages/react/src/contexts/FlowHandlerProvider.tsx index da05489b..5ebce16c 100644 --- a/packages/react/src/contexts/FlowHandlerProvider.tsx +++ b/packages/react/src/contexts/FlowHandlerProvider.tsx @@ -8,7 +8,6 @@ import type { VerificationMethods, } from '@corbado/shared-ui'; import { FlowHandler, FlowHandlerEvents, ScreenNames } from '@corbado/shared-ui'; -import type { ProjectConfig } from '@corbado/types'; import i18n from 'i18next'; import type { FC, PropsWithChildren } from 'react'; import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'; @@ -34,7 +33,8 @@ export const FlowHandlerProvider: FC> = ({ const [currentUserState, setCurrentUserState] = useState({}); const [currentFlow, setCurrentFlow] = useState(); const [initialized, setInitialized] = useState(false); - const [projectConfig, setProjectConfig] = useState(undefined); + const [userNameRequired, setUserNameRequired] = useState(true); + const [allowUserRegistration, setAllowUserRegistration] = useState(true); const currentFlowType = useRef(); const verificationMethod = useRef(); const onFlowChangeCbId = useRef(0); @@ -53,7 +53,7 @@ export const FlowHandlerProvider: FC> = ({ } const projectConfig = projectConfigResult.val; - const flowHandler = new FlowHandler(projectConfig, onLoggedIn, initialFlowType); + const flowHandler = new FlowHandler(corbadoApp, projectConfig, onLoggedIn, initialFlowType); onFlowChangeCbId.current = flowHandler.onFlowChange(updates => { updates.flowName && setCurrentFlow(updates.flowName); @@ -72,10 +72,11 @@ export const FlowHandlerProvider: FC> = ({ setCurrentUserState(value); }); - await flowHandler.init(corbadoApp, i18n); + await flowHandler.init(i18n); - setProjectConfig(projectConfig); setFlowHandler(flowHandler); + setUserNameRequired(flowHandler.userNameRequired); + setAllowUserRegistration(flowHandler.allowUserRegistration); setInitialized(true); })(); @@ -112,7 +113,8 @@ export const FlowHandlerProvider: FC> = ({ currentUserState, currentVerificationMethod: verificationMethod.current, initialized, - projectConfig, + userNameRequired, + allowUserRegistration, changeFlow, navigateBack, emitEvent, diff --git a/packages/react/src/screens/base/authentication/login/Start.tsx b/packages/react/src/screens/base/authentication/login/Start.tsx index 856b586d..9ed3f4f8 100644 --- a/packages/react/src/screens/base/authentication/login/Start.tsx +++ b/packages/react/src/screens/base/authentication/login/Start.tsx @@ -6,7 +6,7 @@ import { AuthFormScreen, FormInput } from '../../../../components'; import useFlowHandler from '../../../../hooks/useFlowHandler'; export const Start = () => { - const { emitEvent, currentUserState, projectConfig } = useFlowHandler(); + const { emitEvent, currentUserState, allowUserRegistration } = useFlowHandler(); const { t } = useTranslation('translation', { keyPrefix: `authentication.login.start` }); const [loading, setLoading] = useState(false); const initialized = useRef(false); @@ -29,7 +29,7 @@ export const Start = () => { const headerText = useMemo(() => t('header'), [t]); const subHeaderText = useMemo(() => t('subheader'), [t]); const flowChangeButtonText = useMemo( - () => (projectConfig?.allowUserRegistration ? t('button_signup') : undefined), + () => (allowUserRegistration ? t('button_signup') : undefined), [t], ); const emailFieldLabel = useMemo(() => t('textField_email'), [t]); diff --git a/packages/react/src/screens/base/authentication/signup/Start.tsx b/packages/react/src/screens/base/authentication/signup/Start.tsx index 8f5fd1cf..7dbdfae6 100644 --- a/packages/react/src/screens/base/authentication/signup/Start.tsx +++ b/packages/react/src/screens/base/authentication/signup/Start.tsx @@ -7,7 +7,7 @@ import { AuthFormScreen, FormInput } from '../../../../components'; import useFlowHandler from '../../../../hooks/useFlowHandler'; export const Start = () => { - const { currentUserState, projectConfig, emitEvent } = useFlowHandler(); + const { currentUserState, userNameRequired, emitEvent } = useFlowHandler(); const { t } = useTranslation('translation', { keyPrefix: `authentication.signup.start` }); const [emailError, setEmailError] = useState(null); const [userNameError, setUserNameError] = useState(null); @@ -31,7 +31,7 @@ export const Start = () => { const handleSubmit = useCallback(() => { setLoading(true); - const fullName = projectConfig?.userFullNameRequired ? fullNameRef.current?.value : emailRef.current?.value; + const fullName = userNameRequired ? fullNameRef.current?.value : emailRef.current?.value; void emitEvent(FlowHandlerEvents.PrimaryButton, { userStateUpdate: { email: emailRef.current?.value, fullName }, @@ -48,7 +48,7 @@ export const Start = () => { submitButtonText={submitButtonText} loading={loading} > - {projectConfig?.userFullNameRequired && ( + {userNameRequired && ( = ({ onSignedUp, navigateToLogin }) => { - const { projectConfig } = useFlowHandler(); - const { setGlobalError } = useCorbado(); - - if (!projectConfig?.allowUserRegistration) { - setGlobalError(NonRecoverableError.userRegistrationNotAllowed()); - } - return (
void> = []; #onUserStateChangeCallbacks: Array<(v: UserState) => void> = []; @@ -34,12 +35,23 @@ export class FlowHandler { * The constructor initializes the FlowHandler with a flow name, a project configuration, and a flow handler configuration. * It sets the current flow to the specified flow, the current screen to the Start screen, and initializes the screen history as an empty array. */ - constructor(projectConfig: ProjectConfig, onLoggedIn: () => void, initialFlowType: FlowType = FlowType.SignUp) { - if (!projectConfig.allowUserRegistration) { - initialFlowType = FlowType.Login; + constructor(corbadoApp: CorbadoApp | undefined, projectConfig: ProjectConfig, onLoggedIn: () => void, initialFlowType?: FlowType) { + if (!corbadoApp) { + throw new Error('corbadoApp is undefined. This should not happen.'); } - this.#config = new FlowHandlerConfig(onLoggedIn, projectConfig, initialFlowType); + let flowType = initialFlowType; + + if (projectConfig.allowUserRegistration === false) { + if (initialFlowType === FlowType.SignUp) { + corbadoApp.globalErrors.next(NonRecoverableError.userRegistrationNotAllowed()) + } else { + flowType = FlowType.Login; + } + } + + this.#corbadoApp = corbadoApp; + this.#config = new FlowHandlerConfig(onLoggedIn, projectConfig, flowType); this.#screenHistory = []; this.#currentScreen = this.#config.initialScreenName; } @@ -48,11 +60,7 @@ export class FlowHandler { * Initializes the FlowHandler. * Call this function after registering all callbacks. */ - async init(corbadoApp: CorbadoApp | undefined, i18next: i18n) { - if (!corbadoApp) { - throw new Error('corbadoApp is undefined. This should not happen.'); - } - + async init(i18next: i18n) { const passkeysSupported = await canUsePasskeys(); this.#state = new FlowHandlerState( @@ -63,7 +71,7 @@ export class FlowHandler { emailError: undefined, }, passkeysSupported, - corbadoApp, + this.#corbadoApp, i18next, ); @@ -86,6 +94,14 @@ export class FlowHandler { return this.#config.verificationMethod; } + get userNameRequired() { + return this.#config.userNameRequired; + } + + get allowUserRegistration() { + return this.#config.allowUserRegistration; + } + /** * Method to add a callback function to be called when the current flow changes. * @param cb The callback function to be called when the current flow changes. diff --git a/packages/shared-ui/src/flowHandler/flowHandlerConfig.ts b/packages/shared-ui/src/flowHandler/flowHandlerConfig.ts index de36bdfe..8f37f2fb 100644 --- a/packages/shared-ui/src/flowHandler/flowHandlerConfig.ts +++ b/packages/shared-ui/src/flowHandler/flowHandlerConfig.ts @@ -14,11 +14,13 @@ export class FlowHandlerConfig { readonly #onLoggedIn: () => void; readonly #initialScreenName: ScreenNames; readonly #flowDetails: FlowDetails; + readonly #projectConfig: ProjectConfig; #flowType: FlowType; constructor(onLoggedIn: () => void, projectConfig: ProjectConfig, initialFlowType: FlowType = FlowType.SignUp) { this.#onLoggedIn = onLoggedIn; this.#flowType = initialFlowType; + this.#projectConfig = projectConfig; this.#flowDetails = this.#getFlowDetails(projectConfig); this.#initialScreenName = this.#getInitialScreenName(); } @@ -47,6 +49,14 @@ export class FlowHandlerConfig { return this.#flowDetails[this.#flowType].options.verificationMethod ?? 'emailOtp'; } + get userNameRequired() { + return this.#projectConfig.userFullNameRequired; + } + + get allowUserRegistration() { + return this.#projectConfig.allowUserRegistration; + } + // The update method allows the type of flow to be changed, // and updates the flow name and options accordingly. update(flowType: FlowType) { diff --git a/playground/react/.env b/playground/react/.env index 8875c052..abc9d0a0 100644 --- a/playground/react/.env +++ b/playground/react/.env @@ -1,5 +1,5 @@ # Flow: PasskeySignupWithEmailOTPFallback -REACT_APP_CORBADO_PROJECT_ID=pro-8793272752372175738 +REACT_APP_CORBADO_PROJECT_ID=pro-503401103218055321 # Flow: PasskeySignupWithEmailOTPFallback + Email Link verification method # REACT_APP_CORBADO_PROJECT_ID=pro-423122463392265807 \ No newline at end of file