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