delete account

master
alex 2024-01-28 00:13:51 +01:00
parent e99613e767
commit 451f2297fd
6 changed files with 212 additions and 26 deletions

View File

@ -67,6 +67,10 @@
"failedInternetProblem": {
"title": "Anfrage fehlgeschlagen",
"description": "Bitte überprüfen Sie Ihre Internetverbindung und versuchen Sie es erneut."
},
"passwordIncorrect": {
"title": "Passwort falsch",
"description": "Bitte überprüfen Sie Ihr Passwort und versuchen Sie es erneut."
}
}
},
@ -214,13 +218,7 @@
"title": "Google Kalender trennen",
"description": "Aus Sicherheitsgründen müssen Sie Ihr Passwort eingeben, um die Verbindung zu Ihrem Google Kalender zu trennen.",
"checkboxDeleteCalendars": "Kalender für Öffnungszeiten und Termine löschen (Alle Termine werden gelöscht und können nicht wiederhergestellt werden)",
"button": "Google Kalender trennen",
"request": {
"400": {
"title": "Passwort ungültig",
"description": "Bitte überprüfen Sie Ihr Passwort und versuchen Sie es erneut."
}
}
"button": "Google Kalender trennen"
},
"calendarFrameCustomerView": "Terminkalenderansicht der Kunden"
},
@ -283,7 +281,30 @@
}
},
"deleteAccount": {
"cardTitle": "Konto löschen"
"cardTitle": "Konto löschen",
"info": "Ihr Konto und alle Ihre Daten endgültig löschen.",
"button": "Konto löschen",
"modal": {
"title": "Konto löschen",
"info": "Ihr Konto wird sofort deaktiviert und nach {{days}} Tagen gelöscht. Während dieser Zeit können Sie Ihr Konto wiederherstellen, indem Sie sich erneut anmelden.",
"why": "Warum löschen Sie Ihr Konto?",
"whyRuleRequired": "Bitte wählen Sie einen Grund",
"radioOptions": {
"notNeeded": "Ich benötige es nicht mehr",
"notUseful": "Ich finde es nicht nützlich",
"other": "Sonstiges"
},
"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",
"description": "Bitte überprüfen Sie Ihr Passwort und versuchen Sie es erneut."
}
}
}
}
}
}

View File

@ -67,6 +67,10 @@
"failedInternetProblem": {
"title": "Request failed",
"description": "The request failed. Please check your internet connection and try again."
},
"passwordIncorrect": {
"title": "Password incorrect",
"description": "Please check your password and try again."
}
}
},
@ -217,13 +221,7 @@
"title": "Unlink Google Calendar",
"description": "For security reasons, you need to enter your password to unlink your Google Calendar.",
"checkboxDeleteCalendars": "Delete calendar for opening hours and appointments (all appointments are deleted and cannot be restored)",
"button": "Unlink Google Calendar",
"request": {
"400": {
"title": "Password incorrect",
"description": "Please check your password and try again."
}
}
"button": "Unlink Google Calendar"
},
"calendarFrameCustomerView": "Appointment diary view of customers"
},
@ -292,7 +290,30 @@
}
},
"deleteAccount": {
"cardTitle": "Delete account"
"cardTitle": "Delete account",
"info": "Permanently delete your account and all your data.",
"button": "Delete account",
"modal": {
"title": "Delete account",
"info": "Your account will be deactivated immediately and deleted after {{days}} days. During this time, you can restore your account by logging in again.",
"why": "Why are you deleting your account?",
"whyRuleRequired": "Please select a reason",
"radioOptions": {
"notNeeded": "I don't need it anymore",
"notUseful": "I don't find it useful",
"other": "Other"
},
"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",
"description": "Please check your password and try again."
}
}
}
}
}
}

View File

@ -108,6 +108,7 @@ export function MyModalCloseConfirmButtonFooter({
onCancel,
onConfirm,
isConfirmButtonLoading,
danger = false,
}) {
const { t } = useTranslation();
@ -115,6 +116,7 @@ export function MyModalCloseConfirmButtonFooter({
<>
<Button onClick={onCancel}>{t("common.button.close")}</Button>
<Button
danger={danger}
onClick={onConfirm}
type="primary"
loading={isConfirmButtonLoading}

View File

@ -19,6 +19,7 @@ import {
getUserSessionFromLocalStorage,
myFetch,
showInputsInvalidNotification,
showPasswordIncorrectNotification,
} from "../../../utils";
import { useEffect, useRef, useState } from "react";
import MyCenteredContainer from "../../../Components/MyContainer";
@ -406,14 +407,7 @@ function CardPersonalCalendarSettings({ settings }) {
setIsRequesting(false);
if (errStatus === 400) {
notificationApi["error"]({
message: t(
"calendar.unlinkGoogleCalendar.request.400.title"
),
description: t(
"calendar.unlinkGoogleCalendar.request.400.description"
),
});
showPasswordIncorrectNotification(notificationApi, t);
}
});
})

View File

