customer-dashboard/src/Pages/Store/Services/index.js

1078 lines
35 KiB
JavaScript

import { CaretRightOutlined, PlusOutlined } from "@ant-design/icons";
import {
Avatar,
Button,
Card,
Collapse,
Flex,
Form,
Grid,
Skeleton,
Space,
Spin,
Tooltip,
Typography,
notification,
} from "antd";
import { useTranslation } from "react-i18next";
import { useEffect, useState } from "react";
import {
AppStyle,
Constants,
myFetch,
showInputsInvalidNotification,
} from "../../../utils";
import { useParams } from "react-router-dom";
import MyModal, {
MyModalCloseCreateButtonFooter,
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";
import CountUp from "react-countup";
const { useBreakpoint } = Grid;
export default function StoreServices() {
const { t } = useTranslation();
const [notificationApi, notificationContextHolder] =
notification.useNotification();
const screenBreakpoint = useBreakpoint();
const { storeId } = useParams();
const [isRequestingServices, setIsRequestingServices] = useState(false);
const [addEditServiceModalOptions, setAddEditServiceModalOptions] = useState({
mode: "add", // add | edit
isOpen: false,
service: null,
});
const [
addEditServiceActivityModalOptions,
setAddEditServiceActivityModalOptions,
] = useState({
mode: "add", // add | edit
isOpen: false,
activity: null,
});
const [servicesData, setServicesData] = useState({
services: [],
users: [],
});
const fetchServices = () => {
setIsRequestingServices(true);
myFetch({
url: `/store/services/${storeId}`,
method: "GET",
notificationApi: notificationApi,
t: t,
})
.then((data) => {
setIsRequestingServices(false);
setServicesData(data);
})
.catch(() => {});
};
useEffect(() => fetchServices(), []);
return (
<>
{notificationContextHolder}
<div
style={{
display: "flex",
justifyContent: "space-between",
flexDirection: screenBreakpoint.xs ? "column" : "row",
paddingBottom: screenBreakpoint.xs ? 16 : 0,
}}
>
<h1>
{t("storeServices.pageTitle")} {" ("}
<CountUp end={servicesData.services.length} />
{")"}
</h1>
<ModalAddEditService
storeId={storeId}
fetchServices={fetchServices}
addEditServiceModalOptions={addEditServiceModalOptions}
setAddEditServiceModalOptions={setAddEditServiceModalOptions}
/>
</div>
<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" /> */}
<div
style={{
display: "flex",
justifyContent: "center",
paddingTop: 70,
}}
>
<Spin />
</div>
</>
) : servicesData.services.length > 0 ? (
<>
{servicesData.services.map((service) => (
<Service
key={service.service_id}
service={service}
users={servicesData.users}
storeId={storeId}
setAddEditServiceActivityModalOptions={
setAddEditServiceActivityModalOptions
}
setAddEditServiceModalOptions={setAddEditServiceModalOptions}
fetchServices={fetchServices}
/>
))}
</>
) : (
<MyEmpty />
)}
</Space>
<ModalAddEditServiceActivity
fetchServices={fetchServices}
addEditServiceActivityModalOptions={addEditServiceActivityModalOptions}
setAddEditServiceActivityModalOptions={
setAddEditServiceActivityModalOptions
}
users={servicesData.users}
/>
</>
);
}
function Service({
service,
users,
storeId,
setAddEditServiceActivityModalOptions,
setAddEditServiceModalOptions,
fetchServices,
}) {
const { t } = useTranslation();
const [notificationApi, notificationContextHolder] =
notification.useNotification();
const [isRequestingActivities, setIsRequestingActivities] = useState(false);
const [isOpen, setIsOpen] = useState(false);
const [serviceActivities, setServiceActivities] = useState([]);
const fetchServiceActivities = () => {
if (!isOpen) return;
setIsRequestingActivities(true);
myFetch({
url: `/store/services/activities/${storeId}/${service.service_id}`,
method: "GET",
notificationApi: notificationApi,
t: t,
})
.then((data) => {
setIsRequestingActivities(false);
setServiceActivities(data.activities);
})
.catch((errStatus) => {
console.log(errStatus);
});
};
useEffect(() => fetchServiceActivities(), [isOpen]);
const expandIcon = ({ isActive }) => {
if (isRequestingActivities) return <Spin size="small" />;
return <CaretRightOutlined rotate={isActive ? 90 : 0} />;
};
return (
<>
{notificationContextHolder}
<Collapse
key={service.service_id}
onChange={(e) => setIsOpen(e.length !== 0)}
expandIcon={expandIcon}
items={[
{
key: "1",
label: (
<div
style={{
display: "flex",
justifyContent: "space-between",
alignItems: "center",
}}
>
<span>{service.name}</span>
<Space>
{/*
<ArrowUpOutlined
disabled
onClick={(e) => e.stopPropagation()}
/>
<ArrowDownOutlined
disabled
onClick={(e) => e.stopPropagation()}
/>
*/}
<MyPlusIcon
onClick={(e) => {
e.stopPropagation();
setAddEditServiceActivityModalOptions({
mode: "add",
isOpen: true,
service: service,
});
}}
/>
<MyEditIcon
onClick={(e) => {
e.stopPropagation();
setAddEditServiceModalOptions({
mode: "edit",
isOpen: true,
service: service,
});
}}
/>
<MyDeleteIcon
onClick={(e) => e.stopPropagation()}
propsPopconfirm={{
placement: "left",
}}
onConfirm={() => {
return myFetch({
url: `/store/services/${service.service_id}`,
method: "DELETE",
notificationApi: notificationApi,
t: t,
});
}}
onFetchSuccess={fetchServices}
popConfirmTitle={t(
"storeServices.popConfirmDeleteService.title"
)}
popConfirmDescription={t(
"storeServices.popConfirmDeleteService.description"
)}
/>
</Space>
</div>
),
children: (
<Space
key={`space-${service.service_id}`}
direction="vertical"
style={{ width: "100%" }}
>
{isRequestingActivities ? (
<Skeleton active>
<Card title="loading">
<p>loading</p>
<p>loading</p>
<p>loading</p>
</Card>
</Skeleton>
) : (
<>
{serviceActivities.length === 0 ? (
<MyEmpty />
) : (
serviceActivities.map((activity) => {
let userList = [];
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]);
}
}
}
} 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}
style={{ backgroundColor: "#fafbfb" }}
hoverable
extra={
<Space>
<Avatar.Group maxCount={2} size="small">
{userList.map((user) => (
<Tooltip
key={user.user_id}
title={user.username}
>
<Avatar
size="small"
style={{
backgroundColor:
AppStyle.colors.primary,
}}
>
{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({
url: `/store/services/activity/${activity.activity_id}`,
method: "DELETE",
notificationApi: notificationApi,
t: t,
});
}}
onFetchSuccess={fetchServiceActivities}
popConfirmTitle={t(
"storeServices.popConfirmDeleteServiceActivity.title"
)}
popConfirmDescription={t(
"storeServices.popConfirmDeleteServiceActivity.description"
)}
/>
</Space>
}
>
<Typography.Paragraph type="secondary">
{activity.description}
</Typography.Paragraph>
<Flex justify="space-around">
<p>{activity.price} </p>
<Typography.Paragraph>
{activity.duration}{" "}
{activity.duration === 1
? t("common.unit.minute")
: t("common.unit.minutes")}{" "}
{/*<Typography.Text type="secondary">
{durationToHoursAndMinutes(
t,
activity.duration
)}
</Typography.Text> */}
</Typography.Paragraph>
</Flex>
</Card>
);
})
)}
</>
)}
</Space>
),
},
]}
/>
</>
);
}
function durationToHoursAndMinutes(t, duration) {
const MINUTES_IN_HOUR = 60;
const singularHourText = t("common.unit.hour");
const pluralHourText = t("common.unit.hours");
const singularMinuteText = t("common.unit.minute");
const pluralMinuteText = t("common.unit.minutes");
const hours = Math.floor(duration / MINUTES_IN_HOUR);
const minutes = duration % MINUTES_IN_HOUR;
if (hours === 0 && minutes < 61) {
return "";
}
let response = "";
if (hours === 0) {
response = `${minutes} ${
minutes === 1 ? singularMinuteText : pluralMinuteText
}`;
} else if (minutes === 0) {
response = `${hours} ${hours === 1 ? singularHourText : pluralHourText}`;
} else {
response = `${hours} ${hours === 1 ? singularHourText : pluralHourText} ${t(
"common.unit.separator"
)} ${minutes} ${minutes === 1 ? singularMinuteText : pluralMinuteText}`;
}
return `(${response})`;
}
// this modal is used to create and edit services
function ModalAddEditService({
storeId,
fetchServices,
addEditServiceModalOptions,
setAddEditServiceModalOptions,
}) {
const { t } = useTranslation();
const [notificationApi, notificationContextHolder] =
notification.useNotification();
const screenBreakpoint = useBreakpoint();
const [form] = Form.useForm();
const [isRequesting, setIsRequesting] = useState(false);
const handleModalClose = () => {
setAddEditServiceModalOptions({
...addEditServiceModalOptions,
isOpen: false,
mode: "add",
});
form.resetFields();
};
useEffect(() => {
if (!addEditServiceModalOptions.isOpen) return;
if (addEditServiceModalOptions.mode === "edit") {
form.setFieldsValue({
serviceName: addEditServiceModalOptions.service.name,
});
}
}, [addEditServiceModalOptions.isOpen]);
return (
<>
{notificationContextHolder}
<Button
type="primary"
icon={<PlusOutlined />}
block={screenBreakpoint.xs}
onClick={() =>
setAddEditServiceModalOptions({
...addEditServiceModalOptions,
isOpen: true,
})
}
>
{t("storeServices.buttonAddService")}
</Button>
<MyModal
title={
addEditServiceModalOptions.mode === "add"
? t("storeServices.modalAddService.title")
: t("storeServices.modalEditService.title")
}
isOpen={addEditServiceModalOptions.isOpen}
onCancel={handleModalClose}
footer={
addEditServiceModalOptions.mode === "add" ? (
<MyModalCloseCreateButtonFooter
onCancel={handleModalClose}
isCreateButtonLoading={isRequesting}
onCreate={() => {
form
.validateFields()
.then((values) => {
setIsRequesting(true);
myFetch({
url: "/store/services/service",
method: "POST",
body: {
storeId: storeId,
name: values.serviceName,
},
notificationApi: notificationApi,
t: t,
})
.then(() => {
setIsRequesting(false);
handleModalClose();
fetchServices();
})
.catch((errStatus) => {
setIsRequesting(false);
if (errStatus === 400) {
notificationApi["error"]({
message: t("common.request.inputsInvalid.title"),
description: t(
"common.request.inputsInvalid.description"
),
});
}
});
})
.catch(() =>
showInputsInvalidNotification(notificationApi, t)
);
}}
/>
) : (
<MyModalCloseSaveButtonFooter
onCancel={handleModalClose}
isSaveButtonLoading={isRequesting}
onSave={() => {
// if the service name didn't change, don't send a request
let formServiceName = form.getFieldValue("serviceName");
if (
addEditServiceModalOptions.service.name === formServiceName
) {
handleModalClose();
return;
}
form
.validateFields()
.then(() => {
setIsRequesting(true);
myFetch({
url: "/store/services/update",
method: "POST",
body: {
serviceId:
addEditServiceModalOptions.service.service_id,
name: formServiceName,
},
notificationApi: notificationApi,
t: t,
})
.then(() => {
setIsRequesting(false);
handleModalClose();
fetchServices();
})
.catch((errStatus) => {
setIsRequesting(false);
if (errStatus === 400) {
notificationApi["error"]({
message: t("common.request.inputsInvalid.title"),
description: t(
"common.request.inputsInvalid.description"
),
});
}
});
})
.catch(() =>
showInputsInvalidNotification(notificationApi, t)
);
}}
/>
)
}
>
<Form form={form} layout="vertical" requiredMark={false}>
<ServiceNameFormInput formItemName="serviceName" />
</Form>
</MyModal>
</>
);
}
function ModalAddEditServiceActivity({
fetchServices,
addEditServiceActivityModalOptions,
setAddEditServiceActivityModalOptions,
users,
}) {
const { t } = useTranslation();
const [notificationApi, notificationContextHolder] =
notification.useNotification();
const [form] = Form.useForm();
const [isRequesting, setIsRequesting] = useState(false);
const [selectedEmployeesRowKeys, setSelectedEmployeesRowKeys] = useState([]);
const handleModalClose = () => {
setAddEditServiceActivityModalOptions({
...addEditServiceActivityModalOptions,
isOpen: false,
});
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;
if (addEditServiceActivityModalOptions.mode === "edit") {
form.setFieldsValue({
serviceActivityName: addEditServiceActivityModalOptions.activity.name,
serviceActivityDescription:
addEditServiceActivityModalOptions.activity.description,
serviceActivityPrice: addEditServiceActivityModalOptions.activity.price,
serviceActivityDurationMinutes:
addEditServiceActivityModalOptions.activity.duration,
});
setSelectedEmployeesRowKeys(
addEditServiceActivityModalOptions.activity.StoreServiceActivityUsers
.length === 0
? users.map((user) => user.user_id)
: addEditServiceActivityModalOptions.activity.StoreServiceActivityUsers.map(
(user) => user.user_id
)
);
} else {
setSelectedEmployeesRowKeys(users.map((user) => user.user_id));
}
}, [addEditServiceActivityModalOptions.isOpen]);
return (
<>
{notificationContextHolder}
<MyModal
title={
addEditServiceActivityModalOptions.mode === "add"
? t("storeServices.modalAddServiceActivity.title")
: t("storeServices.modalEditServiceActivity.title")
}
isOpen={addEditServiceActivityModalOptions.isOpen}
onCancel={handleModalClose}
footer={
addEditServiceActivityModalOptions.mode === "add" ? (
<MyModalCloseCreateButtonFooter
onCancel={handleModalClose}
isCreateButtonLoading={isRequesting}
onCreate={() => {
form
.validateFields()
.then((values) => {
setIsRequesting(true);
myFetch({
url: "/store/services/activity",
method: "POST",
body: {
serviceId:
addEditServiceActivityModalOptions.service.service_id,
name: values.serviceActivityName,
description: values.serviceActivityDescription,
price: values.serviceActivityPrice,
duration: values.serviceActivityDurationMinutes,
userIds:
selectedEmployeesRowKeys.length === users.length
? []
: selectedEmployeesRowKeys,
},
notificationApi: notificationApi,
t: t,
})
.then(() => {
setIsRequesting(false);
handleModalClose();
fetchServices();
})
.catch((errStatus) => {
setIsRequesting(false);
if (errStatus === 400) {
notificationApi["error"]({
message: t("common.request.inputsInvalid.title"),
description: t(
"common.request.inputsInvalid.description"
),
});
}
});
})
.catch(() =>
showInputsInvalidNotification(notificationApi, t)
);
}}
/>
) : (
<MyModalCloseSaveButtonFooter
onCancel={handleModalClose}
isSaveButtonLoading={isRequesting}
onSave={() => {
const formServiceActivityName = form.getFieldValue(
"serviceActivityName"
);
const formServiceActivityDescription = form.getFieldValue(
"serviceActivityDescription"
);
const formServiceActivityPrice = form.getFieldValue(
"serviceActivityPrice"
);
const formServiceActivityDurationMinutes = form.getFieldValue(
"serviceActivityDurationMinutes"
);
// if the service didn't change, don't send a request
if (
addEditServiceActivityModalOptions.activity.name ===
formServiceActivityName &&
addEditServiceActivityModalOptions.activity.description ===
formServiceActivityDescription &&
addEditServiceActivityModalOptions.activity.price ===
formServiceActivityPrice &&
addEditServiceActivityModalOptions.activity.duration ===
formServiceActivityDurationMinutes &&
(selectedEmployeesRowKeys.length === users.length ||
addEditServiceActivityModalOptions.activity
.StoreServiceActivityUsers.length ===
selectedEmployeesRowKeys.length)
) {
handleModalClose();
return;
}
let validateFields = [];
let body = {
activityId:
addEditServiceActivityModalOptions.activity.activity_id,
};
if (
formServiceActivityName !==
addEditServiceActivityModalOptions.activity.name
) {
validateFields.push("serviceActivityName");
body.name = formServiceActivityName;
}
// description is not required
body.description = formServiceActivityDescription;
if (
formServiceActivityPrice !==
addEditServiceActivityModalOptions.activity.price
) {
validateFields.push("serviceActivityPrice");
body.price = formServiceActivityPrice;
}
let formDuration = formServiceActivityDurationMinutes;
if (
formDuration !==
addEditServiceActivityModalOptions.activity.duration
) {
validateFields.push("serviceActivityDurationMinutes");
body.duration = formDuration;
}
body.userIds = selectedEmployeesRowKeys;
form
.validateFields()
.then(() => {
setIsRequesting(true);
myFetch({
url: "/store/services/activity/update",
method: "POST",
body: body,
notificationApi: notificationApi,
t: t,
})
.then(() => {
setIsRequesting(false);
handleModalClose();
fetchServices();
})
.catch((errStatus) => {
setIsRequesting(false);
if (errStatus === 400) {
notificationApi["error"]({
message: t("common.request.inputsInvalid.title"),
description: t(
"common.request.inputsInvalid.description"
),
});
}
});
})
.catch(() =>
showInputsInvalidNotification(notificationApi, t)
);
}}
/>
)
}
>
<Form form={form} layout="vertical" requiredMark={false}>
<ServiceActivityNameFormInput formItemName="serviceActivityName" />
<ServiceActivityDescriptionFormInput formItemName="serviceActivityDescription" />
<ServiceActivityPriceFormInput formItemName="serviceActivityPrice" />
<ServiceActivityDurationMinutesFormInput formItemName="serviceActivityDurationMinutes" />
<Space direction="vertical" style={{ width: "100%" }}>
<Typography.Text>
{t("storeServices.serviceActivityResponsible")}
</Typography.Text>
<Typography.Text type="secondary">
{t("storeServices.serviceActivityResponsibleDescription")}
</Typography.Text>
<MyTable
props={{
rowSelection: {
selectedRowKeys: selectedEmployeesRowKeys,
onChange: (newSelectedRowKeys) =>
setSelectedEmployeesRowKeys(newSelectedRowKeys),
},
loading: isRequesting,
columns: getTableColumns(),
dataSource: getTableItems(),
size: "small",
pagination: false,
}}
/>
</Space>
</Form>
</MyModal>
</>
);
}
function ServiceNameFormInput({ formItemName }) {
const { t } = useTranslation();
return (
<MyFormInput
formItemName={formItemName}
propsInput={{
showCount: true,
}}
minLength={Constants.GLOBALS.MIN_STORE_SERVICE_NAME_LENGTH}
maxLength={Constants.GLOBALS.MAX_STORE_SERVICE_NAME_LENGTH}
label={t("storeServices.serviceName")}
ruleMessageValueRequired={t(
"storeServices.inputRules.serviceNameRequired"
)}
ruleMessageValueMinLengthRequired={t(
"storeServices.inputRules.serviceNameMinLength",
{
minLength: Constants.GLOBALS.MIN_STORE_SERVICE_NAME_LENGTH,
}
)}
inputPlaceholder={t("storeServices.serviceNamePlaceholder")}
/>
);
}
function ServiceActivityNameFormInput({ formItemName }) {
const { t } = useTranslation();
return (
<MyFormInput
formItemName={formItemName}
propsInput={{
showCount: true,
}}
minLength={Constants.GLOBALS.MIN_STORE_SERVICE_ACTIVITY_NAME_LENGTH}
maxLength={Constants.GLOBALS.MAX_STORE_SERVICE_ACTIVITY_NAME_LENGTH}
label={t("storeServices.serviceActivityName")}
ruleMessageValueRequired={t(
"storeServices.inputRules.serviceActivityNameRequired"
)}
ruleMessageValueMinLengthRequired={t(
"storeServices.inputRules.serviceActivityNameMinLength",
{
minLength: Constants.GLOBALS.MIN_STORE_SERVICE_ACTIVITY_NAME_LENGTH,
}
)}
inputPlaceholder={t("storeServices.serviceActivityNamePlaceholder")}
/>
);
}
function ServiceActivityDescriptionFormInput({
formItemName,
setIsInputValid,
}) {
const { t } = useTranslation();
return (
<MyFormInput
propsInput={{
showCount: true,
}}
inputType="textarea"
inputNotRequired
formItemName={formItemName}
setIsInputValid={setIsInputValid}
maxLength={
Constants.GLOBALS.MAX_STORE_SERVICE_ACTIVITY_DESCRIPTION_LENGTH
}
label={t("storeServices.serviceActivityDescription")}
ruleMessageValueRequired={t(
"storeServices.inputRules.serviceActivityDescriptionRequired"
)}
ruleMessageValueMinLengthRequired={t(
"storeServices.inputRules.serviceActivityDescriptionMinLength",
{
minLength:
Constants.GLOBALS.MIN_STORE_SERVICE_ACTIVITY_DESCRIPTION_LENGTH,
}
)}
inputPlaceholder={t(
"storeServices.serviceActivityDescriptionPlaceholder"
)}
/>
);
}
function ServiceActivityPriceFormInput({ formItemName }) {
const { t } = useTranslation();
return (
<MyFormInput
propsInput={{
addonAfter: t("storeServices.serviceActivityPriceUnit"),
}}
inputType="number"
formItemName={formItemName}
minLength={Constants.GLOBALS.MIN_STORE_SERVICE_ACTIVITY_PRICE}
maxLength={Constants.GLOBALS.MAX_STORE_SERVICE_ACTIVITY_PRICE}
label={t("storeServices.serviceActivityPrice")}
ruleMessageValueRequired={t(
"storeServices.inputRules.serviceActivityPriceRequired"
)}
inputPlaceholder={t("storeServices.serviceActivityPricePlaceholder")}
/>
);
}
/*
function ServiceActivityDurationHoursFormInput({
formItemName,
setIsInputValid,
}) {
const { t } = useTranslation();
return (
<MyFormInput
propsInput={{
addonAfter: t("storeServices.serviceActivityDurationHoursUnit"),
}}
inputType="number"
formItemName={formItemName}
setIsInputValid={setIsInputValid}
minLength={Constants.GLOBALS.MIN_STORE_SERVICE_ACTIVITY_DURATION_HOURS}
maxLength={Constants.GLOBALS.MAX_STORE_SERVICE_ACTIVITY_DURATION_HOURS}
label={t("storeServices.serviceActivityDurationHours")}
ruleMessageValueRequired={t(
"storeServices.inputRules.serviceActivityDurationHoursRequired"
)}
inputPlaceholder={t(
"storeServices.serviceActivityDurationHoursPlaceholder"
)}
/>
);
}
*/
function ServiceActivityDurationMinutesFormInput({
formItemName,
setIsInputValid,
}) {
const { t } = useTranslation();
return (
<MyFormInput
propsInput={{
addonAfter: t("storeServices.serviceActivityDurationMinutesUnit"),
}}
inputType="number"
formItemName={formItemName}
setIsInputValid={setIsInputValid}
minLength={Constants.GLOBALS.MIN_STORE_SERVICE_ACTIVITY_DURATION_MINUTES}
maxLength={Constants.GLOBALS.MAX_STORE_SERVICE_ACTIVITY_DURATION_MINUTES}
label={t("storeServices.serviceActivityDurationMinutes")}
ruleMessageValueRequired={t(
"storeServices.inputRules.serviceActivityDurationMinutesRequired"
)}
inputPlaceholder={t(
"storeServices.serviceActivityDurationMinutesPlaceholder"
)}
/>
);
}