master
alex 2024-01-13 19:43:02 +01:00
parent a3c979c5b7
commit ec9516e5e4
10 changed files with 586 additions and 264 deletions

View File

@ -7,7 +7,13 @@
"delete": "Löschen", "delete": "Löschen",
"confirm": "Bestätigen", "confirm": "Bestätigen",
"create": "Erstellen", "create": "Erstellen",
"edit": "Bearbeiten" "edit": "Bearbeiten",
"logout": "Abmelden"
},
"tooltip": {
"edit": "Bearbeiten",
"delete": "Löschen",
"add": "Hinzufügen"
}, },
"action": "Aktion", "action": "Aktion",
"contactAdmin": "Bitte kontaktieren Sie einen Administrator", "contactAdmin": "Bitte kontaktieren Sie einen Administrator",
@ -86,6 +92,7 @@
"serviceActivityDurationMinutes": "Dauer der Tätigkeit (Minuten)", "serviceActivityDurationMinutes": "Dauer der Tätigkeit (Minuten)",
"serviceActivityDurationMinutesPlaceholder": "Geben Sie die Dauer der Tätigkeit in Minuten ein", "serviceActivityDurationMinutesPlaceholder": "Geben Sie die Dauer der Tätigkeit in Minuten ein",
"serviceActivityDurationMinutesUnit": "Minuten", "serviceActivityDurationMinutesUnit": "Minuten",
"serviceActivityResponsible": "Verantwortliche Mitarbeiter",
"inputRules": { "inputRules": {
"serviceNameRequired": "Name der Dienstleistung ist erforderlich", "serviceNameRequired": "Name der Dienstleistung ist erforderlich",
"serviceNameMinLength": "Name der Dienstleistung muss mindestens {{minLength}} Zeichen lang sein", "serviceNameMinLength": "Name der Dienstleistung muss mindestens {{minLength}} Zeichen lang sein",
@ -108,6 +115,17 @@
}, },
"modalEditServiceActivity": { "modalEditServiceActivity": {
"title": "Tätigkeit bearbeiten" "title": "Tätigkeit bearbeiten"
},
"popConfirmDeleteService": {
"title": "Dienstleistung löschen",
"description": "Sind Sie sicher, dass Sie diese Dienstleistung löschen möchten?"
},
"popConfirmDeleteServiceActivity": {
"title": "Tätigkeit löschen",
"description": "Sind Sie sicher, dass Sie diese Tätigkeit löschen möchten?"
} }
},
"calendar": {
"pageTitle": "Kalender"
} }
} }

View File

@ -7,7 +7,13 @@
"delete": "Delete", "delete": "Delete",
"confirm": "Confirm", "confirm": "Confirm",
"create": "Create", "create": "Create",
"edit": "Edit" "edit": "Edit",
"logout": "Logout"
},
"tooltip": {
"edit": "Edit",
"delete": "Delete",
"add": "Add"
}, },
"action": "Action", "action": "Action",
"contactAdmin": "Please contact an administrator", "contactAdmin": "Please contact an administrator",
@ -89,6 +95,7 @@
"serviceActivityDurationMinutes": "Duration of activity (minutes)", "serviceActivityDurationMinutes": "Duration of activity (minutes)",
"serviceActivityDurationMinutesPlaceholder": "Enter the duration of the activity in minutes", "serviceActivityDurationMinutesPlaceholder": "Enter the duration of the activity in minutes",
"serviceActivityDurationMinutesUnit": "Minutes", "serviceActivityDurationMinutesUnit": "Minutes",
"serviceActivityResponsible": "Responsible employees",
"inputRules": { "inputRules": {
"serviceNameRequired": "Service name is required", "serviceNameRequired": "Service name is required",
"serviceNameMinLength": "Service name must be at least {{minLength}} characters long", "serviceNameMinLength": "Service name must be at least {{minLength}} characters long",
@ -111,6 +118,17 @@
}, },
"modalEditServiceActivity": { "modalEditServiceActivity": {
"title": "Edit activity" "title": "Edit activity"
},
"popConfirmDeleteService": {
"title": "Delete service",
"description": "Are you sure you want to delete this service?"
},
"popConfirmDeleteServiceActivity": {
"title": "Delete activity",
"description": "Are you sure you want to delete this activity?"
} }
},
"calendar": {
"pageTitle": "Calendar"
} }
} }

View File

