export account

master
alex 2024-02-03 22:36:37 +01:00
parent 5e0af4aa88
commit eb74f42aa1
4 changed files with 296 additions and 131 deletions

View File

@ -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",

View File

@ -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",

View File

@ -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();

View File

@ -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>
),
};
});
@ -305,8 +302,12 @@ function YourProfile({
}, [language, analyticsEnabled, username, accountName]);
return (
<Card title={t("userProfile.yourProfile.cardTitle")}>
<Form form={form} layout="vertical" requiredMark={false}>
<Form.Item name="language" label={t("userProfile.yourProfile.language")}>
<Form.Item
name="language"
label={t("userProfile.yourProfile.language")}
>
{requestState === RequestState.INIT ? (
<Skeleton.Input active block></Skeleton.Input>
) : (
@ -340,7 +341,9 @@ function YourProfile({
)}
</Form.Item>
<MyUsernameFormInput showSkeleton={requestState === RequestState.INIT} />
<MyUsernameFormInput
showSkeleton={requestState === RequestState.INIT}
/>
<MyAccountNameFormInput
showSkeleton={requestState === RequestState.INIT}
@ -348,6 +351,7 @@ function YourProfile({
disableAccountNameCheck={requestData.account_name === accountName}
/>
</Form>
</Card>
);
}
@ -417,7 +421,13 @@ function ChangePassword({
};
return (
<Form form={form} layout="vertical" autoComplete="off" requiredMark={false}>
<Card title={t("userProfile.changePassword.cardTitle")}>
<Form
form={form}
layout="vertical"
autoComplete="off"
requiredMark={false}
>
<MyPasswordFormInput
propsInput={{
id: "currentPassword",
@ -480,6 +490,7 @@ function ChangePassword({
</Space>
</Form.Item>
</Form>
</Card>
);
}
@ -583,6 +594,7 @@ function YourSessions() {
useEffect(() => requestSessions(), []);
return (
<Card title={t("userProfile.yourSessions.cardTitle")}>
<MyTable
props={{
loading: isRequesting,
@ -590,21 +602,40 @@ function YourSessions() {
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>
);
}