@oneblink/apps-react 11.0.0-beta.2 → 11.0.0-beta.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"file":"cognito.js","sourceRoot":"","sources":["../../../src/apps/services/cognito.ts"],"names":[],"mappings":"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","sourcesContent":["import { jwtDecode } from 'jwt-decode'\n\nimport AWSCognitoClient, {\n DEFAULT_MFA_SETTINGS,\n LoginAttemptResponse,\n MfaMethod,\n MfaRequirementCheckResult,\n MfaSettings,\n} from './AWSCognitoClient'\n\nimport * as offlineService from '../offline-service'\nimport { userService } from '@oneblink/sdk-core'\nimport { MiscTypes } from '@oneblink/types'\nimport { HTTPError, postRequest } from './fetch'\nimport tenants from '../tenants'\nimport OneBlinkAppsError from './errors/oneBlinkAppsError'\n\ninterface CognitoServiceData {\n oAuthClientId: string\n loginDomain: string\n region: string\n redirectUri: string\n logoutUri: string\n}\n\nconst CONTINUE_TO = 'continueTo'\n\nlet awsCognitoClient: null | AWSCognitoClient = null\n\nfunction init(cognitoServiceData: CognitoServiceData) {\n console.log('Initiating CognitoIdentityServiceProvider', cognitoServiceData)\n\n awsCognitoClient = new AWSCognitoClient({\n clientId: cognitoServiceData.oAuthClientId,\n region: cognitoServiceData.region,\n loginDomain: cognitoServiceData.loginDomain,\n redirectUri: cognitoServiceData.redirectUri,\n logoutUri: cognitoServiceData.logoutUri,\n })\n}\n\n/**\n * Register a listener function that will be call when authentication tokens are\n * updated or removed.\n *\n * #### Example\n *\n * ```js\n * const listener = async () => {\n * // Check if the user is logged in still\n * const isLoggedIn = authService.isLoggedIn()\n * }\n * const deregister = await authService.registerAuthListener(listener)\n *\n * // When no longer needed, remember to deregister the listener\n * deregister()\n * ```\n *\n * @param listener\n * @returns\n */\nfunction registerAuthListener(listener: () => unknown): () => void {\n if (!awsCognitoClient) {\n throw new Error(\n '\"authService\" has not been initiated. You must call the init() function before attempting to register a listener.',\n )\n }\n return awsCognitoClient.registerListener(listener)\n}\n\n/**\n * Create a session for a user by entering a username and password. If the user\n * requires a password reset, the \"resetPasswordCallback\" property will be\n * returned. This function should be called with the new password once entered\n * by the user. If the user requires an MFA token, the \"mfa\" property will be\n * returned. Its \"codeCallback\" should be called with the one-time token. The\n * functions returned are recursive and the result from each of them is the same\n * result from the loginUsernamePassword() function. Each time the response\n * includes a callback, you will need to begin the process again until all\n * callbacks are handled.\n *\n * #### Example\n *\n * ```js\n * async function handleLoginAttemptResponse({\n * resetPasswordCallback,\n * mfa,\n * }) {\n * // \"resetPasswordCallback\" will be undefined if a password reset was not required.\n * if (resetPasswordCallback) {\n * // Prompt the user to enter a new password\n * const newPassword = prompt(\n * 'The password you entered was only temporary, and must be reset for security purposes. Please enter your new password below to continue.',\n * )\n * const resetPasswordResponse =\n * await resetPasswordCallback(newPassword)\n * return await handleLoginAttemptResponse(resetPasswordResponse)\n * }\n *\n * // \"mfa\" will be undefined if MFA is not setup.\n * if (mfa) {\n * // Prompt the user to enter an MFA code\n * const code = prompt(\n * mfa.method === 'email'\n * ? 'Please enter the one-time code sent to your email.'\n * : 'Please enter a one-time code from your MFA app.',\n * )\n * const mfaCodeResponse = await mfa.codeCallback(code)\n * return await handleLoginAttemptResponse(mfaCodeResponse)\n * }\n * }\n *\n * const username = 'user@email.io'\n * const password = 'P@$5w0rd'\n *\n * const loginAttemptResponse = await authService.loginUsernamePassword(\n * username,\n * password,\n * )\n *\n * await handleLoginAttemptResponse(loginAttemptResponse)\n * ```\n *\n * @param username\n * @param password\n * @returns\n */\nasync function loginUsernamePassword(username: string, password: string) {\n if (!awsCognitoClient) {\n throw new Error(\n '\"authService\" has not been initiated. You must call the init() function before attempting to login.',\n )\n }\n console.log('Attempting sign using username', username)\n return awsCognitoClient.loginUsernamePassword(\n username.toLowerCase(),\n password,\n )\n}\n\n/**\n * Redirect the user to the login screen. Passing an `identityProvider` is\n * optionally, it will allow users to skip the login page and be directed\n * straight to that providers login page\n *\n * #### Example\n *\n * ```js\n * // OPtionally pass a\n * const identityProvider = 'Google'\n * await authService.loginHostedUI(identityProvider)\n * // User will be redirected to login page or promise will resolve\n * ```\n *\n * @param identityProviderName\n * @returns\n */\nasync function loginHostedUI(identityProviderName?: string): Promise<void> {\n if (!awsCognitoClient) {\n throw new Error(\n '\"authService\" has not been initiated. You must call the init() function before attempting to login.',\n )\n }\n const continueTo = `${window.location.pathname}${window.location.search}`\n localStorage.setItem(CONTINUE_TO, continueTo)\n\n return awsCognitoClient.loginHostedUI(identityProviderName)\n}\n\n/**\n * This function should be called when the user is redirected back to your app\n * after a login attempt. It will use the query string add the redirect URL to\n * create a session for the current user. It will return a URL as a `string`\n * that should be redirected to within your app.\n *\n * #### Example\n *\n * ```js\n * try {\n * const continueTo = await authService.handleAuthentication()\n * // Redirect the user back to where they were before attempting to login\n * window.location.href = continueTo\n * } catch (error) {\n * // handle failed login attempts here.\n * }\n * ```\n *\n * @returns\n */\nasync function handleAuthentication(): Promise<string> {\n if (!awsCognitoClient) {\n throw new Error(\n '\"authService\" has not been initiated. You must call the init() function before attempting to handle authentication in URL.',\n )\n }\n\n const continueTo = localStorage.getItem(CONTINUE_TO) || '/'\n if (isLoggedIn()) {\n console.log('Already authenticated, redirecting to:', continueTo)\n } else {\n await awsCognitoClient.handleAuthentication()\n }\n\n localStorage.removeItem(CONTINUE_TO)\n\n return continueTo\n}\n\n/**\n * Allow the currently logged in user to change their password by passing their\n * existing password and a new password.\n *\n * #### Example\n *\n * ```js\n * const currentPassword = 'P@$5w0rd'\n * const newPassword = 'P@$5w0rD'\n * await authService.changePassword(currentPassword, newPassword)\n * ```\n *\n * @param existingPassword\n * @param newPassword\n * @returns\n */\nasync function changePassword(existingPassword: string, newPassword: string) {\n if (!awsCognitoClient) {\n throw new Error(\n '\"authService\" has not been initiated. You must call the init() function before attempting to change passwords.',\n )\n }\n\n return await awsCognitoClient.changePassword(existingPassword, newPassword)\n}\n\n/**\n * Allow a user to start the forgot password process. The user will be emailed a\n * temporary code that must be passed with a new password to the function\n * returned.\n *\n * #### Example\n *\n * ```js\n * const username = 'user@email.io'\n * const finishForgotPassword = await authService.forgotPassword(username)\n *\n * // Prompt the user to enter the code and a new password\n * const code = prompt(\n * 'You have been emailed a verification code, please enter it here.',\n * )\n * const newPassword = prompt('Please enter a new password to continue.')\n * await finishForgotPassword(code, newPassword)\n * ```\n *\n * @param username\n * @param formsAppId Used to give the resulting email sent to the user\n * associated forms app branding and sending address\n * @returns\n */\nasync function forgotPassword(\n username: string,\n /**\n * Used to give the resulting email sent to the user associated forms app\n * branding and sending address\n */\n formsAppId?: number,\n): Promise<(code: string, password: string) => Promise<void>> {\n if (!awsCognitoClient) {\n throw new Error(\n '\"authService\" has not been initiated. You must call the init() function before starting the forgot password process.',\n )\n }\n\n try {\n const url = `${tenants.current.apiOrigin}/authentication/reset-password`\n await postRequest(url, {\n username,\n formsAppId,\n })\n } catch (err) {\n const error = err as HTTPError\n switch (error.status) {\n case 400: {\n throw new OneBlinkAppsError(error.message, {\n title: 'Invalid Request',\n httpStatusCode: error.status,\n })\n }\n default: {\n throw new OneBlinkAppsError(\n 'An unknown error has occurred. Please contact support if the problem persists.',\n {\n originalError: error,\n httpStatusCode: error.status,\n },\n )\n }\n }\n }\n\n return async (code, password) => {\n await awsCognitoClient?.confirmForgotPassword({\n username,\n code,\n password,\n })\n }\n}\n\n/**\n * Redirect the user to the logout screen to clear the users session on the\n * hosted login page. User will then be redirected to `/logout`. After being\n * redirected back to the application, the `logout()` function should be called\n * to clear the session data from browser storage.\n *\n * #### Example\n *\n * ```js\n * authService.logoutHostedUI()\n * ```\n */\nfunction logoutHostedUI(): void {\n if (awsCognitoClient) {\n awsCognitoClient.logoutHostedUI()\n }\n}\n\nasync function logout() {\n if (awsCognitoClient) {\n await awsCognitoClient.logout()\n }\n}\n\n/**\n * Check if the user is currently logged in\n *\n * #### Example\n *\n * ```js\n * const isLoggedIn = authService.isLoggedIn()\n * // handle user being logged in or not\n * ```\n *\n * @returns\n */\nfunction isLoggedIn(): boolean {\n return !!(awsCognitoClient && awsCognitoClient._getRefreshToken())\n}\n\nasync function getCognitoIdToken(): Promise<string | undefined> {\n if (!awsCognitoClient) {\n return\n }\n\n if (offlineService.isOffline()) {\n return awsCognitoClient._getIdToken()\n }\n\n return await awsCognitoClient.getIdToken()\n}\n\n/**\n * Get current users profile based on there Id Token payload. This will return\n * `null` if the the current user is not logged in.\n *\n * #### Example\n *\n * ```js\n * const profile = authService.getUserProfile()\n * if (profile) {\n * // Use profile here\n * }\n * ```\n *\n * @returns\n */\nfunction getUserProfile(): MiscTypes.UserProfile | null {\n if (!awsCognitoClient) {\n return null\n }\n const idToken = awsCognitoClient._getIdToken()\n if (!idToken) {\n return null\n }\n\n const jwtToken = jwtDecode(idToken)\n return userService.parseUserProfile(jwtToken) || null\n}\n\nexport function getUsername(): string | undefined {\n const profile = getUserProfile()\n if (!profile) {\n return undefined\n }\n\n return profile.username\n}\n\n/**\n * A friendly `string` that represents the current user. Uses first name, last\n * name, full name and username. This will return `null` the current user is not\n * logged in.\n *\n * #### Example\n *\n * ```js\n * const name = authService.getUserFriendlyName()\n * if (name) {\n * // Display current user's name\n * }\n * ```\n *\n * @returns\n */\nfunction getUserFriendlyName(): string | undefined {\n const profile = getUserProfile()\n if (!profile) {\n return\n }\n\n return userService.getUserFriendlyName(profile)\n}\n\n/**\n * Generate a QR code link to display to a user after they have initiated\n * authenticator app MFA setup.\n *\n * #### Example\n *\n * ```js\n * const mfaAuthenticatorAppSetupQrCodeUrl =\n * mfaService.generateMfaAuthenticatorAppQrCodeUrl()\n * if (mfaAuthenticatorAppSetupQrCodeUrl) {\n * // use mfaAuthenticatorAppSetupQrCodeUrl to display QR code to user\n * }\n * ```\n *\n * @returns\n */\nfunction generateMfaAuthenticatorAppQrCodeUrl(\n mfaAuthenticatorAppSetup: Awaited<\n ReturnType<typeof setupMfaAuthenticatorApp>\n >,\n): string | undefined {\n const profile = getUserProfile()\n if (!profile || !mfaAuthenticatorAppSetup) {\n return\n }\n\n return `otpauth://totp/${tenants.current.productShortName}:${profile.email}?secret=${mfaAuthenticatorAppSetup.secretCode}&issuer=${tenants.current.productShortName}`\n}\n\n/**\n * Check if the current user meets an MFA requirement.\n *\n * #### Example\n *\n * ```js\n * const { mfaSettings, userMeetsMfaRequirement } =\n * await mfaService.checkIsMfaEnabled('any')\n * if (userMeetsMfaRequirement) {\n * // User has met the MFA requirement\n * } else {\n * // Prompt user to set up MFA\n * }\n * ```\n *\n * @returns\n */\nasync function checkIsMfaEnabled(\n mfaRequirement: MiscTypes.MfaRequirement | undefined,\n): Promise<MfaRequirementCheckResult> {\n if (!awsCognitoClient) {\n throw new Error(\n '\"authService\" has not been initiated. You must call the init() function before checking if the current user has MFA enabled.',\n )\n }\n\n return await awsCognitoClient.checkIsMfaEnabled(mfaRequirement)\n}\n\nasync function getMfaSettings(abortSignal?: AbortSignal) {\n if (!awsCognitoClient) {\n throw new Error(\n '\"authService\" has not been initiated. You must call the init() function before checking MFA settings.',\n )\n }\n\n return await awsCognitoClient.getMfaSettings(abortSignal)\n}\n\nasync function updateUserPhoneNumber(phoneNumber: string) {\n if (!awsCognitoClient) {\n throw new Error(\n '\"authService\" has not been initiated. You must call the init() function before updating the user phone number.',\n )\n }\n\n return await awsCognitoClient.updateUserPhoneNumber(phoneNumber)\n}\n\nasync function removeUserPhoneNumber() {\n if (!awsCognitoClient) {\n throw new Error(\n '\"authService\" has not been initiated. You must call the init() function before removing the user phone number.',\n )\n }\n\n return await awsCognitoClient.removeUserPhoneNumber()\n}\n\nasync function sendPhoneNumberVerificationCode() {\n if (!awsCognitoClient) {\n throw new Error(\n '\"authService\" has not been initiated. You must call the init() function before sending a phone number verification code.',\n )\n }\n\n return await awsCognitoClient.sendPhoneNumberVerificationCode()\n}\n\nasync function verifyUserPhoneNumber(code: string) {\n if (!awsCognitoClient) {\n throw new Error(\n '\"authService\" has not been initiated. You must call the init() function before verifying the user phone number.',\n )\n }\n\n return await awsCognitoClient.verifyUserPhoneNumber(code)\n}\n\nasync function setupSmsMfa(options?: { preferred?: boolean }) {\n if (!awsCognitoClient) {\n throw new Error(\n '\"authService\" has not been initiated. You must call the init() function before attempting to setup SMS MFA.',\n )\n }\n\n return await awsCognitoClient.setupSmsMfa(options)\n}\n\nasync function disableMfaMethod(method: MfaMethod) {\n if (!awsCognitoClient) {\n throw new Error(\n '\"authService\" has not been initiated. You must call the init() function before attempting to disable an MFA method.',\n )\n }\n\n return await awsCognitoClient.disableMfaMethod(method)\n}\n\nasync function setPreferredMfaMethod(method: MfaMethod) {\n if (!awsCognitoClient) {\n throw new Error(\n '\"authService\" has not been initiated. You must call the init() function before attempting to set the preferred MFA method.',\n )\n }\n\n return await awsCognitoClient.setPreferredMfaMethod(method)\n}\n\n/**\n * Setup authenticator app MFA for the current user. The result will include a\n * callback that should be called with the valid TOTP from an authenticator\n * app.\n *\n * #### Example\n *\n * ```js\n * const { secretCode, mfaCodeCallback } =\n * await mfaService.setupMfaAuthenticatorApp()\n * // Prompt the user to enter an MFA code\n * const code = prompt(\n * `Please enter a one-time code from your MFA app after creating a new entry with secret: ${secretCode}.`,\n * )\n * await mfaCodeCallback(code)\n * ```\n *\n * @returns\n */\nasync function setupMfaAuthenticatorApp(options?: { preferred?: boolean }) {\n if (!awsCognitoClient) {\n throw new Error(\n '\"authService\" has not been initiated. You must call the init() function before attempting to setup authenticator app MFA.',\n )\n }\n\n return await awsCognitoClient.setupMfaAuthenticatorApp(options)\n}\n\nexport {\n init,\n registerAuthListener,\n loginUsernamePassword,\n loginHostedUI,\n handleAuthentication,\n changePassword,\n forgotPassword,\n logoutHostedUI,\n logout,\n isLoggedIn,\n getCognitoIdToken,\n getUserProfile,\n getUserFriendlyName,\n checkIsMfaEnabled,\n getMfaSettings,\n updateUserPhoneNumber,\n removeUserPhoneNumber,\n sendPhoneNumberVerificationCode,\n verifyUserPhoneNumber,\n disableMfaMethod,\n setPreferredMfaMethod,\n setupSmsMfa,\n setupMfaAuthenticatorApp,\n generateMfaAuthenticatorAppQrCodeUrl,\n DEFAULT_MFA_SETTINGS,\n}\nexport type {\n LoginAttemptResponse,\n MfaMethod,\n MfaRequirementCheckResult,\n MfaSettings,\n}\n"]}
1
+ {"version":3,"file":"cognito.js","sourceRoot":"","sources":["../../../src/apps/services/cognito.ts"],"names":[],"mappings":"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","sourcesContent":["import { jwtDecode } from 'jwt-decode'\n\nimport AWSCognitoClient, {\n DEFAULT_MFA_SETTINGS,\n LoginAttemptResponse,\n MfaMethod,\n MfaSettings,\n} from './AWSCognitoClient'\n\nimport * as offlineService from '../offline-service'\nimport { userService } from '@oneblink/sdk-core'\nimport { MiscTypes } from '@oneblink/types'\nimport { HTTPError, postRequest } from './fetch'\nimport tenants from '../tenants'\nimport OneBlinkAppsError from './errors/oneBlinkAppsError'\n\ninterface CognitoServiceData {\n oAuthClientId: string\n loginDomain: string\n region: string\n redirectUri: string\n logoutUri: string\n}\n\nconst CONTINUE_TO = 'continueTo'\n\nlet awsCognitoClient: null | AWSCognitoClient = null\n\nfunction init(cognitoServiceData: CognitoServiceData) {\n console.log('Initiating CognitoIdentityServiceProvider', cognitoServiceData)\n\n awsCognitoClient = new AWSCognitoClient({\n clientId: cognitoServiceData.oAuthClientId,\n region: cognitoServiceData.region,\n loginDomain: cognitoServiceData.loginDomain,\n redirectUri: cognitoServiceData.redirectUri,\n logoutUri: cognitoServiceData.logoutUri,\n })\n}\n\n/**\n * Register a listener function that will be call when authentication tokens are\n * updated or removed.\n *\n * #### Example\n *\n * ```js\n * const listener = async () => {\n * // Check if the user is logged in still\n * const isLoggedIn = authService.isLoggedIn()\n * }\n * const deregister = await authService.registerAuthListener(listener)\n *\n * // When no longer needed, remember to deregister the listener\n * deregister()\n * ```\n *\n * @param listener\n * @returns\n */\nfunction registerAuthListener(listener: () => unknown): () => void {\n if (!awsCognitoClient) {\n throw new Error(\n '\"authService\" has not been initiated. You must call the init() function before attempting to register a listener.',\n )\n }\n return awsCognitoClient.registerListener(listener)\n}\n\n/**\n * Create a session for a user by entering a username and password. If the user\n * requires a password reset, the \"resetPasswordCallback\" property will be\n * returned. This function should be called with the new password once entered\n * by the user. If the user requires an MFA token, the \"mfa\" property will be\n * returned. Its \"codeCallback\" should be called with the one-time token. The\n * functions returned are recursive and the result from each of them is the same\n * result from the loginUsernamePassword() function. Each time the response\n * includes a callback, you will need to begin the process again until all\n * callbacks are handled.\n *\n * #### Example\n *\n * ```js\n * async function handleLoginAttemptResponse({\n * resetPasswordCallback,\n * mfa,\n * }) {\n * // \"resetPasswordCallback\" will be undefined if a password reset was not required.\n * if (resetPasswordCallback) {\n * // Prompt the user to enter a new password\n * const newPassword = prompt(\n * 'The password you entered was only temporary, and must be reset for security purposes. Please enter your new password below to continue.',\n * )\n * const resetPasswordResponse =\n * await resetPasswordCallback(newPassword)\n * return await handleLoginAttemptResponse(resetPasswordResponse)\n * }\n *\n * // \"mfa\" will be undefined if MFA is not setup.\n * if (mfa) {\n * // Prompt the user to enter an MFA code\n * const code = prompt(\n * mfa.method === 'email'\n * ? 'Please enter the one-time code sent to your email.'\n * : 'Please enter a one-time code from your MFA app.',\n * )\n * const mfaCodeResponse = await mfa.codeCallback(code)\n * return await handleLoginAttemptResponse(mfaCodeResponse)\n * }\n * }\n *\n * const username = 'user@email.io'\n * const password = 'P@$5w0rd'\n *\n * const loginAttemptResponse = await authService.loginUsernamePassword(\n * username,\n * password,\n * )\n *\n * await handleLoginAttemptResponse(loginAttemptResponse)\n * ```\n *\n * @param username\n * @param password\n * @returns\n */\nasync function loginUsernamePassword(username: string, password: string) {\n if (!awsCognitoClient) {\n throw new Error(\n '\"authService\" has not been initiated. You must call the init() function before attempting to login.',\n )\n }\n console.log('Attempting sign using username', username)\n return awsCognitoClient.loginUsernamePassword(\n username.toLowerCase(),\n password,\n )\n}\n\n/**\n * Redirect the user to the login screen. Passing an `identityProvider` is\n * optionally, it will allow users to skip the login page and be directed\n * straight to that providers login page\n *\n * #### Example\n *\n * ```js\n * // OPtionally pass a\n * const identityProvider = 'Google'\n * await authService.loginHostedUI(identityProvider)\n * // User will be redirected to login page or promise will resolve\n * ```\n *\n * @param identityProviderName\n * @returns\n */\nasync function loginHostedUI(identityProviderName?: string): Promise<void> {\n if (!awsCognitoClient) {\n throw new Error(\n '\"authService\" has not been initiated. You must call the init() function before attempting to login.',\n )\n }\n const continueTo = `${window.location.pathname}${window.location.search}`\n localStorage.setItem(CONTINUE_TO, continueTo)\n\n return awsCognitoClient.loginHostedUI(identityProviderName)\n}\n\n/**\n * This function should be called when the user is redirected back to your app\n * after a login attempt. It will use the query string add the redirect URL to\n * create a session for the current user. It will return a URL as a `string`\n * that should be redirected to within your app.\n *\n * #### Example\n *\n * ```js\n * try {\n * const continueTo = await authService.handleAuthentication()\n * // Redirect the user back to where they were before attempting to login\n * window.location.href = continueTo\n * } catch (error) {\n * // handle failed login attempts here.\n * }\n * ```\n *\n * @returns\n */\nasync function handleAuthentication(): Promise<string> {\n if (!awsCognitoClient) {\n throw new Error(\n '\"authService\" has not been initiated. You must call the init() function before attempting to handle authentication in URL.',\n )\n }\n\n const continueTo = localStorage.getItem(CONTINUE_TO) || '/'\n if (isLoggedIn()) {\n console.log('Already authenticated, redirecting to:', continueTo)\n } else {\n await awsCognitoClient.handleAuthentication()\n }\n\n localStorage.removeItem(CONTINUE_TO)\n\n return continueTo\n}\n\n/**\n * Allow the currently logged in user to change their password by passing their\n * existing password and a new password.\n *\n * #### Example\n *\n * ```js\n * const currentPassword = 'P@$5w0rd'\n * const newPassword = 'P@$5w0rD'\n * await authService.changePassword(currentPassword, newPassword)\n * ```\n *\n * @param existingPassword\n * @param newPassword\n * @returns\n */\nasync function changePassword(existingPassword: string, newPassword: string) {\n if (!awsCognitoClient) {\n throw new Error(\n '\"authService\" has not been initiated. You must call the init() function before attempting to change passwords.',\n )\n }\n\n return await awsCognitoClient.changePassword(existingPassword, newPassword)\n}\n\n/**\n * Allow a user to start the forgot password process. The user will be emailed a\n * temporary code that must be passed with a new password to the function\n * returned.\n *\n * #### Example\n *\n * ```js\n * const username = 'user@email.io'\n * const finishForgotPassword = await authService.forgotPassword(username)\n *\n * // Prompt the user to enter the code and a new password\n * const code = prompt(\n * 'You have been emailed a verification code, please enter it here.',\n * )\n * const newPassword = prompt('Please enter a new password to continue.')\n * await finishForgotPassword(code, newPassword)\n * ```\n *\n * @param username\n * @param formsAppId Used to give the resulting email sent to the user\n * associated forms app branding and sending address\n * @returns\n */\nasync function forgotPassword(\n username: string,\n /**\n * Used to give the resulting email sent to the user associated forms app\n * branding and sending address\n */\n formsAppId?: number,\n): Promise<(code: string, password: string) => Promise<void>> {\n if (!awsCognitoClient) {\n throw new Error(\n '\"authService\" has not been initiated. You must call the init() function before starting the forgot password process.',\n )\n }\n\n try {\n const url = `${tenants.current.apiOrigin}/authentication/reset-password`\n await postRequest(url, {\n username,\n formsAppId,\n })\n } catch (err) {\n const error = err as HTTPError\n switch (error.status) {\n case 400: {\n throw new OneBlinkAppsError(error.message, {\n title: 'Invalid Request',\n httpStatusCode: error.status,\n })\n }\n default: {\n throw new OneBlinkAppsError(\n 'An unknown error has occurred. Please contact support if the problem persists.',\n {\n originalError: error,\n httpStatusCode: error.status,\n },\n )\n }\n }\n }\n\n return async (code, password) => {\n await awsCognitoClient?.confirmForgotPassword({\n username,\n code,\n password,\n })\n }\n}\n\n/**\n * Redirect the user to the logout screen to clear the users session on the\n * hosted login page. User will then be redirected to `/logout`. After being\n * redirected back to the application, the `logout()` function should be called\n * to clear the session data from browser storage.\n *\n * #### Example\n *\n * ```js\n * authService.logoutHostedUI()\n * ```\n */\nfunction logoutHostedUI(): void {\n if (awsCognitoClient) {\n awsCognitoClient.logoutHostedUI()\n }\n}\n\nasync function logout() {\n if (awsCognitoClient) {\n await awsCognitoClient.logout()\n }\n}\n\n/**\n * Check if the user is currently logged in\n *\n * #### Example\n *\n * ```js\n * const isLoggedIn = authService.isLoggedIn()\n * // handle user being logged in or not\n * ```\n *\n * @returns\n */\nfunction isLoggedIn(): boolean {\n return !!(awsCognitoClient && awsCognitoClient._getRefreshToken())\n}\n\nasync function getCognitoIdToken(): Promise<string | undefined> {\n if (!awsCognitoClient) {\n return\n }\n\n if (offlineService.isOffline()) {\n return awsCognitoClient._getIdToken()\n }\n\n return await awsCognitoClient.getIdToken()\n}\n\n/**\n * Get current users profile based on there Id Token payload. This will return\n * `null` if the the current user is not logged in.\n *\n * #### Example\n *\n * ```js\n * const profile = authService.getUserProfile()\n * if (profile) {\n * // Use profile here\n * }\n * ```\n *\n * @returns\n */\nfunction getUserProfile(): MiscTypes.UserProfile | null {\n if (!awsCognitoClient) {\n return null\n }\n const idToken = awsCognitoClient._getIdToken()\n if (!idToken) {\n return null\n }\n\n const jwtToken = jwtDecode(idToken)\n return userService.parseUserProfile(jwtToken) || null\n}\n\nexport function getUsername(): string | undefined {\n const profile = getUserProfile()\n if (!profile) {\n return undefined\n }\n\n return profile.username\n}\n\n/**\n * A friendly `string` that represents the current user. Uses first name, last\n * name, full name and username. This will return `null` the current user is not\n * logged in.\n *\n * #### Example\n *\n * ```js\n * const name = authService.getUserFriendlyName()\n * if (name) {\n * // Display current user's name\n * }\n * ```\n *\n * @returns\n */\nfunction getUserFriendlyName(): string | undefined {\n const profile = getUserProfile()\n if (!profile) {\n return\n }\n\n return userService.getUserFriendlyName(profile)\n}\n\n/**\n * Generate a QR code link to display to a user after they have initiated\n * authenticator app MFA setup.\n *\n * #### Example\n *\n * ```js\n * const mfaAuthenticatorAppSetupQrCodeUrl =\n * mfaService.generateMfaAuthenticatorAppQrCodeUrl()\n * if (mfaAuthenticatorAppSetupQrCodeUrl) {\n * // use mfaAuthenticatorAppSetupQrCodeUrl to display QR code to user\n * }\n * ```\n *\n * @returns\n */\nfunction generateMfaAuthenticatorAppQrCodeUrl(\n mfaAuthenticatorAppSetup: Awaited<\n ReturnType<typeof setupMfaAuthenticatorApp>\n >,\n): string | undefined {\n const profile = getUserProfile()\n if (!profile || !mfaAuthenticatorAppSetup) {\n return\n }\n\n return `otpauth://totp/${tenants.current.productShortName}:${profile.email}?secret=${mfaAuthenticatorAppSetup.secretCode}&issuer=${tenants.current.productShortName}`\n}\n\nasync function getMfaSettings(abortSignal?: AbortSignal) {\n if (!awsCognitoClient) {\n throw new Error(\n '\"authService\" has not been initiated. You must call the init() function before checking MFA settings.',\n )\n }\n\n return await awsCognitoClient.getMfaSettings(abortSignal)\n}\n\nasync function updateUserPhoneNumber(phoneNumber: string) {\n if (!awsCognitoClient) {\n throw new Error(\n '\"authService\" has not been initiated. You must call the init() function before updating the user phone number.',\n )\n }\n\n return await awsCognitoClient.updateUserPhoneNumber(phoneNumber)\n}\n\nasync function removeUserPhoneNumber() {\n if (!awsCognitoClient) {\n throw new Error(\n '\"authService\" has not been initiated. You must call the init() function before removing the user phone number.',\n )\n }\n\n return await awsCognitoClient.removeUserPhoneNumber()\n}\n\nasync function verifyUserPhoneNumber(code: string) {\n if (!awsCognitoClient) {\n throw new Error(\n '\"authService\" has not been initiated. You must call the init() function before verifying the user phone number.',\n )\n }\n\n return await awsCognitoClient.verifyUserPhoneNumber(code)\n}\n\nasync function setupSmsMfa(options?: { preferred?: boolean }) {\n if (!awsCognitoClient) {\n throw new Error(\n '\"authService\" has not been initiated. You must call the init() function before attempting to setup SMS MFA.',\n )\n }\n\n return await awsCognitoClient.setupSmsMfa(options)\n}\n\nasync function disableMfaMethod(method: MfaMethod) {\n if (!awsCognitoClient) {\n throw new Error(\n '\"authService\" has not been initiated. You must call the init() function before attempting to disable an MFA method.',\n )\n }\n\n return await awsCognitoClient.disableMfaMethod(method)\n}\n\nasync function setPreferredMfaMethod(method: MfaMethod) {\n if (!awsCognitoClient) {\n throw new Error(\n '\"authService\" has not been initiated. You must call the init() function before attempting to set the preferred MFA method.',\n )\n }\n\n return await awsCognitoClient.setPreferredMfaMethod(method)\n}\n\n/**\n * Setup authenticator app MFA for the current user. The result will include a\n * callback that should be called with the valid TOTP from an authenticator\n * app.\n *\n * #### Example\n *\n * ```js\n * const { secretCode, mfaCodeCallback } =\n * await mfaService.setupMfaAuthenticatorApp()\n * // Prompt the user to enter an MFA code\n * const code = prompt(\n * `Please enter a one-time code from your MFA app after creating a new entry with secret: ${secretCode}.`,\n * )\n * await mfaCodeCallback(code)\n * ```\n *\n * @returns\n */\nasync function setupMfaAuthenticatorApp(options?: { preferred?: boolean }) {\n if (!awsCognitoClient) {\n throw new Error(\n '\"authService\" has not been initiated. You must call the init() function before attempting to setup authenticator app MFA.',\n )\n }\n\n return await awsCognitoClient.setupMfaAuthenticatorApp(options)\n}\n\nexport {\n init,\n registerAuthListener,\n loginUsernamePassword,\n loginHostedUI,\n handleAuthentication,\n changePassword,\n forgotPassword,\n logoutHostedUI,\n logout,\n isLoggedIn,\n getCognitoIdToken,\n getUserProfile,\n getUserFriendlyName,\n getMfaSettings,\n updateUserPhoneNumber,\n removeUserPhoneNumber,\n verifyUserPhoneNumber,\n disableMfaMethod,\n setPreferredMfaMethod,\n setupSmsMfa,\n setupMfaAuthenticatorApp,\n generateMfaAuthenticatorAppQrCodeUrl,\n DEFAULT_MFA_SETTINGS,\n}\nexport type { LoginAttemptResponse, MfaMethod, MfaSettings }\n"]}
@@ -9,7 +9,7 @@ function getResendCoolDownRemainingSeconds(sentAt, now) {
9
9
  if (!sentAt) {
10
10
  return 0;
11
11
  }
12
- const elapsedSeconds = Math.floor((now - sentAt) / 1000);
12
+ const elapsedSeconds = Math.max(0, Math.floor((now - sentAt) / 1000));
13
13
  return Math.max(0, PHONE_VERIFICATION_RESEND_COOL_DOWN_SECONDS - elapsedSeconds);
14
14
  }
