React 18 and Vite (#4510)

This commit is contained in:
Matthew Penner 2022-11-25 13:25:03 -07:00 committed by GitHub
parent 1bb1b13f6d
commit 21613fa602
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
244 changed files with 4547 additions and 8933 deletions

View file

@ -1,28 +1,29 @@
import * as React from 'react';
import { useStoreState } from 'easy-peasy';
import type { FormikHelpers } from 'formik';
import { Formik } from 'formik';
import { useEffect, useRef, useState } from 'react';
import { Link } from 'react-router-dom';
import Reaptcha from 'reaptcha';
import tw from 'twin.macro';
import { object, string } from 'yup';
import requestPasswordResetEmail from '@/api/auth/requestPasswordResetEmail';
import { httpErrorToHuman } from '@/api/http';
import LoginFormContainer from '@/components/auth/LoginFormContainer';
import { useStoreState } from 'easy-peasy';
import Field from '@/components/elements/Field';
import { Formik, FormikHelpers } from 'formik';
import { object, string } from 'yup';
import tw from 'twin.macro';
import Button from '@/components/elements/Button';
import Reaptcha from 'reaptcha';
import Field from '@/components/elements/Field';
import useFlash from '@/plugins/useFlash';
interface Values {
email: string;
}
export default () => {
function ForgotPasswordContainer() {
const ref = useRef<Reaptcha>(null);
const [token, setToken] = useState('');
const { clearFlashes, addFlash } = useFlash();
const { enabled: recaptchaEnabled, siteKey } = useStoreState((state) => state.settings.data!.recaptcha);
const { enabled: recaptchaEnabled, siteKey } = useStoreState(state => state.settings.data!.recaptcha);
useEffect(() => {
clearFlashes();
@ -34,7 +35,7 @@ export default () => {
// If there is no token in the state yet, request the token and then abort this submit request
// since it will be re-submitted when the recaptcha data is returned by the component.
if (recaptchaEnabled && !token) {
ref.current!.execute().catch((error) => {
ref.current!.execute().catch(error => {
console.error(error);
setSubmitting(false);
@ -45,17 +46,19 @@ export default () => {
}
requestPasswordResetEmail(email, token)
.then((response) => {
.then(response => {
resetForm();
addFlash({ type: 'success', title: 'Success', message: response });
})
.catch((error) => {
.catch(error => {
console.error(error);
addFlash({ type: 'error', title: 'Error', message: httpErrorToHuman(error) });
})
.then(() => {
setToken('');
if (ref.current) ref.current.reset();
if (ref.current !== null) {
void ref.current.reset();
}
setSubmitting(false);
});
@ -92,9 +95,9 @@ export default () => {
ref={ref}
size={'invisible'}
sitekey={siteKey || '_invalid_key'}
onVerify={(response) => {
onVerify={response => {
setToken(response);
submitForm();
void submitForm();
}}
onExpire={() => {
setSubmitting(false);
@ -114,4 +117,6 @@ export default () => {
)}
</Formik>
);
};
}
export default ForgotPasswordContainer;

View file

@ -1,28 +1,29 @@
import React, { useState } from 'react';
import { Link, RouteComponentProps } from 'react-router-dom';
import type { ActionCreator } from 'easy-peasy';
import { useFormikContext, withFormik } from 'formik';
import { useState } from 'react';
import type { Location, RouteProps } from 'react-router-dom';
import { Link, useLocation, useNavigate } from 'react-router-dom';
import tw from 'twin.macro';
import loginCheckpoint from '@/api/auth/loginCheckpoint';
import LoginFormContainer from '@/components/auth/LoginFormContainer';
import { ActionCreator } from 'easy-peasy';
import { StaticContext } from 'react-router';
import { useFormikContext, withFormik } from 'formik';
import useFlash from '@/plugins/useFlash';
import { FlashStore } from '@/state/flashes';
import Field from '@/components/elements/Field';
import tw from 'twin.macro';
import Button from '@/components/elements/Button';
import Field from '@/components/elements/Field';
import useFlash from '@/plugins/useFlash';
import type { FlashStore } from '@/state/flashes';
interface Values {
code: string;
recoveryCode: '';
}
type OwnProps = RouteComponentProps<Record<string, string | undefined>, StaticContext, { token?: string }>;
type OwnProps = RouteProps;
type Props = OwnProps & {
clearAndAddHttpError: ActionCreator<FlashStore['clearAndAddHttpError']['payload']>;
};
const LoginCheckpointContainer = () => {
function LoginCheckpointContainer() {
const { isSubmitting, setFieldValue } = useFormikContext<Values>();
const [isMissingDevice, setIsMissingDevice] = useState(false);
@ -53,7 +54,7 @@ const LoginCheckpointContainer = () => {
onClick={() => {
setFieldValue('code', '');
setFieldValue('recoveryCode', '');
setIsMissingDevice((s) => !s);
setIsMissingDevice(s => !s);
}}
css={tw`cursor-pointer text-xs text-neutral-500 tracking-wide uppercase no-underline hover:text-neutral-700`}
>
@ -70,12 +71,12 @@ const LoginCheckpointContainer = () => {
</div>
</LoginFormContainer>
);
};
}
const EnhancedForm = withFormik<Props, Values>({
const EnhancedForm = withFormik<Props & { location: Location }, Values>({
handleSubmit: ({ code, recoveryCode }, { setSubmitting, props: { clearAndAddHttpError, location } }) => {
loginCheckpoint(location.state?.token || '', code, recoveryCode)
.then((response) => {
.then(response => {
if (response.complete) {
// @ts-expect-error this is valid
window.location = response.intended || '/';
@ -84,7 +85,7 @@ const EnhancedForm = withFormik<Props, Values>({
setSubmitting(false);
})
.catch((error) => {
.catch(error => {
console.error(error);
setSubmitting(false);
clearAndAddHttpError({ error });
@ -97,16 +98,17 @@ const EnhancedForm = withFormik<Props, Values>({
}),
})(LoginCheckpointContainer);
export default ({ history, location, ...props }: OwnProps) => {
export default ({ ...props }: OwnProps) => {
const { clearAndAddHttpError } = useFlash();
const location = useLocation();
const navigate = useNavigate();
if (!location.state?.token) {
history.replace('/auth/login');
navigate('/auth/login');
return null;
}
return (
<EnhancedForm clearAndAddHttpError={clearAndAddHttpError} history={history} location={location} {...props} />
);
return <EnhancedForm clearAndAddHttpError={clearAndAddHttpError} location={location} {...props} />;
};

View file

@ -1,14 +1,16 @@
import React, { useEffect, useRef, useState } from 'react';
import { Link, RouteComponentProps } from 'react-router-dom';
import { useStoreState } from 'easy-peasy';
import type { FormikHelpers } from 'formik';
import { Formik } from 'formik';
import { useEffect, useRef, useState } from 'react';
import { Link, useNavigate } from 'react-router-dom';
import Reaptcha from 'reaptcha';
import tw from 'twin.macro';
import { object, string } from 'yup';
import login from '@/api/auth/login';
import LoginFormContainer from '@/components/auth/LoginFormContainer';
import { useStoreState } from 'easy-peasy';
import { Formik, FormikHelpers } from 'formik';
import { object, string } from 'yup';
import Field from '@/components/elements/Field';
import tw from 'twin.macro';
import Button from '@/components/elements/Button';
import Reaptcha from 'reaptcha';
import useFlash from '@/plugins/useFlash';
interface Values {
@ -16,12 +18,14 @@ interface Values {
password: string;
}
const LoginContainer = ({ history }: RouteComponentProps) => {
function LoginContainer() {
const ref = useRef<Reaptcha>(null);
const [token, setToken] = useState('');
const { clearFlashes, clearAndAddHttpError } = useFlash();
const { enabled: recaptchaEnabled, siteKey } = useStoreState((state) => state.settings.data!.recaptcha);
const { enabled: recaptchaEnabled, siteKey } = useStoreState(state => state.settings.data!.recaptcha);
const navigate = useNavigate();
useEffect(() => {
clearFlashes();
@ -33,7 +37,7 @@ const LoginContainer = ({ history }: RouteComponentProps) => {
// If there is no token in the state yet, request the token and then abort this submit request
// since it will be re-submitted when the recaptcha data is returned by the component.
if (recaptchaEnabled && !token) {
ref.current!.execute().catch((error) => {
ref.current!.execute().catch(error => {
console.error(error);
setSubmitting(false);
@ -44,16 +48,16 @@ const LoginContainer = ({ history }: RouteComponentProps) => {
}
login({ ...values, recaptchaData: token })
.then((response) => {
.then(response => {
if (response.complete) {
// @ts-expect-error this is valid
window.location = response.intended || '/';
return;
}
history.replace('/auth/login/checkpoint', { token: response.confirmationToken });
navigate('/auth/login/checkpoint', { state: { token: response.confirmationToken } });
})
.catch((error) => {
.catch(error => {
console.error(error);
setToken('');
@ -89,7 +93,7 @@ const LoginContainer = ({ history }: RouteComponentProps) => {
ref={ref}
size={'invisible'}
sitekey={siteKey || '_invalid_key'}
onVerify={(response) => {
onVerify={response => {
setToken(response);
submitForm();
}}
@ -111,6 +115,6 @@ const LoginContainer = ({ history }: RouteComponentProps) => {
)}
</Formik>
);
};
}
export default LoginContainer;

View file

@ -1,6 +1,7 @@
import React, { forwardRef } from 'react';
import { forwardRef } from 'react';
import * as React from 'react';
import { Form } from 'formik';
import styled from 'styled-components/macro';
import styled from 'styled-components';
import { breakpoint } from '@/theme';
import FlashMessageRender from '@/components/FlashMessageRender';
import tw from 'twin.macro';

View file

@ -1,6 +1,5 @@
import React, { useState } from 'react';
import { RouteComponentProps } from 'react-router';
import { Link } from 'react-router-dom';
import { useState } from 'react';
import { Link, useParams } from 'react-router-dom';
import performPasswordReset from '@/api/auth/performPasswordReset';
import { httpErrorToHuman } from '@/api/http';
import LoginFormContainer from '@/components/auth/LoginFormContainer';
@ -18,7 +17,7 @@ interface Values {
passwordConfirmation: string;
}
export default ({ match, location }: RouteComponentProps<{ token: string }>) => {
function ResetPasswordContainer() {
const [email, setEmail] = useState('');
const { clearFlashes, addFlash } = useStoreActions((actions: Actions<ApplicationStore>) => actions.flashes);
@ -28,14 +27,16 @@ export default ({ match, location }: RouteComponentProps<{ token: string }>) =>
setEmail(parsed.get('email') || '');
}
const params = useParams<'token'>();
const submit = ({ password, passwordConfirmation }: Values, { setSubmitting }: FormikHelpers<Values>) => {
clearFlashes();
performPasswordReset(email, { token: match.params.token, password, passwordConfirmation })
performPasswordReset(email, { token: params.token ?? '', password, passwordConfirmation })
.then(() => {
// @ts-expect-error this is valid
window.location = '/';
})
.catch((error) => {
.catch(error => {
console.error(error);
setSubmitting(false);
@ -56,7 +57,6 @@ export default ({ match, location }: RouteComponentProps<{ token: string }>) =>
.min(8, 'Your new password should be at least 8 characters in length.'),
passwordConfirmation: string()
.required('Your new password does not match.')
// @ts-expect-error this is valid
.oneOf([ref('password'), null], 'Your new password does not match.'),
})}
>
@ -95,4 +95,6 @@ export default ({ match, location }: RouteComponentProps<{ token: string }>) =>
)}
</Formik>
);
};
}
export default ResetPasswordContainer;