@ -3,20 +3,24 @@ import {
Card,
Form,
Popconfirm,
Radio,
Select,
Skeleton,
Space,
Switch,
Tabs,
Tag,
Typography,
notification,
} from "antd";
import {
Constants,
EncodeStringToBase64,
FormatDatetime,
handleLogout,
myFetch,
showInputsInvalidNotification,
showPasswordIncorrectNotification,
} from "../../utils";
import { useTranslation } from "react-i18next";
import { useEffect, useRef, useState } from "react";
@ -27,12 +31,16 @@ import {
import { LogoutOutlined } from "@ant-design/icons";
import {
MyAccountNameFormInput,
MyFormInput,
MyPasswordFormInput,
MyUsernameFormInput,
} from "../../Components/MyFormInputs";
import { MySupsenseFallback } from "../../Components/MySupsenseFallback";
import { useSideBarContext } from "../../Contexts/SideBarContext";
import MyTable from "../../Components/MyTable";
import MyModal, {
MyModalCloseConfirmButtonFooter,
} from "../../Components/MyModal";
const globalRequestStatePreview = {
global: RequestState.INIT,
@ -586,5 +594,134 @@ function YourSessions() {
}
function DeleteAccount() {
return <div>Delete account, Password and feedback</div>;
const { t } = useTranslation();
const [notificationApi, notificationContextHolder] =
notification.useNotification();
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 (
<>
{notificationContextHolder}
<Space direction="vertical">
<Typography.Text>{t("userProfile.deleteAccount.info")}</Typography.Text>
<Button type="primary" danger onClick={() => setIsModalOpen(true)}>
{t("userProfile.deleteAccount.button")}
</Button>
</Space>
<MyModal
title={t("userProfile.deleteAccount.modal.title")}
isOpen={isModalOpen}
onCancel={handleModalClose}
footer={
<MyModalCloseConfirmButtonFooter
danger
isConfirmButtonLoading={isRequesting}
onConfirm={() => {
form
.validateFields()
.then((values) => {
setIsRequesting(true);
myFetch({
url: "/user/profile/delete",
method: "DELETE",
body: {
feedback: values.improve,
reason: values["deleteReason"],
password: EncodeStringToBase64(values.password),
},
})
.then(() => {
setIsRequesting(false);
window.location.reload();
})
.catch((errStatus) => {
setIsRequesting(false);
if (errStatus === 400) {
showPasswordIncorrectNotification(notificationApi, t);
}
});
})
.catch(() => setIsRequesting(false));
}}
onCancel={handleModalClose}
/>
}
>
<Form form={form} layout="vertical" requiredMark={false}>
<Typography.Paragraph type="secondary">
{t("userProfile.deleteAccount.modal.info", {
days: Constants.ACCOUNT_DELETED_AFTER_DAYS,
})}
</Typography.Paragraph>
<Form.Item
name="deleteReason"
label={t("userProfile.deleteAccount.modal.why")}
required
rules={[
{
required: true,
message: t("userProfile.deleteAccount.modal.whyRuleRequired"),
},
]}
>
<Radio.Group>
<Space direction="vertical">
<Radio value="notNeeded">
{t("userProfile.deleteAccount.modal.radioOptions.notNeeded")}
</Radio>
<Radio value="notUseful">
{t("userProfile.deleteAccount.modal.radioOptions.notUseful")}
</Radio>
<Radio value="other">
{t("userProfile.deleteAccount.modal.radioOptions.other")}
</Radio>
</Space>
</Radio.Group>
</Form.Item>
<MyFormInput
formItemName="improve"
minLength={Constants.GLOBALS.MIN_FEEDBACK_LENGTH}
maxLength={Constants.GLOBALS.MAX_FEEDBACK_LENGTH}
inputType="textarea"
propsInput={{
showCount: true,
}}
label={t("userProfile.deleteAccount.modal.improveLabel")}
ruleMessageValueRequired={t(
"userProfile.deleteAccount.modal.improveRequired"
)}
ruleMessageValueMinLengthRequired={t(
"userProfile.deleteAccount.modal.improveMinLengthRequired",
{
minLength: Constants.GLOBALS.MIN_FEEDBACK_LENGTH,
}
)}
/>
<MyPasswordFormInput />
</Form>
</MyModal>
</>
);
}

View File

@ -68,10 +68,13 @@ export const Constants = {
MAX_CALENDAR_FUTURE_BOOKING_DAYS: 365,
MIN_CALENDAR_EARLIEST_BOOKING_TIME: 0,
MAX_CALENDAR_EARLIEST_BOOKING_TIME: 60 * 24, // 24 hours in minutes
MIN_FEEDBACK_LENGTH: 10,
MAX_FEEDBACK_LENGTH: 1024,
},
DELAY_ACCOUNT_NAME_CHECK: 250,
CLARITY_PROJECT_ID: "kr0pale8uy",
KK_JOBS_URL: "https://kk-innovation.eu/jobs/",
ACCOUNT_DELETED_AFTER_DAYS: 30,
};
export const AppStyle = {
@ -247,8 +250,16 @@ export function showInputsInvalidNotification(notificationApi, t) {
});
}
export function showPasswordIncorrectNotification(notificationApi, t) {
notificationApi["warning"]({
message: t("common.request.passwordIncorrect.title"),
description: t("common.request.passwordIncorrect.description"),
});
}
export function handleLogout({ setUserSession }) {
setUserSession();
if (setUserSession !== undefined) setUserSession();
window.location.href = "/";
}