15
15
  function usePhoneVerificationResendCoolDown(sentAt) {
@@ -19,10 +19,7 @@ function usePhoneVerificationResendCoolDown(sentAt) {
19
19
  if (!sentAt) {
20
20
  return;
21
21
  }
22
- const remaining = getResendCoolDownRemainingSeconds(sentAt, Date.now());
23
- if (remaining <= 0) {
24
- return;
25
- }
22
+ setNow(Date.now());
26
23
  const intervalId = window.setInterval(() => {
27
24
  setNow(Date.now());
28
25
  }, 1000);
@@ -31,13 +28,12 @@ function usePhoneVerificationResendCoolDown(sentAt) {
31
28
  return remainingSeconds;
32
29
  }
33
30
  function MfaPhoneNumberDialog() {
34
- const { isPhoneNumberDialogOpen, mfaSettings, phoneVerificationCodeSentAt, closePhoneNumberDialog, savePhoneNumber, verifyPhoneNumber, resendPhoneNumberVerificationCode, } = useMfa();
31
+ const { isPhoneNumberDialogOpen, mfaSettings, phoneVerificationCodeSentAt, closePhoneNumberDialog, savePhoneNumber, verifyPhoneNumber, } = useMfa();
35
32
  const isPhoneVerificationRequired = phoneVerificationCodeSentAt !== undefined;
36
33
  const [phoneNumber, setPhoneNumber] = React.useState('');
37
34
  const [verificationCode, setVerificationCode] = React.useState('');
38
35
  const resendCoolDownSeconds = usePhoneVerificationResendCoolDown(phoneVerificationCodeSentAt);
39
36
  const [isSaving, startSaving, stopSaving] = useBooleanState(false);
40
- const [isResending, startResending, stopResending] = useBooleanState(false);
41
37
  React.useEffect(() => {
42
38
  if (isPhoneNumberDialogOpen) {
43
39
  setPhoneNumber(mfaSettings.sms.phoneNumber || '');
@@ -87,14 +83,14 @@ function MfaPhoneNumberDialog() {
87
83
  verificationCode,
88
84
  ]);
89
85
  const handleResendVerificationCode = React.useCallback(async () => {
90
- startResending();
86
+ startSaving();
91
87
  try {
92
- await resendPhoneNumberVerificationCode();
88
+ await savePhoneNumber(phoneNumber);
93
89
  }
94
90
  finally {
95
- stopResending();
91
+ stopSaving();
96
92
  }
97
- }, [resendPhoneNumberVerificationCode, startResending, stopResending]);
93
+ }, [phoneNumber, savePhoneNumber, startSaving, stopSaving]);
98
94
  return (_jsx(Dialog, { open: isPhoneNumberDialogOpen, onClose: () => {
99
95
  if (!isSaving) {
100
96
  closePhoneNumberDialog();
@@ -103,9 +99,9 @@ function MfaPhoneNumberDialog() {
103
99
  ? 'Verify Phone Number'
104
100
  : 'Save Phone Number' }), _jsx(DialogContent, { dividers: true, children: isPhoneVerificationRequired ? (_jsxs(_Fragment, { children: [_jsxs(Typography, { variant: "body2", paragraph: true, children: ["Enter the verification code sent to ", phoneNumber, "."] }), _jsx(InputField, { autoFocus: true, margin: "none", name: "verificationCode", label: "Verification Code", fullWidth: true, placeholder: "XXXXXX", variant: "outlined", value: verificationCode, onChange: (event) => {
105
101
  setVerificationCode(event.target.value);
106
- }, disabled: isSaving, "data-cypress": "mfa-phone-verification-code" }, "verification-code"), _jsx(Box, { marginTop: 1, children: _jsx(Button, { type: "button", variant: "text", size: "small", disabled: resendCoolDownSeconds > 0 || isSaving || isResending, onClick: handleResendVerificationCode, "data-cypress": "mfa-phone-resend-button", children: resendCoolDownSeconds > 0
107
- ? `Send again (${resendCoolDownSeconds}s)`
108
- : 'Send again' }) })] })) : (_jsxs(_Fragment, { children: [_jsx(Typography, { variant: "body2", paragraph: true, children: "Enter your phone number to receive SMS verification codes when signing in." }), _jsx(InputField, { autoFocus: true, margin: "none", name: "phoneNumber", label: "Phone Number", fullWidth: true, placeholder: "+61400000000", variant: "outlined", value: phoneNumber, onChange: (event) => {
102
+ }, disabled: isSaving, "data-cypress": "mfa-phone-verification-code" }, "verification-code"), _jsx(Box, { marginTop: 1, children: _jsx(Button, { type: "button", variant: "text", size: "small", sx: { textTransform: 'none' }, disabled: resendCoolDownSeconds > 0 || isSaving, onClick: handleResendVerificationCode, "data-cypress": "mfa-phone-resend-button", children: resendCoolDownSeconds > 0
103
+ ? `Send Again (${resendCoolDownSeconds}s)`
104
+ : 'Send Again' }) })] })) : (_jsxs(_Fragment, { children: [_jsx(Typography, { variant: "body2", paragraph: true, children: "Enter your phone number to receive SMS verification codes when signing in." }), _jsx(InputField, { autoFocus: true, margin: "none", name: "phoneNumber", label: "Phone Number", fullWidth: true, placeholder: "+61400000000", variant: "outlined", value: phoneNumber, onChange: (event) => {
109
105
  setPhoneNumber(event.target.value);
110
106
  }, disabled: isSaving, helperText: "Include your country code, for example +61400000000.", "data-cypress": "mfa-phone-number" }, "phone-number")] })) }), _jsxs(DialogActions, { children: [_jsx(Button, { type: "button", onClick: closePhoneNumberDialog, disabled: isSaving, children: "Cancel" }), isPhoneVerificationRequired ? (_jsx(Button, { type: "submit", variant: "contained", disabled: !verificationCode || isSaving, "data-cypress": "mfa-phone-verify-button", children: "Verify" })) : (_jsx(Button, { type: "submit", variant: "contained", disabled: !phoneNumber || isSaving, "data-cypress": "mfa-phone-save-button", children: "Save" }))] })] }) }));
111
107
  }
