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'; import '../../Styles/OverAllStyle/OverAllStyle.scss'; 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) => ( {(page - 1) * 10 + index + 1} ), }, { title: 'Break Name', dataIndex: 'BreakName', key: 'BreakName', editable: true, render: (text) => {text}, 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 ? ( {/* {record.ActiveStatus === "A" ? ( */} // ((UserType === 'Super Admin') || // (UserType === "Super Admin User" && SAAccessCommonMaster?.UpdateAccess === "Y") || // (UserType === 'Employee' && empData?.UpdateAccess === "Y") || // (UserType === 'Admin')) // ? actionsFormatter(record, index) // : null } /> {/* ) : ( "" )} */} {/* {record.ActiveStatus === "A" ? ( */} statusFormatter(record)} /> {/* ) : ( )} */} ), // ) : 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 (
{ await validateSafeInput(value); if (value?.length > 20) { return Promise.reject( 'Shift Name Max 20 characters allowed' ); } else { return Promise.resolve(); } }, }, ]} > Shift Name} isOnChange={ formType == 'edit' || editDataval ? true : false } autocomplete="off" /> Start Time} isOnChange={true} onChange={onFromTimeChange} valueData={fromTime} /> End Time} isOnChange={true} onChange={onToTimeChange} valueData={toTime} /> { 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)' ); } }, }, ]} > Grace Period (Min) } type="number" autoComplete="off" min={1} max={60} maxLength={2} isOnChange={ formType == 'edit' || editDataval ? true : false } />
{ await validateSafeInput(value); if (value?.length > 20) { return Promise.reject( 'Break Name Max 20 characters allowed' ); } else { return Promise.resolve(); } }, }, ]} > Break Name} autocomplete="off" isOnChange={ formType == 'edit' || editDataval ? true : false } /> Break Start Time } isOnChange={true} onChange={onBrakeFromTimeChange} valueData={BrakeFromTime} /> Break End Time } isOnChange={true} onChange={onBrakeToTimeChange} valueData={BrakeToTime} />
} // handleSubmit={handleSubmit} />
); }; export default ShiftForm;