customer-dashboard/src/Pages/Authentication/Login.js

378 lines
11 KiB
JavaScript

import { Button, Flex, Form, Result, Space, Typography } from "antd";
import { useRef, useState } from "react";
import { useTranslation } from "react-i18next";
import { useNavigate } from "react-router-dom";
import {
Constants,
EncodeStringToBase64,
myFetch,
setUserSessionToLocalStorage,
showInputsInvalidNotification,
showUnkownErrorNotification,
} from "../../utils";
import {
MyLanguageSwitch,
MyRecaptcha,
PendingEmailVerification,
PrivacyPolicyCheckbox,
RememberMeCheckbox,
} from ".";
import {
MyEmailFormInput,
MyPasswordFormInput,
} from "../../Components/MyFormInputs";
const LoginStep = {
LOGIN: 1,
PENDING_DELETION: 2,
INIT_LOGIN: 3,
BANNED: 4,
_BACK_TO_PASSWORD: 5, // needed for going back from pending deletion to password step as the useEffect for the account name is triggered and would set the step to account name
PENDING_EMAIL_VERIFICATION: 6,
INIT_PAYMENT: 7,
};
// First step: account name -> get state of account by backend
// Second step: if account is active -> password -> login otherwise show the state of the account (e. g. deleted, banned)
export function Login({ notificationApi }) {
const { t } = useTranslation();
const navigate = useNavigate();
const [step, setStep] = useState(LoginStep.LOGIN);
const [isRequesting, setIsRequesting] = useState(false);
const recaptchaRef = useRef(null);
const recaptchaValueRef = useRef(null);
const [form] = Form.useForm();
// const email = Form.useWatch("email", form);
const showErrorNotification = (errStatus) => {
if (errStatus === 400) {
notificationApi["error"]({
message: t("authentication.login.request.400.title"),
description: t("authentication.login.request.400.description"),
});
}
};
/*
useEffect(() => {
if (!email) return;
// triggered if step was set to pending deletion and the user wants to reactivate the account
if (step === LoginStep._BACK_TO_PASSWORD) {
setStep(LoginStep.LOGIN);
return;
}
// reset step if account name changed for handling the state of the account
if (step === LoginStep.LOGIN || step === LoginStep.INIT_LOGIN) {
setStep(LoginStep.ACCOUNT_NAME);
}
}, [email]); */
if (step === LoginStep.PENDING_DELETION) {
return (
<Result
status="warning"
title={t("authentication.login.stateAccountPendingDeletion.title")}
subTitle={t(
"authentication.login.stateAccountPendingDeletion.description"
)}
extra={[
<Button key={0} onClick={() => setStep(LoginStep.LOGIN)}>
{t("common.button.cancel")}
</Button>,
<Button
key={1}
type="primary"
onClick={() => setStep(LoginStep._BACK_TO_PASSWORD)}
>
{t("authentication.login.stateAccountPendingDeletion.button")}
</Button>,
]}
/>
);
}
if (step === LoginStep.BANNED) {
return (
<Result
status="error"
title={t("authentication.login.stateAccountBanned.title")}
subTitle={
<Space direction="vertical">
<Typography.Text type="secondary">
{t("authentication.login.stateAccountBanned.infoSupport")}
</Typography.Text>
<Button type="link" href={`mailto:${Constants.SUPPORT_EMAIL}`}>
{Constants.SUPPORT_EMAIL}
</Button>
</Space>
}
extra={[
<Button
key={0}
onClick={() => {
setStep(LoginStep.LOGIN);
}}
>
{t("authentication.login.stateAccountBanned.backButton")}
</Button>,
]}
/>
);
}
if (step === LoginStep.PENDING_EMAIL_VERIFICATION) {
return <PendingEmailVerification />;
}
if (step === LoginStep.INIT_PAYMENT) {
return (
<Result
status="warning"
title={t("authentication.login.stateInitPayment.title")}
subTitle={t("authentication.login.stateInitPayment.description")}
/>
);
}
return (
<Form
form={form}
layout="vertical"
requiredMark={false}
initialValues={{
rememberMe: false,
}}
>
{step === LoginStep.INIT_LOGIN && (
<Typography.Paragraph type="secondary">
{t("authentication.login.stateInitLogin.info")}
</Typography.Paragraph>
)}
<MyEmailFormInput hasFeedback={false} disableEmailCheck />
<MyPasswordFormInput />
<Flex justify="space-between">
<RememberMeCheckbox />
<Button
type="link"
onClick={() =>
navigate(Constants.ROUTE_PATHS.AUTHENTICATION.FORGOT_PASSWORD)
}
>
{t("authentication.login.forgotPassword")}
</Button>
</Flex>
<MyRecaptcha
recaptchaRef={recaptchaRef}
recaptchaValueRef={recaptchaValueRef}
/>
<PrivacyPolicyCheckbox />
<Button
type="primary"
size="large"
block
loading={isRequesting}
htmlType="submit"
onClick={() => {
let validateFields = [];
if (step === LoginStep.ACCOUNT_NAME) {
validateFields = ["email"];
} else {
validateFields = [
"email",
"password",
"rememberMe",
"recaptcha",
"privacyPolicy",
];
}
form
.validateFields(validateFields)
.then((values) => {
setIsRequesting(true);
myFetch({
url: `/user/auth/login`,
method: "POST",
body: {
email: values.email.toLocaleLowerCase(),
password: EncodeStringToBase64(values.password),
recaptcha: recaptchaValueRef.current,
},
notificationApi: notificationApi,
t: t,
})
.then((data) => {
setIsRequesting(false);
if (data.state === undefined) {
if (
step === LoginStep.LOGIN ||
step === LoginStep.INIT_LOGIN
) {
setUserSessionToLocalStorage(data.XAuthorization);
window.location.href = "/";
}
return;
}
switch (data.state) {
case Constants.ACCOUNT_STATE.PENDING_DELETION:
setStep(LoginStep.PENDING_DELETION);
break;
case Constants.ACCOUNT_STATE.BANNED:
setStep(LoginStep.BANNED);
break;
case Constants.ACCOUNT_STATE.INIT_LOGGING:
setStep(LoginStep.INIT_LOGIN);
break;
case Constants.ACCOUNT_STATE.PENDING_EMAIL_VERIFICATION:
setStep(LoginStep.PENDING_EMAIL_VERIFICATION);
break;
case Constants.ACCOUNT_STATE.INIT_PAYMENT:
setStep(LoginStep.INIT_PAYMENT);
break;
default:
showUnkownErrorNotification(notificationApi, t);
break;
}
})
.catch((errStatus) => {
showErrorNotification(errStatus);
setIsRequesting(false);
recaptchaRef.current.reset();
});
})
.catch(() => showInputsInvalidNotification(notificationApi, t));
}}
>
{t("authentication.login.button")}
</Button>
<Flex justify="center" style={{ paddingTop: 12 }}>
<Typography.Text>
{t("authentication.login.dontHaveAccount")}{" "}
<Button
type="link"
style={{ padding: 0 }}
onClick={() =>
navigate(Constants.ROUTE_PATHS.AUTHENTICATION.SIGN_UP)
}
>
{t("authentication.signUpLink")}
</Button>
</Typography.Text>
</Flex>
<MyLanguageSwitch />
</Form>
);
}
const FORGOT_PASSWORD_STEP = {
ENTER_EMAIL: 1,
RESET_LINK_SENT: 2,
};
export function ForgotPassword({ notificationApi }) {
const { t } = useTranslation();
const [form] = Form.useForm();
const navigate = useNavigate();
const [step, setStep] = useState(FORGOT_PASSWORD_STEP.ENTER_EMAIL);
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>
);
}