@@ -1 +1 @@
1
- {"version":3,"file":"MfaPhoneNumberDialog.js","sourceRoot":"","sources":["../../../src/components/mfa/MfaPhoneNumberDialog.tsx"],"names":[],"mappings":"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","sourcesContent":["import * as React from 'react'\nimport {\n Dialog,\n DialogActions,\n DialogContent,\n DialogTitle,\n Button,\n Typography,\n Box,\n} from '@mui/material'\nimport useBooleanState from '../../hooks/useBooleanState'\nimport useMfa from '../../hooks/useMfa'\nimport InputField from '../InputField'\n\nconst PHONE_VERIFICATION_RESEND_COOL_DOWN_SECONDS = 60\n\nfunction getResendCoolDownRemainingSeconds(\n sentAt: number | undefined,\n now: number,\n) {\n if (!sentAt) {\n return 0\n }\n\n const elapsedSeconds = Math.floor((now - sentAt) / 1000)\n return Math.max(\n 0,\n PHONE_VERIFICATION_RESEND_COOL_DOWN_SECONDS - elapsedSeconds,\n )\n}\n\nfunction usePhoneVerificationResendCoolDown(sentAt: number | undefined) {\n const [now, setNow] = React.useState(() => Date.now())\n\n const remainingSeconds = getResendCoolDownRemainingSeconds(sentAt, now)\n\n React.useEffect(() => {\n if (!sentAt) {\n return\n }\n\n const remaining = getResendCoolDownRemainingSeconds(sentAt, Date.now())\n if (remaining <= 0) {\n return\n }\n\n const intervalId = window.setInterval(() => {\n setNow(Date.now())\n }, 1000)\n\n return () => window.clearInterval(intervalId)\n }, [sentAt])\n\n return remainingSeconds\n}\n\nfunction MfaPhoneNumberDialog() {\n const {\n isPhoneNumberDialogOpen,\n mfaSettings,\n phoneVerificationCodeSentAt,\n closePhoneNumberDialog,\n savePhoneNumber,\n verifyPhoneNumber,\n resendPhoneNumberVerificationCode,\n } = useMfa()\n\n const isPhoneVerificationRequired = phoneVerificationCodeSentAt !== undefined\n\n const [phoneNumber, setPhoneNumber] = React.useState('')\n const [verificationCode, setVerificationCode] = React.useState('')\n const resendCoolDownSeconds = usePhoneVerificationResendCoolDown(\n phoneVerificationCodeSentAt,\n )\n const [isSaving, startSaving, stopSaving] = useBooleanState(false)\n const [isResending, startResending, stopResending] = useBooleanState(false)\n\n React.useEffect(() => {\n if (isPhoneNumberDialogOpen) {\n setPhoneNumber(mfaSettings.sms.phoneNumber || '')\n setVerificationCode('')\n }\n }, [isPhoneNumberDialogOpen, mfaSettings.sms.phoneNumber])\n\n const handleSavePhoneNumber = React.useCallback(async () => {\n startSaving()\n try {\n await savePhoneNumber(phoneNumber)\n } finally {\n stopSaving()\n }\n }, [phoneNumber, savePhoneNumber, startSaving, stopSaving])\n\n const handleVerifyPhoneNumber = React.useCallback(async () => {\n startSaving()\n try {\n await verifyPhoneNumber(verificationCode)\n } finally {\n stopSaving()\n }\n }, [verificationCode, verifyPhoneNumber, startSaving, stopSaving])\n\n const handleSubmit = React.useCallback(\n (event: React.SubmitEvent<HTMLFormElement>) => {\n event.preventDefault()\n\n if (isSaving) {\n return\n }\n\n if (isPhoneVerificationRequired) {\n if (!verificationCode) {\n return\n }\n\n void handleVerifyPhoneNumber()\n return\n }\n\n if (!phoneNumber) {\n return\n }\n\n void handleSavePhoneNumber()\n },\n [\n handleSavePhoneNumber,\n handleVerifyPhoneNumber,\n isPhoneVerificationRequired,\n isSaving,\n phoneNumber,\n verificationCode,\n ],\n )\n\n const handleResendVerificationCode = React.useCallback(async () => {\n startResending()\n try {\n await resendPhoneNumberVerificationCode()\n } finally {\n stopResending()\n }\n }, [resendPhoneNumberVerificationCode, startResending, stopResending])\n\n return (\n <Dialog\n open={isPhoneNumberDialogOpen}\n onClose={() => {\n if (!isSaving) {\n closePhoneNumberDialog()\n }\n }}\n fullWidth\n maxWidth=\"sm\"\n >\n <form onSubmit={handleSubmit}>\n <DialogTitle>\n {isPhoneVerificationRequired\n ? 'Verify Phone Number'\n : 'Save Phone Number'}\n </DialogTitle>\n <DialogContent dividers>\n {isPhoneVerificationRequired ? (\n <>\n <Typography variant=\"body2\" paragraph>\n Enter the verification code sent to {phoneNumber}.\n </Typography>\n <InputField\n key=\"verification-code\"\n autoFocus\n margin=\"none\"\n name=\"verificationCode\"\n label=\"Verification Code\"\n fullWidth\n placeholder=\"XXXXXX\"\n variant=\"outlined\"\n value={verificationCode}\n onChange={(event) => {\n setVerificationCode(event.target.value)\n }}\n disabled={isSaving}\n data-cypress=\"mfa-phone-verification-code\"\n />\n <Box marginTop={1}>\n <Button\n type=\"button\"\n variant=\"text\"\n size=\"small\"\n disabled={\n resendCoolDownSeconds > 0 || isSaving || isResending\n }\n onClick={handleResendVerificationCode}\n data-cypress=\"mfa-phone-resend-button\"\n >\n {resendCoolDownSeconds > 0\n ? `Send again (${resendCoolDownSeconds}s)`\n : 'Send again'}\n </Button>\n </Box>\n </>\n ) : (\n <>\n <Typography variant=\"body2\" paragraph>\n Enter your phone number to receive SMS verification codes when\n signing in.\n </Typography>\n <InputField\n key=\"phone-number\"\n autoFocus\n margin=\"none\"\n name=\"phoneNumber\"\n label=\"Phone Number\"\n fullWidth\n placeholder=\"+61400000000\"\n variant=\"outlined\"\n value={phoneNumber}\n onChange={(event) => {\n setPhoneNumber(event.target.value)\n }}\n disabled={isSaving}\n helperText=\"Include your country code, for example +61400000000.\"\n data-cypress=\"mfa-phone-number\"\n />\n </>\n )}\n </DialogContent>\n <DialogActions>\n <Button\n type=\"button\"\n onClick={closePhoneNumberDialog}\n disabled={isSaving}\n >\n Cancel\n </Button>\n {isPhoneVerificationRequired ? (\n <Button\n type=\"submit\"\n variant=\"contained\"\n disabled={!verificationCode || isSaving}\n data-cypress=\"mfa-phone-verify-button\"\n >\n Verify\n </Button>\n ) : (\n <Button\n type=\"submit\"\n variant=\"contained\"\n disabled={!phoneNumber || isSaving}\n data-cypress=\"mfa-phone-save-button\"\n >\n Save\n </Button>\n )}\n </DialogActions>\n </form>\n </Dialog>\n )\n}\n\n/**\n * React Component that lets users enter and verify a phone number for SMS MFA.\n * Typically rendered by `<MultiFactorAuthentication />` within an `<MfaProvider\n * />` tree.\n *\n * @returns\n */\nexport default React.memo(MfaPhoneNumberDialog)\n"]}
1
+ {"version":3,"file":"MfaPhoneNumberDialog.js","sourceRoot":"","sources":["../../../src/components/mfa/MfaPhoneNumberDialog.tsx"],"names":[],"mappings":"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","sourcesContent":["import * as React from 'react'\nimport {\n Dialog,\n DialogActions,\n DialogContent,\n DialogTitle,\n Button,\n Typography,\n Box,\n} from '@mui/material'\nimport useBooleanState from '../../hooks/useBooleanState'\nimport useMfa from '../../hooks/useMfa'\nimport InputField from '../InputField'\n\nconst PHONE_VERIFICATION_RESEND_COOL_DOWN_SECONDS = 60\n\nfunction getResendCoolDownRemainingSeconds(\n sentAt: number | undefined,\n now: number,\n) {\n if (!sentAt) {\n return 0\n }\n\n const elapsedSeconds = Math.max(0, Math.floor((now - sentAt) / 1000))\n return Math.max(\n 0,\n PHONE_VERIFICATION_RESEND_COOL_DOWN_SECONDS - elapsedSeconds,\n )\n}\n\nfunction usePhoneVerificationResendCoolDown(sentAt: number | undefined) {\n const [now, setNow] = React.useState(() => Date.now())\n\n const remainingSeconds = getResendCoolDownRemainingSeconds(sentAt, now)\n\n React.useEffect(() => {\n if (!sentAt) {\n return\n }\n\n setNow(Date.now())\n\n const intervalId = window.setInterval(() => {\n setNow(Date.now())\n }, 1000)\n\n return () => window.clearInterval(intervalId)\n }, [sentAt])\n\n return remainingSeconds\n}\n\nfunction MfaPhoneNumberDialog() {\n const {\n isPhoneNumberDialogOpen,\n mfaSettings,\n phoneVerificationCodeSentAt,\n closePhoneNumberDialog,\n savePhoneNumber,\n verifyPhoneNumber,\n } = useMfa()\n\n const isPhoneVerificationRequired = phoneVerificationCodeSentAt !== undefined\n\n const [phoneNumber, setPhoneNumber] = React.useState('')\n const [verificationCode, setVerificationCode] = React.useState('')\n const resendCoolDownSeconds = usePhoneVerificationResendCoolDown(\n phoneVerificationCodeSentAt,\n )\n const [isSaving, startSaving, stopSaving] = useBooleanState(false)\n\n React.useEffect(() => {\n if (isPhoneNumberDialogOpen) {\n setPhoneNumber(mfaSettings.sms.phoneNumber || '')\n setVerificationCode('')\n }\n }, [isPhoneNumberDialogOpen, mfaSettings.sms.phoneNumber])\n\n const handleSavePhoneNumber = React.useCallback(async () => {\n startSaving()\n try {\n await savePhoneNumber(phoneNumber)\n } finally {\n stopSaving()\n }\n }, [phoneNumber, savePhoneNumber, startSaving, stopSaving])\n\n const handleVerifyPhoneNumber = React.useCallback(async () => {\n startSaving()\n try {\n await verifyPhoneNumber(verificationCode)\n } finally {\n stopSaving()\n }\n }, [verificationCode, verifyPhoneNumber, startSaving, stopSaving])\n\n const handleSubmit = React.useCallback(\n (event: React.SubmitEvent<HTMLFormElement>) => {\n event.preventDefault()\n\n if (isSaving) {\n return\n }\n\n if (isPhoneVerificationRequired) {\n if (!verificationCode) {\n return\n }\n\n void handleVerifyPhoneNumber()\n return\n }\n\n if (!phoneNumber) {\n return\n }\n\n void handleSavePhoneNumber()\n },\n [\n handleSavePhoneNumber,\n handleVerifyPhoneNumber,\n isPhoneVerificationRequired,\n isSaving,\n phoneNumber,\n verificationCode,\n ],\n )\n\n const handleResendVerificationCode = React.useCallback(async () => {\n startSaving()\n try {\n await savePhoneNumber(phoneNumber)\n } finally {\n stopSaving()\n }\n }, [phoneNumber, savePhoneNumber, startSaving, stopSaving])\n\n return (\n <Dialog\n open={isPhoneNumberDialogOpen}\n onClose={() => {\n if (!isSaving) {\n closePhoneNumberDialog()\n }\n }}\n fullWidth\n maxWidth=\"sm\"\n >\n <form onSubmit={handleSubmit}>\n <DialogTitle>\n {isPhoneVerificationRequired\n ? 'Verify Phone Number'\n : 'Save Phone Number'}\n </DialogTitle>\n <DialogContent dividers>\n {isPhoneVerificationRequired ? (\n <>\n <Typography variant=\"body2\" paragraph>\n Enter the verification code sent to {phoneNumber}.\n </Typography>\n <InputField\n key=\"verification-code\"\n autoFocus\n margin=\"none\"\n name=\"verificationCode\"\n label=\"Verification Code\"\n fullWidth\n placeholder=\"XXXXXX\"\n variant=\"outlined\"\n value={verificationCode}\n onChange={(event) => {\n setVerificationCode(event.target.value)\n }}\n disabled={isSaving}\n data-cypress=\"mfa-phone-verification-code\"\n />\n <Box marginTop={1}>\n <Button\n type=\"button\"\n variant=\"text\"\n size=\"small\"\n sx={{ textTransform: 'none' }}\n disabled={resendCoolDownSeconds > 0 || isSaving}\n onClick={handleResendVerificationCode}\n data-cypress=\"mfa-phone-resend-button\"\n >\n {resendCoolDownSeconds > 0\n ? `Send Again (${resendCoolDownSeconds}s)`\n : 'Send Again'}\n </Button>\n </Box>\n </>\n ) : (\n <>\n <Typography variant=\"body2\" paragraph>\n Enter your phone number to receive SMS verification codes when\n signing in.\n </Typography>\n <InputField\n key=\"phone-number\"\n autoFocus\n margin=\"none\"\n name=\"phoneNumber\"\n label=\"Phone Number\"\n fullWidth\n placeholder=\"+61400000000\"\n variant=\"outlined\"\n value={phoneNumber}\n onChange={(event) => {\n setPhoneNumber(event.target.value)\n }}\n disabled={isSaving}\n helperText=\"Include your country code, for example +61400000000.\"\n data-cypress=\"mfa-phone-number\"\n />\n </>\n )}\n </DialogContent>\n <DialogActions>\n <Button\n type=\"button\"\n onClick={closePhoneNumberDialog}\n disabled={isSaving}\n >\n Cancel\n </Button>\n {isPhoneVerificationRequired ? (\n <Button\n type=\"submit\"\n variant=\"contained\"\n disabled={!verificationCode || isSaving}\n data-cypress=\"mfa-phone-verify-button\"\n >\n Verify\n </Button>\n ) : (\n <Button\n type=\"submit\"\n variant=\"contained\"\n disabled={!phoneNumber || isSaving}\n data-cypress=\"mfa-phone-save-button\"\n >\n Save\n </Button>\n )}\n </DialogActions>\n </form>\n </Dialog>\n )\n}\n\n/**\n * React Component that lets users enter and verify a phone number for SMS MFA.\n * Typically rendered by `<MultiFactorAuthentication />` within an `<MfaProvider\n * />` tree.\n *\n * @returns\n */\nexport default React.memo(MfaPhoneNumberDialog)\n"]}
@@ -83,7 +83,7 @@ function BarcodeScannerCameraLoader(props) {
83
83
  }