@ -0,0 +1,8 @@
import { Empty } from "antd";
import { useTranslation } from "react-i18next";
export function MyEmpty({ children }) {
const { t } = useTranslation();
return <Empty description={t("common.noDataFound")}>{children}</Empty>;
}

View File

@ -1,12 +1,166 @@
import { import {
CopyOutlined, DeleteOutlined,
EyeInvisibleOutlined, EditOutlined,
EyeOutlined, PlusOutlined,
ReloadOutlined, QuestionCircleOutlined,
} from "@ant-design/icons"; } from "@ant-design/icons";
import { Tooltip } from "antd"; import { Popconfirm, Tooltip } from "antd";
import { useState } from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
export function MyDeleteIcon({
propsPopconfirm,
propsTooltip,
onConfirm,
onFetchSuccess,
popConfirmTitle,
popConfirmDescription,
onClick,
}) {
const { t } = useTranslation();
const [open, setOpen] = useState(false);
return (
<MyIcon
propsPopconfirm={{
...propsPopconfirm,
icon: <QuestionCircleOutlined style={{ color: "red" }} />,
open: open,
}}
propsTooltip={propsTooltip}
onConfirm={onConfirm}
onFetchSuccess={() => {
setOpen(false);
onFetchSuccess();
}}
onCancel={() => setOpen(false)}
popConfirmTitle={popConfirmTitle}
popConfirmDescription={popConfirmDescription}
popConfirmOkText={t("common.button.delete")}
tooltipTitle={t("common.tooltip.delete")}
icon={
<DeleteOutlined
onClick={(e) => {
setOpen(true);
if (onClick) onClick(e);
}}
/>
}
/>
);
}
export function MyEditIcon({ onClick }) {
const { t } = useTranslation();
return (
<MyIcon
popconfirmDisabled
tooltipTitle={t("common.tooltip.edit")}
icon={<EditOutlined onClick={onClick} />}
/>
);
}
export function MyPlusIcon({ onClick }) {
const { t } = useTranslation();
return (
<MyIcon
popconfirmDisabled
tooltipTitle={t("common.tooltip.add")}
icon={<PlusOutlined onClick={onClick} />}
/>
);
}
export function MyIcon({
popconfirmDisabled,
propsPopconfirm,
propsTooltip,
onConfirm,
onFetchSuccess,
onCancel,
popConfirmTitle,
popConfirmDescription,
popConfirmOkText,
tooltipTitle,
icon,
}) {
const { t } = useTranslation();
const [isRequesting, setIsRequesting] = useState(false);
const content = (
<Tooltip {...propsTooltip} title={tooltipTitle}>
{icon}
</Tooltip>
);
if (popconfirmDisabled) {
return content;
}
return (
<Popconfirm
{...propsPopconfirm}
title={popConfirmTitle}
description={popConfirmDescription}
okText={popConfirmOkText}
cancelText={t("common.button.cancel")}
okButtonProps={{ loading: isRequesting }}
onCancel={() => {
if (onCancel) onCancel();
}}
onConfirm={() => {
setIsRequesting(true);
onConfirm()
.then(() => {
setIsRequesting(false);
onFetchSuccess();
})
.catch(() => {
setIsRequesting(false);
});
}}
>
{content}
</Popconfirm>
);
}
/*
<Popconfirm
title={t(
"employees.popConfirmDeleteEmployee.title"
)}
description={t(
"employees.popConfirmDeleteEmployee.description"
)}
okText={t("common.button.delete")}
onConfirm={() => {
setIsRequesting(true);
myFetch("/users", "DELETE", {
userId: record.key,
})
.then(() => fetchEmployees())
.catch((errStatus) => {
console.log(errStatus);
setIsRequesting(false);
});
}}
>
<DeleteOutlined />
</Popconfirm>
*/
/*
export function MyCopyIcon({ text, notificationApi }) { export function MyCopyIcon({ text, notificationApi }) {
const { t } = useTranslation(); const { t } = useTranslation();
@ -48,3 +202,4 @@ export function MyReloadIcon({ onClick }) {
</Tooltip> </Tooltip>
); );
} }
*/

View File

