From 3e3ba8e00d030e833f56b9a4c70c3d2abb14745c Mon Sep 17 00:00:00 2001 From: Vincent Date: Sat, 30 May 2026 18:33:09 -0400 Subject: [PATCH 1/5] Updating the drivers --- .../User/AvailableTable/AvailableTable.tsx | 603 ++++++++++++++++-- controllers/DriverController.js | 380 ++++++++++- models/driver.js | 600 ++++++++++++++++- 3 files changed, 1517 insertions(+), 66 deletions(-) diff --git a/client/src/containers/User/AvailableTable/AvailableTable.tsx b/client/src/containers/User/AvailableTable/AvailableTable.tsx index ebadde69..177cc0f3 100644 --- a/client/src/containers/User/AvailableTable/AvailableTable.tsx +++ b/client/src/containers/User/AvailableTable/AvailableTable.tsx @@ -72,11 +72,126 @@ interface Load { interface Driver { id?: string; + + firstName?: string; + lastName?: string; + displayName?: string; + profilePhoto?: string; + description?: string; company?: string; + + archived?: boolean; + status?: string; + + phoneNumber?: string; + alternatePhone?: string; + email?: string; + preferredContactMethod?: string; + website?: string; + + city?: string; + state?: string; + zipCode?: string; + country?: string; + + currentLocationCity?: string; + currentLocationState?: string; + + willingToRelocate?: boolean; + willingToTravelNationwide?: boolean; + + driverType?: string; + vehicleType?: string; + availableNow?: boolean; + + hasCDL?: boolean; + cdlClass?: string; + + licenseNumber?: string; + licenseState?: string; + licenseExpirationDate?: string; + + hazmatEndorsement?: boolean; + tankerEndorsement?: boolean; + doublesTriplesEndorsement?: boolean; + passengerEndorsement?: boolean; + schoolBusEndorsement?: boolean; + + twicCard?: boolean; + passportReady?: boolean; + + yearsExperience?: number; + + accidentsLast3Years?: number; + movingViolationsLast3Years?: number; + + duiHistory?: boolean; + felonyHistory?: boolean; + + dryVanExperience?: boolean; + reeferExperience?: boolean; + flatbedExperience?: boolean; + stepDeckExperience?: boolean; + rgnExperience?: boolean; + + hotshotExperience?: boolean; + boxTruckExperience?: boolean; + straightTruckExperience?: boolean; + cargoVanExperience?: boolean; + sprinterVanExperience?: boolean; + + employmentType?: string; + + desiredPay?: number; + payType?: string; + + availableDate?: string; + + currentlyEmployed?: boolean; + + prefersLocal?: boolean; + prefersRegional?: boolean; + prefersOTR?: boolean; + + preferredHomeTime?: string; + preferredStates?: string; + maxDistanceFromHome?: number; + + medicalCardExpiration?: string; + + clearinghouseRegistered?: boolean; + sapCompleted?: boolean; + + ownerOperator?: boolean; + ownsTruck?: boolean; + + truckYear?: number; + truckMake?: string; + truckModel?: string; + + truckType?: string; + trailerType?: string; + + rating?: number; + + completedJobs?: number; + cancelledJobs?: number; + noShows?: number; + + emailVerified?: boolean; + phoneVerified?: boolean; + identityVerified?: boolean; + + backgroundCheckVerified?: boolean; + insuranceVerified?: boolean; + userId?: string; } +// const LOAD_KEYS = Object.keys(defaultLoad); +// const DRIVER_KEYS = Object.keys(defaultDriver); + // ====================================================== // DEFAULT LOAD // ====================================================== @@ -138,16 +253,28 @@ const defaultLoad: Load = { company: "", }; -const normalizeDate = ( - value?: string | null -) => { - if (!value || value.trim() === "") { - return null; - } +// const normalizeDate = ( +// value?: string | null +// ) => { +// if (!value || value.trim() === "") { +// return null; +// } + +// const date = new Date(value); + +// if (isNaN(date.getTime())) { +// return null; +// } + +// return date.toISOString(); +// }; +const normalizeDate = (value?: string | null) => { + if (!value || value.trim() === "") return null; const date = new Date(value); if (isNaN(date.getTime())) { + console.warn("Invalid date:", value); return null; } @@ -160,12 +287,16 @@ const normalizeDate = ( const AvailableTable: React.FC = () => { const API_BASE = process.env.REACT_APP_API_BASE_URL || "http://localhost:3001"; + // const API_BASE = React.useMemo( + // () => process.env.REACT_APP_API_BASE_URL || "http://localhost:3001", + // [] + // ); const [loads, setLoads] = useState([]); - const [drivers, setDrivers] = useState([]); + const [drivers, setDrivers] = useState([]); const [userLoads, setUserLoads] = useState([]); - const [userDrivers, setUserDrivers] = useState([]); + const [userDrivers, setUserDrivers] = useState([]); const [loadFilters, setLoadFilters] = useState({ search: "", @@ -187,15 +318,135 @@ const AvailableTable: React.FC = () => { const [driverFilters, setDriverFilters] = useState({ search: "", company: "", - description: "", + city: "", + state: "", + driverType: "", + vehicleType: "", + hasCDL: "", + cdlClass: "", + ownerOperator: "", + availableNow: "", }); const [newLoad, setNewLoad] = useState(defaultLoad); - const [newDriver, setNewDriver] = useState({ + const defaultDriver: Driver = { + firstName: "", + lastName: "", + displayName: "", + profilePhoto: "", + description: "", company: "", - }); + + status: "AVAILABLE", + + phoneNumber: "", + alternatePhone: "", + email: "", + preferredContactMethod: "", + website: "", + + city: "", + state: "", + zipCode: "", + country: "USA", + + currentLocationCity: "", + currentLocationState: "", + + willingToRelocate: false, + willingToTravelNationwide: false, + + driverType: "DELIVERY", + vehicleType: "", + + availableNow: true, + + hasCDL: false, + cdlClass: "", + + licenseNumber: "", + licenseState: "", + licenseExpirationDate: "", + + hazmatEndorsement: false, + tankerEndorsement: false, + doublesTriplesEndorsement: false, + passengerEndorsement: false, + schoolBusEndorsement: false, + + twicCard: false, + passportReady: false, + + yearsExperience: 0, + + accidentsLast3Years: 0, + movingViolationsLast3Years: 0, + + duiHistory: false, + felonyHistory: false, + + dryVanExperience: false, + reeferExperience: false, + flatbedExperience: false, + stepDeckExperience: false, + rgnExperience: false, + + hotshotExperience: false, + boxTruckExperience: false, + straightTruckExperience: false, + cargoVanExperience: false, + sprinterVanExperience: false, + + employmentType: "", + + desiredPay: 0, + payType: "", + + availableDate: "", + + currentlyEmployed: false, + + prefersLocal: false, + prefersRegional: false, + prefersOTR: false, + + preferredHomeTime: "", + preferredStates: "", + maxDistanceFromHome: 0, + + medicalCardExpiration: "", + + clearinghouseRegistered: false, + sapCompleted: false, + + ownerOperator: false, + ownsTruck: false, + + truckYear: 0, + truckMake: "", + truckModel: "", + + truckType: "", + trailerType: "", + + rating: 0, + + completedJobs: 0, + cancelledJobs: 0, + noShows: 0, + + emailVerified: false, + phoneVerified: false, + identityVerified: false, + + backgroundCheckVerified: false, + insuranceVerified: false, + }; + + const [newDriver, setNewDriver] = + useState(defaultDriver); useEffect(() => { console.log( @@ -225,7 +476,7 @@ const AvailableTable: React.FC = () => { const userId = localStorage.getItem("userId"); if (userId) { - setUserDrivers(data.filter((d: any) => d.userId === userId)); + setUserDrivers(data.filter((d: Driver) => d.userId === userId)); } }, [API_BASE]); @@ -238,11 +489,31 @@ const AvailableTable: React.FC = () => { // LOAD FILTER (FULL FIELD SUPPORT) // ====================================================== const filteredLoads = loads.filter((l) => { - const q = loadFilters.search.toLowerCase(); + // const q = loadFilters.search.toLowerCase(); + const q = (loadFilters.search || "").toLowerCase(); + // const matchesGlobal = + // l.postReference?.toLowerCase().includes(q) || + // l.originCity?.toLowerCase().includes(q) || + // l.destinationCity?.toLowerCase().includes(q) || + // l.brokerName?.toLowerCase().includes(q); return ( - (!q || JSON.stringify(l).toLowerCase().includes(q)) && + (!q || + [ + l.postReference, + l.originCity, + l.originState, + l.destinationCity, + l.destinationState, + l.brokerName, + l.loadSource + ] + .filter(Boolean) + .join(" ") + .toLowerCase() + .includes(q) + ) && (!loadFilters.postReference || l.postReference?.toLowerCase().includes(loadFilters.postReference.toLowerCase())) && (!loadFilters.originCity || @@ -276,14 +547,76 @@ const AvailableTable: React.FC = () => { // DRIVER FILTER // ====================================================== const filteredDrivers = drivers.filter((d: Driver) => { - const q = driverFilters.search.toLowerCase(); + // const q = + // driverFilters.search.toLowerCase(); + const q = (driverFilters.search || "").toLowerCase(); + + const normalizeBool = (val: any) => { + if (val === true || val === "true" || val === 1 || val === "1") return "true"; + if (val === false || val === "false" || val === 0 || val === "0") return "false"; + return ""; + }; return ( - (!q || JSON.stringify(d).toLowerCase().includes(q)) && + (!q || + JSON.stringify(d) + .toLowerCase() + .includes(q)) && + (!driverFilters.company || - d.company?.toLowerCase().includes(driverFilters.company.toLowerCase())) && - (!driverFilters.description || - d.description?.toLowerCase().includes(driverFilters.description.toLowerCase())) + d.company + ?.toLowerCase() + .includes( + driverFilters.company.toLowerCase() + )) && + + (!driverFilters.city || + d.city + ?.toLowerCase() + .includes( + driverFilters.city.toLowerCase() + )) && + + (!driverFilters.state || + d.state + ?.toLowerCase() + .includes( + driverFilters.state.toLowerCase() + )) && + + (!driverFilters.driverType || + d.driverType + ?.toLowerCase() + .includes( + driverFilters.driverType.toLowerCase() + )) && + + (!driverFilters.vehicleType || + d.vehicleType + ?.toLowerCase() + .includes( + driverFilters.vehicleType.toLowerCase() + )) && + + // (!driverFilters.hasCDL || + // String(d.hasCDL) === driverFilters.hasCDL) && + (!driverFilters.hasCDL || + normalizeBool(d.hasCDL) === driverFilters.hasCDL) && + + (!driverFilters.cdlClass || + d.cdlClass?.toLowerCase().includes(driverFilters.cdlClass.toLowerCase())) && + + // (!driverFilters.ownerOperator || + // String(d.ownerOperator) === driverFilters.ownerOperator) && + + (!driverFilters.ownerOperator || + normalizeBool(d.ownerOperator) === driverFilters.ownerOperator) && + + // (!driverFilters.availableNow || + // String(d.availableNow) === driverFilters.availableNow)&& + + (!driverFilters.availableNow || + normalizeBool(d.availableNow) === driverFilters.availableNow) ); }); @@ -292,6 +625,18 @@ const AvailableTable: React.FC = () => { fetchDrivers(); }; + const parseValue = (key: string, value: any, prev: any) => { + const original = prev[key]; + + if (typeof original === "number") return value === "" ? 0 : Number(value); + + // if (typeof original === "boolean") return value === "true"; + if (typeof original === "boolean") { + if (value === "") return false; + return value === "true"; + } + return value; + }; // ====================================================== // RENDER // ====================================================== @@ -422,6 +767,93 @@ const AvailableTable: React.FC = () => { setDriverFilters((p) => ({ ...p, search: e.target.value })) } /> + + setDriverFilters((p) => ({ + ...p, + company: e.target.value, + })) + } + /> + + + setDriverFilters((p) => ({ + ...p, + city: e.target.value, + })) + } + /> + + + setDriverFilters((p) => ({ + ...p, + state: e.target.value, + })) + } + /> + + + setDriverFilters((p) => ({ + ...p, + driverType: e.target.value, + })) + } + /> + + + setDriverFilters((p) => ({ + ...p, + vehicleType: e.target.value, + })) + } + /> + + + + + + @@ -431,18 +863,40 @@ const AvailableTable: React.FC = () => { ====================================================== */}

All Loads

-
+ {/*
*/} + {loads.length === 0 ? ( +

No loads found

+ ) : ( +
+ )}

My Loads

-
+ {/*
*/} + {userLoads.length === 0 ? ( +

No loads found

+ ) : ( +
+ )} +

All Drivers

-
+ {/*
*/} + {drivers.length === 0 ? ( +

No drivers found

+ ) : ( +
+ )}

My Drivers

-
+ {/*
*/} + {userDrivers.length === 0 ? ( +

No drivers found

+ ) : ( +
+ )} + {/* ====================================================== @@ -493,7 +947,6 @@ const AvailableTable: React.FC = () => { const userId = localStorage.getItem("userId"); console.log("USER ID:", userId); - // const payload = { // ...newLoad, @@ -727,11 +1180,14 @@ const AvailableTable: React.FC = () => { + value={ + (newLoad as any)[key] === undefined || (newLoad as any)[key] === null + ? "" + : String((newLoad as any)[key]) + } onChange={(e) => setNewLoad((p: any) => ({ ...p, - [key]: e.target.value, + [key]: parseValue(key, e.target.value, p), })) } /> @@ -765,30 +1221,87 @@ const AvailableTable: React.FC = () => { const userId = localStorage.getItem("userId"); - await axios.post(`${API_BASE}/api/drivers`, { + const payload = { ...newDriver, + userId, - }); - setNewDriver({ description: "", company: "" }); + yearsExperience: Number( + newDriver.yearsExperience || 0 + ), + + desiredPay: Number( + newDriver.desiredPay || 0 + ), + + completedJobs: Number( + newDriver.completedJobs || 0 + ), + + cancelledJobs: Number( + newDriver.cancelledJobs || 0 + ), + + noShows: Number( + newDriver.noShows || 0 + ), + + rating: Number( + newDriver.rating || 0 + ), + + truckYear: Number( + newDriver.truckYear || 0 + ), + + maxDistanceFromHome: Number( + newDriver.maxDistanceFromHome || 0 + ), + + availableDate: + normalizeDate( + newDriver.availableDate + ), + + medicalCardExpiration: + normalizeDate( + newDriver.medicalCardExpiration + ), + + licenseExpirationDate: + normalizeDate( + newDriver.licenseExpirationDate + ), + }; + + await axios.post( + `${API_BASE}/api/drivers`, + payload + ); + + setNewDriver(defaultDriver); refreshAll(); }} > - - setNewDriver((p) => ({ ...p, description: e.target.value })) - } - /> - - - setNewDriver((p) => ({ ...p, company: e.target.value })) - } - /> + {Object.keys(defaultDriver).map( + (key) => ( + + setNewDriver((p: any) => ({ + ...p, + [key]: parseValue(key, e.target.value, p), + })) + } + /> + ) + )}
+ {/*
*/} + + {/* ====================================================== @@ -900,15 +906,19 @@ const AvailableTable: React.FC = () => { {drivers.length === 0 ? (

No drivers found

) : ( -
- )} + )}

My Drivers

{/*
*/} {userDrivers.length === 0 ? (

No drivers found

) : ( -
+ + + )} diff --git a/client/src/containers/User/AvailableTable/DriversTable.tsx b/client/src/containers/User/AvailableTable/DriversTable.tsx new file mode 100644 index 00000000..67404f2a --- /dev/null +++ b/client/src/containers/User/AvailableTable/DriversTable.tsx @@ -0,0 +1,102 @@ +import React from "react"; +import { Link } from "react-router-dom"; +import styles from "./AvailableTable.module.css"; + +interface Driver { + [key: string]: any; +} + +interface DriversTableProps { + data: Driver[]; + title: string; +} + +const formatValue = (value: any) => { + if (value === null || value === undefined) { + return ""; + } + + if (typeof value === "boolean") { + return value ? "Yes" : "No"; + } + + if (typeof value === "object") { + return JSON.stringify(value); + } + + return String(value); +}; + +const DriversTable: React.FC = ({ + data, + title, +}) => { + if (!data || data.length === 0) { + return ( +
+

{title}

+ +
+ No drivers available +
+
+ ); + } + + const columns = Array.from( + new Set( + data.flatMap((driver) => + Object.keys(driver || {}) + ) + ) + ); + + return ( +
+

{title}

+ +
+
+ + + {columns.map((column) => ( + + ))} + + + + + {data.map((driver, index) => ( + + {columns.map((column) => ( + + ))} + + ))} + +
{column}
+ {column === "userId" && + driver.userId ? ( + + View + + ) : ( + formatValue( + driver[column] + ) + )} +
+ + + ); +}; + +export default React.memo(DriversTable); \ No newline at end of file diff --git a/client/src/containers/User/AvailableTable/LoadTable.tsx b/client/src/containers/User/AvailableTable/LoadTable.tsx new file mode 100644 index 00000000..e69de29b