84
84
  return _jsx(BarcodeScanner, { ...props, cameraDevices: state.result });
85
85
  }
86
- function BarcodeScanner({ id, restrictedBarcodeTypes, onScan, onClose, ...props }) {
86
+ function BarcodeScanner({ id, restrictedBarcodeTypes, onScan, onClose, cameraDevices, ...props }) {
87
87
  const formatsToSupport = React.useMemo(() => {
88
88
  return restrictedBarcodeTypes === null || restrictedBarcodeTypes === void 0 ? void 0 : restrictedBarcodeTypes.reduce((memo, barcodeType) => {
89
89
  const format = Html5QrcodeSupportedFormats[barcodeType];
@@ -93,36 +93,83 @@ function BarcodeScanner({ id, restrictedBarcodeTypes, onScan, onClose, ...props
93
93
  return memo;
94
94
  }, []);
95
95
  }, [restrictedBarcodeTypes]);
96
+ const [scannerState, setScannerState] = React.useState({ state: 'loading' });
96
97
  React.useEffect(() => {
98
+ setScannerState({ state: 'loading' });
97
99
  const html5Qrcode = new Html5Qrcode(id, {
98
100
  verbose: !!localStorage.getItem('BARCODE_SCANNER_VERBOSE'),
99
101
  formatsToSupport: (formatsToSupport === null || formatsToSupport === void 0 ? void 0 : formatsToSupport.length) ? formatsToSupport : undefined,
100
102
  });
101
- html5Qrcode
102
- .start({
103
- facingMode: 'environment',
104
- }, {
103
+ const backFacingCamera = cameraDevices.find((device) => /back|rear|environment/i.test(device.label));
104
+ const preferredCamera = backFacingCamera !== null && backFacingCamera !== void 0 ? backFacingCamera : cameraDevices[0];
105
+ const scanConfig = {
105
106
  fps: 20,
106
- qrbox: {
107
- width: 400,
108
- height: 400,
107
+ qrbox: (viewfinderWidth, viewfinderHeight) => {
108
+ const size = Math.min(400, Math.floor(Math.min(viewfinderWidth, viewfinderHeight) * 0.75));
109
+ return { width: size, height: size };
109
110
  },
110
- }, function onScanSuccess(decodedText, decodedResult) {
111
+ };
112
+ const onScanSuccess = (decodedText, decodedResult) => {
111
113
  console.log('Barcode scanner decoded result:', decodedResult);
112
114
  onScan(decodedText);
113
- }, function onScanFailure() {
115
+ };
116
+ const onScanFailure = () => {
114
117
  // do nothing and keep scanning
115
- })
116
- .catch((error) => {
117
- console.warn('Failed to start scanning', error);
118
- });
118
+ };
119
+ const abortController = new AbortController();
120
+ const begin = async () => {
121
+ try {
122
+ // Attempt to start with the back facing camera
123
+ await html5Qrcode.start({ deviceId: preferredCamera.id }, scanConfig, onScanSuccess, onScanFailure);
124
+ if (abortController.signal.aborted) {
125
+ return;
126
+ }
127
+ setScannerState({ state: 'ready' });
128
+ }
129
+ catch (deviceIdError) {
130
+ if (abortController.signal.aborted) {
131
+ return;
132
+ }
133
+ console.warn('Failed to start scanning with deviceId', deviceIdError);
134
+ try {
135
+ // If the back facing camera is not available, try to start in environment mode
136
+ await html5Qrcode.start({ facingMode: 'environment' }, scanConfig, onScanSuccess, onScanFailure);
137
+ if (abortController.signal.aborted) {
138
+ return;
139
+ }
140
+ setScannerState({ state: 'ready' });
141
+ }
142
+ catch (facingModeError) {
143
+ if (abortController.signal.aborted) {
144
+ return;
145
+ }
146
+ console.warn('Failed to start scanning', facingModeError);
147
+ setScannerState({
148
+ state: 'error',
149
+ error: facingModeError instanceof Error
150
+ ? facingModeError
151
+ : new Error(String(facingModeError)),
152
+ });
153
+ }
154
+ }
155
+ };
156
+ begin();
119
157
  return () => {
120
- html5Qrcode.stop().catch((error) => {
158
+ abortController.abort();
159
+ if (!html5Qrcode.isScanning) {
160
+ return;
161
+ }
162
+ try {
163
+ html5Qrcode.stop().catch((error) => {
164
+ console.warn('Failed to stop barcode scanner', error);
165
+ });
166
+ }
167
+ catch (error) {
121
168
  console.warn('Failed to stop barcode scanner', error);
122
- });
169
+ }
123
170
  };
124
- }, [formatsToSupport, id, onScan]);
125
- return (_jsxs(BarcodeScannerFigure, { onClose: onClose, children: [_jsx("div", { className: "figure-content-absolute-center", children: _jsx(OnLoading, { small: true }) }), _jsx("div", { id: id, className: "ob-figure__barcode-scanner", "aria-describedby": props['aria-describedby'] })] }));
171
+ }, [cameraDevices, formatsToSupport, id, onScan]);
172
+ return (_jsxs(BarcodeScannerFigure, { onClose: onClose, children: [scannerState.state === 'loading' && (_jsx("div", { className: "figure-content-absolute-center", children: _jsx(OnLoading, { small: true }) })), scannerState.state === 'error' && (_jsx(BarcodeScannerError, { title: "Whoops...", message: scannerState.error.message })), _jsx("div", { id: id, className: "ob-figure__barcode-scanner", "aria-describedby": props['aria-describedby'] })] }));
126
173
  }
127
174
  function BarcodeScannerFigure({ onClose, children, }) {
128
175
  return (_jsxs("div", { children: [_jsx("figure", { className: "ob-figure", children: children }), _jsx("div", { className: "buttons ob-buttons", children: _jsx("button", { type: "button", className: "button ob-button ob-button__cancel is-light cypress-cancel-scan-barcode-button", onClick: onClose, children: "Cancel" }) })] }));
@@ -1 +1 @@
1
- {"version":3,"file":"FormElementBarcodeScanner.js","sourceRoot":"","sources":["../../src/form-elements/FormElementBarcodeScanner.tsx"],"names":[],"mappings":"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","sourcesContent":["import * as React from 'react'\nimport {\n Html5Qrcode,\n CameraDevice,\n Html5QrcodeSupportedFormats,\n} from 'html5-qrcode'\nimport CopyToClipboardButton from '../components/renderer/CopyToClipboardButton'\nimport useBooleanState from '../hooks/useBooleanState'\nimport LookupButton from '../components/renderer/LookupButton'\nimport { FormTypes } from '@oneblink/types'\nimport FormElementLabelContainer from '../components/renderer/FormElementLabelContainer'\nimport useLookupNotification, {\n LookupNotificationContext,\n} from '../hooks/useLookupNotification'\nimport { FormElementValueChangeHandler, IsDirtyProps } from '../types/form'\nimport useLoadDataState from '../hooks/useLoadDataState'\nimport OnLoading from '../components/renderer/OnLoading'\nimport useElementAriaDescribedby from '../hooks/useElementAriaDescribedby'\nimport MaterialIcon from '../components/MaterialIcon'\nimport FormElementValidationMessage from '../components/renderer/FormElementValidationMessage'\n\ntype Props = {\n id: string\n element: FormTypes.BarcodeScannerElement\n value: unknown | undefined\n onChange: FormElementValueChangeHandler<string>\n displayValidationMessage: boolean\n validationMessage: string | undefined\n autocompleteAttributes?: string\n} & IsDirtyProps\n\nfunction FormElementBarcodeScanner({\n id,\n element,\n value,\n onChange,\n validationMessage,\n displayValidationMessage,\n isDirty,\n setIsDirty,\n autocompleteAttributes,\n}: Props) {\n const ariaDescribedby = useElementAriaDescribedby(id, element)\n const [isCameraOpen, startBarcodeScanner, stopBarcodeScanner] =\n useBooleanState(false)\n const [error, setError] = React.useState<Error | null>(null)\n const { onLookup } = useLookupNotification(value)\n const handleScan = React.useCallback(\n (newValue: string | undefined) => {\n setIsDirty()\n onChange(element, {\n value: newValue,\n })\n stopBarcodeScanner()\n onLookup()\n },\n [element, onChange, onLookup, setIsDirty, stopBarcodeScanner],\n )\n\n const openBarcodeScanner = React.useCallback(() => {\n if (window.cordova) {\n setError(null)\n // @ts-expect-error ???\n window.cordova.plugins.barcodeScanner.scan(\n // @ts-expect-error ???\n (result) => {\n if (!result.cancelled) {\n handleScan(result.text)\n }\n },\n // @ts-expect-error ???\n (error) => {\n setError(\n new Error(\n `An error has occurred: \"${error}\". Please click \"Cancel\" below to try again. If the problem persists, please contact support.`,\n ),\n )\n },\n {\n showFlipCameraButton: true,\n showTorchButton: true,\n },\n )\n } else {\n startBarcodeScanner()\n }\n }, [handleScan, startBarcodeScanner])\n\n const { isLookingUp } = React.useContext(LookupNotificationContext)\n const isDisplayingValidationMessage =\n (isDirty || displayValidationMessage) && !!validationMessage && !isLookingUp\n\n const text = typeof value === 'string' ? value : ''\n return (\n <div className=\"cypress-barcode-scanner-element\">\n <FormElementLabelContainer\n className=\"ob-barcode-scanner\"\n element={element}\n id={id}\n required={element.required}\n >\n {error && (\n <figure className=\"ob-figure\">\n <div className=\"figure-content has-text-centered\">\n <div>\n <h4 className=\"title is-4\">Whoops...</h4>\n <p>{error.message}</p>\n </div>\n </div>\n </figure>\n )}\n\n {isCameraOpen ? (\n <BarcodeScannerSupported\n id={`${id}==BARCODE_SCANNER`}\n restrictedBarcodeTypes={\n element.restrictBarcodeTypes\n ? element.restrictedBarcodeTypes\n : undefined\n }\n onScan={handleScan}\n onClose={stopBarcodeScanner}\n aria-describedby={ariaDescribedby}\n />\n ) : (\n <div>\n <div className=\"field has-addons\">\n <div className=\"control is-expanded has-icons-right\">\n <input\n type=\"text\"\n placeholder={element.placeholderValue}\n id={id}\n name={element.name}\n className=\"input ob-input cypress-barcode-scanner-control has-margin-bottom-8\"\n value={text}\n onChange={(e) =>\n onChange(element, {\n value: e.target.value || undefined,\n })\n }\n required={element.required}\n disabled={element.readOnly}\n onBlur={setIsDirty}\n aria-describedby={ariaDescribedby}\n autoComplete={autocompleteAttributes}\n aria-required={element.required}\n />\n <span className=\"ob-input-icon icon is-small is-right\">\n <MaterialIcon className=\"is-size-5\">\n document_scanner\n </MaterialIcon>\n </span>\n </div>\n {!!element.readOnly && !!value && (\n <div className=\"control\">\n <CopyToClipboardButton\n className=\"button is-input-addon copy-button cypress-copy-to-clipboard-button\"\n text={text}\n />\n </div>\n )}\n <LookupButton\n isInputButton\n value={value}\n validationMessage={validationMessage}\n lookupButtonConfig={element.lookupButton}\n overrideRequiredMessage={undefined}\n />\n </div>\n\n <button\n type=\"button\"\n className=\"button ob-button ob-button__open is-primary cypress-start-scan-barcode-button\"\n disabled={element.readOnly}\n onClick={openBarcodeScanner}\n >\n Scan Barcode\n </button>\n </div>\n )}\n\n {isDisplayingValidationMessage && (\n <FormElementValidationMessage message={validationMessage} />\n )}\n </FormElementLabelContainer>\n </div>\n )\n}\n\nexport default React.memo(FormElementBarcodeScanner)\n\ntype BarcodeScannerProps = {\n id: string\n restrictedBarcodeTypes: FormTypes.BarcodeScannerElement['restrictedBarcodeTypes']\n onScan: (barcode: string | undefined) => void\n onClose: () => void\n 'aria-describedby'?: string\n}\n\nfunction BarcodeScannerSupported(props: BarcodeScannerProps) {\n const { onClose } = props\n if (!navigator.mediaDevices?.getUserMedia) {\n return (\n <BarcodeScannerFigure onClose={onClose}>\n <BarcodeScannerError\n title=\"Unsupported Device\"\n message=\"Your device does not support accessing your camera.\"\n />\n </BarcodeScannerFigure>\n )\n }\n\n return <BarcodeScannerCameraLoader {...props} />\n}\n\nfunction BarcodeScannerCameraLoader(props: BarcodeScannerProps) {\n const { onClose } = props\n const [state] = useLoadDataState(Html5Qrcode.getCameras)\n switch (state.status) {\n case 'LOADING': {\n return (\n <BarcodeScannerFigure onClose={onClose}>\n <div className=\"figure-content has-text-centered\">\n <OnLoading small />\n </div>\n </BarcodeScannerFigure>\n )\n }\n case 'ERROR': {\n return (\n <BarcodeScannerFigure onClose={onClose}>\n <BarcodeScannerError\n title=\"Whoops...\"\n message={\n state.error.name === 'NotAllowedError'\n ? 'Cannot scan for barcodes without granting the application access to the camera.'\n : state.error.message\n }\n />\n </BarcodeScannerFigure>\n )\n }\n }\n\n if (!state.result.length) {\n return (\n <BarcodeScannerFigure onClose={onClose}>\n <BarcodeScannerError\n title=\"No Cameras Available\"\n message=\"Your device does not have an accessible camera.\"\n />\n </BarcodeScannerFigure>\n )\n }\n\n return <BarcodeScanner {...props} cameraDevices={state.result} />\n}\n\nfunction BarcodeScanner({\n id,\n restrictedBarcodeTypes,\n onScan,\n onClose,\n ...props\n}: BarcodeScannerProps & {\n cameraDevices: CameraDevice[]\n}) {\n const formatsToSupport = React.useMemo(() => {\n return restrictedBarcodeTypes?.reduce<Html5QrcodeSupportedFormats[]>(\n (memo, barcodeType) => {\n const format =\n Html5QrcodeSupportedFormats[\n barcodeType as keyof typeof Html5QrcodeSupportedFormats\n ]\n if (format !== undefined) {\n memo.push(format)\n }\n return memo\n },\n [],\n )\n }, [restrictedBarcodeTypes])\n\n React.useEffect(() => {\n const html5Qrcode = new Html5Qrcode(id, {\n verbose: !!localStorage.getItem('BARCODE_SCANNER_VERBOSE'),\n formatsToSupport: formatsToSupport?.length ? formatsToSupport : undefined,\n })\n\n html5Qrcode\n .start(\n {\n facingMode: 'environment',\n },\n {\n fps: 20,\n qrbox: {\n width: 400,\n height: 400,\n },\n },\n function onScanSuccess(decodedText, decodedResult) {\n console.log('Barcode scanner decoded result:', decodedResult)\n onScan(decodedText)\n },\n function onScanFailure() {\n // do nothing and keep scanning\n },\n )\n .catch((error) => {\n console.warn('Failed to start scanning', error)\n })\n\n return () => {\n html5Qrcode.stop().catch((error) => {\n console.warn('Failed to stop barcode scanner', error)\n })\n }\n }, [formatsToSupport, id, onScan])\n\n return (\n <BarcodeScannerFigure onClose={onClose}>\n <div className=\"figure-content-absolute-center\">\n <OnLoading small />\n </div>\n <div\n id={id}\n className=\"ob-figure__barcode-scanner\"\n aria-describedby={props['aria-describedby']}\n />\n </BarcodeScannerFigure>\n )\n}\n\nfunction BarcodeScannerFigure({\n onClose,\n children,\n}: {\n onClose: () => void\n children: React.ReactNode\n}) {\n return (\n <div>\n <figure className=\"ob-figure\">{children}</figure>\n <div className=\"buttons ob-buttons\">\n <button\n type=\"button\"\n className=\"button ob-button ob-button__cancel is-light cypress-cancel-scan-barcode-button\"\n onClick={onClose}\n >\n Cancel\n </button>\n </div>\n </div>\n )\n}\n\nfunction BarcodeScannerError({\n title,\n message,\n}: {\n title: string\n message: string\n}) {\n return (\n <div className=\"figure-content has-text-centered\" role=\"alert\">\n <div>\n <h4 className=\"title is-4\">{title}</h4>\n <p className=\"has-margin-bottom-6\">{message}</p>\n <p>\n Please click <b>Cancel</b> below and type in the barcode value\n manually.\n </p>\n </div>\n </div>\n )\n}\n"]}
1
+ {"version":3,"file":"FormElementBarcodeScanner.js","sourceRoot":"","sources":["../../src/form-elements/FormElementBarcodeScanner.tsx"],"names":[],"mappings":"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","sourcesContent":["import * as React from 'react'\nimport {\n Html5Qrcode,\n CameraDevice,\n Html5QrcodeSupportedFormats,\n} from 'html5-qrcode'\nimport CopyToClipboardButton from '../components/renderer/CopyToClipboardButton'\nimport useBooleanState from '../hooks/useBooleanState'\nimport LookupButton from '../components/renderer/LookupButton'\nimport { FormTypes } from '@oneblink/types'\nimport FormElementLabelContainer from '../components/renderer/FormElementLabelContainer'\nimport useLookupNotification, {\n LookupNotificationContext,\n} from '../hooks/useLookupNotification'\nimport { FormElementValueChangeHandler, IsDirtyProps } from '../types/form'\nimport useLoadDataState from '../hooks/useLoadDataState'\nimport OnLoading from '../components/renderer/OnLoading'\nimport useElementAriaDescribedby from '../hooks/useElementAriaDescribedby'\nimport MaterialIcon from '../components/MaterialIcon'\nimport FormElementValidationMessage from '../components/renderer/FormElementValidationMessage'\n\ntype Props = {\n id: string\n element: FormTypes.BarcodeScannerElement\n value: unknown | undefined\n onChange: FormElementValueChangeHandler<string>\n displayValidationMessage: boolean\n validationMessage: string | undefined\n autocompleteAttributes?: string\n} & IsDirtyProps\n\nfunction FormElementBarcodeScanner({\n id,\n element,\n value,\n onChange,\n validationMessage,\n displayValidationMessage,\n isDirty,\n setIsDirty,\n autocompleteAttributes,\n}: Props) {\n const ariaDescribedby = useElementAriaDescribedby(id, element)\n const [isCameraOpen, startBarcodeScanner, stopBarcodeScanner] =\n useBooleanState(false)\n const [error, setError] = React.useState<Error | null>(null)\n const { onLookup } = useLookupNotification(value)\n const handleScan = React.useCallback(\n (newValue: string | undefined) => {\n setIsDirty()\n onChange(element, {\n value: newValue,\n })\n stopBarcodeScanner()\n onLookup()\n },\n [element, onChange, onLookup, setIsDirty, stopBarcodeScanner],\n )\n\n const openBarcodeScanner = React.useCallback(() => {\n if (window.cordova) {\n setError(null)\n // @ts-expect-error ???\n window.cordova.plugins.barcodeScanner.scan(\n // @ts-expect-error ???\n (result) => {\n if (!result.cancelled) {\n handleScan(result.text)\n }\n },\n // @ts-expect-error ???\n (error) => {\n setError(\n new Error(\n `An error has occurred: \"${error}\". Please click \"Cancel\" below to try again. If the problem persists, please contact support.`,\n ),\n )\n },\n {\n showFlipCameraButton: true,\n showTorchButton: true,\n },\n )\n } else {\n startBarcodeScanner()\n }\n }, [handleScan, startBarcodeScanner])\n\n const { isLookingUp } = React.useContext(LookupNotificationContext)\n const isDisplayingValidationMessage =\n (isDirty || displayValidationMessage) && !!validationMessage && !isLookingUp\n\n const text = typeof value === 'string' ? value : ''\n return (\n <div className=\"cypress-barcode-scanner-element\">\n <FormElementLabelContainer\n className=\"ob-barcode-scanner\"\n element={element}\n id={id}\n required={element.required}\n >\n {error && (\n <figure className=\"ob-figure\">\n <div className=\"figure-content has-text-centered\">\n <div>\n <h4 className=\"title is-4\">Whoops...</h4>\n <p>{error.message}</p>\n </div>\n </div>\n </figure>\n )}\n\n {isCameraOpen ? (\n <BarcodeScannerSupported\n id={`${id}==BARCODE_SCANNER`}\n restrictedBarcodeTypes={\n element.restrictBarcodeTypes\n ? element.restrictedBarcodeTypes\n : undefined\n }\n onScan={handleScan}\n onClose={stopBarcodeScanner}\n aria-describedby={ariaDescribedby}\n />\n ) : (\n <div>\n <div className=\"field has-addons\">\n <div className=\"control is-expanded has-icons-right\">\n <input\n type=\"text\"\n placeholder={element.placeholderValue}\n id={id}\n name={element.name}\n className=\"input ob-input cypress-barcode-scanner-control has-margin-bottom-8\"\n value={text}\n onChange={(e) =>\n onChange(element, {\n value: e.target.value || undefined,\n })\n }\n required={element.required}\n disabled={element.readOnly}\n onBlur={setIsDirty}\n aria-describedby={ariaDescribedby}\n autoComplete={autocompleteAttributes}\n aria-required={element.required}\n />\n <span className=\"ob-input-icon icon is-small is-right\">\n <MaterialIcon className=\"is-size-5\">\n document_scanner\n </MaterialIcon>\n </span>\n </div>\n {!!element.readOnly && !!value && (\n <div className=\"control\">\n <CopyToClipboardButton\n className=\"button is-input-addon copy-button cypress-copy-to-clipboard-button\"\n text={text}\n />\n </div>\n )}\n <LookupButton\n isInputButton\n value={value}\n validationMessage={validationMessage}\n lookupButtonConfig={element.lookupButton}\n overrideRequiredMessage={undefined}\n />\n </div>\n\n <button\n type=\"button\"\n className=\"button ob-button ob-button__open is-primary cypress-start-scan-barcode-button\"\n disabled={element.readOnly}\n onClick={openBarcodeScanner}\n >\n Scan Barcode\n </button>\n </div>\n )}\n\n {isDisplayingValidationMessage && (\n <FormElementValidationMessage message={validationMessage} />\n )}\n </FormElementLabelContainer>\n </div>\n )\n}\n\nexport default React.memo(FormElementBarcodeScanner)\n\ntype BarcodeScannerProps = {\n id: string\n restrictedBarcodeTypes: FormTypes.BarcodeScannerElement['restrictedBarcodeTypes']\n onScan: (barcode: string | undefined) => void\n onClose: () => void\n 'aria-describedby'?: string\n}\n\nfunction BarcodeScannerSupported(props: BarcodeScannerProps) {\n const { onClose } = props\n if (!navigator.mediaDevices?.getUserMedia) {\n return (\n <BarcodeScannerFigure onClose={onClose}>\n <BarcodeScannerError\n title=\"Unsupported Device\"\n message=\"Your device does not support accessing your camera.\"\n />\n </BarcodeScannerFigure>\n )\n }\n\n return <BarcodeScannerCameraLoader {...props} />\n}\n\nfunction BarcodeScannerCameraLoader(props: BarcodeScannerProps) {\n const { onClose } = props\n const [state] = useLoadDataState(Html5Qrcode.getCameras)\n switch (state.status) {\n case 'LOADING': {\n return (\n <BarcodeScannerFigure onClose={onClose}>\n <div className=\"figure-content has-text-centered\">\n <OnLoading small />\n </div>\n </BarcodeScannerFigure>\n )\n }\n case 'ERROR': {\n return (\n <BarcodeScannerFigure onClose={onClose}>\n <BarcodeScannerError\n title=\"Whoops...\"\n message={\n state.error.name === 'NotAllowedError'\n ? 'Cannot scan for barcodes without granting the application access to the camera.'\n : state.error.message\n }\n />\n </BarcodeScannerFigure>\n )\n }\n }\n\n if (!state.result.length) {\n return (\n <BarcodeScannerFigure onClose={onClose}>\n <BarcodeScannerError\n title=\"No Cameras Available\"\n message=\"Your device does not have an accessible camera.\"\n />\n </BarcodeScannerFigure>\n )\n }\n\n return <BarcodeScanner {...props} cameraDevices={state.result} />\n}\n\nfunction BarcodeScanner({\n id,\n restrictedBarcodeTypes,\n onScan,\n onClose,\n cameraDevices,\n ...props\n}: BarcodeScannerProps & {\n cameraDevices: CameraDevice[]\n}) {\n const formatsToSupport = React.useMemo(() => {\n return restrictedBarcodeTypes?.reduce<Html5QrcodeSupportedFormats[]>(\n (memo, barcodeType) => {\n const format =\n Html5QrcodeSupportedFormats[\n barcodeType as keyof typeof Html5QrcodeSupportedFormats\n ]\n if (format !== undefined) {\n memo.push(format)\n }\n return memo\n },\n [],\n )\n }, [restrictedBarcodeTypes])\n\n const [scannerState, setScannerState] = React.useState<\n { state: 'loading' } | { state: 'ready' } | { state: 'error'; error: Error }\n >({ state: 'loading' })\n\n React.useEffect(() => {\n setScannerState({ state: 'loading' })\n\n const html5Qrcode = new Html5Qrcode(id, {\n verbose: !!localStorage.getItem('BARCODE_SCANNER_VERBOSE'),\n formatsToSupport: formatsToSupport?.length ? formatsToSupport : undefined,\n })\n\n const backFacingCamera = cameraDevices.find((device) =>\n /back|rear|environment/i.test(device.label),\n )\n const preferredCamera = backFacingCamera ?? cameraDevices[0]\n const scanConfig = {\n fps: 20,\n qrbox: (viewfinderWidth: number, viewfinderHeight: number) => {\n const size = Math.min(\n 400,\n Math.floor(Math.min(viewfinderWidth, viewfinderHeight) * 0.75),\n )\n return { width: size, height: size }\n },\n }\n\n const onScanSuccess = (decodedText: string, decodedResult: unknown) => {\n console.log('Barcode scanner decoded result:', decodedResult)\n onScan(decodedText)\n }\n const onScanFailure = () => {\n // do nothing and keep scanning\n }\n\n const abortController = new AbortController()\n\n const begin = async () => {\n try {\n // Attempt to start with the back facing camera\n await html5Qrcode.start(\n { deviceId: preferredCamera.id },\n scanConfig,\n onScanSuccess,\n onScanFailure,\n )\n if (abortController.signal.aborted) {\n return\n }\n setScannerState({ state: 'ready' })\n } catch (deviceIdError) {\n if (abortController.signal.aborted) {\n return\n }\n console.warn('Failed to start scanning with deviceId', deviceIdError)\n try {\n // If the back facing camera is not available, try to start in environment mode\n await html5Qrcode.start(\n { facingMode: 'environment' },\n scanConfig,\n onScanSuccess,\n onScanFailure,\n )\n if (abortController.signal.aborted) {\n return\n }\n setScannerState({ state: 'ready' })\n } catch (facingModeError) {\n if (abortController.signal.aborted) {\n return\n }\n console.warn('Failed to start scanning', facingModeError)\n setScannerState({\n state: 'error',\n error:\n facingModeError instanceof Error\n ? facingModeError\n : new Error(String(facingModeError)),\n })\n }\n }\n }\n\n begin()\n\n return () => {\n abortController.abort()\n if (!html5Qrcode.isScanning) {\n return\n }\n try {\n html5Qrcode.stop().catch((error) => {\n console.warn('Failed to stop barcode scanner', error)\n })\n } catch (error) {\n console.warn('Failed to stop barcode scanner', error)\n }\n }\n }, [cameraDevices, formatsToSupport, id, onScan])\n\n return (\n <BarcodeScannerFigure onClose={onClose}>\n {scannerState.state === 'loading' && (\n <div className=\"figure-content-absolute-center\">\n <OnLoading small />\n </div>\n )}\n {scannerState.state === 'error' && (\n <BarcodeScannerError\n title=\"Whoops...\"\n message={scannerState.error.message}\n />\n )}\n <div\n id={id}\n className=\"ob-figure__barcode-scanner\"\n aria-describedby={props['aria-describedby']}\n />\n </BarcodeScannerFigure>\n )\n}\n\nfunction BarcodeScannerFigure({\n onClose,\n children,\n}: {\n onClose: () => void\n children: React.ReactNode\n}) {\n return (\n <div>\n <figure className=\"ob-figure\">{children}</figure>\n <div className=\"buttons ob-buttons\">\n <button\n type=\"button\"\n className=\"button ob-button ob-button__cancel is-light cypress-cancel-scan-barcode-button\"\n onClick={onClose}\n >\n Cancel\n </button>\n </div>\n </div>\n )\n}\n\nfunction BarcodeScannerError({\n title,\n message,\n}: {\n title: string\n message: string\n}) {\n return (\n <div className=\"figure-content has-text-centered\" role=\"alert\">\n <div>\n <h4 className=\"title is-4\">{title}</h4>\n <p className=\"has-margin-bottom-6\">{message}</p>\n <p>\n Please click <b>Cancel</b> below and type in the barcode value\n manually.\n </p>\n </div>\n </div>\n )\n}\n"]}
@@ -29,7 +29,6 @@ export declare const MfaContext: React.Context<MfaState & {
29
29
  closePhoneNumberDialog: () => void;
30
30
  savePhoneNumber: (phoneNumber: string) => Promise<void>;
31
31
  verifyPhoneNumber: (code: string) => Promise<void>;
32
- resendPhoneNumberVerificationCode: () => Promise<void>;
33
32
  beginRemovingPhoneNumber: () => void;
34
33
  cancelRemovingPhoneNumber: () => void;
35
34
  completeRemovingPhoneNumber: () => Promise<void>;
@@ -108,7 +107,6 @@ export default function useMfa(): MfaState & {
108
107
  closePhoneNumberDialog: () => void;
109
108
  savePhoneNumber: (phoneNumber: string) => Promise<void>;
110
109
  verifyPhoneNumber: (code: string) => Promise<void>;
111
- resendPhoneNumberVerificationCode: () => Promise<void>;
112
110
  beginRemovingPhoneNumber: () => void;
113
111
  cancelRemovingPhoneNumber: () => void;
114
112
  completeRemovingPhoneNumber: () => Promise<void>;
@@ -22,7 +22,6 @@ export const MfaContext = React.createContext({
22
22
  closePhoneNumberDialog: () => { },
23
23
  savePhoneNumber: async () => { },
24
24
  verifyPhoneNumber: async () => { },
25
- resendPhoneNumberVerificationCode: async () => { },
26
25
  beginRemovingPhoneNumber: () => { },
27
26
  cancelRemovingPhoneNumber: () => { },
28
27
  completeRemovingPhoneNumber: async () => { },
@@ -331,22 +330,6 @@ export function MfaProvider({ children, isExternalIdentityProviderUser, }) {
331
330
  }));
332
331
  }
333
332
  }, [setupSmsMfaMethod]);
334
- const resendPhoneNumberVerificationCode = React.useCallback(async () => {
335
- setState((currentState) => ({
336
- ...currentState,
337
- setupError: undefined,
338
- phoneVerificationCodeSentAt: Date.now(),
339
- }));
340
- try {
341
- await mfaService.sendPhoneNumberVerificationCode();
342
- }
343
- catch (error) {
344
- setState((currentState) => ({
345
- ...currentState,
346
- setupError: error,
347
- }));
348
- }
349
- }, []);
350
333
  const beginRemovingPhoneNumber = React.useCallback(() => {
351
334
  setState((currentState) => ({
352
335
  ...currentState,
@@ -506,7 +489,6 @@ export function MfaProvider({ children, isExternalIdentityProviderUser, }) {
506
489
  closePhoneNumberDialog,
507
490
  savePhoneNumber,
508
491
  verifyPhoneNumber,
509
- resendPhoneNumberVerificationCode,
510
492
  beginRemovingPhoneNumber,
511
493
  cancelRemovingPhoneNumber,
512
494
  completeRemovingPhoneNumber,
@@ -529,7 +511,6 @@ export function MfaProvider({ children, isExternalIdentityProviderUser, }) {
529
511
  closePhoneNumberDialog,
530
512
  savePhoneNumber,
531
513
  verifyPhoneNumber,
532
- resendPhoneNumberVerificationCode,
533
514
  beginRemovingPhoneNumber,
534
515
  cancelRemovingPhoneNumber,
535
516
  completeRemovingPhoneNumber,