fix
All checks were successful
Build And Deploy Main / build-and-deploy (push) Successful in 35s

This commit is contained in:
2026-03-12 18:11:37 -04:00
parent 722cb2f85c
commit 8878c9c45b
4 changed files with 171 additions and 36 deletions

View File

@@ -1,11 +1,10 @@
import React, {useState, useEffect} from "react";
import { useNavigate, useParams } from "react-router-dom";
import { useParams } from "react-router-dom";
import { CustomerService, SignatureRequestService } from "../../services";
import SignatureCanvas from 'react-signature-canvas';
import moment from 'moment';
const DriverSignature = () => {
const navigate = useNavigate();
const urlParams = useParams();
const [signatureRequest, setSignatureRequest] = useState(undefined);
@@ -19,28 +18,45 @@ const DriverSignature = () => {
}
const submitSignature = () => {
var fabricCanvas = document.getElementsByClassName('sigCanvas')[0]; //real ID here
var scaledCanvas = document.createElement('canvas'); //off-screen canvas
scaledCanvas.width = 400; //size of new canvas, make sure they are proportional
scaledCanvas.height = 200; //compared to original canvas
// scale original image to new canvas
var ctx = scaledCanvas.getContext('2d');
ctx.drawImage(fabricCanvas, 0, 0, scaledCanvas.width, scaledCanvas.height);
const fabricCanvas = document.getElementsByClassName('sigCanvas')[0];
if (!fabricCanvas || !signatureRequest?.id) {
window.alert('Signature request is not ready. Please refresh and try again.');
return;
}
const routeId = `${signatureRequest?.route_id || ''}`.trim();
const driverId = `${signatureRequest?.driver_id || ''}`.trim();
const dateArr = moment(signatureRequest?.route_date)?.format('MM/DD/YYYY')?.split('/') || [];
const fileName = `${signatureRequest?.route_id}_${signatureRequest?.driver_id}_${dateArr[0]}_${dateArr[1]}`;
const month = `${dateArr[0] || ''}`.trim();
const day = `${dateArr[1] || ''}`.trim();
if (!routeId || !driverId || !month || !day || month.toLowerCase().includes('invalid')) {
window.alert('Invalid route signature key. Please ask admin to regenerate signature link.');
return;
}
const fileName = `${routeId}_${driverId}_${month}_${day}`;
const scaledCanvas = document.createElement('canvas');
scaledCanvas.width = 400;
scaledCanvas.height = 200;
const ctx = scaledCanvas.getContext('2d');
ctx.drawImage(fabricCanvas, 0, 0, scaledCanvas.width, scaledCanvas.height);
scaledCanvas.toBlob(function(blob) {
if (!blob) {
window.alert('Failed to read signature image. Please draw signature again.');
return;
}
const formData = new FormData();
formData.append('file', blob, `${fileName}.jpg`);
CustomerService.uploadAvatar(fileName, formData).then(() => {
SignatureRequestService.updateSignatureRequest(signatureRequest?.id, { status: 'done'}).then(data => {
SignatureRequestService.updateSignatureRequest(signatureRequest?.id, { status: 'done'}).then(() => {
SignatureRequestService.getSignatureRequestById(urlParams.id).then((data) => {
setSignatureRequest(data?.data);
})
})
})
}).catch(() => {
window.alert('Failed to upload signature. Please try again.');
});
})
}

View File

@@ -67,17 +67,64 @@ const RouteReportWithSignature = () => {
}
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);
});
let isMounted = true;
const toDateTokens = (dateValue) => {
const tokenSet = new Set();
const localFormatted = moment(dateValue)?.format('MM/DD/YYYY');
const utcFormatted = moment.utc(dateValue)?.format('MM/DD/YYYY');
[localFormatted, utcFormatted].forEach((formatted) => {
if (!formatted || formatted.toLowerCase().includes('invalid')) return;
const [month, day] = formatted.split('/');
if (month && day) {
tokenSet.add(`${month}_${day}`);
}
});
return Array.from(tokenSet).map((token) => token.split('_'));
};
const loadSignature = async () => {
if (!currentRoute?.id || !currentRoute?.schedule_date) {
if (isMounted) setSignature(undefined);
return;
}
const routeId = currentRoute.id;
const requestRes = await SignatureRequestService.getAllSignatureRequests({ route_id: routeId }).catch(() => ({ data: [] }));
const requestList = requestRes?.data || [];
const driverIds = Array.from(new Set([
currentRoute?.driver,
...requestList.map((item) => item?.driver_id)
].filter(Boolean)));
const datePairs = [];
[currentRoute?.schedule_date, ...requestList.map((item) => item?.route_date)].forEach((dateValue) => {
toDateTokens(dateValue).forEach((pair) => datePairs.push(pair));
});
const uniqueDatePairs = Array.from(new Set(datePairs.map((pair) => `${pair[0]}_${pair[1]}`)))
.map((token) => token.split('_'));
for (const driverId of driverIds) {
for (const [month, day] of uniqueDatePairs) {
try {
const data = await CustomerService.getAvatar(`${routeId}_${driverId}_${month}_${day}`);
if (data?.data) {
if (isMounted) setSignature(data.data);
return;
}
} catch (error) {
// Continue trying candidate keys.
}
}
}
if (isMounted) setSignature(undefined);
};
loadSignature();
CustomerService.getAvatar(`center_director_signature_site_${site}`).then(data => {
if (data?.data) {
setDirectorSignature(data?.data)
}
});
}, [currentRoute]);
return () => {
isMounted = false;
};
}, [currentRoute?.id, currentRoute?.driver, currentRoute?.schedule_date, site]);
useEffect(() => {
CustomerService.getAllCustomers()

View File

@@ -4,7 +4,7 @@ import { useNavigate, useSearchParams } from "react-router-dom";
import { selectInboundRoutes, selectTomorrowAllRoutes, selectTomorrowInboundRoutes, selectTomorrowOutboundRoutes, selectHistoryInboundRoutes, selectHistoryRoutes, selectHistoryOutboundRoutes, selectOutboundRoutes, selectAllRoutes, selectAllActiveVehicles, selectAllActiveDrivers, transRoutesSlice } from "./../../store";
import RoutesSection from "./RoutesSection";
import PersonnelSection from "./PersonnelSection";
import { AuthService, CustomerService, TransRoutesService, DriverService, EventsService, DailyRoutesTemplateService, ReportService } from "../../services";
import { AuthService, CustomerService, TransRoutesService, DriverService, EventsService, DailyRoutesTemplateService, ReportService, SignatureRequestService } from "../../services";
import { PERSONAL_ROUTE_STATUS, ROUTE_STATUS, CUSTOMER_TYPE_TEXT, PERSONAL_ROUTE_STATUS_TEXT, PICKUP_STATUS, PICKUP_STATUS_TEXT, REPORT_TYPE } from "../../shared";
import moment from 'moment';
import DatePicker from "react-datepicker";
@@ -710,16 +710,52 @@ const RoutesDashboard = () => {
}, []);
useEffect(() => {
const toDateTokens = (dateValue) => {
const tokenSet = new Set();
const localFormatted = moment(dateValue)?.format('MM/DD/YYYY');
const utcFormatted = moment.utc(dateValue)?.format('MM/DD/YYYY');
[localFormatted, utcFormatted].forEach((formatted) => {
if (!formatted || formatted.toLowerCase().includes('invalid')) return;
const [month, day] = formatted.split('/');
if (month && day) {
tokenSet.add(`${month}_${day}`);
}
});
return Array.from(tokenSet).map((token) => token.split('_'));
};
const resolveRouteSignature = async (routeItem) => {
const requestRes = await SignatureRequestService.getAllSignatureRequests({ route_id: routeItem?.id }).catch(() => ({ data: [] }));
const requestList = requestRes?.data || [];
const driverIds = Array.from(new Set([
routeItem?.driver,
...requestList.map((item) => item?.driver_id)
].filter(Boolean)));
const datePairs = [];
[routeItem?.schedule_date, dateSelected, ...requestList.map((item) => item?.route_date)].forEach((dateValue) => {
toDateTokens(dateValue).forEach((pair) => datePairs.push(pair));
});
const uniqueDatePairs = Array.from(new Set(datePairs.map((pair) => `${pair[0]}_${pair[1]}`)))
.map((token) => token.split('_'));
for (const driverId of driverIds) {
for (const [month, day] of uniqueDatePairs) {
try {
const result = await CustomerService.getAvatar(`${routeItem.id}_${driverId}_${month}_${day}`);
if (result?.data) {
return result.data;
}
} catch (ex) {
// Continue trying candidate keys.
}
}
}
return undefined;
};
TransRoutesService.getAll(moment(dateSelected)?.format('MM/DD/YYYY')).then(data => {
const routesResults = data.data;
const finalRoutes = routesResults.map(async (routeItem) => {
const dateArr = moment(dateSelected)?.format('MM/DD/YYYY')?.split('/') || [];
try {
const result = await CustomerService.getAvatar(`${routeItem.id}_${routeItem.driver}_${dateArr[0]}_${dateArr[1]}`);
return result?.data ? Object.assign({}, routeItem, {signature: result?.data}) : routeItem;
} catch (ex) {
return routeItem;
}
const signature = await resolveRouteSignature(routeItem);
return signature ? Object.assign({}, routeItem, {signature}) : routeItem;
});
Promise.all(finalRoutes).then(finalRoutesData => {
setRoutesForSignature(finalRoutesData);

View File

@@ -1,7 +1,7 @@
import React, {useState, useEffect} from "react";
import { useSelector } from "react-redux";
import { useNavigate } from "react-router-dom";
import { CustomerService, DriverService, EmployeeService, EventsService, TransRoutesService } from "../../services";
import { CustomerService, DriverService, EmployeeService, EventsService, SignatureRequestService, TransRoutesService } from "../../services";
import { selectAllActiveDrivers, selectAllActiveVehicles } from "./../../store";
import moment from 'moment';
import DatePicker from "react-datepicker";
@@ -95,6 +95,47 @@ const RouteSignatureList = () => {
useEffect(() => {
const site = EventsService.site;
const toDateTokens = (dateValue) => {
const tokenSet = new Set();
const localFormatted = moment(dateValue)?.format('MM/DD/YYYY');
const utcFormatted = moment.utc(dateValue)?.format('MM/DD/YYYY');
[localFormatted, utcFormatted].forEach((formatted) => {
if (!formatted || formatted.toLowerCase().includes('invalid')) return;
const [month, day] = formatted.split('/');
if (month && day) {
tokenSet.add(`${month}_${day}`);
}
});
return Array.from(tokenSet).map((token) => token.split('_'));
};
const resolveRouteSignature = async (routeItem) => {
const requestRes = await SignatureRequestService.getAllSignatureRequests({ route_id: routeItem?.id }).catch(() => ({ data: [] }));
const requestList = requestRes?.data || [];
const driverIds = Array.from(new Set([
routeItem?.driver,
...requestList.map((item) => item?.driver_id)
].filter(Boolean)));
const datePairs = [];
[routeItem?.schedule_date, dateSelected, ...requestList.map((item) => item?.route_date)].forEach((dateValue) => {
toDateTokens(dateValue).forEach((pair) => datePairs.push(pair));
});
const uniqueDatePairs = Array.from(new Set(datePairs.map((pair) => `${pair[0]}_${pair[1]}`)))
.map((token) => token.split('_'));
for (const driverId of driverIds) {
for (const [month, day] of uniqueDatePairs) {
try {
const result = await CustomerService.getAvatar(`${routeItem.id}_${driverId}_${month}_${day}`);
if (result?.data) {
return result.data;
}
} catch (ex) {
// Continue trying candidate keys.
}
}
}
return undefined;
};
CustomerService.getAvatar(`center_director_signature_site_${site}`).then(data => {
if (data?.data) {
setDirectorSignature(data?.data)
@@ -103,13 +144,8 @@ const RouteSignatureList = () => {
TransRoutesService.getAll(moment(dateSelected)?.format('MM/DD/YYYY')).then(data => {
const routesResults = data.data;
const finalRoutes = routesResults.map(async (routeItem) => {
const dateArr = moment(dateSelected)?.format('MM/DD/YYYY')?.split('/') || [];
try {
const result = await CustomerService.getAvatar(`${routeItem.id}_${routeItem.driver}_${dateArr[0]}_${dateArr[1]}`);
return result?.data ? Object.assign({}, routeItem, {signature: result?.data}) : routeItem;
} catch (ex) {
return routeItem;
}
const signature = await resolveRouteSignature(routeItem);
return signature ? Object.assign({}, routeItem, {signature}) : routeItem;
});
Promise.all(finalRoutes).then(finalRoutesData => {
setRoutes(finalRoutesData);