Skip to content

Commit

Permalink
Error manager with dynamic values
Browse files Browse the repository at this point in the history
  • Loading branch information
JeffGreiner-eaton committed Mar 12, 2024
1 parent 5a807c3 commit 846f89c
Show file tree
Hide file tree
Showing 5 changed files with 87 additions and 53 deletions.
93 changes: 51 additions & 42 deletions login-workflow/example/src/actions/RegistrationUIActions.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -61,18 +61,27 @@ export const ProjectRegistrationUIActions: () => RegistrationUIActions = () => (
requestRegistrationCode: async (email: string): Promise<string> => {
await sleep(800);
if (isRandomFailure()) {
throw new Error('Sorry, there was a problem sending your request.');
// throw new Error('Sorry, there was a problem sending your request.');
}
return 'a1b2c3';
throw new Error('', {
cause: {
errorMessage: 'ERROR_MESSAGE.EMAIL_ERROR_MESSAGE',
errorOptions: { email: email },
title: 'ERROR_MESSAGE.EMAIL_ERROR_TITLE',
titleOptions: {timestamp: Date.now()},

}
});
return 'a1b2c3';
},

createPassword: async (password: string): Promise<boolean> => {
await sleep(800);
if (isRandomFailure()) {
throw new Error('Sorry, there was a problem sending your request.');
}
return true;
},
createPassword: async (password: string): Promise<boolean> => {
await sleep(800);
if (isRandomFailure()) {
throw new Error('Sorry, there was a problem sending your request.');
}
return true;
},

setAccountDetails: async (details: AccountDetails): Promise<boolean> => {
await sleep(800);
Expand All @@ -82,37 +91,37 @@ export const ProjectRegistrationUIActions: () => RegistrationUIActions = () => (
return true;
},

/**
* The user has tapped on an email link inviting them to register with the application.
* The application should validate the code provided by the link.
*
* @param validationCode Registration code provided from the link.
* @param validationEmail Email provided from the invitation email link (optional) `?email=addr%40domain.com`.
*
* @returns Resolves when the code is valid. True if registration is complete, False if account information is needed.
* If the code is not valid a rejection will occur with an error message.
*/
validateUserRegistrationRequest: async (
validationCode: string,
validationEmail?: string
): Promise<{ codeValid: boolean | string; accountExists?: boolean }> => {
await sleep(800);

if (isRandomFailure()) {
throw new Error('Sorry, there was a problem sending your request.');
}
return { codeValid: true, accountExists: false };
},

completeRegistration: async (userData: object): Promise<{ email: string; organizationName: string }> => {
const email = '[email protected]';
const organizationName = 'Acme Co.';
const userInfo = { email, organizationName };

await sleep(1000);
if (isRandomFailure()) {
throw new Error('Sorry, there was a problem sending your request.');
}
return userInfo;
},
/**
* The user has tapped on an email link inviting them to register with the application.
* The application should validate the code provided by the link.
*
* @param validationCode Registration code provided from the link.
* @param validationEmail Email provided from the invitation email link (optional) `?email=addr%40domain.com`.
*
* @returns Resolves when the code is valid. True if registration is complete, False if account information is needed.
* If the code is not valid a rejection will occur with an error message.
*/
validateUserRegistrationRequest: async (
validationCode: string,
validationEmail?: string
): Promise<{ codeValid: boolean | string; accountExists?: boolean }> => {
await sleep(800);

if (isRandomFailure()) {
throw new Error('Sorry, there was a problem sending your request.');
}
return { codeValid: true, accountExists: false };
},

completeRegistration: async (userData: object): Promise<{ email: string; organizationName: string }> => {
const email = '[email protected]';
const organizationName = 'Acme Co.';
const userInfo = { email, organizationName };

await sleep(1000);
if (isRandomFailure()) {
throw new Error('Sorry, there was a problem sending your request.');
}
return userInfo;
},
});
4 changes: 4 additions & 0 deletions login-workflow/example/src/translations/dictionary/english.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@ const resources: AppTranslationsFile = {
CHANGE_PASSWORD: 'Change Password',
MY_ACCOUNT: 'My Account',
},
ERROR_MESSAGE: {
EMAIL_ERROR_MESSAGE: '{{email}} is already registered',
EMAIL_ERROR_TITLE: 'Error {{timestamp}}'
},
},
};
export default resources;
4 changes: 4 additions & 0 deletions login-workflow/example/src/translations/dictionary/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@ export type AppTranslations = {
CHANGE_PASSWORD: string;
MY_ACCOUNT: string;
};
ERROR_MESSAGE: {
EMAIL_ERROR_MESSAGE: string;
EMAIL_ERROR_TITLE: string;
};
};
export type AppTranslationsFile = {
translation: AppTranslations;
Expand Down
33 changes: 23 additions & 10 deletions login-workflow/src/components/Error/ErrorManager.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@ import React, { useCallback } from 'react';
import { BasicDialog } from '../Dialog/BasicDialog';
import ErrorMessageBox from './ErrorMessageBox';
import { SxProps, Theme } from '@mui/material/styles';
import { TFunction } from 'i18next';
import { TFunction, TOptions } from 'i18next';

export type AuthError = { cause: { title: string; errorMessage: string } };
export type AuthError = { cause: { title: string; errorMessage: string, errorOptions?: TOptions, titleOptions?: TOptions } };

export type ErrorManagerProps = {
/**
Expand All @@ -28,6 +28,16 @@ export type ErrorManagerProps = {
*/
error?: string;

/**
* Interpolate string with a dynamic value to pass values using t function for message
*/
errorOptions?: TOptions;

/**
* Interpolate string with a dynamic value to pass values using t function for title
*/
titleOptions?: TOptions;

/**
* Translate function to translate error related text
*/
Expand Down Expand Up @@ -80,9 +90,12 @@ const ErrorManager: React.FC<ErrorManagerProps> = (props): JSX.Element => {
mode = 'dialog',
title,
error = '',
onClose = (): void => {},
errorOptions,
titleOptions,
onClose = (): void => { },
dialogConfig,
t = (key: string): string => key,
// eslint-disable-next-line @typescript-eslint/no-unused-vars
t = (key: string, _options?: TOptions): string => key,
messageBoxConfig = {
position: 'top',
},
Expand All @@ -92,31 +105,31 @@ const ErrorManager: React.FC<ErrorManagerProps> = (props): JSX.Element => {
(): JSX.Element => (
<BasicDialog
open={error.length > 0}
title={t(dialogConfig?.title ?? title ?? 'Error')}
body={t(error)}
title={t(dialogConfig?.title ?? title ?? 'Error', titleOptions)}
body={t(error, errorOptions)}
onClose={onClose}
dismissButtonText={t(dialogConfig?.dismissLabel ?? 'Okay')}
sx={dialogConfig?.sx}
/>
),
[dialogConfig, title, error, onClose, t]
[dialogConfig, title, error, errorOptions, titleOptions, onClose, t]
);

const ErrorMessageBoxWithProps = useCallback((): JSX.Element => {
const { dismissible = true, fontColor, backgroundColor, sx } = messageBoxConfig;

return (
<ErrorMessageBox
title={t(messageBoxConfig?.title ?? title ?? 'Error')}
errorMessage={t(error)}
title={t(messageBoxConfig?.title ?? title ?? 'Error', titleOptions)}
errorMessage={t(error, errorOptions)}
dismissible={dismissible}
sx={sx}
backgroundColor={backgroundColor}
fontColor={fontColor}
onClose={onClose}
/>
);
}, [error, title, messageBoxConfig, onClose, t]);
}, [error, errorOptions, titleOptions, title, messageBoxConfig, onClose, t]);

return mode === 'dialog' && error.length > 0 ? (
<>
Expand Down
6 changes: 5 additions & 1 deletion login-workflow/src/contexts/ErrorContext/useErrorManager.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,10 @@ export const useErrorManager = (): {
if (isAuthError(err)) {
return {
...errorConfig,
dialogConfig: { title: err.cause.title },
dialogConfig: { ...errorConfig.dialogConfig, title: err.cause.title },
error: err.cause.errorMessage,
errorOptions: err.cause.errorOptions,
titleOptions: err.cause.titleOptions,
onClose: (): void => {
setError(new Error());
},
Expand All @@ -37,6 +39,8 @@ export const useErrorManager = (): {
cause: {
title: err.cause.title,
errorMessage: err.cause.errorMessage,
errorOptions: err.cause.errorOptions,
titleOptions: err.cause.titleOptions,
},
});
} else {
Expand Down

0 comments on commit 846f89c

Please sign in to comment.