Files
worldshine-redesign/client/src/components/trans-routes/RouteView.js
2026-03-05 18:46:47 -05:00

246 lines
12 KiB
JavaScript

import React, {useState, useEffect} from "react";
import { useSelector } from "react-redux";
import { useParams, useNavigate } from "react-router-dom";
import { selectAllRoutes, selectTomorrowAllRoutes, selectAllActiveDrivers, selectAllActiveVehicles, selectHistoryRoutes } from "./../../store";
import PersonnelSection from "./PersonnelSection";
import { AuthService, CustomerService, SignatureRequestService, EmployeeService } from "../../services";
import moment from 'moment';
import { Breadcrumb, Tabs, Tab, Dropdown, Spinner, Modal, Button } from "react-bootstrap";
import { Download, Pencil } from "react-bootstrap-icons";
import RouteCustomerEditor from "./RouteCustomerEditor";
const RouteView = () => {
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 currentDriver = drivers.find(item => item.id === currentRoute?.driver);
const [fallbackDriver, setFallbackDriver] = useState(undefined);
const [showVehicleDetails, setShowVehicleDetails] = useState(false);
const [signature, setSignature] = useState(undefined);
const [signatureRequest, setSignatureRequest] = useState(undefined);
const paramsQuery = new URLSearchParams(window.location.search);
const scheduleDate = paramsQuery.get('dateSchedule');
const navigate = useNavigate();
const resolvedDriverId = currentDriver?.id || fallbackDriver?.id || currentRoute?.driver;
const resolvedDriverName = currentDriver?.name || fallbackDriver?.name || '';
const closeModal = () => {
setShowVehicleDetails(false);
}
const openModal = () => {
setShowVehicleDetails(true);
}
const getRelatedOutboundRoutesForThisView = () => {
if (allRoutes.find(item => item.id === params.id)) {
return allRoutes.filter(item => item.type==='outbound');
}
if (tomorrowRoutes.find(item => item.id === params.id)) {
return tomorrowRoutes.filter(item => item.type==='outbound');
}
if (historyRoutes.find(item => item.id === params.id)) {
return historyRoutes.filter(item => item.type==='outbound');
}
}
const directToDashboad = () => {
navigate(`/trans-routes/dashboard?dateSchedule=${moment(currentRoute?.schedule_date).format('YYYY-MM-DD')}`);
}
const edit = (editSection) => {
if (scheduleDate) {
navigate(`/trans-routes/edit/${currentRoute?.id}?dateSchedule=${scheduleDate}&editSection=${editSection}`)
} else {
navigate(`/trans-routes/edit/${currentRoute?.id}?editSection=${editSection}`)
}
}
const deleteFile = () => {
if (signature) {
const dateArr = moment(currentRoute?.schedule_date)?.format('MM/DD/YYYY')?.split('/') || [];
CustomerService.deleteFile({name: `${currentRoute?.id}_${currentRoute?.driver}_${dateArr[0]}_${dateArr[1]}`}).then(data => {
setSignature(undefined);
})
}
}
const generateSignatureRequest = () => {
if (!resolvedDriverId) {
window.alert('Driver is not assigned for this route.');
return;
}
SignatureRequestService.createNewSignatureRequest({
driver_id: resolvedDriverId,
driver_name: resolvedDriverName,
route_id: currentRoute?.id,
route_date: currentRoute?.schedule_date,
route_name: currentRoute?.name,
status: 'active',
}).then((data) => {
setSignatureRequest(data.data);
})
}
useEffect(() => {
if (!currentRoute?.driver || currentDriver?.id) {
setFallbackDriver(undefined);
return;
}
EmployeeService.getEmployee(currentRoute?.driver)
.then((data) => {
setFallbackDriver(data?.data);
})
.catch(() => {
setFallbackDriver(undefined);
});
}, [currentRoute?.driver, currentDriver?.id]);
useEffect(() => {
const dateArr = moment(currentRoute?.schedule_date)?.format('MM/DD/YYYY')?.split('/') || [];
CustomerService.getAvatar(`${currentRoute?.id}_${currentRoute?.driver}_${dateArr[0]}_${dateArr[1]}`).then(data => {
setSignature(data.data);
});
SignatureRequestService.getAllSignatureRequests({driver_id: resolvedDriverId, route_id: currentRoute?.id, route_date: currentRoute?.schedule_date}).then((data) => {
if (data?.data?.length > 0) {
setSignatureRequest(data?.data[0]);
}
})
}, [currentRoute, resolvedDriverId]);
return (
<>
<div className="list row mb-4">
<Breadcrumb>
<Breadcrumb.Item href="/">Transportation</Breadcrumb.Item>
<Breadcrumb.Item href="/trans-routes/dashboard">
Transportation Routes
</Breadcrumb.Item>
<Breadcrumb.Item active>
View Route
</Breadcrumb.Item>
</Breadcrumb>
<div className="col-md-12 text-primary">
<h4>
View Route Information <button className="btn btn-link btn-sm" onClick={() => {directToDashboad()}}>Back</button>
</h4>
</div>
</div>
<div className="app-main-content-list-container form-page">
<div className="app-main-content-list-func-container">
<Tabs defaultActiveKey="routeOverview" id="route-view-tab">
<Tab eventKey="routeOverview" title="Route Information">
<h6 className="text-primary">Route Details <button className="btn btn-sm btn-primary" onClick={() => edit('info')}><Pencil size={16} className="me-2"></Pencil>Edit </button></h6>
<div className="app-main-content-fields-section">
<div className="field-body">
<div className="field-label">Route Name</div>
<div className="field-value">{currentRoute?.name}</div>
</div>
<div className="field-body">
<div className="field-label">Vehicle</div>
<div className="field-value">{currentVehicle?.vehicle_number}</div>
</div>
<div className="field-body">
<div className="field-label">Driver</div>
<div className="field-value">{resolvedDriverName || 'Not assigned'}</div>
</div>
<div className="field-body">
<div className="field-label">Route Type</div>
<div className="field-value">{currentRoute?.type}</div>
</div>
</div>
<div className="app-main-content-fields-section">
<div className="field-body">
<div className="field-label">Route Start Time</div>
<div className="field-value">{currentRoute?.start_time && (new Date(currentRoute?.start_time))?.toLocaleTimeString()}</div>
</div>
<div className="field-body">
<div className="field-label">Route End Time</div>
<div className="field-value">{currentRoute?.end_time && (new Date(currentRoute?.end_time))?.toLocaleTimeString()}</div>
</div>
{currentRoute?.type === 'outbound' &&<div className="field-body">
<div className="field-label">Leave Center Time</div>
<div className="field-value">{currentRoute?.start_time && (new Date(currentRoute?.start_time))?.toLocaleTimeString()}</div>
</div>}
{currentRoute?.type === 'outbound' &&<div className="field-body">
<div className="field-label">Estimated Start Time</div>
<div className="field-value">{currentRoute?.estimated_start_time && (new Date(currentRoute?.estimated_start_time))?.toLocaleTimeString()}</div>
</div>}
</div>
<div className="app-main-content-fields-section">
<div className="field-body">
<div className="field-label">Start Mileage</div>
<div className="field-value">{ currentRoute?.start_mileage}</div>
</div>
<div className="field-body">
<div className="field-label">End Mileage</div>
<div className="field-value">{ currentRoute?.end_mileage}</div>
</div>
</div>
<div className="app-main-content-fields-section">
{signature &&<div className="field-body">
<div className="field-label">Driver Signature</div>
<div className="field-value">
{signature && <img width="100px" src={`data:image/jpg;base64, ${signature}`}/>}
</div>
</div>}
{!signature && !signatureRequest && <div className="field-body">
<div className="field-label">Signature Request</div>
<div className="field-value"><button className="btn btn-sm btn-primary" onClick={() => generateSignatureRequest()}>Generate Signature Link For Driver</button></div>
</div>}
{!signature && signatureRequest && <div className="alert alert-success fade show mb-2 mt-2" role="alert">
<div>Please send this to the driver to get signature:</div>
<div>{`${window.location.origin}/signature/${signatureRequest?.id}`}</div>
</div>}
</div>
<div className="app-main-content-fields-section">
<div className="field-body">
<div className="field-label">Checklist</div>
<div className="field-value">
{currentRoute && currentRoute?.checklist_result?.map(item => <div>{`${item?.item}: ${item?.result ? 'Yes': "No"}`}</div>)}
{currentRoute && currentRoute?.checklist_result.length === 0 && <>No Checklist found</>}</div>
</div>
</div>
<RouteCustomerEditor currentRoute={currentRoute} viewMode={true} editFun={edit}></RouteCustomerEditor>
</Tab>
<Tab eventKey="routeStatus" title="Route Status">
<div className="list row">
<div className="col-md-12 mb-4">
{currentRoute && <PersonnelSection transRoutes={[currentRoute]} showCompletedInfo={true} showGroupInfo={true} isInbound={currentRoute?.type === 'inbound' } allowForceEdit={AuthService.canViewRoutes()} sectionName="Personnel Status (click on each user to edit)" relatedOutbound={getRelatedOutboundRoutesForThisView()} vehicle={currentVehicle} driverName={resolvedDriverName} deleteFile={deleteFile}/>}
</div>
</div>
</Tab>
</Tabs>
{/* <div className="list-func-panel">
<button className="btn btn-primary"><Download size={16} className="me-2"></Download>Export</button>
</div> */}
</div>
<Modal show={showVehicleDetails} onHide={() => closeModal()}>
<Modal.Header closeButton>
<Modal.Title>Vehicle Info</Modal.Title>
</Modal.Header>
<Modal.Body>
<>
<div className="mb-2">Vehicle Number: {currentVehicle?.vehicle_number}</div>
<div className="mb-2">Tag: {currentVehicle?.tag}</div>
<div className="mb-2">EzPass: {currentVehicle?.ezpass}</div>
<div className="mb-2">GPS: {currentVehicle?.gps_tag}</div>
<div className="mb-2">Capacity: {currentVehicle?.capacity}</div>
<div className="mb-2">Status: {currentVehicle?.status}</div>
<div className="mb-2">Mileage: {currentVehicle?.mileage}</div>
</>
</Modal.Body>
<Modal.Footer>
<Button variant="secondary" onClick={() => closeModal()}>
Close
</Button>
</Modal.Footer>
</Modal>
</div>
</>
);
};
export default RouteView;