Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
pterodactyl
GitHub Repository: pterodactyl/panel
Path: blob/1.0-develop/resources/scripts/components/auth/LoginContainer.tsx
10266 views
1
import React, { useEffect, useRef, useState } from 'react';
2
import { Link, RouteComponentProps } from 'react-router-dom';
3
import login from '@/api/auth/login';
4
import LoginFormContainer from '@/components/auth/LoginFormContainer';
5
import { useStoreState } from 'easy-peasy';
6
import { Formik, FormikHelpers } from 'formik';
7
import { object, string } from 'yup';
8
import Field from '@/components/elements/Field';
9
import tw from 'twin.macro';
10
import Button from '@/components/elements/Button';
11
import Reaptcha from 'reaptcha';
12
import useFlash from '@/plugins/useFlash';
13
14
interface Values {
15
username: string;
16
password: string;
17
}
18
19
const LoginContainer = ({ history }: RouteComponentProps) => {
20
const ref = useRef<Reaptcha>(null);
21
const [token, setToken] = useState('');
22
23
const { clearFlashes, clearAndAddHttpError } = useFlash();
24
const { enabled: recaptchaEnabled, siteKey } = useStoreState((state) => state.settings.data!.recaptcha);
25
26
useEffect(() => {
27
clearFlashes();
28
}, []);
29
30
const onSubmit = (values: Values, { setSubmitting }: FormikHelpers<Values>) => {
31
clearFlashes();
32
33
// If there is no token in the state yet, request the token and then abort this submit request
34
// since it will be re-submitted when the recaptcha data is returned by the component.
35
if (recaptchaEnabled && !token) {
36
ref.current!.execute().catch((error) => {
37
console.error(error);
38
39
setSubmitting(false);
40
clearAndAddHttpError({ error });
41
});
42
43
return;
44
}
45
46
login({ ...values, recaptchaData: token })
47
.then((response) => {
48
if (response.complete) {
49
// @ts-expect-error this is valid
50
window.location = response.intended || '/';
51
return;
52
}
53
54
history.replace('/auth/login/checkpoint', { token: response.confirmationToken });
55
})
56
.catch((error) => {
57
console.error(error);
58
59
setToken('');
60
if (ref.current) ref.current.reset();
61
62
setSubmitting(false);
63
clearAndAddHttpError({ error });
64
});
65
};
66
67
return (
68
<Formik
69
onSubmit={onSubmit}
70
initialValues={{ username: '', password: '' }}
71
validationSchema={object().shape({
72
username: string().required('A username or email must be provided.'),
73
password: string().required('Please enter your account password.'),
74
})}
75
>
76
{({ isSubmitting, setSubmitting, submitForm }) => (
77
<LoginFormContainer title={'Login to Continue'} css={tw`w-full flex`}>
78
<Field light type={'text'} label={'Username or Email'} name={'username'} disabled={isSubmitting} />
79
<div css={tw`mt-6`}>
80
<Field light type={'password'} label={'Password'} name={'password'} disabled={isSubmitting} />
81
</div>
82
<div css={tw`mt-6`}>
83
<Button type={'submit'} size={'xlarge'} isLoading={isSubmitting} disabled={isSubmitting}>
84
Login
85
</Button>
86
</div>
87
{recaptchaEnabled && (
88
<Reaptcha
89
ref={ref}
90
size={'invisible'}
91
sitekey={siteKey || '_invalid_key'}
92
onVerify={(response) => {
93
setToken(response);
94
submitForm();
95
}}
96
onExpire={() => {
97
setSubmitting(false);
98
setToken('');
99
}}
100
/>
101
)}
102
<div css={tw`mt-6 text-center`}>
103
<Link
104
to={'/auth/password'}
105
css={tw`text-xs text-neutral-500 tracking-wide no-underline uppercase hover:text-neutral-600`}
106
>
107
Forgot password?
108
</Link>
109
</div>
110
</LoginFormContainer>
111
)}
112
</Formik>
113
);
114
};
115
116
export default LoginContainer;
117
118