Add registration & verification tests
This commit is contained in:
parent
ed47cf5f09
commit
dcc90bc99a
10 changed files with 389 additions and 60 deletions
100
app/soapbox/features/verification/__tests__/index.test.tsx
Normal file
100
app/soapbox/features/verification/__tests__/index.test.tsx
Normal file
|
@ -0,0 +1,100 @@
|
||||||
|
import { Map as ImmutableMap } from 'immutable';
|
||||||
|
import React from 'react';
|
||||||
|
import { Route, Switch } from 'react-router-dom';
|
||||||
|
|
||||||
|
import { __stub } from '../../../__mocks__/api';
|
||||||
|
import { render, screen } from '../../../jest/test-helpers';
|
||||||
|
import Verification from '../index';
|
||||||
|
|
||||||
|
const TestableComponent = () => (
|
||||||
|
<Switch>
|
||||||
|
<Route path='/auth/verify' exact><Verification /></Route>
|
||||||
|
<Route path='/' exact><span data-testid='home'>Homepage</span></Route>
|
||||||
|
</Switch>
|
||||||
|
);
|
||||||
|
|
||||||
|
const renderComponent = (store) => render(
|
||||||
|
<TestableComponent />,
|
||||||
|
{},
|
||||||
|
store,
|
||||||
|
{ initialEntries: ['/auth/verify'] },
|
||||||
|
);
|
||||||
|
|
||||||
|
describe('<Verification />', () => {
|
||||||
|
let store;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
store = {
|
||||||
|
verification: ImmutableMap({
|
||||||
|
instance: {
|
||||||
|
isReady: true,
|
||||||
|
registrations: true,
|
||||||
|
},
|
||||||
|
isComplete: false,
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
|
||||||
|
__stub(mock => {
|
||||||
|
mock.onGet('/api/v1/pepe/instance')
|
||||||
|
.reply(200, {
|
||||||
|
age_minimum: 18,
|
||||||
|
approval_required: true,
|
||||||
|
challenges: ['age', 'email', 'sms'],
|
||||||
|
});
|
||||||
|
|
||||||
|
mock.onPost('/api/v1/pepe/registrations')
|
||||||
|
.reply(200, {
|
||||||
|
access_token: 'N-dZmNqNSmTutJLsGjZ5AnJL4sLw_y-N3pn2acSqJY8',
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('When registration is closed', () => {
|
||||||
|
it('successfully redirects to the homepage', () => {
|
||||||
|
const verification = store.verification.setIn(['instance', 'registrations'], false);
|
||||||
|
store.verification = verification;
|
||||||
|
|
||||||
|
renderComponent(store);
|
||||||
|
expect(screen.getByTestId('home')).toHaveTextContent('Homepage');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('When verification is complete', () => {
|
||||||
|
it('successfully renders the Registration component', () => {
|
||||||
|
const verification = store.verification.set('isComplete', true);
|
||||||
|
store.verification = verification;
|
||||||
|
|
||||||
|
renderComponent(store);
|
||||||
|
expect(screen.getByRole('heading')).toHaveTextContent('Register your account');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('Switching verification steps', () => {
|
||||||
|
it('successfully renders the Birthday step', () => {
|
||||||
|
const verification = store.verification.set('currentChallenge', 'age');
|
||||||
|
store.verification = verification;
|
||||||
|
|
||||||
|
renderComponent(store);
|
||||||
|
|
||||||
|
expect(screen.getByRole('heading')).toHaveTextContent('Enter your birth date');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('successfully renders the Email step', () => {
|
||||||
|
const verification = store.verification.set('currentChallenge', 'email');
|
||||||
|
store.verification = verification;
|
||||||
|
|
||||||
|
renderComponent(store);
|
||||||
|
|
||||||
|
expect(screen.getByRole('heading')).toHaveTextContent('Enter your email address');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('successfully renders the SMS step', () => {
|
||||||
|
const verification = store.verification.set('currentChallenge', 'sms');
|
||||||
|
store.verification = verification;
|
||||||
|
|
||||||
|
renderComponent(store);
|
||||||
|
|
||||||
|
expect(screen.getByRole('heading')).toHaveTextContent('Enter your phone number');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
|
@ -1,50 +0,0 @@
|
||||||
import * as React from 'react';
|
|
||||||
import { useDispatch, useSelector } from 'react-redux';
|
|
||||||
import { Redirect } from 'react-router-dom';
|
|
||||||
|
|
||||||
import { fetchVerificationConfig } from 'soapbox/actions/verification';
|
|
||||||
|
|
||||||
import Registration from './registration';
|
|
||||||
import AgeVerification from './steps/age_verification';
|
|
||||||
import EmailVerification from './steps/email_verification';
|
|
||||||
import SmsVerification from './steps/sms_verification';
|
|
||||||
|
|
||||||
const verificationSteps = {
|
|
||||||
email: EmailVerification,
|
|
||||||
sms: SmsVerification,
|
|
||||||
age: AgeVerification,
|
|
||||||
};
|
|
||||||
|
|
||||||
const Verification = () => {
|
|
||||||
const dispatch = useDispatch();
|
|
||||||
|
|
||||||
const isInstanceReady = useSelector((state) => state.getIn(['verification', 'instance', 'isReady'], false) === true);
|
|
||||||
const isRegistrationOpen = useSelector(state => state.getIn(['verification', 'instance', 'registrations'], false) === true);
|
|
||||||
const currentChallenge = useSelector((state) => state.getIn(['verification', 'currentChallenge']));
|
|
||||||
const isVerificationComplete = useSelector((state) => state.getIn(['verification', 'isComplete']));
|
|
||||||
const StepToRender = verificationSteps[currentChallenge];
|
|
||||||
|
|
||||||
React.useEffect(() => {
|
|
||||||
dispatch(fetchVerificationConfig());
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
if (isInstanceReady && !isRegistrationOpen) {
|
|
||||||
return <Redirect to='/' />;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isVerificationComplete) {
|
|
||||||
return (
|
|
||||||
<Registration />
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!currentChallenge) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<StepToRender />
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default Verification;
|
|
58
app/soapbox/features/verification/index.tsx
Normal file
58
app/soapbox/features/verification/index.tsx
Normal file
|
@ -0,0 +1,58 @@
|
||||||
|
import * as React from 'react';
|
||||||
|
import { useDispatch } from 'react-redux';
|
||||||
|
import { Redirect } from 'react-router-dom';
|
||||||
|
|
||||||
|
import { fetchVerificationConfig } from 'soapbox/actions/verification';
|
||||||
|
import { useAppSelector } from 'soapbox/hooks';
|
||||||
|
|
||||||
|
import Registration from './registration';
|
||||||
|
import AgeVerification from './steps/age-verification';
|
||||||
|
import EmailVerification from './steps/email-verification';
|
||||||
|
import SmsVerification from './steps/sms-verification';
|
||||||
|
|
||||||
|
// eslint-disable-next-line no-unused-vars
|
||||||
|
enum ChallengeTypes {
|
||||||
|
EMAIL = 'email', // eslint-disable-line no-unused-vars
|
||||||
|
SMS = 'sms', // eslint-disable-line no-unused-vars
|
||||||
|
AGE = 'age', // eslint-disable-line no-unused-vars
|
||||||
|
}
|
||||||
|
|
||||||
|
const verificationSteps = {
|
||||||
|
email: EmailVerification,
|
||||||
|
sms: SmsVerification,
|
||||||
|
age: AgeVerification,
|
||||||
|
};
|
||||||
|
|
||||||
|
const Verification = () => {
|
||||||
|
const dispatch = useDispatch();
|
||||||
|
|
||||||
|
const isInstanceReady = useAppSelector((state) => state.verification.getIn(['instance', 'isReady'], false) === true);
|
||||||
|
const isRegistrationOpen = useAppSelector(state => state.verification.getIn(['instance', 'registrations'], false) === true);
|
||||||
|
const currentChallenge = useAppSelector((state) => state.verification.getIn(['currentChallenge']) as ChallengeTypes);
|
||||||
|
const isVerificationComplete = useAppSelector((state) => state.verification.get('isComplete'));
|
||||||
|
const StepToRender = verificationSteps[currentChallenge];
|
||||||
|
|
||||||
|
React.useEffect(() => {
|
||||||
|
dispatch(fetchVerificationConfig());
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
if (isInstanceReady && !isRegistrationOpen) {
|
||||||
|
return <Redirect to='/' />;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isVerificationComplete) {
|
||||||
|
return (
|
||||||
|
<Registration />
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!currentChallenge) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<StepToRender />
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Verification;
|
|
@ -20,7 +20,7 @@ const Registration = () => {
|
||||||
const dispatch = useDispatch();
|
const dispatch = useDispatch();
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
|
|
||||||
const isLoading = useSelector((state) => state.getIn(['verification', 'isLoading']));
|
const isLoading = useSelector((state) => state.verification.get('isLoading'));
|
||||||
const siteTitle = useSelector((state) => state.instance.title);
|
const siteTitle = useSelector((state) => state.instance.title);
|
||||||
|
|
||||||
const [state, setState] = React.useState(initialState);
|
const [state, setState] = React.useState(initialState);
|
||||||
|
@ -89,7 +89,7 @@ const Registration = () => {
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className='sm:pt-10 sm:w-2/3 md:w-1/2 mx-auto space-y-4'>
|
<div className='sm:pt-10 sm:w-2/3 md:w-1/2 mx-auto space-y-4'>
|
||||||
<Form onSubmit={handleSubmit} disabled={isLoading}>
|
<Form onSubmit={handleSubmit}>
|
||||||
<FormGroup labelText='Your username'>
|
<FormGroup labelText='Your username'>
|
||||||
<Input
|
<Input
|
||||||
name='username'
|
name='username'
|
||||||
|
|
|
@ -0,0 +1,51 @@
|
||||||
|
import userEvent from '@testing-library/user-event';
|
||||||
|
import { Map as ImmutableMap } from 'immutable';
|
||||||
|
import React from 'react';
|
||||||
|
import '@testing-library/jest-dom';
|
||||||
|
|
||||||
|
import { __stub } from 'soapbox/api';
|
||||||
|
import { fireEvent, render, screen } from 'soapbox/jest/test-helpers';
|
||||||
|
|
||||||
|
import AgeVerification from '../age-verification';
|
||||||
|
|
||||||
|
describe('<AgeVerification />', () => {
|
||||||
|
let store;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
store = {
|
||||||
|
verification: ImmutableMap({
|
||||||
|
ageMinimum: 13,
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
|
||||||
|
__stub(mock => {
|
||||||
|
mock.onPost('/api/v1/pepe/verify_age/confirm')
|
||||||
|
.reply(200, {});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('successfully renders the Birthday step', async() => {
|
||||||
|
render(
|
||||||
|
<AgeVerification />,
|
||||||
|
{},
|
||||||
|
store,
|
||||||
|
);
|
||||||
|
expect(screen.getByRole('heading')).toHaveTextContent('Enter your birth date');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('selects a date', async() => {
|
||||||
|
render(
|
||||||
|
<AgeVerification />,
|
||||||
|
{},
|
||||||
|
store,
|
||||||
|
);
|
||||||
|
|
||||||
|
await userEvent.type(screen.getByLabelText('Birth Date'), '{enter}');
|
||||||
|
|
||||||
|
fireEvent.submit(
|
||||||
|
screen.getByRole('button'), {
|
||||||
|
preventDefault: () => {},
|
||||||
|
},
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1,67 @@
|
||||||
|
import userEvent from '@testing-library/user-event';
|
||||||
|
import React from 'react';
|
||||||
|
import '@testing-library/jest-dom';
|
||||||
|
|
||||||
|
import { __stub } from 'soapbox/api';
|
||||||
|
import { fireEvent, render, screen, waitFor } from 'soapbox/jest/test-helpers';
|
||||||
|
|
||||||
|
import EmailVerification from '../email-verification';
|
||||||
|
|
||||||
|
describe('<EmailVerification />', () => {
|
||||||
|
it('successfully renders the Email step', async() => {
|
||||||
|
render(<EmailVerification />);
|
||||||
|
expect(screen.getByRole('heading')).toHaveTextContent('Enter your email address');
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('with valid data', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
__stub(mock => {
|
||||||
|
mock.onPost('/api/v1/pepe/verify_email/request')
|
||||||
|
.reply(200, {});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('successfully submits', async() => {
|
||||||
|
render(<EmailVerification />);
|
||||||
|
|
||||||
|
await userEvent.type(screen.getByLabelText('Email Address'), 'foo@bar.com{enter}');
|
||||||
|
|
||||||
|
await waitFor(() => {
|
||||||
|
fireEvent.submit(
|
||||||
|
screen.getByRole('button'), {
|
||||||
|
preventDefault: () => {},
|
||||||
|
},
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(screen.getByRole('button')).toHaveTextContent('Resend verification email');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('with invalid data', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
__stub(mock => {
|
||||||
|
mock.onPost('/api/v1/pepe/verify_email/request')
|
||||||
|
.reply(422, {
|
||||||
|
error: 'email_taken',
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('renders errors', async() => {
|
||||||
|
render(<EmailVerification />);
|
||||||
|
|
||||||
|
await userEvent.type(screen.getByLabelText('Email Address'), 'foo@bar.com{enter}');
|
||||||
|
|
||||||
|
await waitFor(() => {
|
||||||
|
fireEvent.submit(
|
||||||
|
screen.getByRole('button'), {
|
||||||
|
preventDefault: () => {},
|
||||||
|
},
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(screen.getByTestId('form-group-error')).toHaveTextContent('is taken');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1,103 @@
|
||||||
|
import userEvent from '@testing-library/user-event';
|
||||||
|
import React from 'react';
|
||||||
|
import '@testing-library/jest-dom';
|
||||||
|
|
||||||
|
import { __stub } from 'soapbox/api';
|
||||||
|
import { fireEvent, render, screen, waitFor } from 'soapbox/jest/test-helpers';
|
||||||
|
|
||||||
|
import SmsVerification from '../sms-verification';
|
||||||
|
|
||||||
|
describe('<SmsVerification />', () => {
|
||||||
|
it('successfully renders the SMS step', async() => {
|
||||||
|
render(<SmsVerification />);
|
||||||
|
expect(screen.getByRole('heading')).toHaveTextContent('Enter your phone number');
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('with valid data', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
__stub(mock => {
|
||||||
|
mock.onPost('/api/v1/pepe/verify_sms/request').reply(200, {});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('successfully submits', async() => {
|
||||||
|
__stub(mock => {
|
||||||
|
mock.onPost('/api/v1/pepe/verify_sms/confirm').reply(200, {});
|
||||||
|
});
|
||||||
|
|
||||||
|
render(<SmsVerification />);
|
||||||
|
|
||||||
|
await userEvent.type(screen.getByLabelText('Phone Number'), '+1 (555) 555-5555');
|
||||||
|
await waitFor(() => {
|
||||||
|
fireEvent.submit(
|
||||||
|
screen.getByRole('button'), {
|
||||||
|
preventDefault: () => {},
|
||||||
|
},
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(screen.getByRole('heading')).toHaveTextContent('Verification code');
|
||||||
|
expect(screen.getByTestId('toast')).toHaveTextContent('A verification code has been sent to your phone number.');
|
||||||
|
|
||||||
|
await userEvent.type(screen.getByLabelText('Please enter verification code. Digit 1'), '1');
|
||||||
|
await userEvent.type(screen.getByLabelText('Digit 2'), '2');
|
||||||
|
await userEvent.type(screen.getByLabelText('Digit 3'), '3');
|
||||||
|
await userEvent.type(screen.getByLabelText('Digit 4'), '4');
|
||||||
|
await userEvent.type(screen.getByLabelText('Digit 5'), '5');
|
||||||
|
await userEvent.type(screen.getByLabelText('Digit 6'), '6');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('handle expired tokens', async() => {
|
||||||
|
__stub(mock => {
|
||||||
|
mock.onPost('/api/v1/pepe/verify_sms/confirm').reply(422, {});
|
||||||
|
});
|
||||||
|
|
||||||
|
render(<SmsVerification />);
|
||||||
|
|
||||||
|
await userEvent.type(screen.getByLabelText('Phone Number'), '+1 (555) 555-5555');
|
||||||
|
await waitFor(() => {
|
||||||
|
fireEvent.submit(
|
||||||
|
screen.getByRole('button'), {
|
||||||
|
preventDefault: () => {},
|
||||||
|
},
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(screen.getByRole('heading')).toHaveTextContent('Verification code');
|
||||||
|
expect(screen.getByTestId('toast')).toHaveTextContent('A verification code has been sent to your phone number.');
|
||||||
|
|
||||||
|
await userEvent.type(screen.getByLabelText('Please enter verification code. Digit 1'), '1');
|
||||||
|
await userEvent.type(screen.getByLabelText('Digit 2'), '2');
|
||||||
|
await userEvent.type(screen.getByLabelText('Digit 3'), '3');
|
||||||
|
await userEvent.type(screen.getByLabelText('Digit 4'), '4');
|
||||||
|
await userEvent.type(screen.getByLabelText('Digit 5'), '5');
|
||||||
|
await userEvent.type(screen.getByLabelText('Digit 6'), '6');
|
||||||
|
|
||||||
|
expect(screen.getByTestId('toast')).toHaveTextContent('Your SMS token has expired.');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('with invalid data', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
__stub(mock => {
|
||||||
|
mock.onPost('/api/v1/pepe/verify_sms/request')
|
||||||
|
.reply(422, {});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('renders errors', async() => {
|
||||||
|
render(<SmsVerification />);
|
||||||
|
|
||||||
|
await userEvent.type(screen.getByLabelText('Phone Number'), '+1 (555) 555-5555');
|
||||||
|
await waitFor(() => {
|
||||||
|
fireEvent.submit(
|
||||||
|
screen.getByRole('button'), {
|
||||||
|
preventDefault: () => {},
|
||||||
|
},
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(screen.getByTestId('toast')).toHaveTextContent('Failed to send SMS message to your phone number.');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
|
@ -28,9 +28,9 @@ const AgeVerification = () => {
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
const dispatch = useDispatch();
|
const dispatch = useDispatch();
|
||||||
|
|
||||||
const isLoading = useSelector((state) => state.getIn(['verification', 'isLoading']));
|
const isLoading = useSelector((state) => state.verification.get('isLoading'));
|
||||||
const ageMinimum = useSelector((state) => state.getIn(['verification', 'ageMinimum']));
|
const ageMinimum = useSelector((state) => state.verification.get('ageMinimum'));
|
||||||
const siteTitle = useSelector((state) => state.instance.title);
|
const siteTitle = useSelector((state) => state.instance.get('title'));
|
||||||
|
|
||||||
const [date, setDate] = React.useState('');
|
const [date, setDate] = React.useState('');
|
||||||
const isValid = typeof date === 'object';
|
const isValid = typeof date === 'object';
|
||||||
|
@ -65,7 +65,7 @@ const AgeVerification = () => {
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className='sm:pt-10 sm:w-2/3 md:w-1/2 mx-auto'>
|
<div className='sm:pt-10 sm:w-2/3 md:w-1/2 mx-auto'>
|
||||||
<Form onSubmit={handleSubmit} disabled={isLoading}>
|
<Form onSubmit={handleSubmit}>
|
||||||
<FormGroup labelText='Birth Date'>
|
<FormGroup labelText='Birth Date'>
|
||||||
<DatePicker
|
<DatePicker
|
||||||
selected={date}
|
selected={date}
|
|
@ -50,7 +50,7 @@ const EmailVerification = () => {
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
const dispatch = useDispatch();
|
const dispatch = useDispatch();
|
||||||
|
|
||||||
const isLoading = useSelector((state) => state.getIn(['verification', 'isLoading']));
|
const isLoading = useSelector((state) => state.verification.get('isLoading'));
|
||||||
|
|
||||||
const [email, setEmail] = React.useState('');
|
const [email, setEmail] = React.useState('');
|
||||||
const [status, setStatus] = React.useState(Statuses.IDLE);
|
const [status, setStatus] = React.useState(Statuses.IDLE);
|
||||||
|
@ -110,7 +110,7 @@ const EmailVerification = () => {
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className='sm:pt-10 sm:w-2/3 md:w-1/2 mx-auto'>
|
<div className='sm:pt-10 sm:w-2/3 md:w-1/2 mx-auto'>
|
||||||
<Form onSubmit={handleSubmit} disabled={isLoading}>
|
<Form onSubmit={handleSubmit}>
|
||||||
<FormGroup labelText='Email Address' errors={errors}>
|
<FormGroup labelText='Email Address' errors={errors}>
|
||||||
<Input
|
<Input
|
||||||
type='email'
|
type='email'
|
|
@ -21,7 +21,7 @@ const SmsVerification = () => {
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
const dispatch = useDispatch();
|
const dispatch = useDispatch();
|
||||||
|
|
||||||
const isLoading = useSelector((state) => state.getIn(['verification', 'isLoading']));
|
const isLoading = useSelector((state) => state.verification.get('isLoading'));
|
||||||
|
|
||||||
const [phone, setPhone] = React.useState('');
|
const [phone, setPhone] = React.useState('');
|
||||||
const [status, setStatus] = React.useState(Statuses.IDLE);
|
const [status, setStatus] = React.useState(Statuses.IDLE);
|
||||||
|
@ -147,7 +147,7 @@ const SmsVerification = () => {
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className='sm:pt-10 sm:w-2/3 md:w-1/2 mx-auto'>
|
<div className='sm:pt-10 sm:w-2/3 md:w-1/2 mx-auto'>
|
||||||
<Form onSubmit={handleSubmit} disabled={isLoading}>
|
<Form onSubmit={handleSubmit}>
|
||||||
<FormGroup labelText='Phone Number'>
|
<FormGroup labelText='Phone Number'>
|
||||||
<Input
|
<Input
|
||||||
type='text'
|
type='text'
|
Loading…
Reference in a new issue