export account
parent
5e0af4aa88
commit
eb74f42aa1
|
@ -33,6 +33,8 @@
|
|||
"accountNamePlaceholder": "Geben Sie Ihren Benutzernamen ein",
|
||||
"accountNamePlaceholderThirdPerson": "Geben Sie den Benutzernamen ein",
|
||||
"accountNameInfo": "Der Benutzername wird verwendet, um sich anzumelden.",
|
||||
"email": "E-Mail",
|
||||
"emailPlaceholder": "Geben Sie Ihre E-Mail ein",
|
||||
"password": "Passwort",
|
||||
"passwordPlaceholder": "Geben Sie Ihr Passwort ein",
|
||||
"noDataFound": "Keine Einträge gefunden",
|
||||
|
@ -53,6 +55,8 @@
|
|||
"accountNameRequired": "Benutzername ist erforderlich",
|
||||
"accountNameMinLength": "Benutzername muss mindestens {{minLength}} Zeichen lang sein",
|
||||
"accountNameTaken": "Benutzername ist bereits vergeben",
|
||||
"emailRequired": "E-Mail ist erforderlich",
|
||||
"emailInvalid": "E-Mail ist ungültig",
|
||||
"passwordRequired": "Passwort ist erforderlich",
|
||||
"passwordMinLength": "Passwort muss mindestens {{minLength}} Zeichen lang sein",
|
||||
"calendarMaxFutureBookingDaysRequired": "Maximaler Buchungszeitraum ist erforderlich",
|
||||
|
@ -285,7 +289,7 @@
|
|||
"yourProfile": "Ihr Profil",
|
||||
"changePassword": "Passwort ändern",
|
||||
"yourSessions": "Ihre Sitzungen",
|
||||
"deleteAccount": "Konto löschen"
|
||||
"yourAccount": "Ihr Konto"
|
||||
},
|
||||
"yourProfile": {
|
||||
"cardTitle": "Ihr Profil",
|
||||
|
@ -318,6 +322,21 @@
|
|||
"description": "Möchten Sie diese Sitzung wirklich abmelden?"
|
||||
}
|
||||
},
|
||||
"accountExport": {
|
||||
"cardTitle": "Konto exportieren",
|
||||
"info": "Exportieren Sie Ihr Konto und alle Daten, die im Laufe der Nutzung des Dashboards entstanden sind.",
|
||||
"button": "Konto export anfordern",
|
||||
"modal": {
|
||||
"title": "Konto export anfordern",
|
||||
"info": "Dies kann einige Zeit in Anspruch nehmen. Wir senden Ihnen eine E-Mail mit dem Download-Link, sobald der Export fertig ist.",
|
||||
"request": {
|
||||
"400": {
|
||||
"title": "Passwort falsch",
|
||||
"description": "Bitte überprüfen Sie Ihr Passwort und versuchen Sie es erneut."
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"deleteAccount": {
|
||||
"cardTitle": "Konto löschen",
|
||||
"info": "Ihr Konto und alle Ihre Daten endgültig löschen.",
|
||||
|
@ -335,7 +354,6 @@
|
|||
"improveLabel": "Wie können wir das Produkt verbessern?",
|
||||
"improveRequired": "Bitte geben Sie Ihr Feedback ein",
|
||||
"improveMinLengthRequired": "Bitte geben Sie mindestens {{minLength}} Zeichen ein",
|
||||
"button": "Konto löschen",
|
||||
"request": {
|
||||
"400": {
|
||||
"title": "Passwort falsch",
|
||||
|
|
|
@ -33,6 +33,8 @@
|
|||
"accountNamePlaceholder": "Enter your account name",
|
||||
"accountNamePlaceholderThirdPerson": "Enter the account name",
|
||||
"accountNameInfo": "The account name is used to log in.",
|
||||
"email": "Email",
|
||||
"emailPlaceholder": "Enter your email",
|
||||
"password": "Password",
|
||||
"passwordPlaceholder": "Enter your password",
|
||||
"noDataFound": "No data found",
|
||||
|
@ -53,6 +55,8 @@
|
|||
"accountNameRequired": "Please enter your account name",
|
||||
"accountNameMinLength": "Account name must be at least {{minLength}} characters",
|
||||
"accountNameTaken": "Account name already exists",
|
||||
"emailRequired": "Please enter your email",
|
||||
"emailInvalid": "Please enter a valid email",
|
||||
"passwordRequired": "Please enter your password",
|
||||
"passwordMinLength": "Password must be at least {{minLength}} characters",
|
||||
"calendarMaxFutureBookingDaysRequired": "Please enter the max. future booking days",
|
||||
|
@ -288,7 +292,7 @@
|
|||
"yourProfile": "Your profile",
|
||||
"changePassword": "Change password",
|
||||
"yourSessions": "Your sessions",
|
||||
"deleteAccount": "Delete account"
|
||||
"yourAccount": "Your account"
|
||||
},
|
||||
"yourProfile": {
|
||||
"cardTitle": "Your profile",
|
||||
|
@ -327,6 +331,21 @@
|
|||
"description": "Are you sure you want to delete this session?"
|
||||
}
|
||||
},
|
||||
"accountExport": {
|
||||
"cardTitle": "Account export",
|
||||
"info": "Export your account and all your data to a ZIP file.",
|
||||
"button": "Export account",
|
||||
"modal": {
|
||||
"title": "Request account export",
|
||||
"info": "Export your account and all data created during the use of the dashboard.",
|
||||
"request": {
|
||||
"400": {
|
||||
"title": "Password incorrect",
|
||||
"description": "Please check your password and try again."
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"deleteAccount": {
|
||||
"cardTitle": "Delete account",
|
||||
"info": "Permanently delete your account and all your data.",
|
||||
|
@ -344,7 +363,6 @@
|
|||
"improveLabel": "How can we improve the product?",
|
||||
"improveRequired": "Please enter your feedback",
|
||||
"improveMinLengthRequired": "Please enter at least {{minLength}} characters",
|
||||
"button": "Delete account",
|
||||
"request": {
|
||||
"400": {
|
||||
"title": "Password incorrect",
|
||||
|
|
|
@ -110,6 +110,28 @@ export function MyPasswordFormInput({
|
|||
);
|
||||
}
|
||||
|
||||
export function MyEmailFormInput() {
|
||||
const { t } = useTranslation();
|
||||
|
||||
return (
|
||||
<MyFormInput
|
||||
formItemName="email"
|
||||
minLength={0}
|
||||
maxLength={64}
|
||||
label={t("common.email")}
|
||||
ruleMessageValueRequired={t("common.inputRules.emailRequired")}
|
||||
inputPlaceholder={t("common.emailPlaceholder")}
|
||||
inputType="email"
|
||||
formItemRules={[
|
||||
{
|
||||
type: "email",
|
||||
message: t("common.inputRules.emailInvalid"),
|
||||
},
|
||||
]}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
export function MyCalendarMaxFutureBookingDaysFormInput({ formItemName }) {
|
||||
const { t } = useTranslation();
|
||||
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
import {
|
||||
Button,
|
||||
Card,
|
||||
Col,
|
||||
Form,
|
||||
Popconfirm,
|
||||
Radio,
|
||||
Row,
|
||||
Select,
|
||||
Skeleton,
|
||||
Space,
|
||||
|
@ -31,6 +33,7 @@ import {
|
|||
import { LogoutOutlined } from "@ant-design/icons";
|
||||
import {
|
||||
MyAccountNameFormInput,
|
||||
MyEmailFormInput,
|
||||
MyFormInput,
|
||||
MyPasswordFormInput,
|
||||
MyUsernameFormInput,
|
||||
|
@ -64,7 +67,6 @@ export default function UserProfile({ setUserSession }) {
|
|||
const tabItems = [
|
||||
{
|
||||
label: t("userProfile.tabs.yourProfile"),
|
||||
cardTitle: t("userProfile.yourProfile.cardTitle"),
|
||||
children: (
|
||||
<YourProfile
|
||||
notificationApi={notificationApi}
|
||||
|
@ -75,7 +77,6 @@ export default function UserProfile({ setUserSession }) {
|
|||
},
|
||||
{
|
||||
label: t("userProfile.tabs.changePassword"),
|
||||
cardTitle: t("userProfile.changePassword.cardTitle"),
|
||||
children: (
|
||||
<ChangePassword
|
||||
notificationApi={notificationApi}
|
||||
|
@ -87,24 +88,20 @@ export default function UserProfile({ setUserSession }) {
|
|||
},
|
||||
{
|
||||
label: t("userProfile.tabs.yourSessions"),
|
||||
cardTitle: t("userProfile.yourSessions.cardTitle"),
|
||||
children: <YourSessions />,
|
||||
},
|
||||
{
|
||||
label: t("userProfile.tabs.deleteAccount"),
|
||||
cardTitle: t("userProfile.deleteAccount.cardTitle"),
|
||||
children: <DeleteAccount />,
|
||||
label: t("userProfile.tabs.yourAccount"),
|
||||
children: <YourAccount />,
|
||||
},
|
||||
].map((item, index) => {
|
||||
return {
|
||||
key: index,
|
||||
...item,
|
||||
children: (
|
||||
<Card title={item.cardTitle}>
|
||||
<MySupsenseFallback spinnerCentered={false}>
|
||||
{item.children}
|
||||
</MySupsenseFallback>
|
||||
</Card>
|
||||
<MySupsenseFallback spinnerCentered={false}>
|
||||
{item.children}
|
||||
</MySupsenseFallback>
|
||||
),
|
||||
};
|
||||
});
|
||||
|
@ -305,49 +302,56 @@ function YourProfile({
|
|||
}, [language, analyticsEnabled, username, accountName]);
|
||||
|
||||
return (
|
||||
<Form form={form} layout="vertical" requiredMark={false}>
|
||||
<Form.Item name="language" label={t("userProfile.yourProfile.language")}>
|
||||
{requestState === RequestState.INIT ? (
|
||||
<Skeleton.Input active block></Skeleton.Input>
|
||||
) : (
|
||||
<Select
|
||||
style={{ width: "100%" }}
|
||||
options={[
|
||||
{
|
||||
value: "en",
|
||||
label: "English",
|
||||
},
|
||||
{
|
||||
value: "de",
|
||||
label: "Deutsch",
|
||||
},
|
||||
]}
|
||||
onChange={(e) => i18n.changeLanguage(e)}
|
||||
/>
|
||||
)}
|
||||
</Form.Item>
|
||||
<Card title={t("userProfile.yourProfile.cardTitle")}>
|
||||
<Form form={form} layout="vertical" requiredMark={false}>
|
||||
<Form.Item
|
||||
name="language"
|
||||
label={t("userProfile.yourProfile.language")}
|
||||
>
|
||||
{requestState === RequestState.INIT ? (
|
||||
<Skeleton.Input active block></Skeleton.Input>
|
||||
) : (
|
||||
<Select
|
||||
style={{ width: "100%" }}
|
||||
options={[
|
||||
{
|
||||
value: "en",
|
||||
label: "English",
|
||||
},
|
||||
{
|
||||
value: "de",
|
||||
label: "Deutsch",
|
||||
},
|
||||
]}
|
||||
onChange={(e) => i18n.changeLanguage(e)}
|
||||
/>
|
||||
)}
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
name="analyticsEnabled"
|
||||
valuePropName="checked"
|
||||
label={t("userProfile.yourProfile.analytics")}
|
||||
extra={t("userProfile.yourProfile.analyticsDescription")}
|
||||
>
|
||||
{requestState === RequestState.INIT ? (
|
||||
<Skeleton.Button shape="round" active />
|
||||
) : (
|
||||
<Switch>{t("userProfile.yourProfile.analytics")}</Switch>
|
||||
)}
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
name="analyticsEnabled"
|
||||
valuePropName="checked"
|
||||
label={t("userProfile.yourProfile.analytics")}
|
||||
extra={t("userProfile.yourProfile.analyticsDescription")}
|
||||
>
|
||||
{requestState === RequestState.INIT ? (
|
||||
<Skeleton.Button shape="round" active />
|
||||
) : (
|
||||
<Switch>{t("userProfile.yourProfile.analytics")}</Switch>
|
||||
)}
|
||||
</Form.Item>
|
||||
|
||||
<MyUsernameFormInput showSkeleton={requestState === RequestState.INIT} />
|
||||
<MyUsernameFormInput
|
||||
showSkeleton={requestState === RequestState.INIT}
|
||||
/>
|
||||
|
||||
<MyAccountNameFormInput
|
||||
showSkeleton={requestState === RequestState.INIT}
|
||||
hasFeedback
|
||||
disableAccountNameCheck={requestData.account_name === accountName}
|
||||
/>
|
||||
</Form>
|
||||
<MyAccountNameFormInput
|
||||
showSkeleton={requestState === RequestState.INIT}
|
||||
hasFeedback
|
||||
disableAccountNameCheck={requestData.account_name === accountName}
|
||||
/>
|
||||
</Form>
|
||||
</Card>
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -417,69 +421,76 @@ function ChangePassword({
|
|||
};
|
||||
|
||||
return (
|
||||
<Form form={form} layout="vertical" autoComplete="off" requiredMark={false}>
|
||||
<MyPasswordFormInput
|
||||
propsInput={{
|
||||
id: "currentPassword",
|
||||
}}
|
||||
formItemName="currentPassword"
|
||||
label={t("userProfile.changePassword.currentPassword")}
|
||||
inputPlaceholder={t(
|
||||
"userProfile.changePassword.currentPasswordPlaceholder"
|
||||
)}
|
||||
/>
|
||||
<Card title={t("userProfile.changePassword.cardTitle")}>
|
||||
<Form
|
||||
form={form}
|
||||
layout="vertical"
|
||||
autoComplete="off"
|
||||
requiredMark={false}
|
||||
>
|
||||
<MyPasswordFormInput
|
||||
propsInput={{
|
||||
id: "currentPassword",
|
||||
}}
|
||||
formItemName="currentPassword"
|
||||
label={t("userProfile.changePassword.currentPassword")}
|
||||
inputPlaceholder={t(
|
||||
"userProfile.changePassword.currentPasswordPlaceholder"
|
||||
)}
|
||||
/>
|
||||
|
||||
<MyPasswordFormInput
|
||||
propsInput={{
|
||||
id: "newPassword",
|
||||
}}
|
||||
formItemName="newPassword"
|
||||
label={t("userProfile.changePassword.newPassword")}
|
||||
inputPlaceholder={t(
|
||||
"userProfile.changePassword.newPasswordPlaceholder"
|
||||
)}
|
||||
/>
|
||||
<MyPasswordFormInput
|
||||
propsInput={{
|
||||
id: "newPassword",
|
||||
}}
|
||||
formItemName="newPassword"
|
||||
label={t("userProfile.changePassword.newPassword")}
|
||||
inputPlaceholder={t(
|
||||
"userProfile.changePassword.newPasswordPlaceholder"
|
||||
)}
|
||||
/>
|
||||
|
||||
<MyPasswordFormInput
|
||||
propsInput={{
|
||||
id: "confirmNewPassword",
|
||||
}}
|
||||
formItemName="confirmNewPassword"
|
||||
label={t("userProfile.changePassword.confirmNewPassword")}
|
||||
inputPlaceholder={t(
|
||||
"userProfile.changePassword.confirmNewPasswordPlaceholder"
|
||||
)}
|
||||
propsFormItem={{
|
||||
dependencies: ["newPassword"],
|
||||
}}
|
||||
formItemRules={({ getFieldValue }) => ({
|
||||
validator(_, value) {
|
||||
if (!value || getFieldValue("newPassword") === value) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
return Promise.reject(
|
||||
new Error(
|
||||
t("userProfile.changePassword.confirmNewPasswordMismatch")
|
||||
)
|
||||
);
|
||||
},
|
||||
})}
|
||||
/>
|
||||
<MyPasswordFormInput
|
||||
propsInput={{
|
||||
id: "confirmNewPassword",
|
||||
}}
|
||||
formItemName="confirmNewPassword"
|
||||
label={t("userProfile.changePassword.confirmNewPassword")}
|
||||
inputPlaceholder={t(
|
||||
"userProfile.changePassword.confirmNewPasswordPlaceholder"
|
||||
)}
|
||||
propsFormItem={{
|
||||
dependencies: ["newPassword"],
|
||||
}}
|
||||
formItemRules={({ getFieldValue }) => ({
|
||||
validator(_, value) {
|
||||
if (!value || getFieldValue("newPassword") === value) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
return Promise.reject(
|
||||
new Error(
|
||||
t("userProfile.changePassword.confirmNewPasswordMismatch")
|
||||
)
|
||||
);
|
||||
},
|
||||
})}
|
||||
/>
|
||||
|
||||
<Form.Item extra={t("userProfile.changePassword.buttonInfo")}>
|
||||
<Space>
|
||||
<Button
|
||||
type="primary"
|
||||
onClick={handlePasswordChange}
|
||||
loading={
|
||||
globalRequestState.changePassword === RequestState.REQUESTING
|
||||
}
|
||||
>
|
||||
{t("userProfile.changePassword.button")}
|
||||
</Button>
|
||||
</Space>
|
||||
</Form.Item>
|
||||
</Form>
|
||||
<Form.Item extra={t("userProfile.changePassword.buttonInfo")}>
|
||||
<Space>
|
||||
<Button
|
||||
type="primary"
|
||||
onClick={handlePasswordChange}
|
||||
loading={
|
||||
globalRequestState.changePassword === RequestState.REQUESTING
|
||||
}
|
||||
>
|
||||
{t("userProfile.changePassword.button")}
|
||||
</Button>
|
||||
</Space>
|
||||
</Form.Item>
|
||||
</Form>
|
||||
</Card>
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -583,28 +594,48 @@ function YourSessions() {
|
|||
useEffect(() => requestSessions(), []);
|
||||
|
||||
return (
|
||||
<MyTable
|
||||
props={{
|
||||
loading: isRequesting,
|
||||
columns: getTableColumns(),
|
||||
dataSource: getTableItems(),
|
||||
}}
|
||||
/>
|
||||
<Card title={t("userProfile.yourSessions.cardTitle")}>
|
||||
<MyTable
|
||||
props={{
|
||||
loading: isRequesting,
|
||||
columns: getTableColumns(),
|
||||
dataSource: getTableItems(),
|
||||
}}
|
||||
/>
|
||||
</Card>
|
||||
);
|
||||
}
|
||||
|
||||
function DeleteAccount() {
|
||||
const { t } = useTranslation();
|
||||
function YourAccount() {
|
||||
const [notificationApi, notificationContextHolder] =
|
||||
notification.useNotification();
|
||||
|
||||
return (
|
||||
<>
|
||||
{notificationContextHolder}
|
||||
|
||||
<Row gutter={[16, 16]}>
|
||||
<Col span={24}>
|
||||
<YourAccountExportDataCard notificationApi={notificationApi} />
|
||||
</Col>
|
||||
|
||||
<Col span={24}>
|
||||
<YourAccountDeleteAccountCard notificationApi={notificationApi} />
|
||||
</Col>
|
||||
</Row>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
function YourAccountExportDataCard({ notificationApi }) {
|
||||
const { t } = useTranslation();
|
||||
|
||||
const [form] = Form.useForm();
|
||||
|
||||
const [isModalOpen, setIsModalOpen] = useState(false);
|
||||
const [isRequesting, setIsRequesting] = useState(false);
|
||||
|
||||
const handleModalClose = () => {
|
||||
setIsModalOpen(false);
|
||||
};
|
||||
const handleModalClose = () => setIsModalOpen(false);
|
||||
|
||||
useEffect(() => {
|
||||
if (!isModalOpen) return;
|
||||
|
@ -613,9 +644,85 @@ function DeleteAccount() {
|
|||
}, [isModalOpen]);
|
||||
|
||||
return (
|
||||
<>
|
||||
{notificationContextHolder}
|
||||
<Card title={t("userProfile.accountExport.cardTitle")}>
|
||||
<Space direction="vertical">
|
||||
<Typography.Text>{t("userProfile.accountExport.info")}</Typography.Text>
|
||||
|
||||
<Button type="default" onClick={() => setIsModalOpen(true)}>
|
||||
{t("userProfile.accountExport.button")}
|
||||
</Button>
|
||||
</Space>
|
||||
|
||||
<MyModal
|
||||
title={t("userProfile.accountExport.modal.title")}
|
||||
isOpen={isModalOpen}
|
||||
onCancel={handleModalClose}
|
||||
footer={
|
||||
<MyModalCloseConfirmButtonFooter
|
||||
isConfirmButtonLoading={isRequesting}
|
||||
onConfirm={() => {
|
||||
form
|
||||
.validateFields()
|
||||
.then((values) => {
|
||||
setIsRequesting(true);
|
||||
|
||||
myFetch({
|
||||
url: "/user/profile/export",
|
||||
method: "POST",
|
||||
body: {
|
||||
email: values.email,
|
||||
password: EncodeStringToBase64(values.password),
|
||||
},
|
||||
})
|
||||
.then(() => {
|
||||
setIsRequesting(false);
|
||||
setIsModalOpen(false);
|
||||
})
|
||||
.catch((errStatus) => {
|
||||
setIsRequesting(false);
|
||||
|
||||
if (errStatus === 400) {
|
||||
showPasswordIncorrectNotification(notificationApi, t);
|
||||
}
|
||||
});
|
||||
})
|
||||
.catch(() => showInputsInvalidNotification(notificationApi, t));
|
||||
}}
|
||||
onCancel={handleModalClose}
|
||||
/>
|
||||
}
|
||||
>
|
||||
<Form form={form} layout="vertical" requiredMark={false}>
|
||||
<Typography.Paragraph type="secondary">
|
||||
{t("userProfile.accountExport.modal.info")}
|
||||
</Typography.Paragraph>
|
||||
|
||||
<MyEmailFormInput />
|
||||
|
||||
<MyPasswordFormInput />
|
||||
</Form>
|
||||
</MyModal>
|
||||
</Card>
|
||||
);
|
||||
}
|
||||
|
||||
function YourAccountDeleteAccountCard({ notificationApi }) {
|
||||
const { t } = useTranslation();
|
||||
|
||||
const [form] = Form.useForm();
|
||||
|
||||
const [isModalOpen, setIsModalOpen] = useState(false);
|
||||
const [isRequesting, setIsRequesting] = useState(false);
|
||||
|
||||
const handleModalClose = () => setIsModalOpen(false);
|
||||
/*useEffect(() => {
|
||||
if (!isModalOpen) return;
|
||||
|
||||
form.resetFields();
|
||||
}, [isModalOpen]); */
|
||||
|
||||
return (
|
||||
<Card title={t("userProfile.deleteAccount.cardTitle")}>
|
||||
<Space direction="vertical">
|
||||
<Typography.Text>{t("userProfile.deleteAccount.info")}</Typography.Text>
|
||||
|
||||
|
@ -660,7 +767,7 @@ function DeleteAccount() {
|
|||
}
|
||||
});
|
||||
})
|
||||
.catch(() => setIsRequesting(false));
|
||||
.catch(() => showInputsInvalidNotification(notificationApi, t));
|
||||
}}
|
||||
onCancel={handleModalClose}
|
||||
/>
|
||||
|
@ -722,6 +829,6 @@ function DeleteAccount() {
|
|||
<MyPasswordFormInput />
|
||||
</Form>
|
||||
</MyModal>
|
||||
</>
|
||||
</Card>
|
||||
);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue