UNPKG

@brightlayer-ui/react-auth-workflow

Version:

Re-usable workflow components for Authentication and Registration within Eaton applications.

171 lines (170 loc) 7.29 kB
/* eslint-disable @typescript-eslint/no-unused-expressions */ import React, { useCallback, useRef, useState, useEffect } from 'react'; import CheckCircle from '@mui/icons-material/CheckCircle'; import { ResetPasswordScreenBase } from './ResetPasswordScreenBase.js'; import { useAuthContext } from '../../contexts/index.js'; import { defaultPasswordRequirements } from '../../constants/index.js'; import { parseQueryString } from '../../utils/index.js'; import { useErrorManager } from '../../contexts/ErrorContext/useErrorManager.js'; import { useTranslation } from 'react-i18next'; /** * Component that renders a ResetPassword screen that allows a user to reset their password and shows a success message upon a successful password reset.. * * @param {ResetPasswordScreenProps} props - props of ResetPasswordScreen * @returns a React JSX Element that renders a ResetPassword screen * * @category Component * */ export const ResetPasswordScreen = (props) => { const { t } = useTranslation(); const passwordRef = useRef(null); const confirmRef = useRef(null); const { triggerError, errorManagerConfig } = useErrorManager(); const errorDisplayConfig = { ...errorManagerConfig, ...props.errorDisplayConfig, onClose: () => { if (props.errorDisplayConfig?.onClose) props.errorDisplayConfig.onClose(); if (errorManagerConfig.onClose) errorManagerConfig?.onClose(); }, }; const { WorkflowCardBaseProps, WorkflowCardHeaderProps, WorkflowCardInstructionProps, WorkflowCardActionsProps, PasswordProps, slots = {}, slotProps = {}, ...otherProps } = props; const [passwordInput, setPasswordInput] = useState(PasswordProps?.initialNewPasswordValue ?? ''); const [confirmInput, setConfirmInput] = useState(PasswordProps?.initialConfirmPasswordValue ?? ''); const [hasVerifyCodeError, setHasVerifyCodeError] = useState(false); const [isLoading, setIsLoading] = useState(false); const [showSuccessScreen, setShowSuccessScreen] = useState(false); const { code, email } = parseQueryString(window.location.search); const { actions, navigate, routeConfig } = useAuthContext(); const passwordReqs = PasswordProps?.passwordRequirements ?? defaultPasswordRequirements(t); const verifyResetCode = useCallback(async () => { try { setIsLoading(true); await actions.verifyResetCode(code, email); } catch (_error) { setHasVerifyCodeError(true); triggerError(_error); } finally { setIsLoading(false); } }, []); const handleOnNext = useCallback(async () => { try { setIsLoading(true); await actions.setPassword(code, passwordInput, email); if (props.showSuccessScreen === false) { navigate(routeConfig.LOGIN); } else { setShowSuccessScreen(true); } } catch (_error) { triggerError(_error); } finally { setIsLoading(false); } }, [actions, code, passwordInput, email, triggerError, props.showSuccessScreen, navigate, routeConfig]); const areValidMatchingPasswords = useCallback(() => { if (passwordReqs?.length === 0) { return confirmInput === passwordInput; } for (const req of passwordReqs) { if (!new RegExp(req.regex).test(passwordInput)) return false; } return confirmInput === passwordInput; }, [passwordReqs, passwordInput, confirmInput]); const updateFields = useCallback((fields) => { setPasswordInput(fields.password); setConfirmInput(fields.confirm); }, [setPasswordInput, setConfirmInput]); useEffect(() => { // eslint-disable-next-line verifyResetCode(); }, []); const workflowCardBaseProps = { loading: isLoading, ...WorkflowCardBaseProps, }; const workflowCardHeaderProps = { title: t('bluiCommon:FORMS.RESET_PASSWORD'), ...WorkflowCardHeaderProps, }; const workflowCardInstructionProps = { instructions: t('bluiAuth:CHANGE_PASSWORD.PASSWORD_INFO'), ...WorkflowCardInstructionProps, }; const workflowCardActionsProps = { showNext: true, showPrevious: true, nextLabel: t('bluiCommon:ACTIONS.NEXT'), previousLabel: t('bluiCommon:ACTIONS.BACK'), canGoNext: passwordInput !== '' && confirmInput !== '' && areValidMatchingPasswords(), ...WorkflowCardActionsProps, onNext: () => { void handleOnNext(); WorkflowCardActionsProps?.onNext?.(); }, onPrevious: () => { navigate(routeConfig.LOGIN); WorkflowCardActionsProps?.onPrevious?.(); }, }; const passwordProps = { newPasswordLabel: t('bluiAuth:CHANGE_PASSWORD.NEW_PASSWORD'), confirmPasswordLabel: t('bluiAuth:CHANGE_PASSWORD.CONFIRM_NEW_PASSWORD'), passwordNotMatchError: t('bluiCommon:FORMS.PASS_MATCH_ERROR'), passwordRequirements: passwordReqs, passwordRef, confirmRef, ...PasswordProps, initialNewPasswordValue: passwordInput, initialConfirmPasswordValue: confirmInput, onPasswordChange: (passwordData) => { updateFields(passwordData); PasswordProps?.onPasswordChange?.(passwordData); }, onSubmit: () => { if (areValidMatchingPasswords()) { void handleOnNext(); WorkflowCardActionsProps?.onNext?.(); PasswordProps?.onSubmit?.(); } }, }; return (React.createElement(ResetPasswordScreenBase, { WorkflowCardBaseProps: workflowCardBaseProps, WorkflowCardHeaderProps: workflowCardHeaderProps, WorkflowCardInstructionProps: workflowCardInstructionProps, WorkflowCardActionsProps: workflowCardActionsProps, PasswordProps: passwordProps, showSuccessScreen: showSuccessScreen, slots: slots, slotProps: { SuccessScreen: { EmptyStateProps: { icon: React.createElement(CheckCircle, { color: "primary", sx: { fontSize: 100 } }), title: t('bluiAuth:PASSWORD_RESET.SUCCESS_MESSAGE'), description: t('bluiAuth:CHANGE_PASSWORD.SUCCESS_MESSAGE'), }, WorkflowCardActionsProps: { showPrevious: false, fullWidthButton: true, showNext: true, nextLabel: t('bluiCommon:ACTIONS.DONE'), onNext: () => { navigate(routeConfig.LOGIN); }, }, ...slotProps.SuccessScreen, }, }, ...otherProps, errorDisplayConfig: { ...errorDisplayConfig, onClose: hasVerifyCodeError ? () => { navigate(routeConfig.LOGIN); // eslint-disable-next-line no-unused-expressions errorDisplayConfig.onClose; } : errorDisplayConfig.onClose, } })); };