@ -1,26 +1,13 @@
import { Table } from "antd"; import { Table } from "antd";
import { useTranslation } from "react-i18next"; import { MyEmpty } from "../MyEmpty";
export default function MyTable({ props }) { export default function MyTable({ props }) {
const { t } = useTranslation();
return ( return (
<Table <Table
{...props} {...props}
scroll={{ x: "max-content" }} scroll={{ x: "max-content" }}
locale={{ locale={{
emptyText: ( emptyText: <MyEmpty />,
<div
style={{
display: "flex",
justifyContent: "center",
alignItems: "center",
height: 110,
}}
>
{t("common.noDataFound")}
</div>
),
}} }}
/> />
); );

View File

@ -46,7 +46,55 @@ export default function Login() {
closable={false} closable={false}
centered centered
keyboard={false} keyboard={false}
footer={null} 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;
}
myFetch(
`/user/auth/${selectedMethod === "1" ? "login" : "signup"}`,
"POST",
body,
{},
myFetchContentType.JSON,
"",
true
)
.then((data) => {
console.log(data.XAuthorization);
setUserSessionToLocalStorage(data.XAuthorization);
window.location.href = "/";
})
.catch((errStatus) => {
showErrorNotification(errStatus);
setIsRequesting(false);
});
})
.catch((info) => {
console.log("Validate Failed:", info);
});
}}
>
{selectedMethod === "1" ? t("login.login") : t("login.signUp")}
</Button>
}
> >
<Tabs <Tabs
defaultActiveKey="1" defaultActiveKey="1"
@ -75,58 +123,6 @@ export default function Login() {
/> />
<MyPasswordFormInput /> <MyPasswordFormInput />
<div style={{ display: "flex", justifyContent: "flex-end" }}>
<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;
}
myFetch(
`/user/auth/${
selectedMethod === "1" ? "login" : "signup"
}`,
"POST",
body,
{},
myFetchContentType.JSON,
"",
true
)
.then((data) => {
console.log(data.XAuthorization);
setUserSessionToLocalStorage(data.XAuthorization);
window.location.href = "/";
})
.catch((errStatus) => {
showErrorNotification(errStatus);
setIsRequesting(false);
});
})
.catch((info) => {
console.log("Validate Failed:", info);
});
}}
>
{selectedMethod === "1" ? t("login.login") : t("login.signUp")}
</Button>
</div>
</Form> </Form>
</Modal> </Modal>
</> </>

View File

@ -1,7 +1,11 @@
import { useTranslation } from "react-i18next";
export default function StoreCalendar() { export default function StoreCalendar() {
const { t } = useTranslation();
return ( return (
<> <>
<h1>Calendar</h1> <h1>{t("calendar.pageTitle")}</h1>
</> </>
); );
} }

View File

