Path: blob/1.0-develop/resources/scripts/components/auth/LoginCheckpointContainer.tsx
10264 views
import React, { useState } from 'react';1import { Link, RouteComponentProps } from 'react-router-dom';2import loginCheckpoint from '@/api/auth/loginCheckpoint';3import LoginFormContainer from '@/components/auth/LoginFormContainer';4import { ActionCreator } from 'easy-peasy';5import { StaticContext } from 'react-router';6import { useFormikContext, withFormik } from 'formik';7import useFlash from '@/plugins/useFlash';8import { FlashStore } from '@/state/flashes';9import Field from '@/components/elements/Field';10import tw from 'twin.macro';11import Button from '@/components/elements/Button';1213interface Values {14code: string;15recoveryCode: '';16}1718type OwnProps = RouteComponentProps<Record<string, string | undefined>, StaticContext, { token?: string }>;1920type Props = OwnProps & {21clearAndAddHttpError: ActionCreator<FlashStore['clearAndAddHttpError']['payload']>;22};2324const LoginCheckpointContainer = () => {25const { isSubmitting, setFieldValue } = useFormikContext<Values>();26const [isMissingDevice, setIsMissingDevice] = useState(false);2728return (29<LoginFormContainer title={'Device Checkpoint'} css={tw`w-full flex`}>30<div css={tw`mt-6`}>31<Field32light33name={isMissingDevice ? 'recoveryCode' : 'code'}34title={isMissingDevice ? 'Recovery Code' : 'Authentication Code'}35description={36isMissingDevice37? 'Enter one of the recovery codes generated when you setup 2-Factor authentication on this account in order to continue.'38: 'Enter the two-factor token generated by your device.'39}40type={'text'}41autoComplete={'one-time-code'}42autoFocus43/>44</div>45<div css={tw`mt-6`}>46<Button size={'xlarge'} type={'submit'} disabled={isSubmitting} isLoading={isSubmitting}>47Continue48</Button>49</div>50<div css={tw`mt-6 text-center`}>51<span52onClick={() => {53setFieldValue('code', '');54setFieldValue('recoveryCode', '');55setIsMissingDevice((s) => !s);56}}57css={tw`cursor-pointer text-xs text-neutral-500 tracking-wide uppercase no-underline hover:text-neutral-700`}58>59{!isMissingDevice ? "I've Lost My Device" : 'I Have My Device'}60</span>61</div>62<div css={tw`mt-6 text-center`}>63<Link64to={'/auth/login'}65css={tw`text-xs text-neutral-500 tracking-wide uppercase no-underline hover:text-neutral-700`}66>67Return to Login68</Link>69</div>70</LoginFormContainer>71);72};7374const EnhancedForm = withFormik<Props, Values>({75handleSubmit: ({ code, recoveryCode }, { setSubmitting, props: { clearAndAddHttpError, location } }) => {76loginCheckpoint(location.state?.token || '', code, recoveryCode)77.then((response) => {78if (response.complete) {79// @ts-expect-error this is valid80window.location = response.intended || '/';81return;82}8384setSubmitting(false);85})86.catch((error) => {87console.error(error);88setSubmitting(false);89clearAndAddHttpError({ error });90});91},9293mapPropsToValues: () => ({94code: '',95recoveryCode: '',96}),97})(LoginCheckpointContainer);9899export default ({ history, location, ...props }: OwnProps) => {100const { clearAndAddHttpError } = useFlash();101102if (!location.state?.token) {103history.replace('/auth/login');104105return null;106}107108return (109<EnhancedForm clearAndAddHttpError={clearAndAddHttpError} history={history} location={location} {...props} />110);111};112113114