Files
worldshine-redesign/client/src/components/trans-routes/PersonnelInfoTable.js
2026-03-09 12:02:24 -04:00

1172 lines
58 KiB
JavaScript

import React, {useState} from "react";
import { useDispatch } from "react-redux";
import { CUSTOMER_TYPE_TEXT, PERSONAL_ROUTE_STATUS, PERSONAL_ROUTE_STATUS_TEXT, PICKUP_STATUS, PICKUP_STATUS_TEXT, REPORT_TYPE } from "../../shared";
import { Modal, Button } from "react-bootstrap";
import { transRoutesSlice } from "./../../store";
import { CSVLink } from "react-csv";
import { ReportService, CustomerService } from "../../services";
import TimePicker from 'react-time-picker';
import 'react-time-picker/dist/TimePicker.css';
import moment from 'moment';
import { useNavigate } from "react-router-dom";
const PersonnelInfoTable = ({transRoutes, showCompletedInfo,
showGroupInfo, allowForceEdit, showFilter,
driverName, vehicle, relatedOutbound,
vehicles, isInbound, deleteFile,
keyword, statusFilter, customerNameFilter,
customerTableId, routeTypeFilter, customerTypeFilter
}) => {
const [show, setShow] = useState(false);
const [showGroupEditor, setShowGroupEditor] = useState(false);
const [showBulkUpdateModal, setShowBulkUpdateModal] = useState(false);
const [customerInEdit, setCustomerInEdit] = useState(undefined);
const [customersInEdit, setCustomersInEdit] = useState([]);
// const [statusFilter, setStatusFilter] = useState('');
// const [customerTypeFilter, setCustomerTypeFilter] = useState('');
// const [customerNameFilter, setCustomerNameFilter] = useState('');
// const [customerTableId, setCustomerTableId] = useState('');
// const [routeTypeFilter, setRouteTypeFilter] = useState('');
const [customerCheckInTime, setCustomerCheckInTime] = useState('');
const [customerCheckOutTime, setCustomerCheckOutTime] = useState('');
const [customerPickUpTime, setCustomerPickUpTime] = useState('');
const [customerDropOffTime, setCustomerDropOffTime] = useState('');
const [customerEstimatedPickUpTime, setCustomerEstimatedPickUpTime] = useState('');
const [customerEstimatedDropOffTime, setCustomerEstimatedDropOffTime] = useState('');
const [customerStatusInRoute, setCustomerStatusInRoute] = useState(false);
const [customerPickupStatusInRoute, setCustomerPickupStatusInRoute] = useState('');
const [customerTransferToRoute, setCustomerTransferToRoute] = useState('');
const [customerAddressOverride, setCustomerAddressOverride] = useState('');
const [customerAddressesList, setCustomerAddressesList] = useState([]);
const [customerNote, setCustomerNote] = useState('');
const [bulkEnterCenterTime, setBulkEnterCenterTime] = useState('');
const [bulkLeaveCenterTime, setBulkLeaveCenterTime] = useState('');
const [bulkCustomerRouteStatus, setBulkCustomerRouteStatus] = useState('');
const [bulkCustomerPickupStatus, setBulkCustomerPickupStatus] = useState('');
const dispatch = useDispatch();
const navigate = useNavigate();
const { updateRoute } = transRoutesSlice.actions;
const params = new URLSearchParams(window.location.search);
const scheduleDate = params.get('dateSchedule');
// const clearFilters = () => {
// setStatusFilter('');
// setCustomerTypeFilter('');
// setRouteTypeFilter('');
// setCustomerNameFilter('');
// setCustomerTableId('');
// }
const openForceEditModal = (customer) => {
if (allowForceEdit) {
// CustomerService.getCustomer(customer?.customer_id).then(data => {
// const fullCustomer = data?.data;
// const result = [];
// if (fullCustomer?.address1 && fullCustomer?.address1 !== '') {
// result.push(fullCustomer?.address1);
// }
// if (fullCustomer?.address2 && fullCustomer?.address2 !== '') {
// result.push(fullCustomer?.address2);
// }
// if (fullCustomer?.address3 && fullCustomer?.address3 !== '') {
// result.push(fullCustomer?.address3);
// }
// if (fullCustomer?.address4 && fullCustomer?.address4 !== '') {
// result.push(fullCustomer?.address4);
// }
// if (fullCustomer?.address5 && fullCustomer?.address5 !== '') {
// result.push(fullCustomer?.address5);
// }
// setCustomerAddressesList(result);
// })
setShow(true);
setCustomerInEdit(customer);
setCustomerCheckInTime(customer.customer_enter_center_time ? new Date(customer.customer_enter_center_time) : '');
setCustomerCheckOutTime(customer.customer_leave_center_time ? new Date(customer.customer_leave_center_time) : '');
setCustomerPickUpTime(customer.customer_pickup_time ? new Date(customer.customer_pickup_time) : '');
setCustomerDropOffTime(customer.customer_dropoff_time ? new Date(customer.customer_dropoff_time) : '');
setCustomerEstimatedPickUpTime(customer.customer_estimated_pickup_time ? new Date(customer.customer_estimated_pickup_time) : '');
setCustomerEstimatedDropOffTime(customer.customer_estimated_dropoff_time ? new Date(customer.customer_estimated_dropoff_time) : '');
setCustomerStatusInRoute(customer.customer_route_status);
setCustomerPickupStatusInRoute(customer.customer_pickup_status);
setCustomerNote(customer?.customer_note);
}
}
const goToReportWithSignature = () => {
navigate(`/trans-routes/route-report-with-signature/${transRoutes[0]?.id}`)
}
const openForceEditGroupModal = (customers) => {
if (allowForceEdit) {
setShowGroupEditor(true);
setCustomersInEdit(customers);
setCustomerCheckInTime('');
setCustomerCheckOutTime('');
setCustomerDropOffTime('');
setCustomerPickUpTime('');
setCustomerStatusInRoute('');
setCustomerEstimatedDropOffTime('');
setCustomerEstimatedPickUpTime('');
setCustomerAddressOverride('');
setCustomerNote('');
}
}
const closeGroupEditorModal = () => {
setCustomersInEdit([]);
setCustomerCheckInTime('');
setCustomerCheckOutTime('');
setCustomerStatusInRoute('');
setCustomerDropOffTime('');
setCustomerPickUpTime('');
setCustomerEstimatedDropOffTime('');
setCustomerEstimatedPickUpTime('');
setCustomerNote('');
setShowGroupEditor(false);
}
const closeModal = () => {
setCustomerCheckInTime('');
setCustomerCheckOutTime('');
setCustomerDropOffTime('');
setCustomerPickUpTime('');
setCustomerStatusInRoute(false);
setCustomerPickupStatusInRoute('');
setCustomerAddressesList([]);
setCustomerEstimatedDropOffTime('');
setCustomerEstimatedPickUpTime('');
setCustomerAddressOverride('');
setCustomerNote('');
setShow(false);
}
const combineDateAndTime = (date, time) => {
const dateObj = moment(date);
const timeObj = moment(time, 'HH:mm');
dateObj.set({
hour: timeObj.get('hour'),
minute: timeObj.get('minute'),
second: timeObj.get('second')
})
return dateObj;
}
const saveRouteCustomerInfo = () => {
const routeId = customerInEdit.routeId;
let removeSignature = false
if (routeId) {
let requestBody = transRoutes.find((route) => route.id === routeId);
const dateStr = requestBody?.schedule_date || '';
const newCustomerList = requestBody.route_customer_list.map((item) => {
let addedFields = {};
if (item.customer_id === customerInEdit.customer_id) {
if (customerCheckInTime && customerCheckInTime !== '') {
addedFields.customer_enter_center_time = combineDateAndTime(dateStr, customerCheckInTime);
addedFields.customer_route_status = PERSONAL_ROUTE_STATUS.IN_CENTER;
} else {
addedFields.customer_enter_center_time = null;
}
if (customerCheckOutTime && customerCheckOutTime !=='') {
addedFields.customer_leave_center_time = combineDateAndTime(dateStr, customerCheckOutTime);
addedFields.customer_route_status = PERSONAL_ROUTE_STATUS.LEFT_CENTER;
} else {
addedFields.customer_leave_center_time = null;
}
if (customerPickUpTime && customerPickUpTime !=='') {
addedFields.customer_pickup_time = combineDateAndTime(dateStr, customerPickUpTime);
addedFields.customer_route_status = PERSONAL_ROUTE_STATUS.PICKED;
removeSignature = true;
} else {
addedFields.customer_pickup_time = null;
}
if (customerDropOffTime && customerDropOffTime !=='') {
addedFields.customer_dropoff_time = combineDateAndTime(dateStr, customerDropOffTime);
addedFields.customer_route_status = PERSONAL_ROUTE_STATUS.DROPPED_OFF;
removeSignature = true;
} else {
addedFields.customer_dropoff_time = null;
}
if (customerEstimatedPickUpTime && customerEstimatedPickUpTime !=='') {
addedFields.customer_estimated_pickup_time = combineDateAndTime(dateStr, customerEstimatedPickUpTime);
} else {
addedFields.customer_estimated_pickup_time = null;
}
// if (customerEstimatedDropOffTime && customerEstimatedDropOffTime !=='') {
// addedFields.customer_estimated_dropoff_time = customerEstimatedDropOffTime;
// }
if (customerAddressOverride && customerAddressOverride !=='') {
addedFields.customer_address_override = customerAddressOverride;
}
if (customerStatusInRoute) {
addedFields.customer_route_status = customerStatusInRoute;
} else {
addedFields.customer_route_status = PERSONAL_ROUTE_STATUS.NO_STATUS;
}
if (customerPickupStatusInRoute && customerPickupStatusInRoute !=='') {
addedFields.customer_pickup_status = customerPickupStatusInRoute;
}
if (customerTransferToRoute && customerTransferToRoute !=='') {
addedFields.customer_transfer_to_route = customerTransferToRoute;
}
if (customerNote && customerNote !== '') {
addedFields.customer_note = customerNote;
}
}
return Object.assign({}, item, addedFields);;
})
requestBody = Object.assign({}, requestBody, {route_customer_list: newCustomerList, updatedAt: new Date(), updatedBy: 'admin'});
let finalParams = { id: routeId, data: requestBody };
if (scheduleDate) {
finalParams = Object.assign({}, finalParams, {dateText: moment(scheduleDate).format('MM/DD/YYYY'), fromSchedule: true})
}
if (dateStr !== '' && dateStr !== moment().format('MM/DD/YYYY')) {
finalParams = Object.assign({}, finalParams, {dateText: dateStr})
}
dispatch(updateRoute(finalParams));
// if (removeSignature && deleteFile) {
// deleteFile();
// }
} else {
window.alert('Fail to update Route: no route Id is attached to this customer.')
}
setShow(false);
}
const saveRouteGroupCustomerInfo = () => {
const routeId = customersInEdit[0]?.routeId;
let removeSignature = false
if (routeId) {
let requestBody = transRoutes.find((route) => route.id === routeId);
const dateStr = requestBody?.schedule_date || '';
const newCustomerList = requestBody.route_customer_list.map((item) => {
let addedFields = {};
if (customersInEdit?.find((customerItem) => customerItem.customer_id === item.customer_id)) {
if (customerCheckInTime && customerCheckInTime !== '') {
addedFields.customer_enter_center_time = combineDateAndTime(dateStr, customerCheckInTime);
addedFields.customer_route_status = PERSONAL_ROUTE_STATUS.IN_CENTER;
}
if (customerCheckOutTime && customerCheckOutTime !=='') {
addedFields.customer_leave_center_time = combineDateAndTime(dateStr, customerCheckOutTime);
addedFields.customer_route_status = PERSONAL_ROUTE_STATUS.LEFT_CENTER;
}
if (customerPickUpTime && customerPickUpTime !=='') {
addedFields.customer_pickup_time = combineDateAndTime(dateStr, customerPickUpTime);
addedFields.customer_route_status = PERSONAL_ROUTE_STATUS.PICKED;
removeSignature = true;
}
if (customerDropOffTime && customerDropOffTime !=='') {
addedFields.customer_dropoff_time = combineDateAndTime(dateStr, customerDropOffTime);
addedFields.customer_route_status = PERSONAL_ROUTE_STATUS.DROPPED_OFF;
removeSignature = true;
}
if (customerStatusInRoute) {
addedFields.customer_route_status = customerStatusInRoute;
} else {
addedFields.customer_route_status = PERSONAL_ROUTE_STATUS.NO_STATUS;
}
}
return Object.assign({}, item, addedFields);;
})
requestBody = Object.assign({}, requestBody, {route_customer_list: newCustomerList, updatedAt: new Date(), updatedBy: 'admin'});
let finalParams = { id: routeId, data: requestBody };
if (scheduleDate) {
finalParams = Object.assign({}, finalParams, {dateText: moment(scheduleDate).format('MM/DD/YYYY'), fromSchedule: true})
}
if (dateStr !== '' && dateStr !== moment().format('MM/DD/YYYY')) {
finalParams = Object.assign({}, finalParams, {dateText: dateStr})
}
dispatch(updateRoute(finalParams));
// if (removeSignature && deleteFile) {
// deleteFile();
// }
// dispatch(updateRoute({ id: routeId, data: requestBody }))
} else {
window.alert('Fail to update Route: no route Id is attached to this customer.')
}
setShowGroupEditor(false);
}
// const getAllRoutesCustomersStatus = (routes) => {
// const result = {};
// for (const route of routes) {
// for (const customer of route.route_customer_list) {
// if ((!showGroupInfo && customer.customer_route_status !== PERSONAL_ROUTE_STATUS.DISABLED) || showGroupInfo) {
// if (result.hasOwnProperty(customer.customer_id)) {
// result[customer.customer_id] = Object.assign(
// {},
// result[customer.customer_id],
// customer,
// route.type === 'inbound' ? { inboundStatus: customer.customer_route_status, inboundRoute: route.id} : {},
// route.type === 'outbound' ? { outboundStatus: customer.customer_route_status, outboundRoute: route.id} : {},
// customer.customer_pickup_status === PICKUP_STATUS.SCHEDULE_ABSENT ? { inboundStatus: PERSONAL_ROUTE_STATUS.SCHEDULED_ABSENT, outboundStatus: PERSONAL_ROUTE_STATUS.SCHEDULED_ABSENT} : {});
// } else {
// result[customer.customer_id] = Object.assign(
// {},
// customer,
// route.type === 'inbound' ? { inboundStatus: customer.customer_route_status, inboundRoute: route.id, outboundStatus: null, outboundRoute: null} : {},
// route.type === 'outbound' ? { outboundStatus: customer.customer_route_status, outboundRoute: route.id, inboundRoute: null, inboundStatus: null} : {},
// customer.customer_pickup_status === PICKUP_STATUS.SCHEDULE_ABSENT ? { inboundStatus: PERSONAL_ROUTE_STATUS.SCHEDULED_ABSENT, outboundStatus: PERSONAL_ROUTE_STATUS.SCHEDULED_ABSENT} : {});
// }
// }
// }
// }
// console.log(result);
// return result;
// };
// const getTextAndClassName = (customer) => {
// if (customer.outboundStatus) {
// return PERSONAL_ROUTE_STATUS_TEXT[customer.outboundStatus];
// } else {
// if (customer.inboundStatus) {
// return PERSONAL_ROUTE_STATUS_TEXT[customer.inboundStatus];
// }
// }
// return PERSONAL_ROUTE_STATUS_TEXT[PERSONAL_ROUTE_STATUS.NO_STATUS];
// };
const getAllCustomers = (routes) => {
let result = [];
for (const route of routes) {
const customerList = route.route_customer_list.map(item => Object.assign({}, item, {routeType: route.type, routeId: route.id, route: route}))
result = result.concat(customerList);
}
return result.sort((a, b) => {
if (a.customer_id < b.customer_id) {
return -1;
} else {
return 1;
}
});
}
const getRouteCustomersWithGroups = () => {
const customerList = transRoutes[0]?.route_customer_list.map((item, index )=> Object.assign({}, item, {routeType: transRoutes[0].type, routeId: transRoutes[0].id}, {index: index+1}));
const result = {};
if (customerList) {
for (const customer of customerList) {
if (customer.customer_group) {
if (result[customer.customer_group]) {
result[customer.customer_group].push(customer);
} else {
result[customer.customer_group] = [];
result[customer.customer_group].push(customer);
}
} else {
if (result.no_group) {
result.no_group.push(customer);
} else {
result.no_group = [];
result.no_group.push(customer);
}
}
}
}
return result;
}
const getSortedFormItems = () => {
const result = getRouteCustomersWithGroups();
let finalResult = [];
for (const key of Object.keys(result)) {
if (key === 'no_group') {
finalResult = finalResult.concat(result[key]);
} else {
finalResult.push({
customer_pickup_order: result[key][0].customer_pickup_order,
customer_group: key,
customers: result[key]
})
}
}
return finalResult.sort((a, b) => a.customer_pickup_order - b.customer_pickup_order);
}
const getTextAndClassName = (customer) => {
if (customer.customer_pickup_status === PICKUP_STATUS.SCHEDULE_ABSENT) {
return PERSONAL_ROUTE_STATUS_TEXT[PERSONAL_ROUTE_STATUS.SCHEDULED_ABSENT];
}
if (customer.customer_route_status) {
return PERSONAL_ROUTE_STATUS_TEXT[customer.customer_route_status];
}
return PERSONAL_ROUTE_STATUS_TEXT[PERSONAL_ROUTE_STATUS.NO_STATUS];
}
const getDisplayPickupOrder = (pickupOrder) => {
if (pickupOrder === undefined || pickupOrder === null || pickupOrder === '') {
return '';
}
const numericValue = Number(pickupOrder);
if (Number.isNaN(numericValue)) {
return pickupOrder;
}
return numericValue + 1;
}
const generateRouteReportData = () => {
const title = ['', '', `Route(路线): ${transRoutes[0].name} Driver(司机): ${driverName} Vehicle(车号): ${vehicle?.vehicle_number} Date(日期): ${transRoutes[0]?.schedule_date}`]
const signature = ['', '', `Driver's Signature(司机签字): ________________________ Manager's Signature(经理签字): ______________________`]
const head = ['No.', 'Name', 'Address', 'Phone', 'Show-Up', 'Pick-Up', 'Arrival', 'Departure', 'Drop-Off', 'Notice', 'Member Type', 'Vehicle Number'];
const chineseHead=['序号', '姓名', '地址', '联系电话', '出勤', '接到时间', '抵达中心', '离开中心', '送达时间', '备注', '用户类别', '车号', ];
const content = [];
const customersList = getSortedFormItems();
let index = 1;
for (let i=0; i<customersList.length; i++) {
if (!customersList[i].customers) {
content.push([index, customersList[i].customer_name, customersList[i].customer_address_override || customersList[i].customer_address, customersList[i].customer_phone, customersList[i].customer_enter_center_time? 'Y': 'N', customersList[i].customer_pickup_time, customersList[i].customer_enter_center_time, customersList[i].customer_leave_center_time, customersList[i].customer_dropoff_time, customersList[i].customer_note, customersList[i].customer_type, vehicle?.vehicle_number]);
index++;
} else {
content.push(['', customersList[i].customer_group, customersList[i].customers[0].customer_group_address]);
for (const customer of customersList[i].customers) {
content.push([index, customer.customer_name, customer.customer_address_override || customer.customer_address, customer.customer_phone, customer.customer_enter_center_time? 'Y': 'N', customer.customer_pickup_time, customer.customer_enter_center_time, customer.customer_leave_center_time, customer.customer_dropoff_time, customer.customer_note,customer.customer_type, vehicle?.vehicle_number]);
index++;
}
}
}
const itemsTitle = ['', 'Items', 'Inspected Result'];
const checklist = [];
transRoutes[0]?.checklist_result?.forEach((item) => {
checklist.push(['', item.item, item.result ? 'Y' : 'N']);
})
return [title, signature, head, chineseHead, ...content, itemsTitle, ...checklist];
}
const generateInboundSeniorsReportData = () => {
const head = ['No.', 'Name', 'Show-Up', 'Vehicle Number'];
const chineseHead=['序号', '姓名', '出勤', '车号'];
const content = [];
let index = 1;
const customersList = getAllCustomers(transRoutes.filter(route => route.type === 'inbound'))?.filter(customer => (customer.customer_pickup_status !== PICKUP_STATUS.SCHEDULE_ABSENT) && (![PERSONAL_ROUTE_STATUS.NO_STATUS, PERSONAL_ROUTE_STATUS.UNEXPECTED_ABSENT, PERSONAL_ROUTE_STATUS.SCHEDULED_ABSENT].includes(customer.customer_route_status)));
for (let i=0; i<customersList.length; i++) {
content.push([index, customersList[i].customer_name, customersList[i].customer_route_status !== PERSONAL_ROUTE_STATUS.DISABLED ? 'Y': 'N', vehicles?.find(item => item?.id === customersList[i]?.route?.vehicle)?.vehicle_number]);
index++;
}
const finalNumber = ['Participants Arrived:', customersList.filter(customer => customer.customer_route_status!== PERSONAL_ROUTE_STATUS.DISABLED)?.length];
return [head, chineseHead, ...content, finalNumber ];
}
const generateSeniorTimeReport = () => {
const customersList = getAllCustomers(transRoutes.filter(route => route.type === 'inbound'));
const content = [];
let outboundCustomerList = [];
for (const outboundRoute of relatedOutbound) {
outboundCustomerList = outboundCustomerList.concat(outboundRoute.route_customer_list)
}
const outboundMap = new Map();
for (const outboundCustomer of outboundCustomerList) {
outboundMap.set(outboundCustomer.customer_id, outboundCustomer);
}
for (const customer of customersList) {
const element = {
index: customersList.indexOf(customer)+1,
customer_name: customer.customer_name,
customer_enter_center_time: customer.customer_enter_center_time,
customer_pickup_time: customer.customer_pickup_time,
customer_leave_center_time: outboundMap.get(customer.customer_id)?.customer_leave_center_time,
customer_dropoff_time: outboundMap.get(customer.customer_id)?.customer_dropoff_time,
customer_address: customer.customer_address_override || customer.customer_address,
customer_phone: customer.customer_phone,
customer_note: customer.customer_note,
customer_type: customer.customer_type,
vehicle_number: vehicle?.vehicle_number
}
content.push(element);
}
ReportService.getReportsByRouteIdAndType(transRoutes[0].id, REPORT_TYPE.SENIOR_CONSOLIDATE_REPORT).then(data=> {
if (data.data && data.data.length > 0) {
ReportService.updateReport(data.data[0].id, {type: REPORT_TYPE.SENIOR_CONSOLIDATE_REPORT, driver_name: driverName, vehicle_number: vehicle?.vehicle_number, checklist_result: transRoutes[0]?.checklist_result, route_id: transRoutes[0].id, route_name: transRoutes[0].name, date: transRoutes[0].schedule_date, data: content, head: ['No.', 'Name', 'Phone', 'Address', 'Pickup Time', 'Enter Center Time', 'Leave Center Time', 'Drop Off Time', 'Note', 'Member Type', 'Vehicle Number'], chinese_head: ['序号', '姓名', '电话', '地址', '接到时间', '进入中心时间', '离开中心时间', '送达时间', '备注', '用户类别', '车号']}).then(() => {
window.alert('The report is saved to Database. To get a PDF version, please run your PYTHON EXE Script.')
});
} else {
ReportService.createReport({type: REPORT_TYPE.SENIOR_CONSOLIDATE_REPORT, driver_name: driverName, route_id: transRoutes[0].id, vehicle_number: vehicle?.vehicle_number, checklist_result: transRoutes[0]?.checklist_result, route_name: transRoutes[0].name, date: transRoutes[0].schedule_date, data: content, head: ['No.', 'Name', 'Phone', 'Address', 'Pickup Time', 'Enter Center Time', 'Leave Center Time', 'Drop Off Time', 'Note', 'Member Type', 'Vehicle Number' ], chinese_head: ['序号', '姓名', '电话', '地址', '接到时间', '进入中心时间', '离开中心时间', '送达时间', '备注', '用户类别', '车号' ]}).then(() => {
window.alert('The report is saved to Database. To get a PDF version, please run your PYTHON EXE Script.')
});
}
})
}
const openBulkUpdateModal = () => {
setShowBulkUpdateModal(true);
setBulkEnterCenterTime('');
setBulkLeaveCenterTime('');
setBulkCustomerRouteStatus('');
setBulkCustomerPickupStatus('');
}
const closeBulkUpdateModal = () => {
setShowBulkUpdateModal(false);
setBulkEnterCenterTime('');
setBulkLeaveCenterTime('');
setBulkCustomerRouteStatus('');
setBulkCustomerPickupStatus('');
}
const saveBulkUpdate = () => {
const routeId = transRoutes[0]?.id;
// Debug logging
console.log('=== saveBulkUpdate Debug ===');
console.log('bulkEnterCenterTime:', bulkEnterCenterTime);
console.log('bulkEnterCenterTime type:', typeof bulkEnterCenterTime);
console.log('bulkEnterCenterTime value:', JSON.stringify(bulkEnterCenterTime));
console.log('bulkLeaveCenterTime:', bulkLeaveCenterTime);
console.log('bulkLeaveCenterTime type:', typeof bulkLeaveCenterTime);
console.log('bulkLeaveCenterTime value:', JSON.stringify(bulkLeaveCenterTime));
if (routeId) {
let requestBody = transRoutes.find((route) => route.id === routeId);
const dateStr = requestBody?.schedule_date || '';
console.log('dateStr:', dateStr);
console.log('Number of customers to update:', requestBody.route_customer_list.length);
console.log('Original customer list IDs:', requestBody.route_customer_list.map(c => ({ id: c.customer_id, name: c.customer_name, pickup_status: c.customer_pickup_status })));
const updatedCustomerList = requestBody.route_customer_list.map((item) => {
// Skip customers who are Unscheduled Absent or Scheduled Absent
// Only skip if status is explicitly set to one of these values (not undefined)
if (item.customer_pickup_status &&
(item.customer_pickup_status === PICKUP_STATUS.UNSCHEDULE_ABSENT ||
item.customer_pickup_status === PICKUP_STATUS.SCHEDULE_ABSENT)) {
console.log(`Skipping customer ${item.customer_id} (${item.customer_name}) - status: ${item.customer_pickup_status}`);
return item;
}
let updatedItem = { ...item };
// Debug logging for each customer
console.log(`Processing customer ${item.customer_id} (${item.customer_name})`);
// Check if bulkEnterCenterTime is a valid time string (HH:mm format)
console.log('Checking bulkEnterCenterTime:', {
value: bulkEnterCenterTime,
type: typeof bulkEnterCenterTime,
isTruthy: !!bulkEnterCenterTime,
isString: typeof bulkEnterCenterTime === 'string',
trimmed: typeof bulkEnterCenterTime === 'string' ? bulkEnterCenterTime.trim() : 'N/A',
trimmedLength: typeof bulkEnterCenterTime === 'string' ? bulkEnterCenterTime.trim().length : 0
});
if (bulkEnterCenterTime && typeof bulkEnterCenterTime === 'string' && bulkEnterCenterTime.trim() !== '') {
try {
const combinedTime = combineDateAndTime(dateStr, bulkEnterCenterTime);
const dateValue = combinedTime.toDate();
console.log('Combined enter center time (moment):', combinedTime);
console.log('Combined enter center time (Date):', dateValue);
updatedItem.customer_enter_center_time = dateValue;
// Don't automatically update status when setting time
console.log(`Set customer_enter_center_time for ${item.customer_name} to:`, updatedItem.customer_enter_center_time);
} catch (e) {
console.error('Error combining date and enter center time:', e);
}
} else {
console.log('Skipping bulkEnterCenterTime - condition not met');
}
// Check if bulkLeaveCenterTime is a valid time string (HH:mm format)
console.log('Checking bulkLeaveCenterTime:', {
value: bulkLeaveCenterTime,
type: typeof bulkLeaveCenterTime,
isTruthy: !!bulkLeaveCenterTime,
isString: typeof bulkLeaveCenterTime === 'string',
trimmed: typeof bulkLeaveCenterTime === 'string' ? bulkLeaveCenterTime.trim() : 'N/A',
trimmedLength: typeof bulkLeaveCenterTime === 'string' ? bulkLeaveCenterTime.trim().length : 0
});
if (bulkLeaveCenterTime && typeof bulkLeaveCenterTime === 'string' && bulkLeaveCenterTime.trim() !== '') {
try {
const combinedTime = combineDateAndTime(dateStr, bulkLeaveCenterTime);
const dateValue = combinedTime.toDate();
console.log('Combined leave center time (moment):', combinedTime);
console.log('Combined leave center time (Date):', dateValue);
updatedItem.customer_leave_center_time = dateValue;
// Don't automatically update status when setting time
console.log(`Set customer_leave_center_time for ${item.customer_name} to:`, updatedItem.customer_leave_center_time);
} catch (e) {
console.error('Error combining date and leave center time:', e);
}
} else {
console.log('Skipping bulkLeaveCenterTime - condition not met');
}
console.log(`Final updatedItem for ${item.customer_name}:`, {
customer_id: updatedItem.customer_id,
customer_enter_center_time: updatedItem.customer_enter_center_time,
customer_leave_center_time: updatedItem.customer_leave_center_time
});
if (bulkCustomerRouteStatus && bulkCustomerRouteStatus !== '') {
updatedItem.customer_route_status = bulkCustomerRouteStatus;
}
if (bulkCustomerPickupStatus && bulkCustomerPickupStatus !== '') {
updatedItem.customer_pickup_status = bulkCustomerPickupStatus;
}
return updatedItem;
});
requestBody = Object.assign({}, requestBody, {route_customer_list: updatedCustomerList, updatedAt: new Date(), updatedBy: 'admin'});
// Debug: Log all customers from updated list
console.log('=== All Updated Customers ===');
updatedCustomerList.forEach((customer, index) => {
console.log(`Customer ${index + 1}:`, {
customer_id: customer.customer_id,
customer_name: customer.customer_name,
pickup_status: customer.customer_pickup_status,
customer_enter_center_time: customer.customer_enter_center_time,
customer_leave_center_time: customer.customer_leave_center_time
});
});
let finalParams = { id: routeId, data: requestBody };
if (scheduleDate) {
finalParams = Object.assign({}, finalParams, {dateText: moment(scheduleDate).format('MM/DD/YYYY'), fromSchedule: true})
}
if (dateStr !== '' && dateStr !== moment().format('MM/DD/YYYY')) {
finalParams = Object.assign({}, finalParams, {dateText: dateStr})
}
// Log final payload before dispatch, especially for Wang,Huanran
const wangCustomer = finalParams.data.route_customer_list?.find(c =>
c.customer_id === '63657acff745ffd72affb8d8' || c.customer_name?.includes('Wang,Huanran')
);
console.log('Wang,Huanran customer in final payload:', wangCustomer);
console.log('Final params being dispatched:', {
id: finalParams.id,
data_keys: Object.keys(finalParams.data),
customer_count: finalParams.data.route_customer_list?.length
});
// Stringify to see what would actually be sent (Date serialization)
try {
const stringified = JSON.stringify(finalParams.data.route_customer_list?.slice(0, 2));
console.log('Sample serialized customer list (first 2):', stringified);
} catch (e) {
console.error('Error stringifying:', e);
}
console.log('=== End saveBulkUpdate Debug ===');
dispatch(updateRoute(finalParams));
} else {
window.alert('Fail to update Route: no route Id found.')
}
closeBulkUpdateModal();
}
return (
<>
{!showGroupInfo && (<div className="list row mb-4">
<div className="col-md-12">
<CSVLink className="btn btn-primary btn-sm btn-no-deco" data={generateInboundSeniorsReportData()} filename={`Route Inbound Customers Show-up Report`}>
Generate Inbound Participants Report
</CSVLink>
</div>
</div>)}
{showGroupInfo && (<div className="list row mb-4">
<div className="col-md-12">
<CSVLink className="btn btn-primary btn-no-deco btn-sm me-2" data={generateRouteReportData()} filename={`Route Report - ${transRoutes[0].name} (定线出车单)`}>
Generate Route Reports
</CSVLink>
<button className="btn btn-primary btn-sm me-2" onClick={() => goToReportWithSignature()}>Get Route Report With Signature</button>
<button className="btn btn-primary btn-sm" onClick={() => openBulkUpdateModal()}>Bulk Update Route Customer Time</button>
</div>
</div>)}
{/* {showFilter && (<div>
<h6>Filter:</h6>
<div className="list row">
<div className="col-md-6 col-sm-6 col-xs-12 mb-4">
Participant Status: <select
value={statusFilter}
onChange={(e) => setStatusFilter(e.target.value)}
>
{
[['', {text: ''}], ...Object.entries(PERSONAL_ROUTE_STATUS_TEXT)].map(([key, {text}]) => (
<option key={key} value={key}>{text}</option>
))
}
</select>
</div>
<div className="col-md-6 col-sm-6 col-xs-12 mb-4 ml-4">
Participant Type: <select
value={customerTypeFilter}
onChange={(e) => setCustomerTypeFilter(e.target.value)}
>
{
[['', ''], ...Object.entries(CUSTOMER_TYPE_TEXT)].map(([key, text]) => (
<option key={key} value={key}>{text}</option>
))
}
</select>
</div>
<div className="col-md-6 col-sm-6 col-xs-12 mb-4">
Routes Type: <select
value={routeTypeFilter}
onChange={(e) => setRouteTypeFilter(e.target.value)}
>
<option value=""></option>
<option value="inbound">inbound</option>
<option value="outbound">outbound</option>
</select>
</div>
<div className="col-md-6 col-sm-6 col-xs-12 mb-4">
Participant Name: <input type="text" value={customerNameFilter} onChange={(e) => setCustomerNameFilter(e.target.value)} />
</div>
<div className="col-md-6 col-sm-6 col-xs-12 mb-4">
Table Id: <input type="text" value={customerTableId} onChange={(e) => setCustomerTableId(e.target.value)} />
</div>
<div className="col-md-12 col-sm-12 col-xs-12 mb-4">
<button className="btn btn-primary" onClick={() => clearFilters()}>Clear Filters</button>
</div>
</div>
</div>)} */}
<div className="list row">
<div className="col-md-12 overflow-auto">
<table className="personnel-info-table">
<thead>
<tr>
<th className="th-index">No.</th>
<th>Name</th>
{showCompletedInfo && (<th>Address</th>)}
{showCompletedInfo && (<th>Tel</th>)}
<th>Status</th>
<th>Type</th>
{!showCompletedInfo &&<th>Route Type</th>}
<th>Pick Up Time</th>
<th>Enter Center Time</th>
<th>Leave Center Time</th>
<th>Drop Off Time</th>
{showCompletedInfo && (<th>Schedule Absent</th>)}
{showCompletedInfo && (<th>Schedule Absent Note</th>)}
{showCompletedInfo && (<th>Special Needs</th>)}
{showCompletedInfo && (<th>Pickup Order</th>)}
{showCompletedInfo && (<th>Estimated Pickup Time</th>)}
{!showCompletedInfo && (<th>Vehicle Number</th>)}
{allowForceEdit && <th>Edit</th>}
</tr>
</thead>
<tbody>
{!showGroupInfo && getAllCustomers(transRoutes)
.filter((item) => {
const filterHasValue = (filterField) => filterField && filterField.length > 0
let result1 = true;
let result2 = true;
let result3 = true;
let result4 = true;
let result5 = true;
if (filterHasValue(statusFilter) && getTextAndClassName(item)?.text !== PERSONAL_ROUTE_STATUS_TEXT[statusFilter]?.text) {
result1 = false;
} else {
result1 = true;
}
if ((filterHasValue(customerTypeFilter) && item.customer_type !== customerTypeFilter)) {
result2 = false;
} else {
result2 = true;
}
if (filterHasValue(routeTypeFilter) && item.routeType !== routeTypeFilter) {
result3 = false;
} else {
result3 = true;
}
if (filterHasValue(customerNameFilter) && !item.customer_name?.toLowerCase().includes(customerNameFilter.toLowerCase()) ) {
result4 = false;
} else {
result4 = true;
}
if (filterHasValue(customerTableId) && item.customer_table_id !== customerTableId) {
result5 = false;
} else {
result5 = true;
}
return result1&&result2&&result3&&result4&&result5;
})
//.filter((item) => item?.customer_name?.includes(keyword) || getTextAndClassName(item)?.text?.includes(keyword) || item?.customer_type?.includes(keyword) || item?.table_id?.includes(keyword))
.sort((a, b) => a.customer_name.replace(' ', '') > b.customer_name.replace(' ', '') ? 1: -1 )
.map((customer, index) => {
return (<tr key={index}>
<td className="td-index"> {index + 1}</td>
<td>
{ customer.customer_name}
</td>
{showCompletedInfo && (<td>
{ customer.customer_address_override || customer.customer_address }
</td>)}
{showCompletedInfo && (<td>
{ customer.customer_phone }
</td>)}
<td>
<div className={`${getTextAndClassName(customer).className} status-tag`}>{ getTextAndClassName(customer).text } </div>
</td>
<td>
{ CUSTOMER_TYPE_TEXT[customer.customer_type]}
</td>
{!showCompletedInfo && <td>
{ customer.routeType}
</td>}
<td>{customer.customer_pickup_time && new Date(customer.customer_pickup_time).toLocaleTimeString('en-US', {hour12: false, hour: '2-digit', minute: '2-digit'})}</td>
<td>{customer.customer_enter_center_time && new Date(customer.customer_enter_center_time).toLocaleTimeString('en-US', {hour12: false, hour: '2-digit', minute: '2-digit'})}</td>
<td>{customer.customer_leave_center_time && new Date(customer.customer_leave_center_time).toLocaleTimeString('en-US', {hour12: false, hour: '2-digit', minute: '2-digit'})}</td>
<td>{customer.customer_dropoff_time && new Date(customer.customer_dropoff_time).toLocaleTimeString('en-US', {hour12: false, hour: '2-digit', minute: '2-digit'})}</td>
{showCompletedInfo && (<td>
{ customer.customer_pickup_status === PICKUP_STATUS.SCHEDULE_ABSENT ? 'Yes' : "No" }
</td>)}
{showCompletedInfo && (<td>
{ customer.customer_note }
</td>)}
{showCompletedInfo && (<td>
{ customer.customer_special_needs }
</td>)}
{showCompletedInfo && (<td>
{ getDisplayPickupOrder(customer.customer_pickup_order) }
</td>)}
{showCompletedInfo && (<td>
{ customer.customer_estimated_pickup_time ? new Date(customer.customer_estimated_pickup_time).toLocaleTimeString('en-US', {hour12: false, hour: '2-digit', minute: '2-digit'}) : '' }
</td>)}
{!showCompletedInfo && (<td>
{ vehicle?.vehicle_number || vehicles?.find((item) => item?.id === customer?.route?.vehicle)?.vehicle_number }
</td>)}
{allowForceEdit && (<td>
<button className="btn btn-link btn-sm" onClick={() => openForceEditModal(customer)}>Edit</button>
</td>)}
</tr>)
})}
{showGroupInfo && (() => {
let stopNo = 0;
return getSortedFormItems()
.map((customerItem, index) => {
if (!customerItem.customer_group) {
stopNo += 1;
return (<tr key={index} >
<td className="td-index">{stopNo}</td>
<td>
{ customerItem.customer_name}
</td>
{showCompletedInfo && (<td>
{ customerItem.customer_address_override || customerItem.customer_address }
</td>)}
{showCompletedInfo && (<td>
{ customerItem.customer_phone }
</td>)}
<td> <div className={`${getTextAndClassName(customerItem).className} status-tag`}>
{ getTextAndClassName(customerItem).text } </div>
</td>
<td>
{ CUSTOMER_TYPE_TEXT[customerItem.customer_type]}
</td>
{!showCompletedInfo && <td>
{ customerItem.routeType}
</td>}
<td>{customerItem.customer_pickup_time && new Date(customerItem.customer_pickup_time).toLocaleTimeString('en-US', {hour12: false})}</td>
<td>{customerItem.customer_enter_center_time && new Date(customerItem.customer_enter_center_time).toLocaleTimeString('en-US', {hour12: false})}</td>
<td>{customerItem.customer_leave_center_time && new Date(customerItem.customer_leave_center_time).toLocaleTimeString('en-US', {hour12: false})}</td>
<td>{customerItem.customer_dropoff_time && new Date(customerItem.customer_dropoff_time).toLocaleTimeString('en-US', {hour12: false})}</td>
{showCompletedInfo && (<td>
{ customerItem.customer_pickup_status === PICKUP_STATUS.SCHEDULE_ABSENT ? 'Yes' : "No" }
</td>)}
{showCompletedInfo && (<td>
{ customerItem.customer_note }
</td>)}
{showCompletedInfo && (<td>
{ customerItem.customer_special_needs }
</td>)}
{showCompletedInfo && (<td>
{ getDisplayPickupOrder(customerItem.customer_pickup_order) }
</td>)}
{showCompletedInfo && (<td>
{ customerItem.customer_estimated_pickup_time ? new Date(customerItem.customer_estimated_pickup_time).toLocaleTimeString('en-US', {hour12: false, hour: '2-digit', minute: '2-digit'}) : '' }
</td>)}
{!showCompletedInfo && (<td>
{ vehicle?.vehicle_number }
</td>)}
{allowForceEdit && <td>
<button className="btn btn-link btn-sm" onClick={() => openForceEditModal(customerItem)}>Edit</button>
</td>}
</tr>);
} else {
stopNo += 1;
const groupedRowsStyle = { backgroundColor: '#f3f3f3' };
return (<React.Fragment key={index}>
<tr className="group" style={groupedRowsStyle}>
<td className="td-index">{stopNo}</td>
<td>{customerItem.customer_group}</td>
<td colSpan={showCompletedInfo? 11: 3}>{customerItem.customers[0]?.customer_group_address}</td>
{allowForceEdit && <td>
<button className="btn btn-link btn-sm" onClick={() => openForceEditGroupModal(customerItem.customers)}>Edit Group</button>
</td>}
</tr>
{
customerItem.customers?.map((customer) => (<tr key={customer.customer_id} style={groupedRowsStyle} onClick={() => openForceEditModal(customer)}>
<td className="td-index"></td>
<td className="children">
{ customer.customer_name}
</td>
{showCompletedInfo && (<td>
{ customer.customer_address_override || customer.customer_address }
</td>)}
{showCompletedInfo && (<td>
{ customer.customer_phone }
</td>)}
<td> <div className={`${getTextAndClassName(customer).className} status-tag`}>
{ getTextAndClassName(customer).text } </div>
</td>
<td>
{ CUSTOMER_TYPE_TEXT[customer.customer_type]}
</td>
{!showCompletedInfo && <td>
{ customer.routeType}
</td>}
<td>{customer.customer_pickup_time && new Date(customer.customer_pickup_time).toLocaleTimeString('en-US', {hour12: false})}</td>
<td>{customer.customer_enter_center_time && new Date(customer.customer_enter_center_time).toLocaleTimeString('en-US', {hour12: false})}</td>
<td>{customer.customer_leave_center_time && new Date(customer.customer_leave_center_time).toLocaleTimeString('en-US', {hour12: false})}</td>
<td>{customer.customer_dropoff_time && new Date(customer.customer_dropoff_time).toLocaleTimeString('en-US', {hour12: false})}</td>
{showCompletedInfo && (<td>
{ customer.customer_pickup_status === PICKUP_STATUS.SCHEDULE_ABSENT ? 'Yes' : "No" }
</td>)}
{showCompletedInfo && (<td>
{ customer.customer_note }
</td>)}
{showCompletedInfo && (<td>
{ customer.customer_special_needs }
</td>)}
{showCompletedInfo && (<td>
{ getDisplayPickupOrder(customer.customer_pickup_order) }
</td>)}
{showCompletedInfo && (<td>
{ customer.customer_estimated_pickup_time ? new Date(customer.customer_estimated_pickup_time).toLocaleTimeString('en-US', {hour12: false, hour: '2-digit', minute: '2-digit'}) : '' }
</td>)}
{!showCompletedInfo && (<td>
{ vehicle?.vehicle_number }
</td>)}
{allowForceEdit && <td>
<button className="btn btn-link btn-sm" onClick={() => openForceEditModal(customer)}>Edit</button>
</td>}
</tr>))
}
</React.Fragment>)
}
});
})()}
</tbody>
</table>
</div>
</div>
<Modal show={show} onHide={() => closeModal()}>
<Modal.Header closeButton>
<Modal.Title>Special Edit Customer</Modal.Title>
</Modal.Header>
<Modal.Body>
<>
<div className="app-main-content-fields-section">
{isInbound &&<div className="me-4">
<div className="field-label">Estimated Pickup
</div>
<TimePicker disableClock={true} format={'HH:mm'} value={customerEstimatedPickUpTime} onChange={setCustomerEstimatedPickUpTime} />
</div>}
<div className="me-4">
<div className="field-label">Change Address Just For This Trip
</div>
<input type="text" value={customerAddressOverride} onChange={(e) => setCustomerAddressOverride((e.currentTarget.value))} />
</div>
</div>
<div className="app-main-content-fields-section">
<div className="me-4">
<div className="field-label">Special Checkin
</div>
<TimePicker disableClock={true} format={'HH:mm'} onFocus={() => {if (!customerCheckInTime || customerCheckInTime.length === 0) { setCustomerCheckInTime(new Date())}}} value={customerCheckInTime} onChange={setCustomerCheckInTime} />
</div>
<div className="me-4">
<div className="field-label">Special Checkout
</div>
<TimePicker disableClock={true} format={'HH:mm'} onFocus={() => {if (!customerCheckOutTime || customerCheckOutTime.length === 0) { setCustomerCheckOutTime(new Date())}}} value={customerCheckOutTime} onChange={setCustomerCheckOutTime} />
</div>
<div className="me-4">
<div className="field-label">Special Pickup
</div>
<TimePicker disableClock={true} format={'HH:mm'} onFocus={() => {if (!customerPickUpTime || customerPickUpTime.length === 0) { setCustomerPickUpTime(new Date())}}} value={customerPickUpTime} onChange={setCustomerPickUpTime} />
</div>
<div className="me-4">
<div className="field-label">Special Dropoff
</div>
<TimePicker disableClock={true} format={'HH:mm'} onFocus={() => {if (!customerDropOffTime || customerDropOffTime.length === 0) { setCustomerDropOffTime(new Date())}}} value={customerDropOffTime} onChange={setCustomerDropOffTime} />
</div>
</div>
<div className="app-main-content-fields-section">
<div className="me-4">
<div className="field-label">Special Set Customer Route Status
</div>
<select value={customerStatusInRoute} onChange={(e)=>{setCustomerStatusInRoute(e.currentTarget.value)}}>
<option value=""></option>
{
Object.entries(PERSONAL_ROUTE_STATUS).map((item) => <option key={item[0]} value={item[1]}>
{PERSONAL_ROUTE_STATUS_TEXT[item[1]].text}
</option>)
}
</select>
</div>
<div className="me-4">
<div className="field-label"> Special Set Customer Pickup Status
</div>
<select value={customerPickupStatusInRoute} onChange={(e)=>{setCustomerPickupStatusInRoute(e.currentTarget.value)}}>
<option value=""></option>
{
Object.entries(PICKUP_STATUS).map((item) => <option key={item[0]} value={item[1]}>
{PICKUP_STATUS_TEXT[item[1]]}
</option>)
}
</select>
</div>
</div>
<div className="app-main-content-fields-section">
<div className="me-4">
<div className="field-label">Transfer To Route
</div>
<input type="text" value={customerTransferToRoute} onChange={(e) => {setCustomerTransferToRoute(e.target.value)}}/>
</div>
</div>
<div className="app-main-content-fields-section">
<div className="me-4">
<div className="field-label">Note
</div>
<textarea value={customerNote} onChange={(e) => {setCustomerNote(e.target.value)}}></textarea>
</div>
</div>
</>
</Modal.Body>
<Modal.Footer>
<Button variant="link" size="sm" onClick={() => closeModal()}>
Close
</Button>
<Button variant="primary" size="sm" onClick={() => saveRouteCustomerInfo()}>
Save Changes
</Button>
</Modal.Footer>
</Modal>
<Modal show={showGroupEditor} onHide={() => closeGroupEditorModal()}>
<Modal.Header closeButton>
<Modal.Title>Special Edit Group Participants</Modal.Title>
</Modal.Header>
<Modal.Body>
<>
<div className="app-main-content-fields-section">
{isInbound &&<div className="me-4">
<div className="field-label">Estimated Pickup
</div>
<TimePicker disableClock={true} format={'HH:mm'} value={customerEstimatedPickUpTime} onChange={setCustomerEstimatedPickUpTime} />
</div>}
<div className="me-4">
<div className="field-label">Special Set Users Route Status
</div>
<select value={customerStatusInRoute} onChange={(e)=>{setCustomerStatusInRoute(e.currentTarget.value)}}>
<option value=""></option>
{
Object.entries(PERSONAL_ROUTE_STATUS).map((item) => <option key={item[0]} value={item[1]}>
{PERSONAL_ROUTE_STATUS_TEXT[item[1]].text}
</option>)
}
</select>
</div>
</div>
<div className="app-main-content-fields-section">
<div className="me-4">
<div className="field-label">Special Checkin
</div>
<TimePicker disableClock={true} format={'HH:mm'} onFocus={() => {if (!customerCheckInTime || customerCheckInTime.length === 0) { setCustomerCheckInTime(new Date())}}} value={customerCheckInTime} onChange={setCustomerCheckInTime} />
</div>
<div className="me-4">
<div className="field-label">Special Checkout
</div>
<TimePicker disableClock={true} format={'HH:mm'} onFocus={() => {if (!customerCheckOutTime || customerCheckOutTime.length === 0) { setCustomerCheckOutTime(new Date())}}} value={customerCheckOutTime} onChange={setCustomerCheckOutTime} />
</div>
<div className="me-4">
<div className="field-label">Special Pickup
</div>
<TimePicker disableClock={true} format={'HH:mm'} onFocus={() => {if (!customerPickUpTime || customerPickUpTime.length === 0) { setCustomerPickUpTime(new Date())}}} value={customerPickUpTime} onChange={setCustomerPickUpTime} />
</div>
<div className="me-4">
<div className="field-label">Special Dropoff
</div>
<TimePicker disableClock={true} format={'HH:mm'} onFocus={() => {if (!customerDropOffTime || customerDropOffTime.length === 0) { setCustomerDropOffTime(new Date())}}} value={customerDropOffTime} onChange={setCustomerDropOffTime} />
</div>
</div>
</>
</Modal.Body>
<Modal.Footer>
<Button variant="link" size="sm" onClick={() => closeGroupEditorModal()}>
Close
</Button>
<Button variant="primary" size="sm" onClick={() => saveRouteGroupCustomerInfo()}>
Save Changes
</Button>
</Modal.Footer>
</Modal>
<Modal show={showBulkUpdateModal} onHide={() => closeBulkUpdateModal()}>
<Modal.Header closeButton>
<Modal.Title>Bulk Update Route Customer Time</Modal.Title>
</Modal.Header>
<Modal.Body>
<>
<div className="app-main-content-fields-section">
<div className="me-4">
<div className="field-label">Customer Enter Center Time</div>
<TimePicker disableClock={true} format={'HH:mm'} value={bulkEnterCenterTime} onChange={setBulkEnterCenterTime} />
</div>
<div className="me-4">
<div className="field-label">Customer Leave Center Time</div>
<TimePicker disableClock={true} format={'HH:mm'} value={bulkLeaveCenterTime} onChange={setBulkLeaveCenterTime} />
</div>
</div>
<div className="app-main-content-fields-section">
<div className="me-4">
<div className="field-label">Customer Route Status</div>
<select value={bulkCustomerRouteStatus} onChange={(e) => setBulkCustomerRouteStatus(e.currentTarget.value)}>
<option value=""></option>
{
Object.entries(PERSONAL_ROUTE_STATUS).map((item) => <option key={item[0]} value={item[1]}>
{PERSONAL_ROUTE_STATUS_TEXT[item[1]].text}
</option>)
}
</select>
</div>
<div className="me-4">
<div className="field-label">Customer Pickup Status</div>
<select value={bulkCustomerPickupStatus} onChange={(e) => setBulkCustomerPickupStatus(e.currentTarget.value)}>
<option value=""></option>
{
Object.entries(PICKUP_STATUS).map((item) => <option key={item[0]} value={item[1]}>
{PICKUP_STATUS_TEXT[item[1]]}
</option>)
}
</select>
</div>
</div>
<div className="alert alert-info">
<strong>Note:</strong> This will update all customers in this route who are not Unscheduled Absent or Scheduled Absent.
</div>
</>
</Modal.Body>
<Modal.Footer>
<Button variant="link" size="sm" onClick={() => closeBulkUpdateModal()}>
Cancel
</Button>
<Button variant="primary" size="sm" onClick={() => saveBulkUpdate()}>
Save
</Button>
</Modal.Footer>
</Modal>
</>
);
};
export default PersonnelInfoTable;