Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore(account-settings): overrides cleanup #3131

Merged
merged 12 commits into from
Dec 2, 2022
Original file line number Diff line number Diff line change
Expand Up @@ -121,8 +121,16 @@ function ChangePassword({
const updatePasswordText = translate('Update password');

/* Subcomponents */
const { CurrentPassword, NewPassword, ConfirmPassword, SubmitButton, Error } =
React.useMemo(() => ({ ...DEFAULTS, ...(components ?? {}) }), [components]);
const {
CurrentPassword,
NewPassword,
ConfirmPassword,
SubmitButton,
ErrorMessage,
} = React.useMemo(
() => ({ ...DEFAULTS, ...(components ?? {}) }),
[components]
);

/* Event Handlers */
const handleChange = (event: React.ChangeEvent<HTMLInputElement>) => {
Expand Down Expand Up @@ -213,7 +221,7 @@ function ChangePassword({
<SubmitButton isDisabled={isDisabled} type="submit">
{updatePasswordText}
</SubmitButton>
{errorMessage ? <Error>{errorMessage}</Error> : null}
{errorMessage ? <ErrorMessage>{errorMessage}</ErrorMessage> : null}
</Flex>
</View>
);
Expand All @@ -223,6 +231,6 @@ ChangePassword.CurrentPassword = DEFAULTS.CurrentPassword;
ChangePassword.NewPassword = DEFAULTS.NewPassword;
ChangePassword.ConfirmPassword = DEFAULTS.ConfirmPassword;
ChangePassword.SubmitButton = DEFAULTS.SubmitButton;
ChangePassword.Error = DEFAULTS.Error;
ChangePassword.ErrorMessage = DEFAULTS.ErrorMessage;

export default ChangePassword;
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import React from 'react';
import { Button, PasswordField } from '../../../primitives';
import { ValidationErrors } from '../../shared/ValidationErrors';
import { DefaultError } from '../shared/Defaults';
import { DefaultErrorMessage } from '../shared/Defaults';
import { PasswordFieldComponent } from '../types';
import { ChangePasswordComponents } from './types';

Expand All @@ -23,7 +23,7 @@ const DEFAULTS: Required<ChangePasswordComponents> = {
NewPassword: DefaultPasswordField,
ConfirmPassword: DefaultPasswordField,
SubmitButton: Button,
Error: DefaultError,
ErrorMessage: DefaultErrorMessage,
};

export default DEFAULTS;
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { InputEventType, ValidatorOptions } from '@aws-amplify/ui';
import {
ErrorComponent,
ErrorMessageComponent,
PasswordFieldComponent,
SubmitButtonComponent,
FormValues,
Expand All @@ -11,7 +11,7 @@ export interface ChangePasswordComponents {
NewPassword?: PasswordFieldComponent;
ConfirmPassword?: PasswordFieldComponent;
SubmitButton?: SubmitButtonComponent;
Error?: ErrorComponent;
ErrorMessage?: ErrorMessageComponent;
}

export type ValidateParams = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ function DeleteUser({
const { user, isLoading } = useAuth();

// subcomponents
const { Error, SubmitButton, Warning } = React.useMemo(
const { ErrorMessage, DeleteButton, Warning } = React.useMemo(
() => ({ ...DEFAULTS, ...(components ?? {}) }),
[components]
);
Expand Down Expand Up @@ -89,26 +89,26 @@ function DeleteUser({

return (
<Flex className={ComponentClassName.DeleteUser} direction="column">
<SubmitButton
<DeleteButton
isDisabled={state === 'CONFIRMATION'}
onClick={startConfirmation}
>
{deleteAccountText}
</SubmitButton>
</DeleteButton>
{state === 'CONFIRMATION' || state === 'DELETING' ? (
<Warning
onCancel={handleCancel}
isDisabled={state === 'DELETING'}
onConfirm={handleConfirmDelete}
/>
) : null}
{errorMessage ? <Error>{errorMessage}</Error> : null}
{errorMessage ? <ErrorMessage>{errorMessage}</ErrorMessage> : null}
</Flex>
);
}

DeleteUser.Error = DEFAULTS.Error;
DeleteUser.SubmitButton = DEFAULTS.SubmitButton;
DeleteUser.ErrorMessage = DEFAULTS.ErrorMessage;
DeleteUser.DeleteButton = DEFAULTS.DeleteButton;
DeleteUser.Warning = DEFAULTS.Warning;

export default DeleteUser;
Original file line number Diff line number Diff line change
Expand Up @@ -18,30 +18,40 @@ jest.mock('../../../../internal', () => ({

const deleteUserSpy = jest.spyOn(UIModule, 'deleteUser');

function CustomWarning({ onCancel, onConfirm, isDisabled }) {
function CustomWarning({ onCancel, onConfirm }) {
return (
<Flex direction="column">
<Text variation="warning">Custom Warning Message</Text>
<Button onClick={onCancel}>Back</Button>
<Button variation="primary" onClick={onConfirm} isDisabled={isDisabled}>
<Button variation="primary" onClick={onConfirm}>
Custom Confirm Button
</Button>
</Flex>
);
}

const CustomDeleteButton = ({ onClick, isDisabled }) => {
return (
<Button isDisabled={isDisabled} onClick={onClick}>
Custom Delete Button
</Button>
);
};

const CustomErrorMessage = ({ children }) => (
<>
<Heading>Custom Error Message</Heading>
<Text>{children}</Text>
</>
);

const components: DeleteUserComponents = {
SubmitButton: (props) => <Button {...props}>Custom Delete Button</Button>,
DeleteButton: CustomDeleteButton,
Warning: CustomWarning,
Error: ({ children }) => (
<>
<Heading>Custom Error Message</Heading>
<Text>{children}</Text>
</>
),
ErrorMessage: CustomErrorMessage,
};

describe('ChangePassword', () => {
describe('DeleteUser', () => {
beforeEach(() => {
jest.clearAllMocks();
});
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`ChangePassword renders as expected 1`] = `
exports[`DeleteUser renders as expected 1`] = `
<div>
<div
class="amplify-flex amplify-accountsettings-deleteuser"
Expand All @@ -17,7 +17,7 @@ exports[`ChangePassword renders as expected 1`] = `
</div>
`;

exports[`ChangePassword renders as expected with components overrides 1`] = `
exports[`DeleteUser renders as expected with components overrides 1`] = `
<div>
<div
class="amplify-flex amplify-accountsettings-deleteuser"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import React from 'react';
import { translate } from '@aws-amplify/ui';

import { Button, Card, Flex, Text } from '../../../primitives';
import { DefaultError } from '../shared/Defaults';
import { DefaultErrorMessage } from '../shared/Defaults';
import { DeleteUserComponents, WarningComponent } from './types';

const DefaultWarning: WarningComponent = ({
Expand Down Expand Up @@ -40,8 +40,8 @@ const DefaultWarning: WarningComponent = ({
};

const DEFAULTS: Required<DeleteUserComponents> = {
Error: DefaultError,
SubmitButton: Button,
ErrorMessage: DefaultErrorMessage,
DeleteButton: Button,
Warning: DefaultWarning,
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import React from 'react';

import { AmplifyUser } from '@aws-amplify/ui';

import { ErrorComponent, SubmitButtonComponent } from '../types';
import { ButtonComponent, ErrorMessageComponent } from '../types';

export interface WarningProps {
/** called when end user cancels account deletion */
Expand All @@ -25,8 +25,8 @@ export type DeleteUserState =
| 'ERROR';

export interface DeleteUserComponents {
Error?: ErrorComponent;
SubmitButton?: SubmitButtonComponent;
ErrorMessage?: ErrorMessageComponent;
DeleteButton?: ButtonComponent;
Warning?: WarningComponent;
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import React from 'react';
import { Alert } from '../../../primitives';
import { ErrorComponent } from '../types';
import { ErrorMessageComponent } from '../types';

export const DefaultError: ErrorComponent = (props) => {
export const DefaultErrorMessage: ErrorMessageComponent = (props) => {
return <Alert variation="error" {...props} />;
};
40 changes: 30 additions & 10 deletions packages/react/src/components/AccountSettings/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,30 +6,50 @@ import {
PrimitiveProps,
} from '../../primitives/types';

/**
/*
* These are primitive prop types that account settings component use.
*
* Note that `PrimitiveProps` is used to get native html types, like `onSubmit`.
*/
type CommonPasswordFieldProps = Partial<
PrimitiveProps<PasswordFieldProps, 'input'>
>;
type CommonButtonProps = Partial<PrimitiveProps<ButtonProps, 'button'>>;
type CommonAlertProps = Partial<PrimitiveProps<AlertProps, 'div'>>;
type PasswordFieldPrimitiveProps = PrimitiveProps<PasswordFieldProps, 'input'>;
type ButtonPrimitiveProps = PrimitiveProps<ButtonProps, 'button'>;
type AlertPrimitiveProps = PrimitiveProps<AlertProps, 'div'>;

/*
* These are common prop types for component overrides.
*
* Any essential props for overriding components are marked as required.
*/
type CommonPasswordFieldProps = Partial<PasswordFieldPrimitiveProps> &
Required<Pick<PasswordFieldPrimitiveProps, 'onBlur' | 'onChange' | 'name'>>;
type CommonAlertProps = Partial<PrimitiveProps<AlertProps, 'div'>> &
Required<Pick<AlertPrimitiveProps, 'children'>>;
type CommonButtonProps<T = 'submit' | 'default'> =
Partial<ButtonPrimitiveProps> &
Required<
Pick<
ButtonPrimitiveProps,
'isDisabled' | (T extends 'submit' ? never : 'onClick')
>
>;

/**
* These are overridable component types (e.g. submit button).
/*
* These are component override types.
*/
export type PasswordFieldComponent<Props = {}> = React.ComponentType<
// `Props` generic allows additional props passed on override components
Props & CommonPasswordFieldProps & { validationErrors?: string[] }
>;

export type ButtonComponent<Props = {}> = React.ComponentType<
Props & CommonButtonProps<'default'>
>;

export type SubmitButtonComponent<Props = {}> = React.ComponentType<
Props & CommonButtonProps
Props & CommonButtonProps<'submit'>
>;

export type ErrorComponent<Props = {}> = React.ComponentType<
export type ErrorMessageComponent<Props = {}> = React.ComponentType<
Props & CommonAlertProps
>;

Expand Down