reset password
parent
d6016c3d4d
commit
66b470e46e
|
@ -36,6 +36,7 @@
|
|||
"emailPlaceholderNew": "Geben Sie Ihre neue E-Mail ein",
|
||||
"password": "Passwort",
|
||||
"passwordPlaceholder": "Geben Sie Ihr Passwort ein",
|
||||
"passwordPlaceholderNew": "Geben Sie Ihr neues Passwort ein",
|
||||
"noDataFound": "Keine Einträge gefunden",
|
||||
"calendarMaxFutureBookingDays": "Max. Tage im Voraus",
|
||||
"calendarMinEarliestBookingTime": "Min. früheste Buchungszeit",
|
||||
|
@ -144,6 +145,7 @@
|
|||
"signUpLink": "Jetzt registrieren",
|
||||
"login": {
|
||||
"button": "Anmelden",
|
||||
"forgotPassword": "Passwort vergessen?",
|
||||
"dontHaveAccount": "Sie haben noch kein Konto?",
|
||||
"stateAccountPendingDeletion": {
|
||||
"title": "Anstehende Kontolöschung",
|
||||
|
@ -171,12 +173,22 @@
|
|||
"pendingEmailVerification": {
|
||||
"title": "E-Mail-Verifizierung ausstehend",
|
||||
"description": "Bitte überprüfen Sie Ihr E-Mail-Postfach und klicken Sie auf den Link in der E-Mail, um Ihre E-Mail-Adresse zu verifizieren."
|
||||
},
|
||||
"request": {
|
||||
"400": {
|
||||
"title": "Registrierung fehlgeschlagen",
|
||||
"description": "Bitte überprüfen Sie Ihre Eingaben und versuchen Sie es erneut."
|
||||
}
|
||||
}
|
||||
},
|
||||
"request": {
|
||||
"400": {
|
||||
"title": "Registrierung fehlgeschlagen",
|
||||
"description": "Bitte überprüfen Sie Ihre Eingaben und versuchen Sie es erneut."
|
||||
"forgotPassword": {
|
||||
"title": "Problem beim Anmelden?",
|
||||
"info": "Geben Sie Ihre E-Mail-Adresse ein, und wir senden Ihnen einen Link zum Zurücksetzen Ihres Passworts.",
|
||||
"button": "Passwort zurücksetzen",
|
||||
"backToLogin": "Zurück zur Anmeldung",
|
||||
"resetLinkSent": {
|
||||
"title": "Link zum Zurücksetzen gesendet",
|
||||
"description": "Wir haben Ihnen eine E-Mail mit einem Link zum Zurücksetzen Ihres Passworts geschickt. Bitte prüfen Sie Ihren E-Mail-Posteingang"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -395,9 +407,8 @@
|
|||
"requesting": {
|
||||
"title": "E-Mail-Verifizierung ausstehend"
|
||||
},
|
||||
"Erfolg": {
|
||||
"title": "E-Mail-Überprüfung erfolgreich",
|
||||
"button": "Jetzt anmelden"
|
||||
"success": {
|
||||
"title": "E-Mail-Überprüfung erfolgreich"
|
||||
}
|
||||
},
|
||||
{
|
||||
|
@ -411,6 +422,18 @@
|
|||
"success": {
|
||||
"title": "E-Mail-Änderung erfolgreich"
|
||||
}
|
||||
},
|
||||
{
|
||||
"init": {
|
||||
"title": "Passwort zurücksetzen",
|
||||
"subTitle": "Geben Sie Ihr neues Passwort ein"
|
||||
},
|
||||
"requesting": {
|
||||
"title": "Passwort wird zurückgesetzt"
|
||||
},
|
||||
"success": {
|
||||
"title": "Passwort erfolgreich zurückgesetzt"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
|
|
|
@ -36,6 +36,7 @@
|
|||
"emailPlaceholderNew": "Enter your new email",
|
||||
"password": "Password",
|
||||
"passwordPlaceholder": "Enter your password",
|
||||
"passwordPlaceholderNew": "Enter your new password",
|
||||
"noDataFound": "No data found",
|
||||
"calendarMaxFutureBookingDays": "Max. future booking days",
|
||||
"calendarMinEarliestBookingTime": "Min. earliest booking time",
|
||||
|
@ -144,6 +145,7 @@
|
|||
"signUpLink": "Sign up now",
|
||||
"login": {
|
||||
"button": "Login",
|
||||
"forgotPassword": "Forgot password?",
|
||||
"dontHaveAccount": "Don't have an account?",
|
||||
"stateAccountPendingDeletion": {
|
||||
"title": "Pending account deletion",
|
||||
|
@ -178,6 +180,16 @@
|
|||
"description": "Please check your inputs and try again."
|
||||
}
|
||||
}
|
||||
},
|
||||
"forgotPassword": {
|
||||
"title": "Problem when logging in?",
|
||||
"info": "Enter your email address and we will send you a link to reset your password.",
|
||||
"button": "Send reset link",
|
||||
"backToLogin": "Back to login",
|
||||
"resetLinkSent": {
|
||||
"title": "Reset link sent",
|
||||
"description": "We have sent you an email with a link to reset your password. Please check your email inbox."
|
||||
}
|
||||
}
|
||||
},
|
||||
"services": {
|
||||
|
@ -414,6 +426,18 @@
|
|||
"success": {
|
||||
"title": "Email change successful"
|
||||
}
|
||||
},
|
||||
{
|
||||
"init": {
|
||||
"title": "Password reset",
|
||||
"subTitle": "Enter your new password"
|
||||
},
|
||||
"requesting": {
|
||||
"title": "Resetting password"
|
||||
},
|
||||
"success": {
|
||||
"title": "Password reset successful"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
|
|
|
@ -41,6 +41,15 @@ export function AuthenticationRoutes() {
|
|||
}
|
||||
/>
|
||||
|
||||
<Route
|
||||
path={Constants.ROUTE_PATHS.AUTHENTICATION.FORGOT_PASSWORD}
|
||||
element={
|
||||
<MySupsenseFallback>
|
||||
<Authentication method={AuthenticationMethod.FORGOT_PASSWORD} />
|
||||
</MySupsenseFallback>
|
||||
}
|
||||
/>
|
||||
|
||||
<Route
|
||||
path="*"
|
||||
element={<Navigate to={Constants.ROUTE_PATHS.AUTHENTICATION.LOGIN} />}
|
||||
|
|
|
@ -45,6 +45,7 @@ export function MyPasswordFormInput({
|
|||
label,
|
||||
inputPlaceholder,
|
||||
formItemRules,
|
||||
newPassword,
|
||||
}) {
|
||||
const { t } = useTranslation();
|
||||
|
||||
|
@ -63,7 +64,11 @@ export function MyPasswordFormInput({
|
|||
minLength: Constants.GLOBALS.MIN_PASSWORD_LENGTH,
|
||||
}
|
||||
)}
|
||||
inputPlaceholder={inputPlaceholder || t("common.passwordPlaceholder")}
|
||||
inputPlaceholder={
|
||||
inputPlaceholder || newPassword
|
||||
? t("common.passwordPlaceholderNew")
|
||||
: t("common.passwordPlaceholder")
|
||||
}
|
||||
inputType="password"
|
||||
formItemRules={formItemRules}
|
||||
/>
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import {
|
||||
Button,
|
||||
Checkbox,
|
||||
Divider,
|
||||
Flex,
|
||||
Form,
|
||||
Modal,
|
||||
|
@ -32,6 +33,7 @@ import ReCAPTCHA from "react-google-recaptcha";
|
|||
export const AuthenticationMethod = {
|
||||
LOGIN: 1,
|
||||
SIGNUP: 2,
|
||||
FORGOT_PASSWORD: 3,
|
||||
};
|
||||
|
||||
export default function Authentication({ method }) {
|
||||
|
@ -61,14 +63,38 @@ export default function Authentication({ method }) {
|
|||
|
||||
{method === AuthenticationMethod.LOGIN ? (
|
||||
<Login notificationApi={notificationApi} />
|
||||
) : (
|
||||
) : method === AuthenticationMethod.SIGNUP ? (
|
||||
<SignUp notificationApi={notificationApi} />
|
||||
) : (
|
||||
<ForgotPassword notificationApi={notificationApi} />
|
||||
)}
|
||||
</Modal>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export function MyRecaptcha({ recaptchaRef, recaptchaValueRef }) {
|
||||
const { t } = useTranslation();
|
||||
|
||||
return (
|
||||
<Form.Item
|
||||
name="recaptcha"
|
||||
rules={[
|
||||
{
|
||||
required: true,
|
||||
message: t("common.inputRules.recaptchaRequired"),
|
||||
},
|
||||
]}
|
||||
>
|
||||
<ReCAPTCHA
|
||||
ref={recaptchaRef}
|
||||
sitekey={process.env.REACT_APP_RECAPTCHA_SITE_KEY}
|
||||
onChange={(value) => (recaptchaValueRef.current = value)}
|
||||
/>
|
||||
</Form.Item>
|
||||
);
|
||||
}
|
||||
|
||||
function RememberMeCheckbox() {
|
||||
const { t } = useTranslation();
|
||||
|
||||
|
@ -242,23 +268,22 @@ function Login({ notificationApi }) {
|
|||
>
|
||||
<MyPasswordFormInput />
|
||||
|
||||
<RememberMeCheckbox />
|
||||
<Flex justify="space-between">
|
||||
<RememberMeCheckbox />
|
||||
<Button
|
||||
type="link"
|
||||
onClick={() =>
|
||||
navigate(Constants.ROUTE_PATHS.AUTHENTICATION.FORGOT_PASSWORD)
|
||||
}
|
||||
>
|
||||
{t("authentication.login.forgotPassword")}
|
||||
</Button>
|
||||
</Flex>
|
||||
|
||||
<Form.Item
|
||||
name="recaptcha"
|
||||
rules={[
|
||||
{
|
||||
required: true,
|
||||
message: t("common.inputRules.recaptchaRequired"),
|
||||
},
|
||||
]}
|
||||
>
|
||||
<ReCAPTCHA
|
||||
ref={recaptchaRef}
|
||||
sitekey={process.env.REACT_APP_RECAPTCHA_SITE_KEY}
|
||||
onChange={(value) => (recaptchaValueRef.current = value)}
|
||||
/>
|
||||
</Form.Item>
|
||||
<MyRecaptcha
|
||||
recaptchaRef={recaptchaRef}
|
||||
recaptchaValueRef={recaptchaValueRef}
|
||||
/>
|
||||
|
||||
<PrivacyPolicyCheckbox />
|
||||
</div>
|
||||
|
@ -456,20 +481,7 @@ function SignUp({ notificationApi }) {
|
|||
|
||||
<RememberMeCheckbox />
|
||||
|
||||
<Form.Item
|
||||
name="recaptcha"
|
||||
rules={[
|
||||
{
|
||||
required: true,
|
||||
message: t("common.inputRules.recaptchaRequired"),
|
||||
},
|
||||
]}
|
||||
>
|
||||
<ReCAPTCHA
|
||||
sitekey={process.env.REACT_APP_RECAPTCHA_SITE_KEY}
|
||||
onChange={(value) => (recaptchaValueRef.current = value)}
|
||||
/>
|
||||
</Form.Item>
|
||||
<MyRecaptcha recaptchaValueRef={recaptchaValueRef} />
|
||||
|
||||
<PrivacyPolicyCheckbox />
|
||||
|
||||
|
@ -510,3 +522,98 @@ function PendingEmailVerification() {
|
|||
/>
|
||||
);
|
||||
}
|
||||
|
||||
const FORGOT_PASSWORD_STEP = {
|
||||
ENTER_EMAIL: 1,
|
||||
RESET_LINK_SENT: 2,
|
||||
};
|
||||
|
||||
function ForgotPassword({ notificationApi }) {
|
||||
const { t } = useTranslation();
|
||||
const [form] = Form.useForm();
|
||||
const navigate = useNavigate();
|
||||
|
||||
const [step, setStep] = useState(SignUpStep.SIGN_UP);
|
||||
const [isRequesting, setIsRequesting] = useState(false);
|
||||
const recaptchaValueRef = useRef(null);
|
||||
|
||||
if (step === FORGOT_PASSWORD_STEP.RESET_LINK_SENT) {
|
||||
return (
|
||||
<Result
|
||||
status="warning"
|
||||
title={t("authentication.forgotPassword.resetLinkSent.title")}
|
||||
subTitle={t("authentication.forgotPassword.resetLinkSent.description")}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<Form
|
||||
form={form}
|
||||
layout="vertical"
|
||||
requiredMark={false}
|
||||
initialValues={{
|
||||
rememberMe: false,
|
||||
}}
|
||||
>
|
||||
<Typography.Title level={3} style={{ textAlign: "center" }}>
|
||||
{t("authentication.forgotPassword.title")}
|
||||
</Typography.Title>
|
||||
|
||||
<Typography.Paragraph
|
||||
type="secondary"
|
||||
style={{
|
||||
textAlign: "center",
|
||||
}}
|
||||
>
|
||||
{t("authentication.forgotPassword.info")}
|
||||
</Typography.Paragraph>
|
||||
|
||||
<MyEmailFormInput hasFeedback={true} disableEmailCheck />
|
||||
|
||||
<MyRecaptcha recaptchaValueRef={recaptchaValueRef} />
|
||||
|
||||
<Button
|
||||
type="primary"
|
||||
size="large"
|
||||
block
|
||||
loading={isRequesting}
|
||||
onClick={() => {
|
||||
form
|
||||
.validateFields()
|
||||
.then((values) => {
|
||||
setIsRequesting(true);
|
||||
|
||||
myFetch({
|
||||
url: `/user/auth/forgot-password`,
|
||||
method: "POST",
|
||||
body: {
|
||||
email: values.email.toLocaleLowerCase(),
|
||||
recaptcha: recaptchaValueRef.current,
|
||||
},
|
||||
notificationApi: notificationApi,
|
||||
t: t,
|
||||
})
|
||||
.then(() => setStep(FORGOT_PASSWORD_STEP.RESET_LINK_SENT))
|
||||
.catch(() => {
|
||||
setIsRequesting(false);
|
||||
showUnkownErrorNotification(notificationApi, t);
|
||||
});
|
||||
})
|
||||
.catch(() => showInputsInvalidNotification(notificationApi, t));
|
||||
}}
|
||||
>
|
||||
{t("authentication.forgotPassword.button")}
|
||||
</Button>
|
||||
|
||||
<Flex justify="center">
|
||||
<Button
|
||||
type="link"
|
||||
onClick={() => navigate(Constants.ROUTE_PATHS.AUTHENTICATION.LOGIN)}
|
||||
>
|
||||
{t("authentication.forgotPassword.backToLogin")}
|
||||
</Button>
|
||||
</Flex>
|
||||
</Form>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -102,6 +102,52 @@ export default function Verification() {
|
|||
extra: <ButtonToLogin />,
|
||||
},
|
||||
},
|
||||
{
|
||||
init: {
|
||||
title: t("verification.content.2.init.title"),
|
||||
subTitle: t("verification.content.2.init.subTitle"),
|
||||
extra: (
|
||||
<Form form={form} layout="vertical" requiredMark={false}>
|
||||
<MyPasswordFormInput newPassword />
|
||||
|
||||
<Button
|
||||
type="primary"
|
||||
htmlType="submit"
|
||||
block
|
||||
onClick={() => {
|
||||
form
|
||||
.validateFields()
|
||||
.then((values) => {
|
||||
setIsRequesting(RequestState.REQUESTING);
|
||||
|
||||
sendVerifyRequest({
|
||||
password: EncodeStringToBase64(values.password),
|
||||
})
|
||||
.then(() => setIsRequesting(RequestState.SUCCESS))
|
||||
.catch(() => {
|
||||
setIsRequesting(RequestState.INIT);
|
||||
showPasswordIncorrectNotification(notificationApi, t);
|
||||
});
|
||||
})
|
||||
.catch(() =>
|
||||
showInputsInvalidNotification(notificationApi, t)
|
||||
);
|
||||
}}
|
||||
>
|
||||
{t("common.button.confirm")}
|
||||
</Button>
|
||||
</Form>
|
||||
),
|
||||
},
|
||||
requesting: {
|
||||
title: t("verification.content.2.requesting.title"),
|
||||
extra: <Spin size="large" />,
|
||||
},
|
||||
success: {
|
||||
title: t("verification.content.2.success.title"),
|
||||
extra: <ButtonToLogin />,
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
const parsedState = isNaN(state) ? 0 : parseInt(state);
|
||||
|
|
|
@ -46,6 +46,7 @@ export const Constants = {
|
|||
AUTHENTICATION: {
|
||||
LOGIN: "/login",
|
||||
SIGN_UP: "/signup",
|
||||
FORGOT_PASSWORD: "/forgot-password",
|
||||
},
|
||||
VERIFY: "/verify",
|
||||
OVERVIEW: "/",
|
||||
|
|
Loading…
Reference in New Issue