authentication
parent
bfa1a6796c
commit
2456a0ab6d
|
@ -25,7 +25,6 @@
|
||||||
},
|
},
|
||||||
"failed": "Fehlgeschlagen",
|
"failed": "Fehlgeschlagen",
|
||||||
"action": "Aktion",
|
"action": "Aktion",
|
||||||
"contactAdmin": "Bitte kontaktieren Sie einen Administrator",
|
|
||||||
"username": "Anzeigename",
|
"username": "Anzeigename",
|
||||||
"usernamePlaceholder": "Geben Sie Ihren Anzeigename ein",
|
"usernamePlaceholder": "Geben Sie Ihren Anzeigename ein",
|
||||||
"accountName": "Benutzername",
|
"accountName": "Benutzername",
|
||||||
|
@ -71,6 +70,10 @@
|
||||||
"passwordIncorrect": {
|
"passwordIncorrect": {
|
||||||
"title": "Passwort falsch",
|
"title": "Passwort falsch",
|
||||||
"description": "Bitte überprüfen Sie Ihr Passwort und versuchen Sie es erneut."
|
"description": "Bitte überprüfen Sie Ihr Passwort und versuchen Sie es erneut."
|
||||||
|
},
|
||||||
|
"unknownError": {
|
||||||
|
"title": "Ein unbekannter Fehler ist aufgetreten",
|
||||||
|
"description": "Bitte versuchen Sie es erneut."
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -110,20 +113,49 @@
|
||||||
"addEmployee": "Mitarbeiter anlegen",
|
"addEmployee": "Mitarbeiter anlegen",
|
||||||
"editEmployee": "Mitarbeiter bearbeiten",
|
"editEmployee": "Mitarbeiter bearbeiten",
|
||||||
"modalAddEmployee": {
|
"modalAddEmployee": {
|
||||||
"checkboxPasswordChange": "Mitarbeiter auffordern, das Passwort zu ändern (empfohlen)"
|
"checkboxSetPasswordOnLogging": "Mitarbeiter auffordern, beim ersten Anmelden ein eigenes Passwort festzulegen",
|
||||||
|
"checkboxSetPasswordOnLoggingInfo": "Wenn diese Option aktiviert ist, wird der Mitarbeiter beim ersten Anmelden aufgefordert, ein eigenes Passwort festzulegen. Andernfalls können Sie ein Passwort für den Mitarbeiter festlegen."
|
||||||
},
|
},
|
||||||
"popConfirmDeleteEmployee": {
|
"popConfirmDeleteEmployee": {
|
||||||
"title": "Mitarbeiter löschen",
|
"title": "Mitarbeiter löschen",
|
||||||
"description": "Möchten Sie den Mitarbeiter wirklich löschen?"
|
"description": "Möchten Sie den Mitarbeiter wirklich löschen?"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"login": {
|
"authentication": {
|
||||||
"login": "Anmelden",
|
"rememberMe": "Angemeldet bleiben",
|
||||||
"signUp": "Registrieren",
|
"loginLink": "Jetzt anmelden",
|
||||||
|
"signUpLink": "Jetzt registrieren",
|
||||||
|
"login": {
|
||||||
|
"button": "Anmelden",
|
||||||
|
"dontHaveAccount": "Sie haben noch kein Konto?",
|
||||||
|
"stateAccountPendingDeletion": {
|
||||||
|
"title": "Anstehende Kontolöschung",
|
||||||
|
"description": "Wenn Sie sich einloggen, wird die Löschung Ihres Kontos rückgängig gemacht und Ihr Konto wieder aktiviert.",
|
||||||
|
"button": "Konto wiederherstellen"
|
||||||
|
},
|
||||||
|
"stateAccountBanned": {
|
||||||
|
"title": "Konto gesperrt",
|
||||||
|
"infoSupport": "Bitte kontaktieren Sie den Support, um Ihr Konto wiederherzustellen.",
|
||||||
|
"backButton": "Zurück zur Anmeldung"
|
||||||
|
},
|
||||||
|
"stateInitLogin": {
|
||||||
|
"info": "Ihr Konto wurde neu erstellt und hat noch kein Passwort. Bitte legen Sie ein Passwort fest, um sich anzumelden."
|
||||||
|
},
|
||||||
|
"request": {
|
||||||
|
"400": {
|
||||||
|
"title": "Anmeldung fehlgeschlagen",
|
||||||
|
"description": "Bitte überprüfen Sie Ihre Eingaben und versuchen Sie es erneut."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"signUp": {
|
||||||
|
"button": "Registrieren",
|
||||||
|
"alreadyHaveAccount": "Sie haben bereits ein Konto?"
|
||||||
|
},
|
||||||
"request": {
|
"request": {
|
||||||
"400": {
|
"400": {
|
||||||
"title": "Anmeldung fehlgeschlagen",
|
"title": "Registrierung fehlgeschlagen",
|
||||||
"description": "Bitte überprüfen Sie Ihre Eingaben."
|
"description": "Bitte überprüfen Sie Ihre Eingaben und versuchen Sie es erneut."
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -25,7 +25,6 @@
|
||||||
},
|
},
|
||||||
"failed": "Failed",
|
"failed": "Failed",
|
||||||
"action": "Action",
|
"action": "Action",
|
||||||
"contactAdmin": "Please contact an administrator",
|
|
||||||
"username": "Username",
|
"username": "Username",
|
||||||
"usernamePlaceholder": "Enter your username",
|
"usernamePlaceholder": "Enter your username",
|
||||||
"accountName": "Account name",
|
"accountName": "Account name",
|
||||||
|
@ -71,6 +70,10 @@
|
||||||
"passwordIncorrect": {
|
"passwordIncorrect": {
|
||||||
"title": "Password incorrect",
|
"title": "Password incorrect",
|
||||||
"description": "Please check your password and try again."
|
"description": "Please check your password and try again."
|
||||||
|
},
|
||||||
|
"unknownError": {
|
||||||
|
"title": "An unknown error has occurred",
|
||||||
|
"description": "The request failed. Please try again."
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -110,20 +113,49 @@
|
||||||
"addEmployee": "Add employee",
|
"addEmployee": "Add employee",
|
||||||
"editEmployee": "Edit employee",
|
"editEmployee": "Edit employee",
|
||||||
"modalAddEmployee": {
|
"modalAddEmployee": {
|
||||||
"checkboxPasswordChange": "Require employee to change password (recommended)"
|
"checkboxSetPasswordOnLogging": "Ask employees to set their own password when logging in for the first time",
|
||||||
|
"checkboxSetPasswordOnLoggingInfo": "If this option is activated, the employee is prompted to set their own password when they log in for the first time. Otherwise, you can set a password for the employee."
|
||||||
},
|
},
|
||||||
"popConfirmDeleteEmployee": {
|
"popConfirmDeleteEmployee": {
|
||||||
"title": "Delete employee",
|
"title": "Delete employee",
|
||||||
"description": "Are you sure you want to delete this employee?"
|
"description": "Are you sure you want to delete this employee?"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"login": {
|
"authentication": {
|
||||||
"login": "Login",
|
"rememberMe": "Remember me",
|
||||||
"signUp": "Sign up",
|
"loginLink": "Login",
|
||||||
"request": {
|
"signUpLink": "Sign up now",
|
||||||
"400": {
|
"login": {
|
||||||
"title": "Login failed",
|
"button": "Login",
|
||||||
"description": "Please check your inputs and try again."
|
"dontHaveAccount": "Don't have an account?",
|
||||||
|
"stateAccountPendingDeletion": {
|
||||||
|
"title": "Pending account deletion",
|
||||||
|
"description": "By logging in, the deletion of your account will be cancelled and your account reactivated.",
|
||||||
|
"button": "Reactivate account"
|
||||||
|
},
|
||||||
|
"stateAccountBanned": {
|
||||||
|
"title": "Account banned",
|
||||||
|
"infoSupport": "Please contact support to reactivate your account.",
|
||||||
|
"backButton": "Back to login"
|
||||||
|
},
|
||||||
|
"stateInitLogin": {
|
||||||
|
"info": "Your account has been newly created and does not yet have a password. Please set a password to log in."
|
||||||
|
},
|
||||||
|
"request": {
|
||||||
|
"400": {
|
||||||
|
"title": "Login failed",
|
||||||
|
"description": "Please check your inputs and try again."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"signUp": {
|
||||||
|
"button": "Sign up",
|
||||||
|
"alreadyHaveAccount": "Already have an account?",
|
||||||
|
"request": {
|
||||||
|
"400": {
|
||||||
|
"title": "Sign up failed",
|
||||||
|
"description": "Please check your inputs and try again."
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
import "antd/dist/reset.css";
|
import "antd/dist/reset.css";
|
||||||
import "./App.css";
|
import "./App.css";
|
||||||
import Login from "./Pages/Login";
|
|
||||||
import { Layout, Spin, Typography } from "antd";
|
import { Layout, Spin, Typography } from "antd";
|
||||||
import { Constants, UseUserSession, myFetch } from "./utils";
|
import { Constants, UseUserSession, myFetch } from "./utils";
|
||||||
import DashboardLayout from "./Components/DashboardLayout";
|
import DashboardLayout from "./Components/DashboardLayout";
|
||||||
|
@ -14,6 +13,7 @@ import StoresProvider from "./Contexts/StoresContext";
|
||||||
import { clarity } from "react-microsoft-clarity";
|
import { clarity } from "react-microsoft-clarity";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import MyAppLogo from "./Components/MyAppLogo";
|
import MyAppLogo from "./Components/MyAppLogo";
|
||||||
|
import Authentication from "./Pages/Authentication";
|
||||||
|
|
||||||
export function Loading() {
|
export function Loading() {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
@ -90,7 +90,7 @@ export default function App() {
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
if (!userSession) {
|
if (!userSession) {
|
||||||
return <Login />;
|
return <Authentication />;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (appUserData === null) {
|
if (appUserData === null) {
|
||||||
|
|
|
@ -60,11 +60,6 @@ export function SideMenuContent({
|
||||||
key: `${Constants.ROUTE_PATHS.STORE.OVERVIEW}/${store.store_id}`,
|
key: `${Constants.ROUTE_PATHS.STORE.OVERVIEW}/${store.store_id}`,
|
||||||
};
|
};
|
||||||
|
|
||||||
console.warn(
|
|
||||||
"here",
|
|
||||||
`${Constants.ROUTE_PATHS.STORE.OVERVIEW}/${store.store_id}`
|
|
||||||
);
|
|
||||||
|
|
||||||
if (sideBarContext.permissions.includes("settings")) {
|
if (sideBarContext.permissions.includes("settings")) {
|
||||||
groupStore.children.push({
|
groupStore.children.push({
|
||||||
label: t("sideMenu.store.settings"),
|
label: t("sideMenu.store.settings"),
|
||||||
|
|
|
@ -0,0 +1,482 @@
|
||||||
|
import { LoginOutlined } from "@ant-design/icons";
|
||||||
|
import {
|
||||||
|
Button,
|
||||||
|
Checkbox,
|
||||||
|
Flex,
|
||||||
|
Form,
|
||||||
|
Modal,
|
||||||
|
Result,
|
||||||
|
Space,
|
||||||
|
Tabs,
|
||||||
|
Typography,
|
||||||
|
notification,
|
||||||
|
} from "antd";
|
||||||
|
import {
|
||||||
|
Constants,
|
||||||
|
EncodeStringToBase64,
|
||||||
|
myFetch,
|
||||||
|
setUserSessionToLocalStorage,
|
||||||
|
showInputsInvalidNotification,
|
||||||
|
showUnkownErrorNotification,
|
||||||
|
} from "../../utils";
|
||||||
|
import { useEffect, useState } from "react";
|
||||||
|
import {
|
||||||
|
MyAccountNameFormInput,
|
||||||
|
MyPasswordFormInput,
|
||||||
|
MyUsernameFormInput,
|
||||||
|
} from "../../Components/MyFormInputs";
|
||||||
|
import { useTranslation } from "react-i18next";
|
||||||
|
import MyAppLogo from "../../Components/MyAppLogo";
|
||||||
|
|
||||||
|
const AuthenticationMethod = {
|
||||||
|
LOGIN: 1,
|
||||||
|
SIGNUP: 2,
|
||||||
|
};
|
||||||
|
|
||||||
|
export default function Authentication() {
|
||||||
|
const { t, i18n } = useTranslation();
|
||||||
|
const [form] = Form.useForm();
|
||||||
|
|
||||||
|
const [notificationApi, notificationContextHolder] =
|
||||||
|
notification.useNotification();
|
||||||
|
|
||||||
|
const [selectedMethod, setSelectedMethod] = useState(
|
||||||
|
AuthenticationMethod.LOGIN
|
||||||
|
);
|
||||||
|
const [isRequesting, setIsRequesting] = useState(false);
|
||||||
|
|
||||||
|
const showErrorNotification = (errStatus) => {
|
||||||
|
if (errStatus === 400) {
|
||||||
|
notificationApi["error"]({
|
||||||
|
message: t("login.request.400.title"),
|
||||||
|
description: t("login.request.400.description"),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{notificationContextHolder}
|
||||||
|
<Modal
|
||||||
|
open={true}
|
||||||
|
mask={false}
|
||||||
|
closable={false}
|
||||||
|
centered
|
||||||
|
keyboard={false}
|
||||||
|
footer={null}
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
display: "flex",
|
||||||
|
justifyContent: "center",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<MyAppLogo height={80} />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{selectedMethod === AuthenticationMethod.LOGIN ? (
|
||||||
|
<Login
|
||||||
|
switchMethod={() => setSelectedMethod(AuthenticationMethod.SIGNUP)}
|
||||||
|
notificationApi={notificationApi}
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
<SignUp
|
||||||
|
switchMethod={() => setSelectedMethod(AuthenticationMethod.LOGIN)}
|
||||||
|
notificationApi={notificationApi}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</Modal>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function RememberMeCheckbox() {
|
||||||
|
const { t } = useTranslation();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Form.Item name="rememberMe" valuePropName="checked">
|
||||||
|
<Checkbox>{t("authentication.rememberMe")}</Checkbox>
|
||||||
|
</Form.Item>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const LoginStep = {
|
||||||
|
ACCOUNT_NAME: 1,
|
||||||
|
PASSWORD: 2,
|
||||||
|
PENDING_DELETION: 3,
|
||||||
|
INIT_LOGIN: 4,
|
||||||
|
BANNED: 5,
|
||||||
|
};
|
||||||
|
|
||||||
|
// 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)
|
||||||
|
function Login({ switchMethod, notificationApi }) {
|
||||||
|
const { t } = useTranslation();
|
||||||
|
const [isRequesting, setIsRequesting] = useState(false);
|
||||||
|
const [step, setStep] = useState(LoginStep.ACCOUNT_NAME);
|
||||||
|
|
||||||
|
const [form] = Form.useForm();
|
||||||
|
|
||||||
|
const accountName = Form.useWatch("accountName", 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 (!accountName) return;
|
||||||
|
|
||||||
|
console.log("accountName here", step);
|
||||||
|
|
||||||
|
// reset step if account name changed for handling the state of the account
|
||||||
|
if (step === LoginStep.PASSWORD || step === LoginStep.INIT_LOGIN) {
|
||||||
|
console.log("reset step", accountName);
|
||||||
|
setStep(LoginStep.ACCOUNT_NAME);
|
||||||
|
}
|
||||||
|
}, [accountName]);
|
||||||
|
|
||||||
|
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.ACCOUNT_NAME)}>
|
||||||
|
{t("common.button.cancel")}
|
||||||
|
</Button>,
|
||||||
|
<Button
|
||||||
|
key={1}
|
||||||
|
type="primary"
|
||||||
|
onClick={() => {
|
||||||
|
console.log("reactivate account");
|
||||||
|
setStep(LoginStep.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.ACCOUNT_NAME);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{t("authentication.login.stateAccountBanned.backButton")}
|
||||||
|
</Button>,
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
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>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<MyAccountNameFormInput
|
||||||
|
disableAccountNameCheck={true}
|
||||||
|
hasFeedback={false}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
display:
|
||||||
|
step === LoginStep.PASSWORD || step === LoginStep.INIT_LOGIN
|
||||||
|
? "block"
|
||||||
|
: "none",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<MyPasswordFormInput />
|
||||||
|
|
||||||
|
<RememberMeCheckbox />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<Button
|
||||||
|
type="primary"
|
||||||
|
size="large"
|
||||||
|
block
|
||||||
|
loading={isRequesting}
|
||||||
|
onClick={() => {
|
||||||
|
let validateFields = [];
|
||||||
|
|
||||||
|
if (step === LoginStep.ACCOUNT_NAME) {
|
||||||
|
validateFields = ["accountName"];
|
||||||
|
} else {
|
||||||
|
validateFields = ["accountName", "password", "rememberMe"];
|
||||||
|
}
|
||||||
|
|
||||||
|
form
|
||||||
|
.validateFields(validateFields)
|
||||||
|
.then((values) => {
|
||||||
|
setIsRequesting(true);
|
||||||
|
|
||||||
|
let body = {
|
||||||
|
accountName: values.accountName.toLocaleLowerCase(),
|
||||||
|
};
|
||||||
|
|
||||||
|
if (
|
||||||
|
step === LoginStep.PASSWORD ||
|
||||||
|
step === LoginStep.INIT_LOGIN
|
||||||
|
) {
|
||||||
|
body.password = EncodeStringToBase64(values.password);
|
||||||
|
body.rememberMe = values.rememberMe;
|
||||||
|
}
|
||||||
|
|
||||||
|
myFetch({
|
||||||
|
url: `/user/auth/login`,
|
||||||
|
method: "POST",
|
||||||
|
body: body,
|
||||||
|
notificationApi: notificationApi,
|
||||||
|
t: t,
|
||||||
|
})
|
||||||
|
.then((data) => {
|
||||||
|
setIsRequesting(false);
|
||||||
|
|
||||||
|
if (
|
||||||
|
step === LoginStep.PASSWORD ||
|
||||||
|
step === LoginStep.INIT_LOGIN
|
||||||
|
) {
|
||||||
|
setUserSessionToLocalStorage(data.XAuthorization);
|
||||||
|
window.location.href = "/";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data.state === undefined) return;
|
||||||
|
|
||||||
|
switch (data.state) {
|
||||||
|
case Constants.ACCOUNT_STATE.ACTIVE:
|
||||||
|
setStep(LoginStep.PASSWORD);
|
||||||
|
break;
|
||||||
|
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;
|
||||||
|
default:
|
||||||
|
showUnkownErrorNotification(notificationApi, t);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch((errStatus) => {
|
||||||
|
showErrorNotification(errStatus);
|
||||||
|
setIsRequesting(false);
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.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={switchMethod}>
|
||||||
|
{t("authentication.signUpLink")}
|
||||||
|
</Button>
|
||||||
|
</Typography.Text>
|
||||||
|
</Flex>
|
||||||
|
</Form>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function SignUp({ switchMethod, notificationApi }) {
|
||||||
|
const { t, i18n } = useTranslation();
|
||||||
|
const [isRequesting, setIsRequesting] = useState(false);
|
||||||
|
|
||||||
|
const [form] = Form.useForm();
|
||||||
|
|
||||||
|
const showErrorNotification = (errStatus) => {
|
||||||
|
if (errStatus === 400) {
|
||||||
|
notificationApi["error"]({
|
||||||
|
message: t("authentication.signUp.request.400.title"),
|
||||||
|
description: t("authentication.signUp.request.400.description"),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleSubmit = () => {
|
||||||
|
form
|
||||||
|
.validateFields()
|
||||||
|
.then((values) => {
|
||||||
|
setIsRequesting(true);
|
||||||
|
|
||||||
|
let body = {
|
||||||
|
accountName: values.accountName.toLocaleLowerCase(),
|
||||||
|
password: EncodeStringToBase64(values.password),
|
||||||
|
username: values.username,
|
||||||
|
language: i18n.language,
|
||||||
|
rememberMe: values.rememberMe,
|
||||||
|
};
|
||||||
|
|
||||||
|
myFetch({
|
||||||
|
url: `/user/auth/signup`,
|
||||||
|
method: "POST",
|
||||||
|
body: body,
|
||||||
|
notificationApi: notificationApi,
|
||||||
|
t: t,
|
||||||
|
})
|
||||||
|
.then((data) => {
|
||||||
|
setUserSessionToLocalStorage(data.XAuthorization);
|
||||||
|
window.location.href = "/";
|
||||||
|
})
|
||||||
|
.catch((errStatus) => {
|
||||||
|
showErrorNotification(errStatus);
|
||||||
|
setIsRequesting(false);
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.catch(() => showInputsInvalidNotification(notificationApi, t));
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Form form={form} layout="vertical" requiredMark={false}>
|
||||||
|
<MyUsernameFormInput />
|
||||||
|
|
||||||
|
<MyAccountNameFormInput hasFeedback={true} />
|
||||||
|
|
||||||
|
<MyPasswordFormInput />
|
||||||
|
|
||||||
|
<RememberMeCheckbox />
|
||||||
|
|
||||||
|
<Button
|
||||||
|
type="primary"
|
||||||
|
size="large"
|
||||||
|
block
|
||||||
|
onClick={handleSubmit}
|
||||||
|
loading={isRequesting}
|
||||||
|
>
|
||||||
|
{t("authentication.signUp.button")}
|
||||||
|
</Button>
|
||||||
|
|
||||||
|
<Flex justify="center" style={{ paddingTop: 12 }}>
|
||||||
|
<Typography.Text>
|
||||||
|
{t("authentication.signUp.alreadyHaveAccount")}{" "}
|
||||||
|
<Button type="link" style={{ padding: 0 }} onClick={switchMethod}>
|
||||||
|
{t("authentication.loginLink")}
|
||||||
|
</Button>
|
||||||
|
</Typography.Text>
|
||||||
|
</Flex>
|
||||||
|
</Form>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
<Button
|
||||||
|
type="primary"
|
||||||
|
block
|
||||||
|
htmlType="submit"
|
||||||
|
loading={isRequesting}
|
||||||
|
onClick={() => {
|
||||||
|
form
|
||||||
|
.validateFields()
|
||||||
|
.then((values) => {
|
||||||
|
setIsRequesting(true);
|
||||||
|
|
||||||
|
let body = {
|
||||||
|
accountName: values.accountName.toLocaleLowerCase(),
|
||||||
|
password: EncodeStringToBase64(values.password),
|
||||||
|
};
|
||||||
|
|
||||||
|
if (selectedMethod === "2") {
|
||||||
|
body.username = values.username;
|
||||||
|
body.language = i18n.language;
|
||||||
|
}
|
||||||
|
|
||||||
|
myFetch({
|
||||||
|
url: `/user/auth/${
|
||||||
|
selectedMethod === "1" ? "login" : "signup"
|
||||||
|
}`,
|
||||||
|
method: "POST",
|
||||||
|
body: body,
|
||||||
|
notificationApi: notificationApi,
|
||||||
|
t: t,
|
||||||
|
})
|
||||||
|
.then((data) => {
|
||||||
|
setUserSessionToLocalStorage(data.XAuthorization);
|
||||||
|
window.location.href = "/";
|
||||||
|
})
|
||||||
|
.catch((errStatus) => {
|
||||||
|
showErrorNotification(errStatus);
|
||||||
|
setIsRequesting(false);
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.catch(() => showInputsInvalidNotification(notificationApi, t));
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{selectedMethod === AuthenticationMethod.LOGIN
|
||||||
|
? t("authentication.login.button")
|
||||||
|
: t("authentication.signUp.button")}
|
||||||
|
</Button>
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
<Tabs
|
||||||
|
defaultActiveKey="1"
|
||||||
|
items={[
|
||||||
|
{
|
||||||
|
key: "1",
|
||||||
|
label: t("login.login"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: "2",
|
||||||
|
label: t("login.signUp"),
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
centered
|
||||||
|
onChange={(activeKey) => setSelectedMethod(activeKey)}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<Form form={form} layout="vertical" requiredMark={false}>
|
||||||
|
{selectedMethod === "2" && <MyUsernameFormInput />}
|
||||||
|
|
||||||
|
<MyAccountNameFormInput
|
||||||
|
disableAccountNameCheck={selectedMethod === "1"}
|
||||||
|
hasFeedback={selectedMethod === "2"}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<MyPasswordFormInput />
|
||||||
|
</Form>
|
||||||
|
*/
|
|
@ -1,131 +0,0 @@
|
||||||
import { LoginOutlined } from "@ant-design/icons";
|
|
||||||
import { Button, Form, Modal, Tabs, notification } from "antd";
|
|
||||||
import {
|
|
||||||
EncodeStringToBase64,
|
|
||||||
myFetch,
|
|
||||||
setUserSessionToLocalStorage,
|
|
||||||
showInputsInvalidNotification,
|
|
||||||
} from "../../utils";
|
|
||||||
import { useState } from "react";
|
|
||||||
import {
|
|
||||||
MyAccountNameFormInput,
|
|
||||||
MyPasswordFormInput,
|
|
||||||
MyUsernameFormInput,
|
|
||||||
} from "../../Components/MyFormInputs";
|
|
||||||
import { useTranslation } from "react-i18next";
|
|
||||||
import MyAppLogo from "../../Components/MyAppLogo";
|
|
||||||
|
|
||||||
export default function Login() {
|
|
||||||
const { t, i18n } = useTranslation();
|
|
||||||
const [form] = Form.useForm();
|
|
||||||
|
|
||||||
const [notificationApi, notificationContextHolder] =
|
|
||||||
notification.useNotification();
|
|
||||||
|
|
||||||
const [selectedMethod, setSelectedMethod] = useState("1");
|
|
||||||
const [isRequesting, setIsRequesting] = useState(false);
|
|
||||||
|
|
||||||
const showErrorNotification = (errStatus) => {
|
|
||||||
if (errStatus === 400) {
|
|
||||||
notificationApi["error"]({
|
|
||||||
message: t("login.request.400.title"),
|
|
||||||
description: t("login.request.400.description"),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
{notificationContextHolder}
|
|
||||||
<Modal
|
|
||||||
open={true}
|
|
||||||
mask={false}
|
|
||||||
closable={false}
|
|
||||||
centered
|
|
||||||
keyboard={false}
|
|
||||||
footer={
|
|
||||||
<Button
|
|
||||||
type="primary"
|
|
||||||
htmlType="submit"
|
|
||||||
icon={<LoginOutlined />}
|
|
||||||
loading={isRequesting}
|
|
||||||
onClick={() => {
|
|
||||||
form
|
|
||||||
.validateFields()
|
|
||||||
.then((values) => {
|
|
||||||
setIsRequesting(true);
|
|
||||||
|
|
||||||
let body = {
|
|
||||||
accountName: values.accountName.toLocaleLowerCase(),
|
|
||||||
password: EncodeStringToBase64(values.password),
|
|
||||||
};
|
|
||||||
|
|
||||||
if (selectedMethod === "2") {
|
|
||||||
body.username = values.username;
|
|
||||||
body.language = i18n.language;
|
|
||||||
}
|
|
||||||
|
|
||||||
myFetch({
|
|
||||||
url: `/user/auth/${
|
|
||||||
selectedMethod === "1" ? "login" : "signup"
|
|
||||||
}`,
|
|
||||||
method: "POST",
|
|
||||||
body: body,
|
|
||||||
notificationApi: notificationApi,
|
|
||||||
t: t,
|
|
||||||
})
|
|
||||||
.then((data) => {
|
|
||||||
setUserSessionToLocalStorage(data.XAuthorization);
|
|
||||||
window.location.href = "/";
|
|
||||||
})
|
|
||||||
.catch((errStatus) => {
|
|
||||||
showErrorNotification(errStatus);
|
|
||||||
setIsRequesting(false);
|
|
||||||
});
|
|
||||||
})
|
|
||||||
.catch(() => showInputsInvalidNotification(notificationApi, t));
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{selectedMethod === "1" ? t("login.login") : t("login.signUp")}
|
|
||||||
</Button>
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
display: "flex",
|
|
||||||
justifyContent: "center",
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<MyAppLogo height={80} />
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<Tabs
|
|
||||||
defaultActiveKey="1"
|
|
||||||
items={[
|
|
||||||
{
|
|
||||||
key: "1",
|
|
||||||
label: t("login.login"),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: "2",
|
|
||||||
label: t("login.signUp"),
|
|
||||||
},
|
|
||||||
]}
|
|
||||||
centered
|
|
||||||
onChange={(activeKey) => setSelectedMethod(activeKey)}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<Form form={form} layout="vertical" requiredMark={false}>
|
|
||||||
{selectedMethod === "2" && <MyUsernameFormInput />}
|
|
||||||
|
|
||||||
<MyAccountNameFormInput
|
|
||||||
disableAccountNameCheck={selectedMethod === "1"}
|
|
||||||
hasFeedback={selectedMethod === "2"}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<MyPasswordFormInput />
|
|
||||||
</Form>
|
|
||||||
</Modal>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
}
|
|
|
@ -202,6 +202,11 @@ function ModalAddEditEmployee({
|
||||||
const screenBreakpoint = useBreakpoint();
|
const screenBreakpoint = useBreakpoint();
|
||||||
const [form] = Form.useForm();
|
const [form] = Form.useForm();
|
||||||
|
|
||||||
|
const checkboxSetPasswordOnLogging = Form.useWatch(
|
||||||
|
"checkboxSetPasswordOnLogging",
|
||||||
|
form
|
||||||
|
);
|
||||||
|
|
||||||
const [isRequesting, setIsRequesting] = useState(false);
|
const [isRequesting, setIsRequesting] = useState(false);
|
||||||
|
|
||||||
const handleModalClose = () => {
|
const handleModalClose = () => {
|
||||||
|
@ -276,10 +281,18 @@ function ModalAddEditEmployee({
|
||||||
storeId: storeId,
|
storeId: storeId,
|
||||||
username: values.username,
|
username: values.username,
|
||||||
accountName: values.accountName,
|
accountName: values.accountName,
|
||||||
password: EncodeStringToBase64(values.password),
|
|
||||||
language: i18n.language,
|
language: i18n.language,
|
||||||
|
passwordSetOnInitLogging:
|
||||||
|
values.checkboxSetPasswordOnLogging,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (
|
||||||
|
!values.checkboxSetPasswordOnLogging &&
|
||||||
|
values.password
|
||||||
|
) {
|
||||||
|
body.password = EncodeStringToBase64(values.password);
|
||||||
|
}
|
||||||
|
|
||||||
if (
|
if (
|
||||||
values.calendarMaxFutureBookingDays !==
|
values.calendarMaxFutureBookingDays !==
|
||||||
storeSettings.calendar_max_future_booking_days
|
storeSettings.calendar_max_future_booking_days
|
||||||
|
@ -415,20 +428,33 @@ function ModalAddEditEmployee({
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<Form form={form} layout="vertical" requiredMark={false}>
|
<Form
|
||||||
|
form={form}
|
||||||
|
layout="vertical"
|
||||||
|
requiredMark={false}
|
||||||
|
initialValues={{
|
||||||
|
checkboxSetPasswordOnLogging: true,
|
||||||
|
}}
|
||||||
|
>
|
||||||
<MyUsernameFormInput />
|
<MyUsernameFormInput />
|
||||||
|
|
||||||
<MyAccountNameFormInput hasFeedback />
|
<MyAccountNameFormInput hasFeedback />
|
||||||
|
|
||||||
{modalOptions.mode === "add" && (
|
{modalOptions.mode === "add" && (
|
||||||
<>
|
<>
|
||||||
<MyPasswordFormInput />
|
<Form.Item
|
||||||
|
name="checkboxSetPasswordOnLogging"
|
||||||
<Form.Item>
|
valuePropName="checked"
|
||||||
<Checkbox defaultChecked disabled>
|
extra={t(
|
||||||
{t("employees.modalAddEmployee.checkboxPasswordChange")}
|
"employees.modalAddEmployee.checkboxSetPasswordOnLoggingInfo"
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
<Checkbox>
|
||||||
|
{t("employees.modalAddEmployee.checkboxSetPasswordOnLogging")}
|
||||||
</Checkbox>
|
</Checkbox>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
|
|
||||||
|
{!checkboxSetPasswordOnLogging && <MyPasswordFormInput />}
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
|
14
src/utils.js
14
src/utils.js
|
@ -77,6 +77,13 @@ export const Constants = {
|
||||||
CLARITY_PROJECT_ID: "kr0pale8uy",
|
CLARITY_PROJECT_ID: "kr0pale8uy",
|
||||||
KK_JOBS_URL: "https://kk-innovation.eu/jobs/",
|
KK_JOBS_URL: "https://kk-innovation.eu/jobs/",
|
||||||
ACCOUNT_DELETED_AFTER_DAYS: 30,
|
ACCOUNT_DELETED_AFTER_DAYS: 30,
|
||||||
|
ACCOUNT_STATE: {
|
||||||
|
ACTIVE: 0,
|
||||||
|
PENDING_DELETION: 1,
|
||||||
|
INIT_LOGGING: 2,
|
||||||
|
BANNED: 3,
|
||||||
|
},
|
||||||
|
SUPPORT_EMAIL: "support@zeitadler.de",
|
||||||
};
|
};
|
||||||
|
|
||||||
export const AppStyle = {
|
export const AppStyle = {
|
||||||
|
@ -259,6 +266,13 @@ export function showPasswordIncorrectNotification(notificationApi, t) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function showUnkownErrorNotification(notificationApi, t) {
|
||||||
|
notificationApi["error"]({
|
||||||
|
message: t("common.request.unknownError.title"),
|
||||||
|
description: t("common.request.unknownError.description"),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
export function handleLogout({ setUserSession }) {
|
export function handleLogout({ setUserSession }) {
|
||||||
if (setUserSession !== undefined) setUserSession();
|
if (setUserSession !== undefined) setUserSession();
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue