diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 599ff0c1b0e..52ee484d013 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -124,3 +124,4 @@ jobs: VALID_PASSWORD: ${{ secrets.VALID_PASSWORD }} VALID_EMAIL_SETUP_MFA: ${{ secrets.VALID_EMAIL_SETUP_MFA }} VALID_PASSWORD_SETUP_MFA: ${{ secrets.VALID_PASSWORD_SETUP_MFA }} + UNVERIFIED_EMAIL: ${{ secrets.UNVERIFIED_EMAIL }} diff --git a/examples/next/pages/ui/components/authenticator/sign-in-sms-mfa/index.page.tsx b/examples/next/pages/ui/components/authenticator/sign-in-sms-mfa/index.page.tsx index f90f7ebb8ed..7c4ab18dff2 100644 --- a/examples/next/pages/ui/components/authenticator/sign-in-sms-mfa/index.page.tsx +++ b/examples/next/pages/ui/components/authenticator/sign-in-sms-mfa/index.page.tsx @@ -1,5 +1,6 @@ import { Authenticator } from '@aws-amplify/ui-react'; -import { Amplify } from 'aws-amplify'; +import { dict } from '@aws-amplify/ui-core'; +import { Amplify, I18n } from 'aws-amplify'; import awsExports from '@environments/auth-with-phone-and-sms-mfa/src/aws-exports'; @@ -10,6 +11,18 @@ Amplify.configure({ }, }); +I18n.putVocabularies(dict); + export default function AuthenticatorWithSmsMfa() { - return ; + return ( + + {({ send }) => { + return ( + <> + + + ); + }} + + ); } diff --git a/examples/next/pages/ui/components/authenticator/sign-in-totp-mfa/index.page.tsx b/examples/next/pages/ui/components/authenticator/sign-in-totp-mfa/index.page.tsx index 0a9c371bca3..a3cdbd2d8a0 100644 --- a/examples/next/pages/ui/components/authenticator/sign-in-totp-mfa/index.page.tsx +++ b/examples/next/pages/ui/components/authenticator/sign-in-totp-mfa/index.page.tsx @@ -1,5 +1,6 @@ import { Authenticator } from '@aws-amplify/ui-react'; -import { Amplify } from 'aws-amplify'; +import { dict } from '@aws-amplify/ui-core'; +import { Amplify, I18n } from 'aws-amplify'; import awsExports from '@environments/auth-with-totp-mfa/src/aws-exports'; @@ -10,6 +11,8 @@ Amplify.configure({ }, }); +I18n.putVocabularies(dict); + export default function SignInTotpMfa() { return ( diff --git a/examples/next/pages/ui/components/authenticator/sign-in-totp-sms-mfa/index.page.tsx b/examples/next/pages/ui/components/authenticator/sign-in-totp-sms-mfa/index.page.tsx index e85d7a6347a..642fa75c16c 100644 --- a/examples/next/pages/ui/components/authenticator/sign-in-totp-sms-mfa/index.page.tsx +++ b/examples/next/pages/ui/components/authenticator/sign-in-totp-sms-mfa/index.page.tsx @@ -1,5 +1,6 @@ import { Authenticator } from 'aws-amplify-react'; -import { Amplify } from 'aws-amplify'; +import { dict } from '@aws-amplify/ui-core'; +import { Amplify, I18n } from 'aws-amplify'; import awsExports from '@environments/auth-with-totp-and-sms-mfa/src/aws-exports'; @@ -10,6 +11,8 @@ Amplify.configure({ }, }); +I18n.putVocabularies(dict); + export default function SignInTotpSmsMfa() { return ; } diff --git a/examples/next/pages/ui/components/authenticator/sign-in-with-email/index.page.tsx b/examples/next/pages/ui/components/authenticator/sign-in-with-email/index.page.tsx index 172b92044d6..760c0853ea5 100644 --- a/examples/next/pages/ui/components/authenticator/sign-in-with-email/index.page.tsx +++ b/examples/next/pages/ui/components/authenticator/sign-in-with-email/index.page.tsx @@ -1,5 +1,6 @@ import { Authenticator } from '@aws-amplify/ui-react'; -import { Amplify } from 'aws-amplify'; +import { dict } from '@aws-amplify/ui-core'; +import { Amplify, I18n } from 'aws-amplify'; import awsExports from '@environments/auth-with-email/src/aws-exports'; Amplify.configure({ @@ -9,6 +10,8 @@ Amplify.configure({ }, }); +I18n.putVocabularies(dict); + export default function AuthenticatorWithEmail() { return ( <> diff --git a/examples/next/pages/ui/components/authenticator/sign-in-with-phone/index.page.tsx b/examples/next/pages/ui/components/authenticator/sign-in-with-phone/index.page.tsx index 6b2905aca2e..010e6cf35a4 100644 --- a/examples/next/pages/ui/components/authenticator/sign-in-with-phone/index.page.tsx +++ b/examples/next/pages/ui/components/authenticator/sign-in-with-phone/index.page.tsx @@ -1,5 +1,6 @@ import { Authenticator } from '@aws-amplify/ui-react'; -import { Amplify } from 'aws-amplify'; +import { dict } from '@aws-amplify/ui-core'; +import { Amplify, I18n } from 'aws-amplify'; import awsExports from '@environments/auth-with-phone-number/src/aws-exports'; Amplify.configure({ @@ -9,6 +10,8 @@ Amplify.configure({ }, }); +I18n.putVocabularies(dict); + export default function AuthenticatorWithPhoneNumber() { return ( <> diff --git a/examples/next/pages/ui/components/authenticator/sign-in-with-username/index.page.tsx b/examples/next/pages/ui/components/authenticator/sign-in-with-username/index.page.tsx index 5b89ff4e790..2b1d1fd3971 100644 --- a/examples/next/pages/ui/components/authenticator/sign-in-with-username/index.page.tsx +++ b/examples/next/pages/ui/components/authenticator/sign-in-with-username/index.page.tsx @@ -1,5 +1,6 @@ import { Authenticator } from '@aws-amplify/ui-react'; -import { Amplify } from 'aws-amplify'; +import { dict } from '@aws-amplify/ui-core'; +import { Amplify, I18n } from 'aws-amplify'; import awsExports from '@environments/auth-with-username-no-attributes/src/aws-exports'; @@ -10,6 +11,8 @@ Amplify.configure({ }, }); +I18n.putVocabularies(dict); + export default function AuthenticatorWithUsername() { return ( diff --git a/examples/next/pages/ui/components/authenticator/sign-up-with-email/index.page.tsx b/examples/next/pages/ui/components/authenticator/sign-up-with-email/index.page.tsx index 0ddca339bd8..d466dc76cc8 100644 --- a/examples/next/pages/ui/components/authenticator/sign-up-with-email/index.page.tsx +++ b/examples/next/pages/ui/components/authenticator/sign-up-with-email/index.page.tsx @@ -1,5 +1,6 @@ import { Authenticator } from '@aws-amplify/ui-react'; -import { Amplify } from 'aws-amplify'; +import { dict } from '@aws-amplify/ui-core'; +import { Amplify, I18n } from 'aws-amplify'; import awsExports from '@environments/auth-with-email/src/aws-exports'; Amplify.configure({ @@ -9,6 +10,8 @@ Amplify.configure({ }, }); +I18n.putVocabularies(dict); + export default function AuthenticatorWithEmail() { return ; } diff --git a/examples/next/pages/ui/components/authenticator/sign-up-with-phone/index.page.tsx b/examples/next/pages/ui/components/authenticator/sign-up-with-phone/index.page.tsx index 67807ecf33a..f4da9f08938 100644 --- a/examples/next/pages/ui/components/authenticator/sign-up-with-phone/index.page.tsx +++ b/examples/next/pages/ui/components/authenticator/sign-up-with-phone/index.page.tsx @@ -1,5 +1,6 @@ import { Authenticator } from '@aws-amplify/ui-react'; -import { Amplify } from 'aws-amplify'; +import { dict } from '@aws-amplify/ui-core'; +import { Amplify, I18n } from 'aws-amplify'; import awsExports from '@environments/auth-with-phone-number/src/aws-exports'; Amplify.configure({ @@ -9,6 +10,8 @@ Amplify.configure({ }, }); +I18n.putVocabularies(dict); + export default function AuthenticatorWithPhone() { return ( <> diff --git a/examples/next/pages/ui/components/authenticator/sign-up/index.page.tsx b/examples/next/pages/ui/components/authenticator/sign-up/index.page.tsx index 2276d14ef40..75c46f59b8a 100644 --- a/examples/next/pages/ui/components/authenticator/sign-up/index.page.tsx +++ b/examples/next/pages/ui/components/authenticator/sign-up/index.page.tsx @@ -1,10 +1,13 @@ import { Authenticator } from '@aws-amplify/ui-react'; -import { Amplify } from 'aws-amplify'; +import { dict } from '@aws-amplify/ui-core'; +import { Amplify, I18n } from 'aws-amplify'; import awsExports from '@environments/auth-with-username-no-attributes/src/aws-exports'; Amplify.configure(awsExports); +I18n.putVocabularies(dict); + export default function AuthenticatorWithUsername() { return ; } diff --git a/examples/next/pages/ui/components/authenticator/withAuthenticator/index.page.tsx b/examples/next/pages/ui/components/authenticator/withAuthenticator/index.page.tsx index c792a240600..c8dbdaa4bc6 100644 --- a/examples/next/pages/ui/components/authenticator/withAuthenticator/index.page.tsx +++ b/examples/next/pages/ui/components/authenticator/withAuthenticator/index.page.tsx @@ -1,9 +1,12 @@ import { withAuthenticator } from '@aws-amplify/ui-react'; -import { Amplify } from 'aws-amplify'; +import { dict } from '@aws-amplify/ui-core'; +import { Amplify, I18n } from 'aws-amplify'; import awsExports from '@environments/auth-with-username-no-attributes/src/aws-exports'; Amplify.configure(awsExports); +I18n.putVocabularies(dict); + function App({ state, send }) { return ( <> diff --git a/packages/core/src/machines/actors/auth/signIn.ts b/packages/core/src/machines/actors/auth/signIn.ts index d8767419ffe..7fae59c6404 100644 --- a/packages/core/src/machines/actors/auth/signIn.ts +++ b/packages/core/src/machines/actors/auth/signIn.ts @@ -58,7 +58,7 @@ export const signInActor = createMachine( }, { actions: 'setUser', - target: 'resolved', + target: 'verifying', }, ], onError: [ @@ -74,6 +74,25 @@ export const signInActor = createMachine( ], }, }, + verifying: { + entry: ['clearError', sendUpdate()], + invoke: { + src: 'checkVerifiedContact', + onDone: [ + { + cond: 'shouldRequestVerification', + target: '#signInActor.verifyUser', + }, + { + target: 'resolved', + }, + ], + onError: { + actions: 'setRemoteError', + target: 'edit', + }, + }, + }, resolved: { always: '#signInActor.resolved' }, rejected: { always: '#signInActor.rejected' }, }, @@ -162,6 +181,65 @@ export const signInActor = createMachine( }, }, }, + verifyUser: { + initial: 'edit', + exit: ['clearFormValues', 'clearError'], + states: { + edit: { + entry: sendUpdate(), + on: { + SUBMIT: 'submit', + SKIP: '#signInActor.resolved', + CHANGE: { actions: 'handleInput' }, + }, + }, + submit: { + entry: 'clearError', + invoke: { + src: 'verifyUser', + onDone: { + target: '#signInActor.confirmVerifyUser', + }, + onError: { + actions: 'setRemoteError', + target: 'edit', + }, + }, + }, + }, + }, + confirmVerifyUser: { + initial: 'edit', + exit: [ + 'clearFormValues', + 'clearError', + 'clearUnverifiedAttributes', + 'clearAttributeToVerify', + ], + states: { + edit: { + entry: sendUpdate(), + on: { + SUBMIT: 'submit', + SKIP: '#signInActor.resolved', + CHANGE: { actions: 'handleInput' }, + }, + }, + submit: { + entry: 'clearError', + invoke: { + src: 'confirmVerifyUser', + onDone: { + target: '#signInActor.resolved', + }, + onError: { + actions: 'setRemoteError', + target: 'edit', + }, + }, + }, + }, + }, resolved: { type: 'final', data: (context) => ({ @@ -202,6 +280,8 @@ export const signInActor = createMachine( clearChallengeName: assign({ challengeName: undefined }), clearError: assign({ remoteError: '' }), clearFormValues: assign({ formValues: {} }), + clearUnverifiedAttributes: assign({ unverifiedAttributes: undefined }), + clearAttributeToVerify: assign({ attributeToVerify: undefined }), }, guards: { shouldConfirmSignIn: (_, event): boolean => { @@ -229,6 +309,17 @@ export const signInActor = createMachine( shouldAutoSignIn: (context) => { return !!(context.intent && context.intent === 'autoSignIn'); }, + shouldRequestVerification: (context, event): boolean => { + const { unverified } = event.data; + + if (Object.keys(unverified).length > 0) { + context.unverifiedAttributes = unverified; + + return true; + } + + return false; + }, }, services: { async signIn(context) { @@ -268,6 +359,32 @@ export const signInActor = createMachine( const { provider } = event.data; const result = await Auth.federatedSignIn({ provider }); + return result; + }, + async checkVerifiedContact(context, event) { + const { user } = context; + const result = await Auth.verifiedContact(user); + + return result; + }, + async verifyUser(context, event) { + const result = await Auth.verifyCurrentUserAttribute( + event.data.unverifiedAttr + ); + + context.attributeToVerify = event.data.unverifiedAttr; + + return result; + }, + async confirmVerifyUser(context, event) { + const { attributeToVerify } = context; + const { confirmation_code: code } = event.data; + + const result = await Auth.verifyCurrentUserAttributeSubmit( + attributeToVerify, + code + ); + return result; }, }, diff --git a/packages/core/src/machines/authMachine.ts b/packages/core/src/machines/authMachine.ts index 701019f5ec6..a301839d970 100644 --- a/packages/core/src/machines/authMachine.ts +++ b/packages/core/src/machines/authMachine.ts @@ -92,6 +92,7 @@ export const authMachine = createMachine( RESEND: { actions: 'forwardToActor' }, SIGN_OUT: { actions: 'forwardToActor' }, SIGN_IN: { actions: 'forwardToActor' }, + SKIP: { actions: 'forwardToActor' }, }, }, { diff --git a/packages/core/src/types/authMachine.ts b/packages/core/src/types/authMachine.ts index bd46faf06e7..a224b556fcc 100644 --- a/packages/core/src/types/authMachine.ts +++ b/packages/core/src/types/authMachine.ts @@ -20,6 +20,8 @@ export interface SignInContext { challengeName?: string; authAttributes?: Record; intent?: string; + unverifiedAttributes?: Record; + attributeToVerify?: string; } export interface SignUpContext { @@ -73,6 +75,7 @@ export type AuthEventTypes = | 'CHANGE' | 'FEDERATED_SIGN_IN' | 'RESET_PASSWORD' + | 'SKIP' | InvokeActorEventTypes; export enum AuthChallengeNames { diff --git a/packages/e2e/.env.example b/packages/e2e/.env.example index 46020a75320..a2537c9cd3a 100644 --- a/packages/e2e/.env.example +++ b/packages/e2e/.env.example @@ -4,6 +4,7 @@ INVALID_EMAIL= UNCONFIRMED_EMAIL= UNKNOWN_EMAIL= VALID_EMAIL= +UNVERIFIED_EMAIL= CONFIRMED_PHONE_NUMBER= FORCE_CHANGE_PHONE_NUMBER= diff --git a/packages/e2e/cypress/integration/ui/components/authenticator/verify-user.feature b/packages/e2e/cypress/integration/ui/components/authenticator/verify-user.feature new file mode 100644 index 00000000000..dc67c7c1e4a --- /dev/null +++ b/packages/e2e/cypress/integration/ui/components/authenticator/verify-user.feature @@ -0,0 +1,18 @@ +Feature: Verify User + + Amplify's SignIn component uses AWS Cognito's authentication + service to provide a sign in experience to your application's + users. + + Background: + Given I'm running the example "ui/components/authenticator/sign-in-federated" + + @next @react + Scenario: Verify User with valid but unverified email + When I type a valid but unverified email "UNVERIFIED_EMAIL" + And I type a valid password "VALID_PASSWORD" + And I click the "Sign in" button + Then I will be redirected to the verify user page + And I click on the first radio button + And I click the "Verify" button + Then I will be redirected to the confirm verify user page diff --git a/packages/e2e/cypress/integration/ui/components/authenticator/verify-user/verify-user.steps.ts b/packages/e2e/cypress/integration/ui/components/authenticator/verify-user/verify-user.steps.ts new file mode 100644 index 00000000000..8427db674ae --- /dev/null +++ b/packages/e2e/cypress/integration/ui/components/authenticator/verify-user/verify-user.steps.ts @@ -0,0 +1,38 @@ +import { And, Given, Then, When } from 'cypress-cucumber-preprocessor/steps'; + +Given("I'm running the example {string}", (url: string) => { + cy.visit(url); +}); + +When('I click on the {string} button', (name: string) => { + cy.findByRole('button', { name }).click(); +}); + +And('I type a valid but unverified email {string}', (email: string) => { + cy.findByRole('textbox', { name: /email/i }).type(Cypress.env(email)); +}); + +And('I type a valid password {string}', (password: string) => { + cy.findByLabelText(/password/i).type(Cypress.env(password)); +}); + +And('I click the {string} button', (name: string) => { + cy.findByRole('button', { name }).click(); +}); + +And('I click on the first radio button', () => { + cy.findByRole('radio').click(); +}); + +Then('I will be redirected to the verify user page', () => { + cy.findByRole('radio').should('exist'); +}); + +Then('I will be redirected to the confirm verify user page', () => { + cy.findByRole('document').contains(new RegExp('Code *', 'i')); +}); + +Then('I see {string}', (message: string) => { + const [messageString, username] = message.split(' '); + cy.get('body').contains([messageString, Cypress.env(username)].join(' ')); +}); diff --git a/packages/react/src/components/Authenticator/ResetPassword/ConfirmResetPassword.tsx b/packages/react/src/components/Authenticator/ResetPassword/ConfirmResetPassword.tsx index 7fa19dd6bb2..5347990d6ca 100644 --- a/packages/react/src/components/Authenticator/ResetPassword/ConfirmResetPassword.tsx +++ b/packages/react/src/components/Authenticator/ResetPassword/ConfirmResetPassword.tsx @@ -4,7 +4,7 @@ import { ConfirmationCodeInput, ErrorText, PasswordInput, - SignInOrSubmitFooter, + TwoButtonSubmitFooter, } from '../shared'; export const ConfirmResetPassword = (): JSX.Element => { @@ -74,7 +74,12 @@ export const ConfirmResetPassword = (): JSX.Element => { - + ); }; diff --git a/packages/react/src/components/Authenticator/ResetPassword/ResetPassword.tsx b/packages/react/src/components/Authenticator/ResetPassword/ResetPassword.tsx index 30cd16c4b8f..7bdbaae4ec2 100644 --- a/packages/react/src/components/Authenticator/ResetPassword/ResetPassword.tsx +++ b/packages/react/src/components/Authenticator/ResetPassword/ResetPassword.tsx @@ -1,6 +1,6 @@ import { getActorState, ResetPasswordState } from '@aws-amplify/ui-core'; import { useAmplify, useAuth } from '../../../hooks'; -import { ErrorText, SignInOrSubmitFooter } from '../shared'; +import { ErrorText, TwoButtonSubmitFooter } from '../shared'; export const ResetPassword = (): JSX.Element => { const amplifyNamespace = 'Authenticator.ResetPassword'; @@ -56,8 +56,11 @@ export const ResetPassword = (): JSX.Element => { - diff --git a/packages/react/src/components/Authenticator/VerifyUser/ConfirmVerifyUser.tsx b/packages/react/src/components/Authenticator/VerifyUser/ConfirmVerifyUser.tsx new file mode 100644 index 00000000000..67245921dcf --- /dev/null +++ b/packages/react/src/components/Authenticator/VerifyUser/ConfirmVerifyUser.tsx @@ -0,0 +1,57 @@ +import { getActorState, SignInState } from '@aws-amplify/ui-core'; +import { I18n } from '@aws-amplify/core'; + +import { useAmplify, useAuth } from '../../../hooks'; +import { + ConfirmationCodeInput, + ErrorText, + TwoButtonSubmitFooter, +} from '../shared'; + +export const ConfirmVerifyUser = (): JSX.Element => { + const amplifyNamespace = 'Authenticator.ConfirmVerifyUser'; + const { + components: { Fieldset, Form, Heading }, + } = useAmplify(amplifyNamespace); + + const [_state, send] = useAuth(); + const actorState: SignInState = getActorState(_state); + const isPending = actorState.matches('confirmVerifyUser.pending'); + + const headerText = I18n.get( + 'Account recovery requires verified contact information' + ); + + return ( +
{ + event.preventDefault(); + + const formData = new FormData(event.target); + + send({ + type: 'SUBMIT', + // @ts-ignore Property 'fromEntries' does not exist on type 'ObjectConstructor'. Do you need to change your target library? Try changing the `lib` compiler option to 'es2019' or later.ts(2550) + data: Object.fromEntries(formData), + }); + }} + > + {headerText} + +
+ +
+ + + + + + ); +}; diff --git a/packages/react/src/components/Authenticator/VerifyUser/VerifyUser.tsx b/packages/react/src/components/Authenticator/VerifyUser/VerifyUser.tsx new file mode 100644 index 00000000000..6c3872e74b3 --- /dev/null +++ b/packages/react/src/components/Authenticator/VerifyUser/VerifyUser.tsx @@ -0,0 +1,89 @@ +import { + getActorState, + getActorContext, + SignInState, + SignInContext, + authInputAttributes, +} from '@aws-amplify/ui-core'; +import { I18n } from '@aws-amplify/core'; + +import { useAmplify, useAuth } from '../../../hooks'; +import { ErrorText, TwoButtonSubmitFooter } from '../shared'; + +const generateRadioGroup = ( + attributes: Record +): JSX.Element[] => { + const radioButtons: JSX.Element[] = []; + + for (const [key, value] of Object.entries(attributes)) { + const radio = ( + + ); + + radioButtons.push(radio); + } + + return radioButtons; +}; + +export const VerifyUser = (): JSX.Element => { + const amplifyNamespace = 'Authenticator.VerifyUser'; + const { + components: { Fieldset, Form, Heading }, + } = useAmplify(amplifyNamespace); + + const [_state, send] = useAuth(); + const actorState: SignInState = getActorState(_state); + const context = getActorContext(_state) as SignInContext; + const isPending = actorState.matches('verifyUser.pending'); + + const headerText = I18n.get( + 'Account recovery requires verified contact information' + ); + const footerSubmitText = isPending ? ( + <>Verifying… + ) : ( + <>{I18n.get('Verify')} + ); + + const verificationRadioGroup = ( +
+ {generateRadioGroup(context.unverifiedAttributes)} +
+ ); + + return ( +
{ + event.preventDefault(); + + const formData = new FormData(event.target); + + send({ + type: 'SUBMIT', + // @ts-ignore Property 'fromEntries' does not exist on type 'ObjectConstructor'. Do you need to change your target library? Try changing the `lib` compiler option to 'es2019' or later.ts(2550) + data: Object.fromEntries(formData), + }); + }} + > + {headerText} + + {verificationRadioGroup} + + + + + + ); +}; diff --git a/packages/react/src/components/Authenticator/VerifyUser/index.ts b/packages/react/src/components/Authenticator/VerifyUser/index.ts new file mode 100644 index 00000000000..89a7dbbe4d7 --- /dev/null +++ b/packages/react/src/components/Authenticator/VerifyUser/index.ts @@ -0,0 +1,2 @@ +export * from './ConfirmVerifyUser'; +export * from './VerifyUser'; diff --git a/packages/react/src/components/Authenticator/index.tsx b/packages/react/src/components/Authenticator/index.tsx index 8281faa4c07..b0a857219dd 100644 --- a/packages/react/src/components/Authenticator/index.tsx +++ b/packages/react/src/components/Authenticator/index.tsx @@ -10,6 +10,7 @@ import { ConfirmResetPassword, ResetPassword } from './ResetPassword'; import { SetupTOTP } from './SetupTOTP'; import { SignIn } from './SignIn'; import { SignUp } from './SignUp'; +import { ConfirmVerifyUser, VerifyUser } from './VerifyUser'; export function Authenticator({ className = null, @@ -61,6 +62,10 @@ export function Authenticator({ return ; case actorState?.matches('confirmResetPassword'): return ; + case actorState?.matches('verifyUser'): + return ; + case actorState?.matches('confirmVerifyUser'): + return ; default: console.warn('Unhandled Auth state', state.value); return null; diff --git a/packages/react/src/components/Authenticator/shared/SignInOrSubmitFooter.tsx b/packages/react/src/components/Authenticator/shared/TwoButtonSubmitFooter.tsx similarity index 52% rename from packages/react/src/components/Authenticator/shared/SignInOrSubmitFooter.tsx rename to packages/react/src/components/Authenticator/shared/TwoButtonSubmitFooter.tsx index 454078e7060..9fc76321f41 100644 --- a/packages/react/src/components/Authenticator/shared/SignInOrSubmitFooter.tsx +++ b/packages/react/src/components/Authenticator/shared/TwoButtonSubmitFooter.tsx @@ -1,29 +1,42 @@ +import { AuthEventTypes } from '@aws-amplify/ui-core'; + import { useAmplify, useAuth } from '../../../hooks'; -export interface SignInOrSubmitFooterProps { +export interface TwoButtonSubmitFooterProps { amplifyNamespace: string; + isPending: boolean; + cancelButtonSendType: AuthEventTypes; + cancelButtonText: string; submitButtonText?: JSX.Element; } -export const SignInOrSubmitFooter = ( - props: SignInOrSubmitFooterProps +export const TwoButtonSubmitFooter = ( + props: TwoButtonSubmitFooterProps ): JSX.Element => { - const { amplifyNamespace, submitButtonText } = props; + const { + amplifyNamespace, + cancelButtonSendType, + cancelButtonText, + isPending, + submitButtonText, + } = props; const { components: { Button, Footer, Spacer }, } = useAmplify(amplifyNamespace); const [state, send] = useAuth(); - const isPending = state.matches('resetPassword.pending'); const defaultSubmitText = isPending ? <>Submitting… : <>Submit; const submitText = submitButtonText || defaultSubmitText; return (