2026-01-27 18:27:29 +05:30
|
|
|
import { useState, useEffect, useRef, useCallback } from 'react';
|
|
|
|
|
import { useDispatch } from 'react-redux';
|
|
|
|
|
import { useNavigate, useLocation } from 'react-router-dom';
|
|
|
|
|
import moment from 'moment';
|
|
|
|
|
import { Form, Tooltip, Collapse, Space, Modal, Table } from 'antd';
|
|
|
|
|
import {
|
|
|
|
|
ArrowRightOutlined,
|
|
|
|
|
PlusCircleOutlined,
|
|
|
|
|
DeleteFilled,
|
|
|
|
|
EditFilled,
|
|
|
|
|
InfoCircleOutlined,
|
|
|
|
|
ReloadOutlined,
|
|
|
|
|
} from '@ant-design/icons';
|
|
|
|
|
import { InputField } from '../../Components/Forms/InputField.jsx';
|
|
|
|
|
import Buttons from '../../Components/Forms/Buttons.jsx';
|
|
|
|
|
import { Messages } from '../../Components/Notifications/Messages';
|
|
|
|
|
import { TimePickers } from '../../Components/Forms/TimePicker.jsx';
|
|
|
|
|
import FormHeader from '../PageComponents/FormHeader.jsx';
|
|
|
|
|
import { changeBreadCrumb } from '../../Features/AppPage/CenterPage.js';
|
|
|
|
|
import { getSession, validateSafeInput } from '../../Services/Others';
|
|
|
|
|
import { postshift, putshift } from '../../Features/ShiftMaster/ShiftMaster.js';
|
|
|
|
|
import './ShiftMaster.scss';
|
|
|
|
|
import { FaPlus } from 'react-icons/fa6';
|
2026-02-11 11:35:57 +05:30
|
|
|
import "../../Styles/OverAllStyle/OverAllStyle.scss";
|
|
|
|
|
|
2026-01-27 18:27:29 +05:30
|
|
|
const subDirectory = import.meta.env.BASE_URL;
|
|
|
|
|
|
|
|
|
|
const ShiftForm = ({ formType }) => {
|
|
|
|
|
const formRef = useRef(null);
|
|
|
|
|
const dispatch = useDispatch();
|
|
|
|
|
const navigate = useNavigate();
|
|
|
|
|
const location = useLocation();
|
|
|
|
|
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 [messageType, setMessageType] = useState(null);
|
|
|
|
|
const [messageData, setMessageData] = useState(null);
|
|
|
|
|
const [fromTime, setFromTime] = useState();
|
|
|
|
|
const [toTime, setToTime] = useState();
|
|
|
|
|
const [BrakeFromTime, setBrakeFromTime] = useState();
|
|
|
|
|
const [BrakeToTime, setBrakeToTime] = useState();
|
|
|
|
|
const [Tabledata, setTabledata] = useState([]);
|
|
|
|
|
const [searchedText, setSearchedText] = useState('');
|
|
|
|
|
const [sortedInfo, setSortedInfo] = useState({});
|
|
|
|
|
const [editDataval, setEditDataval] = useState(false);
|
|
|
|
|
const [page, setpage] = useState(1);
|
|
|
|
|
const [editIndex, setEditIndex] = useState();
|
|
|
|
|
const [BrakeId, setBrakeId] = useState();
|
|
|
|
|
|
|
|
|
|
const items = [
|
|
|
|
|
{
|
|
|
|
|
name: 'Home',
|
|
|
|
|
link: `${subDirectory}app-page/home`,
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
name: 'Shift',
|
|
|
|
|
link: `${subDirectory}setting/shift-master`,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
name: editstate ? 'Edit' : 'New',
|
|
|
|
|
link: null,
|
|
|
|
|
// link: editstate
|
|
|
|
|
// ? `${subDirectory}setting/shift-master/update`
|
|
|
|
|
// : `${subDirectory}setting/shift-master/new`,
|
|
|
|
|
},
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
|
try {
|
|
|
|
|
dispatch(changeBreadCrumb({ items: items }));
|
|
|
|
|
if (formType === 'edit') {
|
|
|
|
|
if (editstate) {
|
|
|
|
|
setFromTime(editstate?.StartTime);
|
|
|
|
|
setToTime(editstate?.EndTime);
|
|
|
|
|
setBrakeFromTime(editstate?.BreakStartTime);
|
|
|
|
|
setBrakeToTime(editstate?.BreakEndTime);
|
|
|
|
|
setTabledata(editstate?.BreakDtl);
|
|
|
|
|
|
|
|
|
|
formRef.current?.setFieldsValue(editstate);
|
|
|
|
|
} else {
|
|
|
|
|
navigate(`${subDirectory}setting/shift-master/`);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} catch (err) {
|
|
|
|
|
console.log(err, 'err');
|
|
|
|
|
}
|
|
|
|
|
}, []);
|
|
|
|
|
|
|
|
|
|
const onFinish = async (values) => {
|
|
|
|
|
// Validate all break times are within shift time range
|
|
|
|
|
const shiftStart = moment(fromTime, 'HH:mm:ss');
|
|
|
|
|
const shiftEnd = moment(toTime, 'HH:mm:ss');
|
|
|
|
|
|
|
|
|
|
for (const breakItem of Tabledata) {
|
|
|
|
|
const breakStart = moment(breakItem.BreakStartTime, 'HH:mm:ss');
|
|
|
|
|
const breakEnd = moment(breakItem.BreakEndTime, 'HH:mm:ss');
|
|
|
|
|
|
|
|
|
|
const isValidBreak = shiftEnd.isBefore(shiftStart)
|
|
|
|
|
? (breakStart.isAfter(shiftStart) || breakStart.isBefore(shiftEnd)) &&
|
|
|
|
|
(breakEnd.isAfter(shiftStart) || breakEnd.isBefore(shiftEnd))
|
|
|
|
|
: breakStart.isBetween(shiftStart, shiftEnd, null, '[]') &&
|
|
|
|
|
breakEnd.isBetween(shiftStart, shiftEnd, null, '[]');
|
|
|
|
|
|
|
|
|
|
if (!isValidBreak) {
|
|
|
|
|
setMessageType('error');
|
|
|
|
|
setMessageData(`Break "${breakItem.BreakName}" is not within shift time range`);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let postData = {
|
|
|
|
|
AppId: getSession('AppId'),
|
|
|
|
|
BranchId: getSession('BranchId'),
|
|
|
|
|
CompId: getSession('CompId'),
|
|
|
|
|
ShiftName: values.ShiftName,
|
|
|
|
|
StartTime: fromTime,
|
|
|
|
|
EndTime: toTime,
|
|
|
|
|
GracePeriod: values.GracePeriod,
|
|
|
|
|
BreakDtl: Tabledata.map((item) => ({
|
|
|
|
|
BreakName: item.BreakName,
|
|
|
|
|
BreakStartTime: item.BreakStartTime,
|
|
|
|
|
BreakEndTime: item.BreakEndTime,
|
|
|
|
|
BreakId: item.BreakId ? item.BreakId : '',
|
|
|
|
|
})),
|
|
|
|
|
CreatedBy: getSession('UserId'),
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
console.log(postData, 'postDatapostDatapostDatapostDatapostData');
|
|
|
|
|
|
|
|
|
|
let response = {};
|
|
|
|
|
if (formType === 'add') {
|
|
|
|
|
response = await dispatch(postshift(postData)).unwrap();
|
|
|
|
|
} else if (formType === 'edit') {
|
|
|
|
|
if (editstate) {
|
|
|
|
|
postData['UpdatedBy'] = getSession('UserId');
|
|
|
|
|
postData['ShiftId'] = editstate?.ShiftId;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
response = await dispatch(putshift(postData)).unwrap();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (response?.data?.statusCode == 1) {
|
|
|
|
|
navigate(`${subDirectory}setting/shift-master/`, {
|
|
|
|
|
state: {
|
|
|
|
|
Notiffy: {
|
|
|
|
|
messageType: 'success',
|
|
|
|
|
messageData: response?.data?.response,
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
});
|
|
|
|
|
} else {
|
|
|
|
|
setMessageType('error');
|
|
|
|
|
setMessageData(response?.data?.response);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const validateTime = (rule, value, callback) => {
|
|
|
|
|
// if either value is not set yet, bail out (required rule will show message)
|
|
|
|
|
if (!fromTime || !toTime) {
|
|
|
|
|
return callback();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// parse safely (allow formats like "HH:mm" or "HH:mm:ss")
|
|
|
|
|
const fromParts = (fromTime || '').split(':').map(s => parseInt(s, 10) || 0);
|
|
|
|
|
const toParts = (toTime || '').split(':').map(s => parseInt(s, 10) || 0);
|
|
|
|
|
|
|
|
|
|
const [fromHour = 0, fromMinute = 0] = fromParts;
|
|
|
|
|
const [toHour = 0, toMinute = 0] = toParts;
|
|
|
|
|
|
|
|
|
|
const fromTotalMinutes = fromHour * 60 + fromMinute;
|
|
|
|
|
const toTotalMinutes = toHour * 60 + toMinute;
|
|
|
|
|
const minutesInDay = 24 * 60;
|
|
|
|
|
let timeDifference = toTotalMinutes - fromTotalMinutes;
|
|
|
|
|
|
|
|
|
|
if (timeDifference < 0) {
|
|
|
|
|
timeDifference = minutesInDay - fromTotalMinutes + toTotalMinutes;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const maxAllowedInterval = 12 * 60;
|
|
|
|
|
|
|
|
|
|
if (timeDifference <= maxAllowedInterval) {
|
|
|
|
|
return callback();
|
|
|
|
|
} else {
|
|
|
|
|
return callback('Shift should not exceed 12 hours');
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const validateBreakTime1 = (rule, value, callback) => {
|
|
|
|
|
if (!value) return callback();
|
|
|
|
|
|
|
|
|
|
const brakeFromTime = moment(BrakeFromTime, 'HH:mm');
|
|
|
|
|
const startTime = moment(fromTime, 'HH:mm');
|
|
|
|
|
const endTime = moment(toTime, 'HH:mm');
|
|
|
|
|
|
|
|
|
|
if (endTime.isBefore(startTime)) {
|
|
|
|
|
// Handle shifts that span across midnight
|
|
|
|
|
if (brakeFromTime.isAfter(startTime) || brakeFromTime.isBefore(endTime)) {
|
|
|
|
|
callback(); // Valid time interval
|
|
|
|
|
} else {
|
|
|
|
|
callback(
|
|
|
|
|
'Break Start Time should be between Shift Start Time and Shift End Time'
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
if (
|
|
|
|
|
brakeFromTime.isBetween(startTime, endTime, null, '[]') ||
|
|
|
|
|
brakeFromTime.isSame(startTime) ||
|
|
|
|
|
brakeFromTime.isSame(endTime)
|
|
|
|
|
) {
|
|
|
|
|
callback(); // Valid time interval
|
|
|
|
|
} else {
|
|
|
|
|
callback(
|
|
|
|
|
'Break Start Time should be between Shift Start Time and Shift End Time'
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const validateBreakTime2 = (rule, value, callback) => {
|
|
|
|
|
if (!value) return callback();
|
|
|
|
|
|
|
|
|
|
const brakeToTime = moment(BrakeToTime, 'HH:mm');
|
|
|
|
|
const brakeFromTime = moment(BrakeFromTime, 'HH:mm');
|
|
|
|
|
const startTime = moment(fromTime, 'HH:mm');
|
|
|
|
|
const endTime = moment(toTime, 'HH:mm');
|
|
|
|
|
|
|
|
|
|
if (endTime.isBefore(startTime)) {
|
|
|
|
|
// Handle shifts that span across midnight
|
|
|
|
|
if (brakeToTime.isAfter(startTime) || brakeToTime.isBefore(endTime)) {
|
|
|
|
|
// Check if BrakeToTime is always greater than BrakeFromTime
|
|
|
|
|
if (brakeToTime.isAfter(brakeFromTime)) {
|
|
|
|
|
callback(); // Valid time interval
|
|
|
|
|
} else {
|
|
|
|
|
callback('Break End Time should be greater than Break Start Time');
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
callback(
|
|
|
|
|
'Break End Time should be between Shift Start Time and Shift End Time'
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
if (
|
|
|
|
|
brakeToTime.isBetween(startTime, endTime, null, '[]') ||
|
|
|
|
|
brakeToTime.isSame(startTime) ||
|
|
|
|
|
brakeToTime.isSame(endTime)
|
|
|
|
|
) {
|
|
|
|
|
// Check if BrakeToTime is always greater than BrakeFromTime
|
|
|
|
|
if (brakeToTime.isAfter(brakeFromTime)) {
|
|
|
|
|
callback(); // Valid time interval
|
|
|
|
|
} else {
|
|
|
|
|
callback('Break End Time should be greater than Break Start Time');
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
callback(
|
|
|
|
|
'Break End Time should be between Shift Start Time and Shift End Time'
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const onFromTimeChange = (time, timeString) => {
|
|
|
|
|
if (timeString) {
|
|
|
|
|
const fromTime = moment(timeString, ['h:mm a']).format('HH:mm:ss');
|
|
|
|
|
setToTime(null);
|
|
|
|
|
setFromTime(fromTime);
|
|
|
|
|
} else {
|
|
|
|
|
setFromTime(null);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const onToTimeChange = (time, timeString) => {
|
|
|
|
|
if (timeString) {
|
|
|
|
|
const toTime = moment(timeString, ['h:mm a']).format('HH:mm:ss');
|
|
|
|
|
setToTime(toTime);
|
|
|
|
|
} else {
|
|
|
|
|
setToTime(null);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const onBrakeFromTimeChange = (time, timeString) => {
|
|
|
|
|
if (timeString) {
|
|
|
|
|
const FromBrakeTime = moment(timeString, ['h:mm a']).format('HH:mm:ss');
|
|
|
|
|
setBrakeFromTime(FromBrakeTime);
|
|
|
|
|
setBrakeToTime(null);
|
|
|
|
|
} else {
|
|
|
|
|
setBrakeFromTime(null);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const onBrakeToTimeChange = (time, timeString) => {
|
|
|
|
|
if (timeString) {
|
|
|
|
|
const toBrakeTime = moment(timeString, ['h:mm a']).format('HH:mm:ss');
|
|
|
|
|
setBrakeToTime(toBrakeTime);
|
|
|
|
|
} else {
|
|
|
|
|
setBrakeToTime(null);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const Columns = [
|
|
|
|
|
{
|
|
|
|
|
title: 'Sl.No',
|
|
|
|
|
key: 'sno',
|
|
|
|
|
align: 'center',
|
|
|
|
|
render: (text, object, index) => (
|
|
|
|
|
<a style={{ color: 'black' }}>{(page - 1) * 10 + index + 1}</a>
|
|
|
|
|
),
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
title: 'Break Name',
|
|
|
|
|
dataIndex: 'BreakName',
|
|
|
|
|
key: 'BreakName',
|
|
|
|
|
editable: true,
|
|
|
|
|
render: (text) => <a style={{ color: 'black' }}>{text}</a>,
|
|
|
|
|
filteredValue: [searchedText],
|
|
|
|
|
onFilter: (value, record) => {
|
|
|
|
|
return (
|
|
|
|
|
String(record.TableName)
|
|
|
|
|
?.toLowerCase()
|
|
|
|
|
?.includes(value?.toLowerCase()) ||
|
|
|
|
|
String(record.TableName)
|
|
|
|
|
?.toLowerCase()
|
|
|
|
|
?.includes(value?.toLowerCase()) ||
|
|
|
|
|
String(record.ChairCount)
|
|
|
|
|
?.toLowerCase()
|
|
|
|
|
?.includes(value?.toLowerCase()) ||
|
|
|
|
|
String(record.ChairLevelSer)
|
|
|
|
|
?.toLowerCase()
|
|
|
|
|
?.includes(value?.toLowerCase()) ||
|
|
|
|
|
String(record.DineInTypeName)
|
|
|
|
|
?.toLowerCase()
|
|
|
|
|
?.includes(value?.toLowerCase())
|
|
|
|
|
);
|
|
|
|
|
},
|
|
|
|
|
sorter: (a, b) => a?.BreakName?.length - b?.BreakName?.length,
|
|
|
|
|
sortOrder: sortedInfo.columnKey === 'BreakName' ? sortedInfo.order : null,
|
|
|
|
|
ellipsis: true,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
title: 'Break Start',
|
|
|
|
|
dataIndex: 'BreakStartTime',
|
|
|
|
|
key: 'BreakStartTime',
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
title: 'Break End',
|
|
|
|
|
dataIndex: 'BreakEndTime',
|
|
|
|
|
key: 'BreakEndTime',
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
title: 'Duration (mins)',
|
|
|
|
|
key: 'Duration',
|
|
|
|
|
align: 'center',
|
|
|
|
|
render: (_, record) => {
|
|
|
|
|
const startTime = moment(record.BreakStartTime, 'HH:mm:ss');
|
|
|
|
|
const endTime = moment(record.BreakEndTime, 'HH:mm:ss');
|
|
|
|
|
const duration = endTime.diff(startTime, 'minutes');
|
|
|
|
|
return duration > 0 ? duration : 0;
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
title: 'Action',
|
|
|
|
|
key: 'Action',
|
|
|
|
|
dataIndex: 'Action',
|
|
|
|
|
align: 'center',
|
|
|
|
|
render: (_, record, index) => (
|
|
|
|
|
// Tabledata.length >= 1 ? (
|
|
|
|
|
<Space size="middle">
|
|
|
|
|
{/* {record.ActiveStatus === "A" ? ( */}
|
|
|
|
|
<a>
|
|
|
|
|
<EditFilled
|
|
|
|
|
style={{ color: '#1292EE' }}
|
|
|
|
|
onClick={
|
|
|
|
|
() =>
|
|
|
|
|
// ((UserType === 'Super Admin') ||
|
|
|
|
|
// (UserType === "Super Admin User" && SAAccessCommonMaster?.UpdateAccess === "Y") ||
|
|
|
|
|
// (UserType === 'Employee' && empData?.UpdateAccess === "Y") ||
|
|
|
|
|
// (UserType === 'Admin'))
|
|
|
|
|
// ?
|
|
|
|
|
actionsFormatter(record, index)
|
|
|
|
|
// : null
|
|
|
|
|
}
|
|
|
|
|
/>
|
|
|
|
|
</a>
|
|
|
|
|
{/* ) : (
|
|
|
|
|
""
|
|
|
|
|
)} */}
|
|
|
|
|
<a>
|
|
|
|
|
{/* {record.ActiveStatus === "A" ? ( */}
|
|
|
|
|
<DeleteFilled
|
|
|
|
|
style={{
|
|
|
|
|
color: '#FF4D4F',
|
|
|
|
|
}}
|
|
|
|
|
onClick={() => statusFormatter(record)}
|
|
|
|
|
/>
|
|
|
|
|
{/* ) : (
|
|
|
|
|
<ReloadOutlined
|
|
|
|
|
style={{
|
|
|
|
|
color: "#ff4d4f",
|
|
|
|
|
pointerEvents: "none"
|
|
|
|
|
}}
|
|
|
|
|
/>
|
|
|
|
|
)} */}
|
|
|
|
|
</a>
|
|
|
|
|
</Space>
|
|
|
|
|
),
|
|
|
|
|
// ) : null,
|
|
|
|
|
},
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
const handleadd = async (values) => {
|
|
|
|
|
try {
|
|
|
|
|
// Validate break time fields before adding
|
|
|
|
|
await formRef.current?.validateFields([
|
|
|
|
|
'BreakName',
|
|
|
|
|
'BreakStartTime',
|
|
|
|
|
'BreakEndTime'
|
|
|
|
|
]);
|
|
|
|
|
|
|
|
|
|
const Formdata = formRef.current?.getFieldsValue();
|
|
|
|
|
const alreadyExists = Tabledata.some(
|
|
|
|
|
(item) => item.BreakName === Formdata?.BreakName
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
if (BrakeFromTime && BrakeToTime && Formdata?.BreakName != undefined) {
|
|
|
|
|
if (!alreadyExists) {
|
|
|
|
|
setTabledata((prev) => {
|
|
|
|
|
const newIndex = prev.length + 1;
|
|
|
|
|
|
|
|
|
|
const datas = {
|
|
|
|
|
BreakName: Formdata?.BreakName,
|
|
|
|
|
BreakStartTime: BrakeFromTime,
|
|
|
|
|
BreakEndTime: BrakeToTime,
|
|
|
|
|
key: newIndex,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
return [...prev, datas];
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
setBrakeFromTime();
|
|
|
|
|
setBrakeToTime();
|
|
|
|
|
formRef.current.resetFields([
|
|
|
|
|
'BreakEndTime',
|
|
|
|
|
'BreakStartTime',
|
|
|
|
|
'BreakName',
|
|
|
|
|
]);
|
|
|
|
|
} else {
|
|
|
|
|
setMessageType('error');
|
|
|
|
|
setMessageData('Break Time Already Exist');
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
setMessageType('error');
|
|
|
|
|
setMessageData('Add Break Time');
|
|
|
|
|
}
|
|
|
|
|
} catch (error) {
|
|
|
|
|
setMessageType('error');
|
|
|
|
|
setMessageData('Please fix validation errors before adding break time');
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const handleEdit = async (values) => {
|
|
|
|
|
try {
|
|
|
|
|
// Validate break time fields before editing
|
|
|
|
|
await formRef.current?.validateFields([
|
|
|
|
|
'BreakName',
|
|
|
|
|
'BreakStartTime',
|
|
|
|
|
'BreakEndTime',
|
|
|
|
|
]);
|
|
|
|
|
|
|
|
|
|
const Formdata = formRef.current?.getFieldsValue();
|
|
|
|
|
const alreadyExists = Tabledata.some(
|
|
|
|
|
(item, idx) =>
|
|
|
|
|
item.BreakName === Formdata?.BreakName && idx !== editIndex
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
if (BrakeFromTime && BrakeToTime && Formdata?.BreakName !== undefined) {
|
|
|
|
|
if (!alreadyExists) {
|
|
|
|
|
const updatedArray = [...Tabledata];
|
|
|
|
|
updatedArray[editIndex] = {
|
|
|
|
|
...updatedArray[editIndex],
|
|
|
|
|
BreakName: Formdata?.BreakName,
|
|
|
|
|
BreakStartTime: BrakeFromTime,
|
|
|
|
|
BreakEndTime: BrakeToTime,
|
|
|
|
|
BreakId: BrakeId,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
setTabledata(updatedArray);
|
|
|
|
|
setBrakeFromTime();
|
|
|
|
|
setBrakeToTime();
|
|
|
|
|
setEditDataval(false);
|
|
|
|
|
formRef.current.resetFields([
|
|
|
|
|
'BreakEndTime',
|
|
|
|
|
'BreakStartTime',
|
|
|
|
|
'BreakName',
|
|
|
|
|
]);
|
|
|
|
|
} else {
|
|
|
|
|
setMessageType('error');
|
|
|
|
|
setMessageData('Break Time Already Exists');
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
setMessageType('error');
|
|
|
|
|
setMessageData('Add Break Time');
|
|
|
|
|
}
|
|
|
|
|
} catch (error) {
|
|
|
|
|
setMessageType('error');
|
|
|
|
|
setMessageData('Please fix validation errors before editing break time');
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const actionsFormatter = async (row, index, rowIndex) => {
|
|
|
|
|
setEditDataval(true);
|
|
|
|
|
setEditIndex(index);
|
|
|
|
|
|
|
|
|
|
console.log(row, rowIndex, 'row, rowIndexrow, rowIndex');
|
|
|
|
|
formRef.current?.setFieldsValue({
|
|
|
|
|
BreakName: row?.BreakName,
|
|
|
|
|
BreakStartTime: row?.BreakStartTime,
|
|
|
|
|
BreakEndTime: row?.BreakEndTime,
|
|
|
|
|
});
|
|
|
|
|
(setBrakeFromTime(row?.BreakStartTime), setBrakeToTime(row?.BreakEndTime));
|
|
|
|
|
setBrakeId(row?.BreakId);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const statusFormatter = (record, index) => {
|
|
|
|
|
let Deleteddata = Tabledata.filter(
|
|
|
|
|
(item) => item.BreakName != record?.BreakName
|
|
|
|
|
);
|
|
|
|
|
setTabledata(Deleteddata);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const onComplete = useCallback(() => {
|
|
|
|
|
setMessageData(null);
|
|
|
|
|
setMessageType(null);
|
|
|
|
|
}, []);
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
<div className="shiftMasterForm-Master" style={{ fontFamily: 'Poppins' }}>
|
|
|
|
|
<div className="pageOverAll">
|
|
|
|
|
<div className="userPage">
|
|
|
|
|
<div className="userPageContent">
|
|
|
|
|
<Messages
|
|
|
|
|
messageType={messageType}
|
|
|
|
|
messageData={messageData}
|
|
|
|
|
onComplete={onComplete}
|
|
|
|
|
/>
|
|
|
|
|
<div className="formName">
|
|
|
|
|
<FormHeader title={'Shift'} />
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<div className="formDiv">
|
|
|
|
|
<Form
|
|
|
|
|
ref={formRef}
|
|
|
|
|
className="formDivAnt"
|
|
|
|
|
onFinish={onFinish}
|
|
|
|
|
initialValues={{ ...editstate }}
|
|
|
|
|
>
|
|
|
|
|
<div className="formDivS">
|
|
|
|
|
<div className="inputForm">
|
|
|
|
|
<Form.Item
|
|
|
|
|
name="ShiftName"
|
|
|
|
|
rules={[
|
|
|
|
|
{
|
|
|
|
|
required: true,
|
|
|
|
|
pattern: /^(?!\s*$).+/,
|
|
|
|
|
message: 'Please Enter Shift Name',
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
validator: async (_, value) => {
|
|
|
|
|
await validateSafeInput(value);
|
|
|
|
|
if (value?.length > 20) {
|
|
|
|
|
return Promise.reject(
|
|
|
|
|
'Shift Name Max 20 characters allowed'
|
|
|
|
|
);
|
|
|
|
|
} else {
|
|
|
|
|
return Promise.resolve();
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
]}
|
|
|
|
|
>
|
|
|
|
|
<InputField
|
|
|
|
|
label={<label class="required">Shift Name</label>}
|
|
|
|
|
isOnChange={
|
|
|
|
|
formType == 'edit' || editDataval ? true : false
|
|
|
|
|
}
|
|
|
|
|
autocomplete="off"
|
|
|
|
|
/>
|
|
|
|
|
</Form.Item>
|
|
|
|
|
|
|
|
|
|
<Form.Item
|
|
|
|
|
name="StartTime"
|
|
|
|
|
rules={[
|
|
|
|
|
{
|
|
|
|
|
required: true,
|
|
|
|
|
message: 'Please Select Shift Start Time',
|
|
|
|
|
},
|
|
|
|
|
]}
|
|
|
|
|
>
|
|
|
|
|
<TimePickers
|
|
|
|
|
label={<label class="required">Start Time</label>}
|
|
|
|
|
isOnChange={true}
|
|
|
|
|
onChange={onFromTimeChange}
|
|
|
|
|
valueData={fromTime}
|
|
|
|
|
/>
|
|
|
|
|
</Form.Item>
|
|
|
|
|
|
|
|
|
|
<Form.Item
|
|
|
|
|
name="EndTime"
|
|
|
|
|
rules={[
|
|
|
|
|
{
|
|
|
|
|
required: true,
|
|
|
|
|
message: 'Please Select Shift End Time',
|
|
|
|
|
},
|
|
|
|
|
{ validator: validateTime },
|
|
|
|
|
]}
|
|
|
|
|
>
|
|
|
|
|
<TimePickers
|
|
|
|
|
label={<label class="required">End Time</label>}
|
|
|
|
|
isOnChange={true}
|
|
|
|
|
onChange={onToTimeChange}
|
|
|
|
|
valueData={toTime}
|
|
|
|
|
/>
|
|
|
|
|
</Form.Item>
|
|
|
|
|
|
|
|
|
|
<Form.Item
|
|
|
|
|
name="GracePeriod"
|
|
|
|
|
rules={[
|
|
|
|
|
{
|
|
|
|
|
required: true,
|
|
|
|
|
pattern: /^(?!\s*$).+/,
|
|
|
|
|
message: 'Please Enter Grace Period',
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
validator: async (_, value) => {
|
|
|
|
|
if (
|
|
|
|
|
value === undefined ||
|
|
|
|
|
value === null ||
|
|
|
|
|
value === ''
|
|
|
|
|
) {
|
|
|
|
|
return Promise.resolve(); // ✅ Allow empty value (optional field)
|
|
|
|
|
}
|
|
|
|
|
await validateSafeInput(value);
|
|
|
|
|
if (value <= 60 && value >= 0) {
|
|
|
|
|
return Promise.resolve();
|
|
|
|
|
} else if (!value) {
|
|
|
|
|
return Promise.reject(
|
|
|
|
|
'Please Enter Grace Period'
|
|
|
|
|
);
|
|
|
|
|
} else {
|
|
|
|
|
return Promise.reject(
|
|
|
|
|
'Please Enter below or equal to (60 mins)'
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
]}
|
|
|
|
|
>
|
|
|
|
|
<InputField
|
|
|
|
|
label={
|
|
|
|
|
<label class="required">Grace Period (Min)</label>
|
|
|
|
|
}
|
|
|
|
|
type="number"
|
|
|
|
|
autoComplete="off"
|
|
|
|
|
min={1}
|
|
|
|
|
max={60}
|
|
|
|
|
maxLength={2}
|
|
|
|
|
isOnChange={
|
|
|
|
|
formType == 'edit' || editDataval ? true : false
|
|
|
|
|
}
|
|
|
|
|
/>
|
|
|
|
|
</Form.Item>
|
|
|
|
|
|
|
|
|
|
<Collapse className="breakTimeSection">
|
|
|
|
|
<Collapse.Panel header="Break Time Configuration" key="1">
|
|
|
|
|
<div
|
|
|
|
|
style={{
|
|
|
|
|
display: 'flex',
|
|
|
|
|
gap: '16px',
|
|
|
|
|
alignItems: 'start',
|
|
|
|
|
flexWrap: 'wrap',
|
|
|
|
|
}}
|
|
|
|
|
>
|
|
|
|
|
<Form.Item
|
|
|
|
|
name="BreakName"
|
|
|
|
|
rules={[
|
|
|
|
|
{
|
|
|
|
|
validator: async (_, value) => {
|
|
|
|
|
await validateSafeInput(value);
|
|
|
|
|
if (value?.length > 20) {
|
|
|
|
|
return Promise.reject(
|
|
|
|
|
'Break Name Max 20 characters allowed'
|
|
|
|
|
);
|
|
|
|
|
} else {
|
|
|
|
|
return Promise.resolve();
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
]}
|
|
|
|
|
>
|
|
|
|
|
<InputField
|
|
|
|
|
label={<label class="required">Break Name</label>}
|
|
|
|
|
autocomplete="off"
|
|
|
|
|
isOnChange={
|
|
|
|
|
formType == 'edit' || editDataval ? true : false
|
|
|
|
|
}
|
|
|
|
|
/>
|
|
|
|
|
</Form.Item>
|
|
|
|
|
|
|
|
|
|
<Form.Item
|
|
|
|
|
name="BreakStartTime"
|
|
|
|
|
rules={[{ validator: validateBreakTime1 }]}
|
|
|
|
|
>
|
|
|
|
|
<TimePickers
|
|
|
|
|
label={
|
|
|
|
|
<label class="required">Break Start Time</label>
|
|
|
|
|
}
|
|
|
|
|
isOnChange={true}
|
|
|
|
|
onChange={onBrakeFromTimeChange}
|
|
|
|
|
valueData={BrakeFromTime}
|
|
|
|
|
/>
|
|
|
|
|
</Form.Item>
|
|
|
|
|
|
|
|
|
|
<Form.Item
|
|
|
|
|
name="BreakEndTime"
|
|
|
|
|
rules={[{ validator: validateBreakTime2 }]}
|
|
|
|
|
>
|
|
|
|
|
<TimePickers
|
|
|
|
|
label={
|
|
|
|
|
<label class="required">Break End Time</label>
|
|
|
|
|
}
|
|
|
|
|
isOnChange={true}
|
|
|
|
|
onChange={onBrakeToTimeChange}
|
|
|
|
|
valueData={BrakeToTime}
|
|
|
|
|
/>
|
|
|
|
|
</Form.Item>
|
|
|
|
|
<button
|
|
|
|
|
type="button"
|
|
|
|
|
className="break-add"
|
|
|
|
|
onClick={() => {
|
|
|
|
|
editDataval ? handleEdit() : handleadd();
|
|
|
|
|
}}
|
|
|
|
|
>
|
|
|
|
|
<FaPlus />
|
|
|
|
|
<p>Add Break</p>
|
|
|
|
|
</button>
|
|
|
|
|
</div>
|
|
|
|
|
</Collapse.Panel>
|
|
|
|
|
</Collapse>
|
|
|
|
|
|
|
|
|
|
<div
|
|
|
|
|
className="Quotation-tables Quotation-tablesShift"
|
|
|
|
|
style={{ maxwidth: '500px', overflowX: 'scroll' }}
|
|
|
|
|
>
|
|
|
|
|
<Table
|
|
|
|
|
bordered
|
|
|
|
|
// components={components}
|
|
|
|
|
// rowClassName="editable-row"
|
|
|
|
|
columns={Columns}
|
|
|
|
|
dataSource={Tabledata}
|
|
|
|
|
// pagination={handlePageChange}
|
|
|
|
|
// onChange={handleChange}
|
|
|
|
|
/>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<div className="submitButton">
|
|
|
|
|
<Buttons
|
|
|
|
|
buttonText="SUBMIT"
|
|
|
|
|
color="901D77"
|
|
|
|
|
icon={<ArrowRightOutlined />}
|
|
|
|
|
// handleSubmit={handleSubmit}
|
|
|
|
|
/>
|
|
|
|
|
</div>
|
|
|
|
|
</Form>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
export default ShiftForm;
|