297 lines
14 KiB
JavaScript
297 lines
14 KiB
JavaScript
import React, {useEffect, useState} from "react";
|
|
import { useSelector,useDispatch } from "react-redux";
|
|
import { useParams, useNavigate } from "react-router-dom";
|
|
import { selectAllRoutes, transRoutesSlice, vehicleSlice, selectTomorrowAllRoutes, selectAllActiveDrivers, selectAllActiveVehicles, selectHistoryRoutes } from "./../../store";
|
|
import { Modal, Button } from "react-bootstrap";
|
|
import RouteCustomerEditor from "./RouteCustomerEditor";
|
|
import { AuthService, TransRoutesService } from "../../services";
|
|
import TimePicker from 'react-time-picker';
|
|
import 'react-time-picker/dist/TimePicker.css';
|
|
import moment from 'moment';
|
|
|
|
const RouteEdit = () => {
|
|
const params = useParams();
|
|
const allRoutes = useSelector(selectAllRoutes);
|
|
const tomorrowRoutes = useSelector(selectTomorrowAllRoutes);
|
|
const historyRoutes = useSelector(selectHistoryRoutes);
|
|
const drivers = useSelector(selectAllActiveDrivers);
|
|
const vehicles = useSelector(selectAllActiveVehicles);
|
|
// const currentRoute = (allRoutes.find(item => item.id === params.id)) || (tomorrowRoutes.find(item => item.id === params.id)) || (historyRoutes.find(item => item.id === params.id)) || {};
|
|
const currentVehicle = vehicles.find(item => item.id === currentRoute?.vehicle ) || [];
|
|
const navigate = useNavigate();
|
|
const dispatch = useDispatch();
|
|
const { updateRoute} = transRoutesSlice.actions;
|
|
const { updateVehicle} = vehicleSlice.actions;
|
|
const [routeName, setRouteName] = useState('');
|
|
const [newDriver, setNewDriver] = useState('');
|
|
const [newVehicle, setNewVehicle] = useState('');
|
|
const [newRouteType, setNewRouteType] = useState('');
|
|
const [showAddCheckItem, setShowAddCheckItem] = useState(false);
|
|
const [showCopyCheckItem, setShowCopyCheckItem] = useState(false);
|
|
const [newChecklistItems, setNewChecklistItems] = useState([]);
|
|
const [selectedRouteChecklistToCopy, setSelectedRouteChecklistToCopy] = useState({});
|
|
const [newCustomerList, setNewCustomerList] = useState([]);
|
|
const [errorMessage, setErrorMessage] = useState(undefined);
|
|
const [estimatedStartTime, setEstimatedStartTime] = useState(undefined);
|
|
const [currentRoute, setCurrentRoute] = useState(undefined);
|
|
const paramsQuery = new URLSearchParams(window.location.search);
|
|
const scheduleDate = paramsQuery.get('dateSchedule');
|
|
const redirectToView = () => {
|
|
if (scheduleDate) {
|
|
navigate(`/trans-routes/${params.id}?dateSchedule=${scheduleDate}`);
|
|
} else {
|
|
navigate(`/trans-routes/${params.id}`);
|
|
}
|
|
}
|
|
|
|
const redirectToDashboard = () => {
|
|
navigate(`/trans-routes/dashboard`);
|
|
}
|
|
|
|
const softDeleteCurrentRoute = () => {
|
|
const data = Object.assign({}, currentRoute, {status: ['disabled']})
|
|
dispatch(updateRoute({ id: currentRoute?.id, data, callback: redirectToDashboard }));
|
|
// redirectToDashboard();
|
|
}
|
|
|
|
const updateCurrentRoute = () => {
|
|
try {
|
|
if (!routeName || routeName === '') { setErrorMessage('Route Name is Required'); return;}
|
|
if (!newRouteType || newRouteType === '') {setErrorMessage('Route Type is Required'); return;}
|
|
if (!newDriver || newDriver === '') {setErrorMessage('Driver is Required'); return;}
|
|
if (!newVehicle || newVehicle === '') {setErrorMessage('Vehicle is Required'); return;}
|
|
let data = Object.assign({}, currentRoute, {name: routeName, driver: newDriver, vehicle: newVehicle, type: newRouteType, route_customer_list: newCustomerList});
|
|
if (estimatedStartTime && estimatedStartTime !== '') {
|
|
data = Object.assign({}, data, {estimated_start_time: combineDateAndTime(currentRoute.schedule_date, estimatedStartTime)})
|
|
}
|
|
let payload = { id: currentRoute?.id, data };
|
|
if ((historyRoutes.find(item => item.id === params.id)) || (scheduleDate && new Date(data.schedule_date) > new Date())) {
|
|
payload = Object.assign({}, payload, {dateText: data.schedule_date});
|
|
if (scheduleDate && new Date(data.schedule_date) > new Date()) {
|
|
payload = Object.assign({}, payload, {fromSchedule: true});
|
|
}
|
|
}
|
|
payload.callback = redirectToView;
|
|
dispatch(updateRoute(payload));
|
|
// TransRoutesService.updateInProgress(data);
|
|
// setTimeout(() => {
|
|
// redirectToView();
|
|
// }, 5000);
|
|
} catch(ex) {
|
|
|
|
}
|
|
}
|
|
|
|
const addItemToArray = () => {
|
|
const arr = [...newChecklistItems, ''];
|
|
setNewChecklistItems(arr);
|
|
}
|
|
|
|
const saveChecklistItems = () => {
|
|
const data = Object.assign({}, currentVehicle, {checklist: newChecklistItems});
|
|
dispatch(updateVehicle({ id: currentVehicle.id, data }));
|
|
setShowAddCheckItem(false);
|
|
}
|
|
|
|
const copyChecklistItems = () => {
|
|
const data = Object.assign({}, currentVehicle, {checklist: vehicles.find(vehicle => vehicle.id === selectedRouteChecklistToCopy.vehicle)?.checklist});
|
|
dispatch(updateVehicle({ id: currentVehicle.id, data }));
|
|
setShowCopyCheckItem(false);
|
|
}
|
|
|
|
const closeAddCheckItemModal = () => {
|
|
setNewChecklistItems([])
|
|
setShowAddCheckItem(false);
|
|
}
|
|
|
|
const showAddCheckItemModal = () => {
|
|
setNewChecklistItems(currentVehicle.checklist)
|
|
setShowAddCheckItem(true);
|
|
}
|
|
|
|
const closeCopyCheckItemModal = () => {
|
|
setSelectedRouteChecklistToCopy({});
|
|
setShowCopyCheckItem(false);
|
|
}
|
|
|
|
const showCopyCheckItemModal = () => {
|
|
setShowCopyCheckItem(true);
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
useEffect(() => {
|
|
if (!AuthService.canAddOrEditRoutes()) {
|
|
window.alert('You haven\'t login yet OR this user does not have access to this page. Please change an admin account to login.')
|
|
AuthService.logout();
|
|
navigate(`/login`);
|
|
}
|
|
TransRoutesService.getRoute(params.id).then(data => {
|
|
setCurrentRoute(data?.data);
|
|
setRouteName(data?.data?.name);
|
|
setNewDriver(data?.data?.driver);
|
|
setNewVehicle(data?.data?.vehicle);
|
|
setNewRouteType(data?.data?.type);
|
|
setEstimatedStartTime(data?.data?.estimated_start_time && new Date(data?.data?.estimated_start_time));
|
|
setNewCustomerList(data?.data?.route_customer_list);
|
|
setErrorMessage(undefined);
|
|
})
|
|
}, []);
|
|
|
|
// useEffect(() => {
|
|
// if (currentRoute) {
|
|
// setRouteName(currentRoute.name);
|
|
// setNewDriver(currentRoute.driver);
|
|
// setNewVehicle(currentRoute.vehicle);
|
|
// setNewRouteType(currentRoute.type);
|
|
// setEstimatedStartTime(currentRoute.estimated_start_time && new Date(currentRoute.estimated_start_time));
|
|
// setNewCustomerList(currentRoute.route_customer_list);
|
|
// }
|
|
// setErrorMessage(undefined);
|
|
// }, [currentRoute])
|
|
|
|
return (
|
|
<>
|
|
<div className="list row mb-4">
|
|
<div className="col-md-12 text-primary">
|
|
<h5>{currentRoute?.name} <button className="btn btn-link btn-sm" onClick={() => {redirectToView()}}>Back To View</button></h5>
|
|
</div>
|
|
</div>
|
|
<div className="list row mb-5">
|
|
<div className="col-md-7 col-sm-7 col-xs-12">
|
|
<button className="btn btn-primary btn-sm me-4" onClick={() => updateCurrentRoute()}> Save Route </button>
|
|
<button className="btn btn-default btn-sm" onClick={() => redirectToView()}> Cancel </button>
|
|
<button className="btn btn-danger btn-sm float-end" onClick={() => softDeleteCurrentRoute()}>Delete Route</button>
|
|
</div>
|
|
{errorMessage && <div className="col-md-6 col-sm-6 col-xs-12 alert alert-danger mt-4">{errorMessage}</div>}
|
|
</div>
|
|
<div className="list row mb-4">
|
|
<div className="col-md-6 mb-4">
|
|
Name(*): <input type="text" value={routeName || ''} onChange={e => setRouteName(e.target.value)}/>
|
|
</div>
|
|
<div className="col-md-6 mb-4">Vehicle(*): <select value={newVehicle} onChange={e => setNewVehicle(e.target.value)}>
|
|
{vehicles.map((vehicle) => (<option key={vehicle.id} value={vehicle.id}>{vehicle.vehicle_number}</option>))}
|
|
</select>
|
|
</div>
|
|
<div className="col-md-6 mb-4">Driver(*): <select value={newDriver} onChange={e => setNewDriver(e.target.value)}>
|
|
{drivers.map((driver) => <option key={driver.id} value={driver.id}>{driver.name}</option>)}
|
|
</select>
|
|
</div>
|
|
<div className="col-md-6 mb-4">Type(*): <select value={newRouteType} onChange={e => setNewRouteType(e.target.value)}>
|
|
<option value="inbound">Inbound</option>
|
|
<option value="outbound">Outbound</option>
|
|
</select>
|
|
</div>
|
|
{
|
|
newRouteType === 'outbound' && (<div className="col-md-6 mb-4">
|
|
Estimated Start TIme: <TimePicker disableClock={true} format={'HH:mm'} value={estimatedStartTime} onChange={setEstimatedStartTime} />
|
|
</div>)
|
|
}
|
|
</div>
|
|
<div className="list row mb-4">
|
|
<div className="col-md-12 mb-4">
|
|
<RouteCustomerEditor currentRoute={currentRoute} setNewCustomerList={setNewCustomerList}></RouteCustomerEditor>
|
|
</div>
|
|
</div>
|
|
{ newVehicle && newVehicle !== '' && (<div className="list row mb-4">
|
|
<div className="col-md-12 create-route-container">
|
|
<h6>Vehicle Info</h6>
|
|
<div className="list row">
|
|
<div className="col-md-4 col-sm-6 col-xs-12 mb-2">Vehicle Number: {vehicles.find(item => item.id === newVehicle)?.vehicle_number}</div>
|
|
<div className="col-md-4 col-sm-6 col-xs-12 mb-2">Tag: {vehicles.find(item => item.id === newVehicle)?.tag}</div>
|
|
<div className="col-md-4 col-sm-6 col-xs-12 mb-2">EzPass: {vehicles.find(item => item.id === newVehicle)?.ezpass}</div>
|
|
<div className="col-md-4 col-sm-6 col-xs-12 mb-2">GPS: {vehicles.find(item => item.id === newVehicle)?.gps_tag}</div>
|
|
<div className="col-md-4 col-sm-6 col-xs-12 mb-2">Capacity: {vehicles.find(item => item.id === newVehicle)?.capacity}</div>
|
|
<div className="col-md-4 col-sm-6 col-xs-12 mb-2">Status: {vehicles.find(item => item.id === newVehicle)?.status}</div>
|
|
<div className="col-md-4 col-sm-6 col-xs-12 mb-2">Mileage: {vehicles.find(item => item.id === newVehicle)?.mileage}</div>
|
|
</div>
|
|
</div>
|
|
</div>)}
|
|
{ newDriver && newDriver !== '' && (<div className="list row mb-4">
|
|
<div className="col-md-12 create-route-container">
|
|
<h6>Driver Info</h6>
|
|
<div className="list row">
|
|
<div className="col-md-4 col-sm-6 col-xs-12 mb-2">Name: {drivers.find(item => item.id === newDriver)?.name}</div>
|
|
<div className="col-md-4 col-sm-6 col-xs-12 mb-2">Preferred Name: {drivers.find(item => item.id === newDriver)?.name_cn}</div>
|
|
<div className="col-md-4 col-sm-6 col-xs-12 mb-2">Driver Capacity: {drivers.find(item => item.id === newDriver)?.driver_capacity}</div>
|
|
<div className="col-md-4 col-sm-6 col-xs-12 mb-2">Roles: {drivers.find(item => item.id === newDriver)?.roles}</div>
|
|
<div className="col-md-4 col-sm-6 col-xs-12 mb-2">Phone: {drivers.find(item => item.id === newDriver)?.phone}</div>
|
|
<div className="col-md-4 col-sm-6 col-xs-12 mb-2">Email: {drivers.find(item => item.id === newDriver)?.email}</div>
|
|
<div className="col-md-4 col-sm-6 col-xs-12 mb-2">Employment Status: {drivers.find(item => item.id === newDriver)?.employment_status}</div>
|
|
</div>
|
|
</div>
|
|
</div>)}
|
|
<div className="list row mb-4">
|
|
<div className="col-md-6">
|
|
<h6>Vehicle Checklist</h6>
|
|
{ currentVehicle?.checklist?.length > 0 && (<table className="mb-4">
|
|
<tbody>
|
|
{currentVehicle.checklist.map((item, index) => (<tr key={index}><td>{item}</td></tr>))}
|
|
</tbody>
|
|
</table>) }
|
|
<div className="mb-4"><button className="btn btn-link btn-sm" onClick={() => showAddCheckItemModal()}>+Add Check Items</button></div>
|
|
<div className="mb-4"><button className="btn btn-link btn-sm" onClick={() => showCopyCheckItemModal()}>Copy Checklist From Other Route</button></div>
|
|
</div>
|
|
|
|
</div>
|
|
<Modal show={showAddCheckItem} onHide={() => closeAddCheckItemModal()}>
|
|
<Modal.Header closeButton>
|
|
<Modal.Title>Add New Checklist Item</Modal.Title>
|
|
</Modal.Header>
|
|
<Modal.Body>
|
|
<>
|
|
{newChecklistItems.map((item, index) => (<div className="mb-4" key={index}><input type="text" value={item} onChange={(e) => setNewChecklistItems([...newChecklistItems].map((a, index1) => {if (index1 === index) {return e.target.value;} return a;}))}/>
|
|
<button className="btn btn-link btn-sm" onClick={(e) => setNewChecklistItems([...newChecklistItems].filter((value, index1) => index1 != index))}>Remove</button>
|
|
</div>))}
|
|
<button className="btn btn-link" onClick={() => addItemToArray()}>+Add New Item</button>
|
|
</>
|
|
</Modal.Body>
|
|
<Modal.Footer>
|
|
<Button variant="secondary" onClick={() => closeAddCheckItemModal()}>
|
|
Close
|
|
</Button>
|
|
<Button variant="primary" onClick={() => saveChecklistItems()}>
|
|
Save Checklist Items
|
|
</Button>
|
|
</Modal.Footer>
|
|
</Modal>
|
|
<Modal show={showCopyCheckItem} onHide={() => closeCopyCheckItemModal()}>
|
|
<Modal.Header closeButton>
|
|
<Modal.Title> Click on Route to Select</Modal.Title>
|
|
</Modal.Header>
|
|
<Modal.Body>
|
|
<>
|
|
{[...allRoutes, ...tomorrowRoutes].filter(r => r.id !== currentRoute?.id).map((route) => {
|
|
return (<div className={`card-container ${route.id === selectedRouteChecklistToCopy.id ? 'selected': ''}`} key={route.id} onClick={() => setSelectedRouteChecklistToCopy(route)}>
|
|
<div>{route.name}</div>
|
|
<div>
|
|
{vehicles.find((a) => a.id === route.vehicle)?.checklist?.map((item, index) => <small key={index} className="me-2">{item}</small>)}
|
|
</div>
|
|
</div>);
|
|
})}
|
|
</>
|
|
</Modal.Body>
|
|
<Modal.Footer>
|
|
<Button variant="secondary" onClick={() => closeCopyCheckItemModal()}>
|
|
Close
|
|
</Button>
|
|
<Button variant="primary" onClick={() => copyChecklistItems()}>
|
|
Copy Checklist Items
|
|
</Button>
|
|
</Modal.Footer>
|
|
</Modal>
|
|
</>
|
|
|
|
);
|
|
};
|
|
|
|
export default RouteEdit; |