services
parent
a3c979c5b7
commit
ec9516e5e4
|
@ -7,7 +7,13 @@
|
|||
"delete": "Löschen",
|
||||
"confirm": "Bestätigen",
|
||||
"create": "Erstellen",
|
||||
"edit": "Bearbeiten"
|
||||
"edit": "Bearbeiten",
|
||||
"logout": "Abmelden"
|
||||
},
|
||||
"tooltip": {
|
||||
"edit": "Bearbeiten",
|
||||
"delete": "Löschen",
|
||||
"add": "Hinzufügen"
|
||||
},
|
||||
"action": "Aktion",
|
||||
"contactAdmin": "Bitte kontaktieren Sie einen Administrator",
|
||||
|
@ -86,6 +92,7 @@
|
|||
"serviceActivityDurationMinutes": "Dauer der Tätigkeit (Minuten)",
|
||||
"serviceActivityDurationMinutesPlaceholder": "Geben Sie die Dauer der Tätigkeit in Minuten ein",
|
||||
"serviceActivityDurationMinutesUnit": "Minuten",
|
||||
"serviceActivityResponsible": "Verantwortliche Mitarbeiter",
|
||||
"inputRules": {
|
||||
"serviceNameRequired": "Name der Dienstleistung ist erforderlich",
|
||||
"serviceNameMinLength": "Name der Dienstleistung muss mindestens {{minLength}} Zeichen lang sein",
|
||||
|
@ -108,6 +115,17 @@
|
|||
},
|
||||
"modalEditServiceActivity": {
|
||||
"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"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,7 +7,13 @@
|
|||
"delete": "Delete",
|
||||
"confirm": "Confirm",
|
||||
"create": "Create",
|
||||
"edit": "Edit"
|
||||
"edit": "Edit",
|
||||
"logout": "Logout"
|
||||
},
|
||||
"tooltip": {
|
||||
"edit": "Edit",
|
||||
"delete": "Delete",
|
||||
"add": "Add"
|
||||
},
|
||||
"action": "Action",
|
||||
"contactAdmin": "Please contact an administrator",
|
||||
|
@ -89,6 +95,7 @@
|
|||
"serviceActivityDurationMinutes": "Duration of activity (minutes)",
|
||||
"serviceActivityDurationMinutesPlaceholder": "Enter the duration of the activity in minutes",
|
||||
"serviceActivityDurationMinutesUnit": "Minutes",
|
||||
"serviceActivityResponsible": "Responsible employees",
|
||||
"inputRules": {
|
||||
"serviceNameRequired": "Service name is required",
|
||||
"serviceNameMinLength": "Service name must be at least {{minLength}} characters long",
|
||||
|
@ -111,6 +118,17 @@
|
|||
},
|
||||
"modalEditServiceActivity": {
|
||||
"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"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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>;
|
||||
}
|
|
@ -1,12 +1,166 @@
|
|||
import {
|
||||
CopyOutlined,
|
||||
EyeInvisibleOutlined,
|
||||
EyeOutlined,
|
||||
ReloadOutlined,
|
||||
DeleteOutlined,
|
||||
EditOutlined,
|
||||
PlusOutlined,
|
||||
QuestionCircleOutlined,
|
||||
} from "@ant-design/icons";
|
||||
import { Tooltip } from "antd";
|
||||
import { Popconfirm, Tooltip } from "antd";
|
||||
import { useState } from "react";
|
||||
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 }) {
|
||||
const { t } = useTranslation();
|
||||
|
||||
|
@ -48,3 +202,4 @@ export function MyReloadIcon({ onClick }) {
|
|||
</Tooltip>
|
||||
);
|
||||
}
|
||||
*/
|
||||
|
|
|
@ -1,26 +1,13 @@
|
|||
import { Table } from "antd";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { MyEmpty } from "../MyEmpty";
|
||||
|
||||
export default function MyTable({ props }) {
|
||||
const { t } = useTranslation();
|
||||
|
||||
return (
|
||||
<Table
|
||||
{...props}
|
||||
scroll={{ x: "max-content" }}
|
||||
locale={{
|
||||
emptyText: (
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
justifyContent: "center",
|
||||
alignItems: "center",
|
||||
height: 110,
|
||||
}}
|
||||
>
|
||||
{t("common.noDataFound")}
|
||||
</div>
|
||||
),
|
||||
emptyText: <MyEmpty />,
|
||||
}}
|
||||
/>
|
||||
);
|
||||
|
|
|
@ -46,7 +46,55 @@ export default function Login() {
|
|||
closable={false}
|
||||
centered
|
||||
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
|
||||
defaultActiveKey="1"
|
||||
|
@ -75,58 +123,6 @@ export default function Login() {
|
|||
/>
|
||||
|
||||
<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>
|
||||
</Modal>
|
||||
</>
|
||||
|
|
|
@ -1,7 +1,11 @@
|
|||
import { useTranslation } from "react-i18next";
|
||||
|
||||
export default function StoreCalendar() {
|
||||
const { t } = useTranslation();
|
||||
|
||||
return (
|
||||
<>
|
||||
<h1>Calendar</h1>
|
||||
<h1>{t("calendar.pageTitle")}</h1>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1,21 +1,16 @@
|
|||
import {
|
||||
ArrowDownOutlined,
|
||||
ArrowUpOutlined,
|
||||
DeleteOutlined,
|
||||
EditOutlined,
|
||||
PlusOutlined,
|
||||
} from "@ant-design/icons";
|
||||
import { PlusOutlined } from "@ant-design/icons";
|
||||
import {
|
||||
Avatar,
|
||||
Button,
|
||||
Card,
|
||||
Collapse,
|
||||
Empty,
|
||||
Form,
|
||||
Grid,
|
||||
Skeleton,
|
||||
Space,
|
||||
Spin,
|
||||
Tooltip,
|
||||
Typography,
|
||||
} from "antd";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { useEffect, useState } from "react";
|
||||
|
@ -26,6 +21,13 @@ import MyModal, {
|
|||
MyModalCloseSaveButtonFooter,
|
||||
} from "../../../Components/MyModal";
|
||||
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;
|
||||
|
||||
|
@ -89,11 +91,21 @@ export default function StoreServices() {
|
|||
<Space direction="vertical" style={{ width: "100%" }}>
|
||||
{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) => (
|
||||
<Service
|
||||
|
@ -105,9 +117,12 @@ export default function StoreServices() {
|
|||
setAddEditServiceActivityModalOptions
|
||||
}
|
||||
setAddEditServiceModalOptions={setAddEditServiceModalOptions}
|
||||
fetchServices={fetchServices}
|
||||
/>
|
||||
))}
|
||||
</>
|
||||
) : (
|
||||
<MyEmpty />
|
||||
)}
|
||||
</Space>
|
||||
|
||||
|
@ -117,6 +132,7 @@ export default function StoreServices() {
|
|||
setAddEditServiceActivityModalOptions={
|
||||
setAddEditServiceActivityModalOptions
|
||||
}
|
||||
users={servicesData.users}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
|
@ -128,7 +144,10 @@ function Service({
|
|||
storeId,
|
||||
setAddEditServiceActivityModalOptions,
|
||||
setAddEditServiceModalOptions,
|
||||
fetchServices,
|
||||
}) {
|
||||
const { t } = useTranslation();
|
||||
|
||||
const [isRequestingActivities, setIsRequestingActivities] = useState(false);
|
||||
const [isOpen, setIsOpen] = useState(false);
|
||||
|
||||
|
@ -172,15 +191,17 @@ function Service({
|
|||
<span>{service.name}</span>
|
||||
|
||||
<Space>
|
||||
<ArrowUpOutlined
|
||||
{/*
|
||||
<ArrowUpOutlined
|
||||
disabled
|
||||
onClick={(e) => e.stopPropagation()}
|
||||
/>
|
||||
<ArrowDownOutlined
|
||||
disabled
|
||||
onClick={(e) => e.stopPropagation()}
|
||||
/>
|
||||
<PlusOutlined
|
||||
/>
|
||||
*/}
|
||||
<MyPlusIcon
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
|
||||
|
@ -191,7 +212,8 @@ function Service({
|
|||
});
|
||||
}}
|
||||
/>
|
||||
<EditOutlined
|
||||
|
||||
<MyEditIcon
|
||||
onClick={(e) => {
|
||||
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>
|
||||
</div>
|
||||
),
|
||||
|
@ -223,50 +263,98 @@ function Service({
|
|||
) : (
|
||||
<>
|
||||
{serviceActivities.length === 0 ? (
|
||||
<Empty />
|
||||
<MyEmpty />
|
||||
) : (
|
||||
serviceActivities.map((activity) => (
|
||||
<Card
|
||||
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>
|
||||
serviceActivities.map((activity) => {
|
||||
let userList = [];
|
||||
|
||||
<ArrowUpOutlined disabled />
|
||||
<ArrowDownOutlined disabled />
|
||||
<EditOutlined
|
||||
onClick={() => {
|
||||
setAddEditServiceActivityModalOptions({
|
||||
mode: "edit",
|
||||
isOpen: true,
|
||||
activity: activity,
|
||||
});
|
||||
}}
|
||||
/>
|
||||
<DeleteOutlined />
|
||||
</Space>
|
||||
if (activity.StoreServiceActivityUsers.length > 0) {
|
||||
// StoreServiceActivityUsers is only an array of user_ids
|
||||
// we need to get the user object from the users array
|
||||
|
||||
for (let i = 0; i < users.length; i++) {
|
||||
for (
|
||||
let j = 0;
|
||||
j < activity.StoreServiceActivityUsers.length;
|
||||
j++
|
||||
) {
|
||||
if (
|
||||
users[i].user_id ===
|
||||
activity.StoreServiceActivityUsers[j].user_id
|
||||
) {
|
||||
userList.push(users[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
>
|
||||
<p>{activity.description}</p>
|
||||
<p>Preis: {activity.price} €</p>
|
||||
<p>Dauer: {activity.duration} Minuten</p>
|
||||
</Card>
|
||||
))
|
||||
} else {
|
||||
// if there are no users assigned to this activity, we just use the whole users array
|
||||
userList = users;
|
||||
}
|
||||
|
||||
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({
|
||||
fetchServices,
|
||||
addEditServiceActivityModalOptions,
|
||||
setAddEditServiceActivityModalOptions,
|
||||
users,
|
||||
}) {
|
||||
const { t } = useTranslation();
|
||||
|
||||
const [isFormValid, setIsFormValid] = useState(
|
||||
defaultModalAddServiceFormValidOptions
|
||||
);
|
||||
const [form] = Form.useForm();
|
||||
const [isRequesting, setIsRequesting] = useState(false);
|
||||
const [selectedEmployeesRowKeys, setSelectedEmployeesRowKeys] = useState([]);
|
||||
|
||||
const handleModalClose = () => {
|
||||
setAddEditServiceActivityModalOptions({
|
||||
|
@ -443,21 +522,28 @@ function ModalAddEditServiceActivity({
|
|||
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(() => {
|
||||
if (!addEditServiceActivityModalOptions.isOpen) return;
|
||||
|
||||
setIsFormValid(
|
||||
addEditServiceActivityModalOptions.mode === "add"
|
||||
? defaultModalAddServiceFormValidOptions
|
||||
: {
|
||||
serviceActivityName: true,
|
||||
serviceActivityDescription: true,
|
||||
serviceActivityPrice: true,
|
||||
serviceActivityDurationHours: true,
|
||||
serviceActivityDurationMinutes: true,
|
||||
}
|
||||
);
|
||||
|
||||
if (addEditServiceActivityModalOptions.mode === "edit") {
|
||||
form.setFieldsValue({
|
||||
serviceActivityName: addEditServiceActivityModalOptions.activity.name,
|
||||
|
@ -470,6 +556,21 @@ function ModalAddEditServiceActivity({
|
|||
serviceActivityDurationMinutes:
|
||||
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]);
|
||||
|
||||
|
@ -486,87 +587,146 @@ function ModalAddEditServiceActivity({
|
|||
addEditServiceActivityModalOptions.mode === "add" ? (
|
||||
<MyModalCloseCreateButtonFooter
|
||||
onCancel={handleModalClose}
|
||||
isCreateButtonDisabled={
|
||||
!isFormValid.serviceActivityName ||
|
||||
!isFormValid.serviceActivityDescription ||
|
||||
!isFormValid.serviceActivityPrice ||
|
||||
!isFormValid.serviceActivityDurationHours ||
|
||||
!isFormValid.serviceActivityDurationMinutes
|
||||
}
|
||||
isCreateButtonLoading={isRequesting}
|
||||
onCreate={() => {
|
||||
setIsRequesting(true);
|
||||
form
|
||||
.validateFields()
|
||||
.then((values) => {
|
||||
setIsRequesting(true);
|
||||
|
||||
myFetch("/store/services/activity", "POST", {
|
||||
serviceId:
|
||||
addEditServiceActivityModalOptions.service.service_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();
|
||||
myFetch("/store/services/activity", "POST", {
|
||||
serviceId:
|
||||
addEditServiceActivityModalOptions.service.service_id,
|
||||
name: values.serviceActivityName,
|
||||
description: values.serviceActivityDescription,
|
||||
price: values.serviceActivityPrice,
|
||||
duration:
|
||||
values.serviceActivityDurationHours * 60 +
|
||||
values.serviceActivityDurationMinutes,
|
||||
userIds:
|
||||
selectedEmployeesRowKeys.length === users.length
|
||||
? []
|
||||
: selectedEmployeesRowKeys,
|
||||
})
|
||||
.then(() => {
|
||||
setIsRequesting(false);
|
||||
handleModalClose();
|
||||
|
||||
fetchServices();
|
||||
fetchServices();
|
||||
})
|
||||
.catch((errStatus) => {
|
||||
console.log(errStatus);
|
||||
});
|
||||
})
|
||||
.catch((errStatus) => {
|
||||
console.log(errStatus);
|
||||
.catch((info) => {
|
||||
console.log("Validate Failed:", info);
|
||||
});
|
||||
}}
|
||||
/>
|
||||
) : (
|
||||
<MyModalCloseSaveButtonFooter
|
||||
onCancel={handleModalClose}
|
||||
isSaveButtonDisabled={
|
||||
!isFormValid.serviceActivityName ||
|
||||
!isFormValid.serviceActivityDescription ||
|
||||
!isFormValid.serviceActivityPrice ||
|
||||
!isFormValid.serviceActivityDurationHours ||
|
||||
!isFormValid.serviceActivityDurationMinutes
|
||||
}
|
||||
isSaveButtonLoading={isRequesting}
|
||||
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 (
|
||||
addEditServiceActivityModalOptions.activity.name ===
|
||||
form.getFieldValue("serviceActivityName") &&
|
||||
formServiceActivityName &&
|
||||
addEditServiceActivityModalOptions.activity.description ===
|
||||
form.getFieldValue("serviceActivityDescription") &&
|
||||
formServiceActivityDescription &&
|
||||
addEditServiceActivityModalOptions.activity.price ===
|
||||
form.getFieldValue("serviceActivityPrice") &&
|
||||
formServiceActivityPrice &&
|
||||
addEditServiceActivityModalOptions.activity.duration ===
|
||||
form.getFieldValue("serviceActivityDurationHours") * 60 +
|
||||
form.getFieldValue("serviceActivityDurationMinutes")
|
||||
formServiceActivityDurationHours * 60 +
|
||||
formServiceActivityDurationMinutes &&
|
||||
(selectedEmployeesRowKeys.length === users.length ||
|
||||
addEditServiceActivityModalOptions.activity
|
||||
.StoreServiceActivityUsers.length ===
|
||||
selectedEmployeesRowKeys.length)
|
||||
) {
|
||||
handleModalClose();
|
||||
console.log("same");
|
||||
return;
|
||||
}
|
||||
|
||||
setIsRequesting(true);
|
||||
|
||||
myFetch("/store/services/activity/update", "POST", {
|
||||
let validateFields = [];
|
||||
let body = {
|
||||
activityId:
|
||||
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) => {
|
||||
console.log(errStatus);
|
||||
.catch((info) => {
|
||||
console.log("Validate Failed:", info);
|
||||
});
|
||||
}}
|
||||
/>
|
||||
|
@ -574,55 +734,36 @@ function ModalAddEditServiceActivity({
|
|||
}
|
||||
>
|
||||
<Form form={form} layout="vertical" requiredMark={false}>
|
||||
<ServiceActivityNameFormInput
|
||||
formItemName="serviceActivityName"
|
||||
setIsInputValid={(isValid) =>
|
||||
setIsFormValid({
|
||||
...isFormValid,
|
||||
serviceActivityName: isValid,
|
||||
})
|
||||
}
|
||||
/>
|
||||
<ServiceActivityNameFormInput formItemName="serviceActivityName" />
|
||||
|
||||
<ServiceActivityDescriptionFormInput
|
||||
formItemName="serviceActivityDescription"
|
||||
setIsInputValid={(isValid) =>
|
||||
setIsFormValid({
|
||||
...isFormValid,
|
||||
serviceActivityDescription: isValid,
|
||||
})
|
||||
}
|
||||
/>
|
||||
<ServiceActivityDescriptionFormInput formItemName="serviceActivityDescription" />
|
||||
|
||||
<ServiceActivityPriceFormInput
|
||||
formItemName="serviceActivityPrice"
|
||||
setIsInputValid={(isValid) =>
|
||||
setIsFormValid({
|
||||
...isFormValid,
|
||||
serviceActivityPrice: isValid,
|
||||
})
|
||||
}
|
||||
/>
|
||||
<ServiceActivityPriceFormInput formItemName="serviceActivityPrice" />
|
||||
|
||||
<ServiceActivityDurationHoursFormInput
|
||||
formItemName="serviceActivityDurationHours"
|
||||
setIsInputValid={(isValid) =>
|
||||
setIsFormValid({
|
||||
...isFormValid,
|
||||
serviceActivityDurationHours: isValid,
|
||||
})
|
||||
}
|
||||
/>
|
||||
<ServiceActivityDurationHoursFormInput formItemName="serviceActivityDurationHours" />
|
||||
|
||||
<ServiceActivityDurationMinutesFormInput
|
||||
formItemName="serviceActivityDurationMinutes"
|
||||
setIsInputValid={(isValid) =>
|
||||
setIsFormValid({
|
||||
...isFormValid,
|
||||
serviceActivityDurationMinutes: isValid,
|
||||
})
|
||||
}
|
||||
/>
|
||||
<ServiceActivityDurationMinutesFormInput formItemName="serviceActivityDurationMinutes" />
|
||||
|
||||
<Space direction="vertical" style={{ width: "100%" }}>
|
||||
<Typography.Text>
|
||||
{t("storeServices.serviceActivityResponsible")}
|
||||
</Typography.Text>
|
||||
|
||||
<MyTable
|
||||
props={{
|
||||
rowSelection: {
|
||||
selectedRowKeys: selectedEmployeesRowKeys,
|
||||
onChange: (newSelectedRowKeys) =>
|
||||
setSelectedEmployeesRowKeys(newSelectedRowKeys),
|
||||
},
|
||||
loading: isRequesting,
|
||||
columns: getTableColumns(),
|
||||
dataSource: getTableItems(),
|
||||
size: "small",
|
||||
pagination: false,
|
||||
}}
|
||||
/>
|
||||
</Space>
|
||||
</Form>
|
||||
</MyModal>
|
||||
);
|
||||
|
@ -651,13 +792,12 @@ function ServiceNameFormInput({ formItemName }) {
|
|||
);
|
||||
}
|
||||
|
||||
function ServiceActivityNameFormInput({ formItemName, setIsInputValid }) {
|
||||
function ServiceActivityNameFormInput({ formItemName }) {
|
||||
const { t } = useTranslation();
|
||||
|
||||
return (
|
||||
<MyFormInput
|
||||
formItemName={formItemName}
|
||||
setIsInputValid={setIsInputValid}
|
||||
minLength={Constants.GLOBALS.MIN_STORE_SERVICE_ACTIVITY_NAME_LENGTH}
|
||||
maxLength={Constants.GLOBALS.MAX_STORE_SERVICE_ACTIVITY_NAME_LENGTH}
|
||||
label={t("storeServices.serviceActivityName")}
|
||||
|
@ -710,7 +850,7 @@ function ServiceActivityDescriptionFormInput({
|
|||
);
|
||||
}
|
||||
|
||||
function ServiceActivityPriceFormInput({ formItemName, setIsInputValid }) {
|
||||
function ServiceActivityPriceFormInput({ formItemName }) {
|
||||
const { t } = useTranslation();
|
||||
|
||||
return (
|
||||
|
@ -720,7 +860,6 @@ function ServiceActivityPriceFormInput({ formItemName, setIsInputValid }) {
|
|||
}}
|
||||
inputType="number"
|
||||
formItemName={formItemName}
|
||||
setIsInputValid={setIsInputValid}
|
||||
minLength={Constants.GLOBALS.MIN_STORE_SERVICE_ACTIVITY_PRICE}
|
||||
maxLength={Constants.GLOBALS.MAX_STORE_SERVICE_ACTIVITY_PRICE}
|
||||
label={t("storeServices.serviceActivityPrice")}
|
||||
|
|
|
@ -13,8 +13,6 @@ export default function UserProfile({ userSession, setUserSession }) {
|
|||
<Button
|
||||
type="primary"
|
||||
onClick={() => {
|
||||
console.log("Logout");
|
||||
|
||||
setUserSession();
|
||||
window.location.href = "/";
|
||||
|
||||
|
@ -27,7 +25,7 @@ export default function UserProfile({ userSession, setUserSession }) {
|
|||
}).catch(console.error);
|
||||
}}
|
||||
>
|
||||
Logout
|
||||
{t("common.button.logout")}
|
||||
</Button>
|
||||
}
|
||||
>
|
||||
|
|
|
@ -54,7 +54,6 @@ export const Constants = {
|
|||
SUPPORT: "/support",
|
||||
USER_PROFILE: "/user-profile",
|
||||
},
|
||||
|
||||
GLOBALS: {
|
||||
MIN_USERNAME_LENGTH: 3,
|
||||
MAX_USERNAME_LENGTH: 20,
|
||||
|
@ -73,7 +72,7 @@ export const Constants = {
|
|||
MIN_STORE_SERVICE_ACTIVITY_DURATION_HOURS: 0,
|
||||
MAX_STORE_SERVICE_ACTIVITY_DURATION_HOURS: 23,
|
||||
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,
|
||||
MAX_AVATAR_SIZE: 5 * 1024 * 1024,
|
||||
|
|
Loading…
Reference in New Issue