2022-11-25 20:25:03 +00:00
|
|
|
import type { ActionCreator } from 'easy-peasy';
|
2020-04-25 20:01:16 +00:00
|
|
|
import { useFormikContext, withFormik } from 'formik';
|
2022-11-25 20:25:03 +00:00
|
|
|
import { useState } from 'react';
|
|
|
|
import type { Location, RouteProps } from 'react-router-dom';
|
|
|
|
import { Link, useLocation, useNavigate } from 'react-router-dom';
|
2020-07-04 21:34:43 +00:00
|
|
|
import tw from 'twin.macro';
|
2022-11-25 20:25:03 +00:00
|
|
|
|
|
|
|
import loginCheckpoint from '@/api/auth/loginCheckpoint';
|
|
|
|
import LoginFormContainer from '@/components/auth/LoginFormContainer';
|
2020-07-04 21:34:43 +00:00
|
|
|
import Button from '@/components/elements/Button';
|
2022-11-25 20:25:03 +00:00
|
|
|
import Field from '@/components/elements/Field';
|
|
|
|
import useFlash from '@/plugins/useFlash';
|
|
|
|
import type { FlashStore } from '@/state/flashes';
|
2020-02-11 17:37:12 +00:00
|
|
|
|
2020-04-25 20:01:16 +00:00
|
|
|
interface Values {
|
|
|
|
code: string;
|
2022-06-26 19:13:52 +00:00
|
|
|
recoveryCode: '';
|
2020-04-25 20:01:16 +00:00
|
|
|
}
|
2020-02-11 17:37:12 +00:00
|
|
|
|
2022-11-25 20:25:03 +00:00
|
|
|
type OwnProps = RouteProps;
|
2020-02-11 17:37:12 +00:00
|
|
|
|
2020-04-25 20:01:16 +00:00
|
|
|
type Props = OwnProps & {
|
2020-10-17 22:02:46 +00:00
|
|
|
clearAndAddHttpError: ActionCreator<FlashStore['clearAndAddHttpError']['payload']>;
|
2022-06-26 19:13:52 +00:00
|
|
|
};
|
2020-02-11 17:37:12 +00:00
|
|
|
|
2022-11-25 20:25:03 +00:00
|
|
|
function LoginCheckpointContainer() {
|
2020-07-03 06:01:02 +00:00
|
|
|
const { isSubmitting, setFieldValue } = useFormikContext<Values>();
|
2022-06-26 19:13:52 +00:00
|
|
|
const [isMissingDevice, setIsMissingDevice] = useState(false);
|
2019-06-17 01:07:57 +00:00
|
|
|
|
2020-04-25 20:01:16 +00:00
|
|
|
return (
|
2020-07-04 21:34:43 +00:00
|
|
|
<LoginFormContainer title={'Device Checkpoint'} css={tw`w-full flex`}>
|
|
|
|
<div css={tw`mt-6`}>
|
2020-04-25 20:01:16 +00:00
|
|
|
<Field
|
2020-07-04 21:34:43 +00:00
|
|
|
light
|
2020-07-03 06:01:02 +00:00
|
|
|
name={isMissingDevice ? 'recoveryCode' : 'code'}
|
|
|
|
title={isMissingDevice ? 'Recovery Code' : 'Authentication Code'}
|
|
|
|
description={
|
|
|
|
isMissingDevice
|
|
|
|
? 'Enter one of the recovery codes generated when you setup 2-Factor authentication on this account in order to continue.'
|
|
|
|
: 'Enter the two-factor token generated by your device.'
|
|
|
|
}
|
2020-07-11 19:07:54 +00:00
|
|
|
type={'text'}
|
2022-05-07 19:25:50 +00:00
|
|
|
autoComplete={'one-time-code'}
|
2020-07-04 21:34:43 +00:00
|
|
|
autoFocus
|
2020-04-25 20:01:16 +00:00
|
|
|
/>
|
|
|
|
</div>
|
2020-07-04 21:34:43 +00:00
|
|
|
<div css={tw`mt-6`}>
|
2022-06-26 19:13:52 +00:00
|
|
|
<Button size={'xlarge'} type={'submit'} disabled={isSubmitting} isLoading={isSubmitting}>
|
2020-07-04 21:34:43 +00:00
|
|
|
Continue
|
|
|
|
</Button>
|
2020-04-25 20:01:16 +00:00
|
|
|
</div>
|
2020-07-04 21:34:43 +00:00
|
|
|
<div css={tw`mt-6 text-center`}>
|
2020-07-03 06:01:02 +00:00
|
|
|
<span
|
|
|
|
onClick={() => {
|
|
|
|
setFieldValue('code', '');
|
|
|
|
setFieldValue('recoveryCode', '');
|
2022-11-25 20:25:03 +00:00
|
|
|
setIsMissingDevice(s => !s);
|
2020-07-03 06:01:02 +00:00
|
|
|
}}
|
2020-07-04 21:34:43 +00:00
|
|
|
css={tw`cursor-pointer text-xs text-neutral-500 tracking-wide uppercase no-underline hover:text-neutral-700`}
|
2020-07-03 06:01:02 +00:00
|
|
|
>
|
2022-06-26 19:13:52 +00:00
|
|
|
{!isMissingDevice ? "I've Lost My Device" : 'I Have My Device'}
|
2020-07-03 06:01:02 +00:00
|
|
|
</span>
|
|
|
|
</div>
|
2020-07-04 21:34:43 +00:00
|
|
|
<div css={tw`mt-6 text-center`}>
|
2020-04-25 20:01:16 +00:00
|
|
|
<Link
|
|
|
|
to={'/auth/login'}
|
2020-07-04 21:34:43 +00:00
|
|
|
css={tw`text-xs text-neutral-500 tracking-wide uppercase no-underline hover:text-neutral-700`}
|
2020-04-25 20:01:16 +00:00
|
|
|
>
|
|
|
|
Return to Login
|
|
|
|
</Link>
|
|
|
|
</div>
|
|
|
|
</LoginFormContainer>
|
|
|
|
);
|
2022-11-25 20:25:03 +00:00
|
|
|
}
|
2019-06-22 20:33:11 +00:00
|
|
|
|
2022-11-25 20:25:03 +00:00
|
|
|
const EnhancedForm = withFormik<Props & { location: Location }, Values>({
|
2020-10-17 22:02:46 +00:00
|
|
|
handleSubmit: ({ code, recoveryCode }, { setSubmitting, props: { clearAndAddHttpError, location } }) => {
|
2020-07-03 06:01:02 +00:00
|
|
|
loginCheckpoint(location.state?.token || '', code, recoveryCode)
|
2022-11-25 20:25:03 +00:00
|
|
|
.then(response => {
|
2019-06-22 23:45:51 +00:00
|
|
|
if (response.complete) {
|
2022-06-26 19:30:05 +00:00
|
|
|
// @ts-expect-error this is valid
|
2019-06-22 23:45:51 +00:00
|
|
|
window.location = response.intended || '/';
|
2020-04-25 20:01:16 +00:00
|
|
|
return;
|
2019-06-22 23:45:51 +00:00
|
|
|
}
|
2020-04-25 20:03:37 +00:00
|
|
|
|
2020-04-25 20:01:16 +00:00
|
|
|
setSubmitting(false);
|
2019-06-22 23:45:51 +00:00
|
|
|
})
|
2022-11-25 20:25:03 +00:00
|
|
|
.catch(error => {
|
2019-06-22 23:45:51 +00:00
|
|
|
console.error(error);
|
2020-04-25 20:01:16 +00:00
|
|
|
setSubmitting(false);
|
2020-10-23 04:33:06 +00:00
|
|
|
clearAndAddHttpError({ error });
|
2019-06-22 23:45:51 +00:00
|
|
|
});
|
2020-04-25 20:01:16 +00:00
|
|
|
},
|
2019-06-17 01:07:57 +00:00
|
|
|
|
2020-04-25 20:01:16 +00:00
|
|
|
mapPropsToValues: () => ({
|
|
|
|
code: '',
|
2020-07-03 06:01:02 +00:00
|
|
|
recoveryCode: '',
|
2020-04-25 20:01:16 +00:00
|
|
|
}),
|
|
|
|
})(LoginCheckpointContainer);
|
|
|
|
|
2022-11-25 20:25:03 +00:00
|
|
|
export default ({ ...props }: OwnProps) => {
|
2020-10-17 22:02:46 +00:00
|
|
|
const { clearAndAddHttpError } = useFlash();
|
2020-04-25 20:01:16 +00:00
|
|
|
|
2022-11-25 20:25:03 +00:00
|
|
|
const location = useLocation();
|
|
|
|
const navigate = useNavigate();
|
|
|
|
|
2020-04-25 20:01:16 +00:00
|
|
|
if (!location.state?.token) {
|
2022-11-25 20:25:03 +00:00
|
|
|
navigate('/auth/login');
|
2020-04-25 20:01:16 +00:00
|
|
|
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
2022-11-25 20:25:03 +00:00
|
|
|
return <EnhancedForm clearAndAddHttpError={clearAndAddHttpError} location={location} {...props} />;
|
2019-06-17 01:07:57 +00:00
|
|
|
};
|