This commit is contained in:
@@ -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.');
|
||||
});
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -67,17 +67,64 @@ const RouteReportWithSignature = () => {
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
const dateArr = moment(currentRoute?.schedule_date)?.format('MM/DD/YYYY')?.split('/') || [];
|
||||
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);
|
||||
};
|
||||
|
||||
CustomerService.getAvatar(`${currentRoute?.id}_${currentRoute?.driver}_${dateArr[0]}_${dateArr[1]}`).then(data => {
|
||||
setSignature(data.data);
|
||||
});
|
||||
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()
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user