515 lines
20 KiB
JavaScript
515 lines
20 KiB
JavaScript
import { useEffect, useRef, useState } from 'react';
|
|
import { useLocation, useNavigate } from 'react-router-dom';
|
|
import { Form, Switch } from 'antd';
|
|
import { Messages } from '../../Components/Notifications/Messages';
|
|
import moment from 'moment';
|
|
import FormHeader from '../PageComponents/FormHeader';
|
|
import { InputField } from '../../Components/Forms/InputField';
|
|
import Buttons from '../../Components/Forms/Buttons';
|
|
import { ArrowRightOutlined } from '@ant-design/icons';
|
|
import { RadioGrpButton } from '../../Components/Forms/RadioGroup.jsx';
|
|
import { TextAreaInput } from '../../Components/Forms/TextArea.jsx';
|
|
import { DatePicProd } from '../../Components/Forms/DatePickerProduct.jsx';
|
|
import '../../Styles/CancelReschedule/Cancellation.scss';
|
|
import { getSession, validateSafeInput } from '../../Services/Others.js';
|
|
import {
|
|
postCancelReshRules,
|
|
putCancelReshRules,
|
|
} from '../../Features/BookingScreen/BookingData/BookingData.js';
|
|
import { useDispatch } from 'react-redux';
|
|
import { changeBreadCrumb } from '../../Features/AppPage/CenterPage.js';
|
|
|
|
const subDirectory = import.meta.env.BASE_URL;
|
|
const Cancellation = ({ formType }) => {
|
|
const formRef = useRef();
|
|
const dispatch = useDispatch();
|
|
const location = useLocation();
|
|
const navigate = useNavigate();
|
|
const state = location?.state;
|
|
const editstate = state?.editstate;
|
|
const CompId = getSession('CompId');
|
|
const BranchId = getSession('BranchId');
|
|
const AppId = getSession('AppId');
|
|
const UserId = getSession('UserId');
|
|
const [ActivityType, setActivityType] = useState(
|
|
editstate?.ActivityType ? editstate?.ActivityType : 'C'
|
|
);
|
|
const [ChargeType, setChargeType] = useState(
|
|
editstate?.ChargeType ? editstate?.ChargeType : 'P'
|
|
);
|
|
const [CancellationfromDate, setCancellationfromDate] = useState();
|
|
const [CancellationToDate, setCancellationToDate] = useState();
|
|
const [messageType, setMessageType] = useState(null);
|
|
const [messageData, setMessageData] = useState(null);
|
|
const [applicableBefore, setApplicableBefore] = useState(null);
|
|
const [isDays, setIsDays] = useState(true);
|
|
const items = [
|
|
{
|
|
name: 'Home',
|
|
link: `${subDirectory}app-page/home`,
|
|
},
|
|
{
|
|
name: 'CancelReschedule',
|
|
link: `${subDirectory}setting/cancel-reschedule-rules`,
|
|
},
|
|
{
|
|
name: editstate ? 'Edit' : 'New',
|
|
link: null,
|
|
// link: editstate ? `${subDirectory}setting/cancel-reschedule-rules/update` : `${subDirectory}setting/cancel-reschedule-rules/new`,
|
|
},
|
|
];
|
|
useEffect(() => {
|
|
if (formType === 'edit') {
|
|
setCancellationfromDate(editstate?.EffectiveFrom + 'T00:00:00');
|
|
setCancellationToDate(editstate?.EffectiveTill + 'T00:00:00');
|
|
setIsDays(editstate && editstate?.ApplicableType === 'D' ? true : false);
|
|
setApplicableBefore(editstate && editstate?.ApplicableBefore);
|
|
dispatch(changeBreadCrumb({ items: items }));
|
|
} else {
|
|
dispatch(changeBreadCrumb({ items: items }));
|
|
formRef.current?.setFieldsValue({ ActivityType: 'C' });
|
|
formRef.current?.setFieldsValue({ ChargeType: 'P' });
|
|
}
|
|
}, []);
|
|
const CancellationFromDatefetch = async (date, dateString) => {
|
|
if (dateString === '') {
|
|
formRef.current?.setFieldsValue({ EffectiveFrom: '' });
|
|
setCancellationfromDate();
|
|
}
|
|
if (dateString) {
|
|
const Date3 = moment(dateString, ['DD-MM-YYYY']).format(
|
|
'YYYY-MM-DDTHH:mm:ss'
|
|
);
|
|
formRef.current?.setFieldsValue({ EffectiveFrom: Date3 });
|
|
setCancellationfromDate(Date3);
|
|
}
|
|
};
|
|
const CancellationToDatefetch = async (date, dateString) => {
|
|
if (dateString === '') {
|
|
formRef.current?.setFieldsValue({ EffectiveTill: '' });
|
|
setCancellationToDate();
|
|
}
|
|
if (dateString) {
|
|
const Date4 = moment(dateString, ['DD-MM-YYYY']).format(
|
|
'YYYY-MM-DDTHH:mm:ss'
|
|
);
|
|
formRef.current?.setFieldsValue({ EffectiveTill: Date4 });
|
|
setCancellationToDate(Date4);
|
|
}
|
|
};
|
|
const selectActivityType = (e) => {
|
|
setActivityType(e);
|
|
formRef.current?.setFieldsValue({ ActivityType: e });
|
|
};
|
|
const selectChargeType = (e) => {
|
|
setChargeType(e);
|
|
formRef.current?.setFieldsValue({ ChargeType: e });
|
|
formRef.current?.setFieldsValue({ ChargesFixed: null });
|
|
};
|
|
|
|
const validateDateRange = (rule, value, callback) => {
|
|
const toDate = moment(CancellationToDate);
|
|
const fromDate = moment(CancellationfromDate);
|
|
|
|
if (toDate.isBefore(fromDate)) {
|
|
callback('To date should be after From date');
|
|
} else {
|
|
callback(); // Valid date range
|
|
}
|
|
};
|
|
|
|
const onFinish = async (values) => {
|
|
const Postdata = {
|
|
CompId: CompId,
|
|
AppId: AppId,
|
|
BranchId: BranchId,
|
|
CreatedBy: UserId,
|
|
ApplicableType: isDays ? 'D' : 'H',
|
|
...values,
|
|
};
|
|
if (formType === 'add') {
|
|
let response = await dispatch(postCancelReshRules(Postdata)).unwrap();
|
|
if (response?.data?.statusCode === 1) {
|
|
setMessageType('success');
|
|
setMessageData(response?.data?.response);
|
|
setTimeout(() => {
|
|
navigate(`${subDirectory}setting/cancel-reschedule-rules`);
|
|
}, 500);
|
|
|
|
formRef.current?.resetFields();
|
|
setCancellationfromDate();
|
|
setCancellationToDate();
|
|
} else {
|
|
setMessageType('error');
|
|
setMessageData(response?.data?.response);
|
|
}
|
|
} else if (formType === 'edit') {
|
|
Postdata['EffectiveFrom'] = moment(values?.EffectiveFrom).format(
|
|
'YYYY-MM-DDTHH:mm:ss'
|
|
);
|
|
Postdata['EffectiveTill'] = moment(values?.EffectiveTill).format(
|
|
'YYYY-MM-DDTHH:mm:ss'
|
|
);
|
|
Postdata['UpdatedBy'] = UserId;
|
|
Postdata['UniqueId'] = editstate?.UniqueId;
|
|
let response = await dispatch(putCancelReshRules(Postdata)).unwrap();
|
|
if (response?.data?.statusCode === 1) {
|
|
setMessageType('success');
|
|
setMessageData(response?.data?.response);
|
|
// setTimeout(() => {
|
|
navigate(`${subDirectory}setting/cancel-reschedule-rules`, {
|
|
state: {
|
|
Notiffy: {
|
|
messageType: 'success',
|
|
messageData: response?.data?.response,
|
|
},
|
|
},
|
|
});
|
|
// }, 50);
|
|
// navigate(`${subDirectory}setting/product-master/`);
|
|
|
|
formRef.current?.resetFields();
|
|
setCancellationfromDate();
|
|
setCancellationToDate();
|
|
} else {
|
|
setMessageType('error');
|
|
setMessageData(response?.data?.response);
|
|
}
|
|
}
|
|
};
|
|
|
|
const handleApplicationBefore = (e) => {
|
|
setApplicableBefore(e?.target?.value);
|
|
};
|
|
|
|
return (
|
|
<>
|
|
<div className="pageOverAll">
|
|
<div className="userPage">
|
|
<div className="userPageContent">
|
|
<Messages messageType={messageType} messageData={messageData} />
|
|
|
|
<div className="formName">
|
|
<FormHeader title={'Cancellation and Reschedule Rules'} />
|
|
</div>
|
|
<div className="formDiv">
|
|
<div className="Cancellation-div">
|
|
<Form
|
|
ref={formRef}
|
|
onFinish={onFinish}
|
|
initialValues={{ ...editstate }}
|
|
>
|
|
<div className="Cancel-div ">
|
|
<div className="cancel-desc-div">
|
|
<Form.Item name="ActivityType">
|
|
<li className="drp_btn_Emp">
|
|
<div className="Cancel-Form-radio">
|
|
<RadioGrpButton
|
|
content={[
|
|
{ value: 'C', label: 'Cancellation' },
|
|
{ value: 'R', label: 'Re-scheduling' },
|
|
]}
|
|
fieldState={true}
|
|
defaultSelect={ActivityType}
|
|
Header={'Activity Type'}
|
|
onSelectFuntion={(e) => selectActivityType(e)}
|
|
onClickFunction={(e) => selectActivityType(e)}
|
|
/>
|
|
</div>
|
|
</li>
|
|
</Form.Item>
|
|
</div>
|
|
<div className="cancel-activitytype">
|
|
<Form.Item name="ChargeType">
|
|
<div className="Dinein-Form-ChairLevelSer">
|
|
<li className="drp_btn_Emp">
|
|
<div className="Dinein-Form-radio">
|
|
<RadioGrpButton
|
|
content={[
|
|
{ value: 'P', label: 'Percentage' },
|
|
{ value: 'F', label: 'Fixed' },
|
|
]}
|
|
fieldState={true}
|
|
defaultSelect={ChargeType}
|
|
Header={'Charge Type'}
|
|
onSelectFuntion={(e) => selectChargeType(e)}
|
|
onClickFunction={(e) => selectChargeType(e)}
|
|
/>
|
|
</div>
|
|
</li>
|
|
</div>
|
|
</Form.Item>
|
|
<Form.Item
|
|
name="ChargesFixed"
|
|
rules={[
|
|
{
|
|
required: true,
|
|
message: 'Please Enter Charges Fixed',
|
|
},
|
|
{
|
|
validator: async (_, value) => {
|
|
await validateSafeInput(value);
|
|
if (!value) {
|
|
return Promise.resolve();
|
|
}
|
|
if (ChargeType === 'P') {
|
|
if (!/^\d{1,3}(\.\d{1,2})?$/.test(value)) {
|
|
return Promise.reject(
|
|
'Invalid format (Max 3 digits, up to 2 decimals)'
|
|
);
|
|
}
|
|
if (parseFloat(value) < 0.01 || parseFloat(value) > 100) {
|
|
return Promise.reject(
|
|
'Charges Percentage must be between 0.01 and 100%'
|
|
);
|
|
}
|
|
}
|
|
if (value?.length > 10) {
|
|
return Promise.reject(
|
|
'Charges Fixed (Max 10 characters allowed)'
|
|
);
|
|
}
|
|
return Promise.resolve();
|
|
},
|
|
},
|
|
]}
|
|
>
|
|
<InputField
|
|
field="Charges"
|
|
autoComplete="off"
|
|
label={
|
|
<label class="required">
|
|
{ChargeType == 'F' ? `Charges Fixed(₹)` : `Charges Percentage(%)`}
|
|
</label>
|
|
}
|
|
isOnChange={editstate?.ChargesFixed ? true : false}
|
|
inputMode="decimal"
|
|
onInput={(e) => {
|
|
const cleanedValue = e.target.value.replace(
|
|
/[^0-9.]/g,
|
|
''
|
|
);
|
|
const parts = cleanedValue.split('.');
|
|
e.target.value =
|
|
parts.length > 2
|
|
? `${parts[0]}.${parts.slice(1).join('')}`
|
|
: cleanedValue;
|
|
}}
|
|
/>
|
|
</Form.Item>
|
|
<Form.Item
|
|
name="ApplicableBefore"
|
|
rules={[
|
|
{
|
|
required: true,
|
|
pattern: /^[1-9]\d*(\.\d+)?$/,
|
|
message: 'Please Enter Applicable Before',
|
|
},
|
|
{
|
|
validator: async (_, value) => {
|
|
await validateSafeInput(value);
|
|
|
|
if (value && value.length > 10) {
|
|
return Promise.reject(
|
|
'Applicable Before should not exceed 10 characters'
|
|
);
|
|
}
|
|
|
|
return Promise.resolve();
|
|
},
|
|
},
|
|
]}
|
|
>
|
|
<div className="swtichDays">
|
|
<div>
|
|
<div className="switch-header required">
|
|
Applicable Type
|
|
</div>
|
|
<Switch
|
|
checked={isDays}
|
|
onChange={(checked) => setIsDays(checked)}
|
|
checkedChildren="Days"
|
|
unCheckedChildren="Hours"
|
|
/>
|
|
</div>
|
|
|
|
<InputField
|
|
onChange={handleApplicationBefore}
|
|
value={applicableBefore}
|
|
field="UPIId"
|
|
autoComplete="off"
|
|
label={
|
|
<label class="required">{`Applicable Before (${isDays ? 'Days' : 'Hours'})`}</label>
|
|
}
|
|
isOnChange={
|
|
editstate?.ApplicableBefore ? true : false
|
|
}
|
|
inputMode="decimal"
|
|
onInput={(e) => {
|
|
const cleanedValue = e.target.value.replace(
|
|
/[^0-9.]/g,
|
|
''
|
|
);
|
|
const parts = cleanedValue.split('.');
|
|
e.target.value =
|
|
parts.length > 2
|
|
? `${parts[0]}.${parts.slice(1).join('')}`
|
|
: cleanedValue;
|
|
}}
|
|
/>
|
|
</div>
|
|
</Form.Item>
|
|
</div>
|
|
</div>
|
|
<div className="Datediv">
|
|
<div className="Cancellation-Date">
|
|
<p className="Cancellation-Date-from-heading required">
|
|
From Date
|
|
</p>
|
|
|
|
<Form.Item
|
|
name="EffectiveFrom"
|
|
rules={[
|
|
{
|
|
required: true,
|
|
pattern: /^(?!\s*$).+/,
|
|
message: 'Please Enter the From Date ',
|
|
},
|
|
]}
|
|
>
|
|
<DatePicProd
|
|
onChange={CancellationFromDatefetch}
|
|
style={{ width: '24vw', height: '2.6rem' }}
|
|
valueData={CancellationfromDate}
|
|
canSelectPast={true}
|
|
cancelFuture={true}
|
|
/>
|
|
</Form.Item>
|
|
</div>
|
|
<div className="Cancellation-Date">
|
|
<p className="Cancellation-Date-from-heading required">
|
|
To Date
|
|
</p>
|
|
|
|
<Form.Item
|
|
name="EffectiveTill"
|
|
rules={[
|
|
{
|
|
required: true,
|
|
pattern: /^(?!\s*$).+/,
|
|
message: 'Please Enter the To Date ',
|
|
},
|
|
{ validator: validateDateRange },
|
|
]}
|
|
// rules={[{ validator: validateDateRange }]}>
|
|
>
|
|
<DatePicProd
|
|
onChange={CancellationToDatefetch}
|
|
style={{ width: '24vw', height: '2.6rem' }}
|
|
valueData={CancellationToDate}
|
|
canSelectPast={true}
|
|
minDate={CancellationfromDate}
|
|
// cancelFuture={true}
|
|
/>
|
|
</Form.Item>
|
|
</div>
|
|
|
|
{ActivityType === 'R' && (
|
|
<div>
|
|
<Form.Item
|
|
name="NoofReschedule"
|
|
rules={[
|
|
{
|
|
required: true,
|
|
pattern: /^(0\d+|\d*\.?\d+)$/,
|
|
message: 'Please Enter Max No.of Rescheduling',
|
|
},
|
|
{
|
|
validator: async (_, value) => {
|
|
await validateSafeInput(value);
|
|
|
|
if (value && value.length > 10) {
|
|
return Promise.reject(
|
|
'Max No.of Rescheduling should not exceed 10 characters'
|
|
);
|
|
}
|
|
|
|
return Promise.resolve();
|
|
},
|
|
},
|
|
]}
|
|
>
|
|
<InputField
|
|
field="NoofReschedule"
|
|
autoComplete="off"
|
|
label={
|
|
<label class="required">
|
|
Max No.of Rescheduling
|
|
</label>
|
|
}
|
|
isOnChange={
|
|
editstate?.NoofReschedule ? true : false
|
|
}
|
|
inputMode="decimal"
|
|
onInput={(e) => {
|
|
const cleanedValue = e.target.value.replace(
|
|
/[^0-9.]/g,
|
|
''
|
|
);
|
|
const parts = cleanedValue.split('.');
|
|
e.target.value =
|
|
parts.length > 2
|
|
? `${parts[0]}.${parts.slice(1).join('')}`
|
|
: cleanedValue;
|
|
}}
|
|
/>
|
|
</Form.Item>
|
|
</div>
|
|
)}
|
|
<Form.Item
|
|
name="Description"
|
|
rules={[
|
|
{
|
|
required: true,
|
|
pattern: /^(?!\s*$).+/,
|
|
message: 'Please Enter Description',
|
|
},
|
|
{
|
|
validator: async (_, value) => {
|
|
await validateSafeInput(value);
|
|
if (value?.length > 100) {
|
|
return Promise.reject(
|
|
'Description (Max 100 characters allowed)'
|
|
);
|
|
}
|
|
return Promise.resolve();
|
|
},
|
|
},
|
|
]}
|
|
>
|
|
<TextAreaInput
|
|
autoComplete="off"
|
|
label={<label className="required">Description</label>}
|
|
isOnChange={editstate?.Description ? true : false}
|
|
/>
|
|
</Form.Item>
|
|
</div>
|
|
<div className="Cancellation-submitButton">
|
|
<Buttons
|
|
buttonText="SUBMIT"
|
|
color="901D77"
|
|
icon={<ArrowRightOutlined />}
|
|
onClick={() => onFinish()}
|
|
/>
|
|
</div>
|
|
</Form>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</>
|
|
);
|
|
};
|
|
export default Cancellation;
|