@ -1,21 +1,16 @@
import { import { PlusOutlined } from "@ant-design/icons";
ArrowDownOutlined,
ArrowUpOutlined,
DeleteOutlined,
EditOutlined,
PlusOutlined,
} from "@ant-design/icons";
import { import {
Avatar, Avatar,
Button, Button,
Card, Card,
Collapse, Collapse,
Empty,
Form, Form,
Grid, Grid,
Skeleton, Skeleton,
Space, Space,
Spin,
Tooltip, Tooltip,
Typography,
} from "antd"; } from "antd";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { useEffect, useState } from "react"; import { useEffect, useState } from "react";
@ -26,6 +21,13 @@ import MyModal, {
MyModalCloseSaveButtonFooter, MyModalCloseSaveButtonFooter,
} from "../../../Components/MyModal"; } from "../../../Components/MyModal";
import { MyFormInput } from "../../../Components/MyFormInputs"; import { MyFormInput } from "../../../Components/MyFormInputs";
import MyTable from "../../../Components/MyTable";
import {
MyDeleteIcon,
MyEditIcon,
MyPlusIcon,
} from "../../../Components/MyIcon";
import { MyEmpty } from "../../../Components/MyEmpty";
const { useBreakpoint } = Grid; const { useBreakpoint } = Grid;
@ -89,11 +91,21 @@ export default function StoreServices() {
<Space direction="vertical" style={{ width: "100%" }}> <Space direction="vertical" style={{ width: "100%" }}>
{isRequestingServices ? ( {isRequestingServices ? (
<> <>
<Skeleton.Input block active size="large" /> {/* <Skeleton.Input block active size="large" />
<Skeleton.Input block active size="large" /> <Skeleton.Input block active size="large" />
<Skeleton.Input block active size="large" /> <Skeleton.Input block active size="large" /> */}
<div
style={{
display: "flex",
justifyContent: "center",
paddingTop: 70,
}}
>
<Spin />
</div>
</> </>
) : ( ) : servicesData.services.length > 0 ? (
<> <>
{servicesData.services.map((service) => ( {servicesData.services.map((service) => (
<Service <Service
@ -105,9 +117,12 @@ export default function StoreServices() {
setAddEditServiceActivityModalOptions setAddEditServiceActivityModalOptions
} }
setAddEditServiceModalOptions={setAddEditServiceModalOptions} setAddEditServiceModalOptions={setAddEditServiceModalOptions}
fetchServices={fetchServices}
/> />
))} ))}
</> </>
) : (
<MyEmpty />
)} )}
</Space> </Space>
@ -117,6 +132,7 @@ export default function StoreServices() {
setAddEditServiceActivityModalOptions={ setAddEditServiceActivityModalOptions={
setAddEditServiceActivityModalOptions setAddEditServiceActivityModalOptions
} }
users={servicesData.users}
/> />
</> </>
); );
@ -128,7 +144,10 @@ function Service({
storeId, storeId,
setAddEditServiceActivityModalOptions, setAddEditServiceActivityModalOptions,
setAddEditServiceModalOptions, setAddEditServiceModalOptions,
fetchServices,
}) { }) {
const { t } = useTranslation();
const [isRequestingActivities, setIsRequestingActivities] = useState(false); const [isRequestingActivities, setIsRequestingActivities] = useState(false);
const [isOpen, setIsOpen] = useState(false); const [isOpen, setIsOpen] = useState(false);
@ -172,15 +191,17 @@ function Service({
<span>{service.name}</span> <span>{service.name}</span>
<Space> <Space>
<ArrowUpOutlined {/*
<ArrowUpOutlined
disabled disabled
onClick={(e) => e.stopPropagation()} onClick={(e) => e.stopPropagation()}
/> />
<ArrowDownOutlined <ArrowDownOutlined
disabled disabled
onClick={(e) => e.stopPropagation()} onClick={(e) => e.stopPropagation()}
/> />
<PlusOutlined */}
<MyPlusIcon
onClick={(e) => { onClick={(e) => {
e.stopPropagation(); e.stopPropagation();
@ -191,7 +212,8 @@ function Service({
}); });
}} }}
/> />
<EditOutlined
<MyEditIcon
onClick={(e) => { onClick={(e) => {
e.stopPropagation(); e.stopPropagation();
@ -202,7 +224,25 @@ function Service({
}); });
}} }}
/> />
<DeleteOutlined onClick={(e) => e.stopPropagation()} /> <MyDeleteIcon
onClick={(e) => e.stopPropagation()}
propsPopconfirm={{
placement: "left",
}}
onConfirm={() => {
return myFetch(
`/store/services/${service.service_id}`,
"DELETE"
);
}}
onFetchSuccess={fetchServices}
popConfirmTitle={t(
"storeServices.popConfirmDeleteService.title"
)}
popConfirmDescription={t(
"storeServices.popConfirmDeleteService.description"
)}
/>
</Space> </Space>
</div> </div>
), ),
@ -223,50 +263,98 @@ function Service({
) : ( ) : (
<> <>
{serviceActivities.length === 0 ? ( {serviceActivities.length === 0 ? (
<Empty /> <MyEmpty />
) : ( ) : (
serviceActivities.map((activity) => ( serviceActivities.map((activity) => {
<Card let userList = [];
key={activity.activity_id}
title={activity.name}
extra={
<Space>
<Avatar.Group maxCount={1} size="small">
{users.map((user) => (
<Tooltip
key={user.user_id}
title={user.username}
>
<Avatar
size="small"
style={{ backgroundColor: "#87d068" }}
>
{user.username.charAt(0)}
</Avatar>
</Tooltip>
))}
</Avatar.Group>
<ArrowUpOutlined disabled /> if (activity.StoreServiceActivityUsers.length > 0) {
<ArrowDownOutlined disabled /> // StoreServiceActivityUsers is only an array of user_ids
<EditOutlined // we need to get the user object from the users array
onClick={() => {
setAddEditServiceActivityModalOptions({ for (let i = 0; i < users.length; i++) {
mode: "edit", for (
isOpen: true, let j = 0;
activity: activity, j < activity.StoreServiceActivityUsers.length;
}); j++
}} ) {
/> if (
<DeleteOutlined /> users[i].user_id ===
</Space> activity.StoreServiceActivityUsers[j].user_id
) {
userList.push(users[i]);
}
}
} }
> } else {
<p>{activity.description}</p> // if there are no users assigned to this activity, we just use the whole users array
<p>Preis: {activity.price} </p> userList = users;
<p>Dauer: {activity.duration} Minuten</p> }
</Card>
)) return (
<Card
key={activity.activity_id}
title={activity.name}
extra={
<Space>
<Avatar.Group maxCount={2} size="small">
{userList.map((user) => (
<Tooltip
key={user.user_id}
title={user.username}
>
<Avatar
size="small"
style={{ backgroundColor: "#87d068" }}
>
{user.username.charAt(0)}
</Avatar>
</Tooltip>
))}
</Avatar.Group>
{/*
<ArrowUpOutlined disabled />
<ArrowDownOutlined disabled />
*/}
<MyEditIcon
onClick={() => {
setAddEditServiceActivityModalOptions({
mode: "edit",
isOpen: true,
activity: activity,
});
}}
/>
<MyDeleteIcon
propsPopconfirm={{
placement: "left",
}}
onConfirm={() => {
return myFetch(
`/store/services/activity/${activity.activity_id}`,
"DELETE"
);
}}
onFetchSuccess={fetchServiceActivities}
popConfirmTitle={t(
"storeServices.popConfirmDeleteServiceActivity.title"
)}
popConfirmDescription={t(
"storeServices.popConfirmDeleteServiceActivity.description"
)}
/>
</Space>
}
>
<p>{activity.description}</p>
<p>Preis: {activity.price} </p>
<p>Dauer: {activity.duration} Minuten</p>
</Card>
);
})
)} )}
</> </>
)} )}
@ -413,26 +501,17 @@ function ModalAddEditService({
); );
} }
let defaultModalAddServiceFormValidOptions = {
serviceActivityName: false,
serviceActivityDescription: false,
serviceActivityPrice: false,
serviceActivityDurationHours: false,
serviceActivityDurationMinutes: false,
};
function ModalAddEditServiceActivity({ function ModalAddEditServiceActivity({
fetchServices, fetchServices,
addEditServiceActivityModalOptions, addEditServiceActivityModalOptions,
setAddEditServiceActivityModalOptions, setAddEditServiceActivityModalOptions,
users,
}) { }) {
const { t } = useTranslation(); const { t } = useTranslation();
const [isFormValid, setIsFormValid] = useState(
defaultModalAddServiceFormValidOptions
);
const [form] = Form.useForm(); const [form] = Form.useForm();
const [isRequesting, setIsRequesting] = useState(false); const [isRequesting, setIsRequesting] = useState(false);
const [selectedEmployeesRowKeys, setSelectedEmployeesRowKeys] = useState([]);
const handleModalClose = () => { const handleModalClose = () => {
setAddEditServiceActivityModalOptions({ setAddEditServiceActivityModalOptions({
@ -443,21 +522,28 @@ function ModalAddEditServiceActivity({
form.resetFields(); form.resetFields();
}; };
const getTableColumns = () => {
return [
{
title: t("common.username"),
dataIndex: "username",
key: "username",
},
];
};
const getTableItems = () => {
return users.map((user) => {
return {
key: user.user_id,
username: user.username,
};
});
};
useEffect(() => { useEffect(() => {
if (!addEditServiceActivityModalOptions.isOpen) return; if (!addEditServiceActivityModalOptions.isOpen) return;
setIsFormValid(
addEditServiceActivityModalOptions.mode === "add"
? defaultModalAddServiceFormValidOptions
: {
serviceActivityName: true,
serviceActivityDescription: true,
serviceActivityPrice: true,
serviceActivityDurationHours: true,
serviceActivityDurationMinutes: true,
}
);
if (addEditServiceActivityModalOptions.mode === "edit") { if (addEditServiceActivityModalOptions.mode === "edit") {
form.setFieldsValue({ form.setFieldsValue({
serviceActivityName: addEditServiceActivityModalOptions.activity.name, serviceActivityName: addEditServiceActivityModalOptions.activity.name,
@ -470,6 +556,21 @@ function ModalAddEditServiceActivity({
serviceActivityDurationMinutes: serviceActivityDurationMinutes:
addEditServiceActivityModalOptions.activity.duration % 60, addEditServiceActivityModalOptions.activity.duration % 60,
}); });
setSelectedEmployeesRowKeys(
addEditServiceActivityModalOptions.activity.StoreServiceActivityUsers
.length === 0
? users.map((user) => user.user_id)
: addEditServiceActivityModalOptions.activity.StoreServiceActivityUsers.map(
(user) => user.user_id
)
);
} else {
form.setFieldsValue({
serviceActivityDurationHours: 0,
});
setSelectedEmployeesRowKeys(users.map((user) => user.user_id));
} }
}, [addEditServiceActivityModalOptions.isOpen]); }, [addEditServiceActivityModalOptions.isOpen]);
@ -486,87 +587,146 @@ function ModalAddEditServiceActivity({
addEditServiceActivityModalOptions.mode === "add" ? ( addEditServiceActivityModalOptions.mode === "add" ? (
<MyModalCloseCreateButtonFooter <MyModalCloseCreateButtonFooter
onCancel={handleModalClose} onCancel={handleModalClose}
isCreateButtonDisabled={
!isFormValid.serviceActivityName ||
!isFormValid.serviceActivityDescription ||
!isFormValid.serviceActivityPrice ||
!isFormValid.serviceActivityDurationHours ||
!isFormValid.serviceActivityDurationMinutes
}
isCreateButtonLoading={isRequesting} isCreateButtonLoading={isRequesting}
onCreate={() => { onCreate={() => {
setIsRequesting(true); form
.validateFields()
.then((values) => {
setIsRequesting(true);
myFetch("/store/services/activity", "POST", { myFetch("/store/services/activity", "POST", {
serviceId: serviceId:
addEditServiceActivityModalOptions.service.service_id, addEditServiceActivityModalOptions.service.service_id,
name: form.getFieldValue("serviceActivityName"), name: values.serviceActivityName,
description: form.getFieldValue("serviceActivityDescription"), description: values.serviceActivityDescription,
price: form.getFieldValue("serviceActivityPrice"), price: values.serviceActivityPrice,
duration: duration:
form.getFieldValue("serviceActivityDurationHours") * 60 + values.serviceActivityDurationHours * 60 +
form.getFieldValue("serviceActivityDurationMinutes"), values.serviceActivityDurationMinutes,
}) userIds:
.then(() => { selectedEmployeesRowKeys.length === users.length
setIsRequesting(false); ? []
handleModalClose(); : selectedEmployeesRowKeys,
})
.then(() => {
setIsRequesting(false);
handleModalClose();
fetchServices(); fetchServices();
})
.catch((errStatus) => {
console.log(errStatus);
});
}) })
.catch((errStatus) => { .catch((info) => {
console.log(errStatus); console.log("Validate Failed:", info);
}); });
}} }}
/> />
) : ( ) : (
<MyModalCloseSaveButtonFooter <MyModalCloseSaveButtonFooter
onCancel={handleModalClose} onCancel={handleModalClose}
isSaveButtonDisabled={
!isFormValid.serviceActivityName ||
!isFormValid.serviceActivityDescription ||
!isFormValid.serviceActivityPrice ||
!isFormValid.serviceActivityDurationHours ||
!isFormValid.serviceActivityDurationMinutes
}
isSaveButtonLoading={isRequesting} isSaveButtonLoading={isRequesting}
onSave={() => { onSave={() => {
const formServiceActivityName = form.getFieldValue(
"serviceActivityName"
);
const formServiceActivityDescription = form.getFieldValue(
"serviceActivityDescription"
);
const formServiceActivityPrice = form.getFieldValue(
"serviceActivityPrice"
);
const formServiceActivityDurationHours = form.getFieldValue(
"serviceActivityDurationHours"
);
const formServiceActivityDurationMinutes = form.getFieldValue(
"serviceActivityDurationMinutes"
);
// if the service name didn't change, don't send a request // if the service name didn't change, don't send a request
if ( if (
addEditServiceActivityModalOptions.activity.name === addEditServiceActivityModalOptions.activity.name ===
form.getFieldValue("serviceActivityName") && formServiceActivityName &&
addEditServiceActivityModalOptions.activity.description === addEditServiceActivityModalOptions.activity.description ===
form.getFieldValue("serviceActivityDescription") && formServiceActivityDescription &&
addEditServiceActivityModalOptions.activity.price === addEditServiceActivityModalOptions.activity.price ===
form.getFieldValue("serviceActivityPrice") && formServiceActivityPrice &&
addEditServiceActivityModalOptions.activity.duration === addEditServiceActivityModalOptions.activity.duration ===
form.getFieldValue("serviceActivityDurationHours") * 60 + formServiceActivityDurationHours * 60 +
form.getFieldValue("serviceActivityDurationMinutes") formServiceActivityDurationMinutes &&
(selectedEmployeesRowKeys.length === users.length ||
addEditServiceActivityModalOptions.activity
.StoreServiceActivityUsers.length ===
selectedEmployeesRowKeys.length)
) { ) {
handleModalClose(); handleModalClose();
console.log("same");
return; return;
} }
setIsRequesting(true); let validateFields = [];
let body = {
myFetch("/store/services/activity/update", "POST", {
activityId: activityId:
addEditServiceActivityModalOptions.activity.activity_id, addEditServiceActivityModalOptions.activity.activity_id,
name: form.getFieldValue("serviceActivityName"), };
description: form.getFieldValue("serviceActivityDescription"),
price: form.getFieldValue("serviceActivityPrice"),
duration:
form.getFieldValue("serviceActivityDurationHours") * 60 +
form.getFieldValue("serviceActivityDurationMinutes"),
})
.then(() => {
setIsRequesting(false);
handleModalClose();
fetchServices(); if (
formServiceActivityName !==
addEditServiceActivityModalOptions.activity.name
) {
validateFields.push("serviceActivityName");
body.name = formServiceActivityName;
}
if (
formServiceActivityDescription !==
addEditServiceActivityModalOptions.activity.description
) {
validateFields.push("serviceActivityDescription");
body.description = formServiceActivityDescription;
}
if (
formServiceActivityPrice !==
addEditServiceActivityModalOptions.activity.price
) {
validateFields.push("serviceActivityPrice");
body.price = formServiceActivityPrice;
}
let formDuration =
formServiceActivityDurationHours * 60 +
formServiceActivityDurationMinutes;
if (
formDuration !==
addEditServiceActivityModalOptions.activity.duration
) {
validateFields.push("serviceActivityDurationHours");
validateFields.push("serviceActivityDurationMinutes");
body.duration = formDuration;
}
body.userIds = selectedEmployeesRowKeys;
form
.validateFields()
.then(() => {
setIsRequesting(true);
myFetch("/store/services/activity/update", "POST", body)
.then(() => {
setIsRequesting(false);
handleModalClose();
fetchServices();
})
.catch((errStatus) => {
console.log(errStatus);
});
}) })
.catch((errStatus) => { .catch((info) => {
console.log(errStatus); console.log("Validate Failed:", info);
}); });
}} }}
/> />
@ -574,55 +734,36 @@ function ModalAddEditServiceActivity({
} }
> >
<Form form={form} layout="vertical" requiredMark={false}> <Form form={form} layout="vertical" requiredMark={false}>
<ServiceActivityNameFormInput <ServiceActivityNameFormInput formItemName="serviceActivityName" />
formItemName="serviceActivityName"
setIsInputValid={(isValid) =>
setIsFormValid({
...isFormValid,
serviceActivityName: isValid,
})
}
/>
<ServiceActivityDescriptionFormInput <ServiceActivityDescriptionFormInput formItemName="serviceActivityDescription" />
formItemName="serviceActivityDescription"
setIsInputValid={(isValid) =>
setIsFormValid({
...isFormValid,
serviceActivityDescription: isValid,
})
}
/>
<ServiceActivityPriceFormInput <ServiceActivityPriceFormInput formItemName="serviceActivityPrice" />
formItemName="serviceActivityPrice"
setIsInputValid={(isValid) =>
setIsFormValid({
...isFormValid,
serviceActivityPrice: isValid,
})
}
/>
<ServiceActivityDurationHoursFormInput <ServiceActivityDurationHoursFormInput formItemName="serviceActivityDurationHours" />
formItemName="serviceActivityDurationHours"
setIsInputValid={(isValid) =>
setIsFormValid({
...isFormValid,
serviceActivityDurationHours: isValid,
})
}
/>
<ServiceActivityDurationMinutesFormInput <ServiceActivityDurationMinutesFormInput formItemName="serviceActivityDurationMinutes" />
formItemName="serviceActivityDurationMinutes"
setIsInputValid={(isValid) => <Space direction="vertical" style={{ width: "100%" }}>
setIsFormValid({ <Typography.Text>
...isFormValid, {t("storeServices.serviceActivityResponsible")}
serviceActivityDurationMinutes: isValid, </Typography.Text>
})
} <MyTable
/> props={{
rowSelection: {
selectedRowKeys: selectedEmployeesRowKeys,
onChange: (newSelectedRowKeys) =>
setSelectedEmployeesRowKeys(newSelectedRowKeys),
},
loading: isRequesting,
columns: getTableColumns(),
dataSource: getTableItems(),
size: "small",
pagination: false,
}}
/>
</Space>
</Form> </Form>
</MyModal> </MyModal>
); );
@ -651,13 +792,12 @@ function ServiceNameFormInput({ formItemName }) {
); );
} }
function ServiceActivityNameFormInput({ formItemName, setIsInputValid }) { function ServiceActivityNameFormInput({ formItemName }) {
const { t } = useTranslation(); const { t } = useTranslation();
return ( return (
<MyFormInput <MyFormInput
formItemName={formItemName} formItemName={formItemName}
setIsInputValid={setIsInputValid}
minLength={Constants.GLOBALS.MIN_STORE_SERVICE_ACTIVITY_NAME_LENGTH} minLength={Constants.GLOBALS.MIN_STORE_SERVICE_ACTIVITY_NAME_LENGTH}
maxLength={Constants.GLOBALS.MAX_STORE_SERVICE_ACTIVITY_NAME_LENGTH} maxLength={Constants.GLOBALS.MAX_STORE_SERVICE_ACTIVITY_NAME_LENGTH}
label={t("storeServices.serviceActivityName")} label={t("storeServices.serviceActivityName")}
@ -710,7 +850,7 @@ function ServiceActivityDescriptionFormInput({
); );
} }
function ServiceActivityPriceFormInput({ formItemName, setIsInputValid }) { function ServiceActivityPriceFormInput({ formItemName }) {
const { t } = useTranslation(); const { t } = useTranslation();
return ( return (
@ -720,7 +860,6 @@ function ServiceActivityPriceFormInput({ formItemName, setIsInputValid }) {
}} }}
inputType="number" inputType="number"
formItemName={formItemName} formItemName={formItemName}
setIsInputValid={setIsInputValid}
minLength={Constants.GLOBALS.MIN_STORE_SERVICE_ACTIVITY_PRICE} minLength={Constants.GLOBALS.MIN_STORE_SERVICE_ACTIVITY_PRICE}
maxLength={Constants.GLOBALS.MAX_STORE_SERVICE_ACTIVITY_PRICE} maxLength={Constants.GLOBALS.MAX_STORE_SERVICE_ACTIVITY_PRICE}
label={t("storeServices.serviceActivityPrice")} label={t("storeServices.serviceActivityPrice")}

View File

@ -13,8 +13,6 @@ export default function UserProfile({ userSession, setUserSession }) {
<Button <Button
type="primary" type="primary"
onClick={() => { onClick={() => {
console.log("Logout");
setUserSession(); setUserSession();
window.location.href = "/"; window.location.href = "/";
@ -27,7 +25,7 @@ export default function UserProfile({ userSession, setUserSession }) {
}).catch(console.error); }).catch(console.error);
}} }}
> >
Logout {t("common.button.logout")}
</Button> </Button>
} }
> >

View File

@ -54,7 +54,6 @@ export const Constants = {
SUPPORT: "/support", SUPPORT: "/support",
USER_PROFILE: "/user-profile", USER_PROFILE: "/user-profile",
}, },
GLOBALS: { GLOBALS: {
MIN_USERNAME_LENGTH: 3, MIN_USERNAME_LENGTH: 3,
MAX_USERNAME_LENGTH: 20, MAX_USERNAME_LENGTH: 20,
@ -73,7 +72,7 @@ export const Constants = {
MIN_STORE_SERVICE_ACTIVITY_DURATION_HOURS: 0, MIN_STORE_SERVICE_ACTIVITY_DURATION_HOURS: 0,
MAX_STORE_SERVICE_ACTIVITY_DURATION_HOURS: 23, MAX_STORE_SERVICE_ACTIVITY_DURATION_HOURS: 23,
MIN_STORE_SERVICE_ACTIVITY_DURATION_MINUTES: 0, MIN_STORE_SERVICE_ACTIVITY_DURATION_MINUTES: 0,
MAX_STORE_SERVICE_ACTIVITY_DURATION_MINUTES: 60, MAX_STORE_SERVICE_ACTIVITY_DURATION_MINUTES: 59,
}, },
DELAY_ACCOUNT_NAME_CHECK: 250, DELAY_ACCOUNT_NAME_CHECK: 250,
MAX_AVATAR_SIZE: 5 * 1024 * 1024, MAX_AVATAR_SIZE: 5 * 1024 * 1024,