From 94ad8ab2620f485f99a1fa5a702ac42ffa577d67 Mon Sep 17 00:00:00 2001 From: dharaneesh-r Date: Mon, 22 Jun 2026 12:17:07 +0530 Subject: [PATCH] updates on the rider and the rider substitution page regarding the crud operations and more change outthere --- src/pages/nearle/riders/RiderSubstitution.js | 54 +++- src/pages/nearle/riders/riders.js | 285 ++++++++++++++++--- 2 files changed, 287 insertions(+), 52 deletions(-) diff --git a/src/pages/nearle/riders/RiderSubstitution.js b/src/pages/nearle/riders/RiderSubstitution.js index 913b563..c1ce1e3 100644 --- a/src/pages/nearle/riders/RiderSubstitution.js +++ b/src/pages/nearle/riders/RiderSubstitution.js @@ -45,11 +45,15 @@ const STATUS_META = { }; export default function RiderSubstitution({ + appId, rows, + allRidersList, substituteRidersList, substituteAssignments, handleAssignSubstitute, onFinalizeSuccess, + selectedDate, + setSelectedDate, DT, BRAND, edge, @@ -58,7 +62,6 @@ export default function RiderSubstitution({ }) { const theme = useTheme(); const isMobile = useMediaQuery(theme.breakpoints.down('md')); - const [selectedDate, setSelectedDate] = useState(dayjs()); const [selectedBatch, setSelectedBatch] = useState('all'); const [isFinalizing, setIsFinalizing] = useState(false); @@ -118,9 +121,8 @@ export default function RiderSubstitution({ }, [selectedDate]); const filteredRows = React.useMemo(() => { - if (selectedBatch === 'all') return rows; - return rows?.filter((row) => getBatchForTime(row.starttime) === selectedBatch); - }, [rows, selectedBatch, getBatchForTime]); + return rows; + }, [rows]); const hasAssignments = Object.values(substituteAssignments || {}).some( (val) => val !== null && val !== undefined @@ -129,8 +131,37 @@ export default function RiderSubstitution({ const handleFinalize = async () => { setIsFinalizing(true); try { - const rawTenantId = localStorage.getItem('tenantid'); - const tenantId = (rawTenantId && rawTenantId !== 'undefined' && rawTenantId !== 'null') ? parseInt(rawTenantId, 10) : 44; + let partnerId = ''; + try { + const rawLocs = localStorage.getItem('applocations'); + if (rawLocs) { + const locs = JSON.parse(rawLocs); + const currentLoc = locs.find((l) => l.applocationid === appId); + if (currentLoc && currentLoc.partnerid) { + partnerId = currentLoc.partnerid; + } else { + const firstValidLoc = locs.find((l) => l.partnerid); + if (firstValidLoc && firstValidLoc.partnerid) { + partnerId = firstValidLoc.partnerid; + } + } + } + } catch (e) { + console.error('Error parsing applocations', e); + } + + if (!partnerId) { + const savedPartnerId = localStorage.getItem('partnerid'); + if (savedPartnerId && savedPartnerId !== 'undefined' && savedPartnerId !== 'null') { + partnerId = savedPartnerId; + } + } + + if (!partnerId || partnerId === '0' || partnerId === 0) { + partnerId = 44; + } + + const tenantId = parseInt(partnerId, 10); const substitutions = Object.entries(substituteAssignments || {}) .filter((entry) => entry[1] !== null && entry[1] !== undefined) @@ -143,7 +174,8 @@ export default function RiderSubstitution({ absent_rider_name: absentRider?.username || absentRider?.fullname || `Rider #${absentRiderId}`, sub_rider_id: parseInt(subRider.userid, 10), sub_rider_name: subRider.username || subRider.fullname || `Rider #${subRider.userid}`, - reason: "Scheduled" + reason: "Scheduled", + batch: selectedBatch }; }); @@ -315,6 +347,8 @@ export default function RiderSubstitution({ filteredRows?.map((row, index) => { const statusMeta = getRowStatusMeta(row); const StatusIcon = statusMeta.icon; + const riderProfile = allRidersList?.find((r) => r.userid === row.userid); + const starttime = riderProfile?.starttime || row.starttime; return ( option?.userid === value?.userid} getOptionLabel={(option) => `${option.username || option.fullname || ''} (#${option.userid})`} @@ -471,6 +505,8 @@ export default function RiderSubstitution({ filteredRows?.map((row, index) => { const statusMeta = getRowStatusMeta(row); const StatusIcon = statusMeta.icon; + const riderProfile = allRidersList?.find((r) => r.userid === row.userid); + const starttime = riderProfile?.starttime || row.starttime; return ( option?.userid === value?.userid} getOptionLabel={(option) => `${option.username || option.fullname || ''} (#${option.userid})`} diff --git a/src/pages/nearle/riders/riders.js b/src/pages/nearle/riders/riders.js index 3673e94..57afa5a 100644 --- a/src/pages/nearle/riders/riders.js +++ b/src/pages/nearle/riders/riders.js @@ -23,7 +23,14 @@ import { Skeleton, useMediaQuery, ToggleButtonGroup, - ToggleButton + ToggleButton, + Dialog, + DialogTitle, + DialogContent, + DialogActions, + Button, + Autocomplete, + TextField } from '@mui/material'; import { useTheme } from '@mui/material/styles'; var utc = require('dayjs/plugin/utc'); @@ -51,7 +58,8 @@ import { MdAccessTime, MdInventory2, MdTwoWheeler, - MdArrowForward + MdArrowForward, + MdDelete } from 'react-icons/md'; import LocationAutocomplete from 'components/nearle_components/LocationAutocomplete'; import PageHeader from 'components/nearle_components/PageHeader'; @@ -164,9 +172,101 @@ const Riders = () => { const totalCols = roleid == 1 ? 11 : 10; const [logsRow, setLogsRow] = useState(null); const [riderLogsdata, setRiderLogsdata] = useState(null); - const [historyFromDate, setHistoryFromDate] = useState(dayjs().startOf('month')); - const [historyToDate, setHistoryToDate] = useState(dayjs().endOf('month')); + const [historyDate, setHistoryDate] = useState(dayjs()); const [historyStatus, setHistoryStatus] = useState('all'); + const [selectedDate, setSelectedDate] = useState(dayjs()); + const [editingSub, setEditingSub] = useState(null); + const [newSubRider, setNewSubRider] = useState(null); + + const getResolvedPartnerId = () => { + let partnerId = ''; + try { + const rawLocs = localStorage.getItem('applocations'); + if (rawLocs) { + const locs = JSON.parse(rawLocs); + const currentLoc = locs.find((l) => l.applocationid === appId); + if (currentLoc && currentLoc.partnerid) { + partnerId = currentLoc.partnerid; + } else { + const firstValidLoc = locs.find((l) => l.partnerid); + if (firstValidLoc && firstValidLoc.partnerid) { + partnerId = firstValidLoc.partnerid; + } + } + } + } catch (e) { + console.error('Error parsing applocations', e); + } + + if (!partnerId) { + const savedPartnerId = localStorage.getItem('partnerid'); + if (savedPartnerId && savedPartnerId !== 'undefined' && savedPartnerId !== 'null') { + partnerId = savedPartnerId; + } + } + + if (!partnerId || partnerId === '0' || partnerId === 0) { + partnerId = 44; + } + return partnerId; + }; + + const getHistoryStatusColor = (status) => { + const s = (status || '').toLowerCase(); + if (s === 'cancelled' || s === 'deleted' || s === 'inactive') return '#ef4444'; // Red + if (s === 'scheduled') return '#0ea5e9'; // Blue + if (s === 'active' || s === 'completed') return '#10b981'; // Green + return '#64748b'; // Gray + }; + + const handleDeleteSubstitution = async (row) => { + if (window.confirm(`Are you sure you want to delete the substitution for ${row.absent_rider_name}?`)) { + try { + const resolvedTenantId = row.tenant_id || row.tenantid || getResolvedPartnerId(); + const url = `${process.env.REACT_APP_URL}/substitutions/${row.id}?tenant_id=${resolvedTenantId}`; + const res = await axios.delete(url); + if (res.data && res.data.status) { + OpenToast('Substitution deleted successfully!', 'success', 2000); + } else { + OpenToast(res.data?.message || 'Failed to delete substitution.', 'error', 2000); + } + } catch (err) { + console.error(err); + OpenToast(err.response?.data?.message || err.message || 'Failed to delete substitution.', 'error', 2000); + } finally { + queryClient.invalidateQueries({ queryKey: ['substitutionsHistory'] }); + } + } + }; + + const handleUpdateSubstitutionSubmit = async () => { + if (!newSubRider) { + OpenToast('Please select a substitute rider', 'error', 2000); + return; + } + try { + const resolvedTenantId = editingSub.tenant_id || editingSub.tenantid || getResolvedPartnerId(); + const url = `${process.env.REACT_APP_URL}/substitutions/${editingSub.id}`; + const payload = { + tenant_id: parseInt(resolvedTenantId, 10), + sub_rider_id: parseInt(newSubRider.userid, 10), + sub_rider_name: newSubRider.username || newSubRider.fullname || `Rider #${newSubRider.userid}` + }; + const res = await axios.put(url, payload); + if (res.data && res.data.status) { + OpenToast('Substitution updated successfully!', 'success', 2000); + } else { + OpenToast(res.data?.message || 'Failed to update substitution.', 'error', 2000); + } + } catch (err) { + console.error(err); + OpenToast(err.response?.data?.message || err.message || 'Failed to update substitution.', 'error', 2000); + } finally { + setEditingSub(null); + setNewSubRider(null); + queryClient.invalidateQueries({ queryKey: ['substitutionsHistory'] }); + } + }; const [substituteAssignments, setSubstituteAssignments] = useState(() => { try { @@ -229,15 +329,18 @@ const Riders = () => { } } - if (!partnerId) { + if (!partnerId || partnerId === '0' || partnerId === 0) { partnerId = 44; // final fallback } - const url = `${process.env.REACT_APP_URL}/partners/getallriders/?applocationid=${appId}&partnerid=${partnerId}`; + const url = `${process.env.REACT_APP_URL}/partners/getallriders/?applocationid=0&partnerid=${partnerId}&pagesize=1000&pageno=1&status=`; const res = await axios.get(url); const allRiders = res.data.details || []; + console.log('Substitute query - all riders returned from API:', allRiders.map(r => ({ userid: r.userid, username: r.username, partnerid: r.partnerid }))); const allowedIds = [1121, 772, 1116]; - return allRiders.filter((rider) => allowedIds.includes(parseInt(rider.userid))); + const filtered = allRiders.filter((rider) => allowedIds.includes(parseInt(rider.userid))); + console.log('Substitute query - filtered allowed riders:', filtered); + return filtered; } catch (err) { console.error(err); return []; @@ -246,10 +349,10 @@ const Riders = () => { }); const { data: subRidersLogsData, isLoading: subRidersLogsLoading } = useQuery({ - queryKey: ['subRidersLogs', appId, debouncedSearch], + queryKey: ['subRidersLogs', appId, debouncedSearch, selectedDate.format('YYYY-MM-DD')], queryFn: async () => { try { - const todayStr = dayjs().format('YYYY-MM-DD'); + const dateStr = selectedDate.format('YYYY-MM-DD'); // Resolve partner ID dynamically let partnerId = ''; @@ -278,11 +381,11 @@ const Riders = () => { } } - if (!partnerId) { + if (!partnerId || partnerId === '0' || partnerId === 0) { partnerId = 44; } - const url = `${process.env.REACT_APP_URL2}/partners/getriderlogs/?applocationid=${appId}&partnerid=${partnerId}&fromdate=${todayStr}&todate=${todayStr}&keyword=${debouncedSearch}`; + const url = `${process.env.REACT_APP_URL2}/partners/getriderlogs/?applocationid=${appId}&partnerid=${partnerId}&fromdate=${dateStr}&todate=${dateStr}&keyword=${debouncedSearch}`; const res = await axios.get(url); return res.data.details || []; } catch (err) { @@ -293,7 +396,7 @@ const Riders = () => { }); const { data: subHistoryData, isLoading: subHistoryLoading } = useQuery({ - queryKey: ['substitutionsHistory', appId, historyFromDate, historyToDate, historyStatus], + queryKey: ['substitutionsHistory', appId, historyDate, historyStatus], queryFn: async () => { try { let partnerId = ''; @@ -322,11 +425,12 @@ const Riders = () => { } } - if (!partnerId) { + if (!partnerId || partnerId === '0' || partnerId === 0) { partnerId = 44; } - let url = `${process.env.REACT_APP_URL}/substitutions?tenant_id=${partnerId}&from_date=${historyFromDate.format('YYYY-MM-DD')}&to_date=${historyToDate.format('YYYY-MM-DD')}`; + const dateStr = historyDate.format('YYYY-MM-DD'); + let url = `${process.env.REACT_APP_URL}/substitutions?tenant_id=${partnerId}&from_date=${dateStr}&to_date=${dateStr}`; if (historyStatus !== 'all') { url += `&status=${historyStatus}`; } @@ -672,33 +776,14 @@ const Riders = () => { newValue && setHistoryFromDate(newValue)} + label="Select Date" + value={historyDate} + onChange={(newValue) => newValue && setHistoryDate(newValue)} slotProps={{ textField: { size: 'small', sx: { - width: 150, - '& .MuiOutlinedInput-root': { - borderRadius: '20px', - '& fieldset': { borderColor: DT.borderSubtle }, - '&:hover fieldset': { borderColor: BRAND }, - '&.Mui-focused fieldset': { borderColor: BRAND } - } - } - } - }} - /> - newValue && setHistoryToDate(newValue)} - slotProps={{ - textField: { - size: 'small', - sx: { - width: 150, + width: 180, '& .MuiOutlinedInput-root': { borderRadius: '20px', '& fieldset': { borderColor: DT.borderSubtle }, @@ -757,9 +842,9 @@ const Riders = () => { px: 1, py: 0.25, borderRadius: 999, - bgcolor: tint('#10b981'), - border: `1px solid ${edge('#10b981')}`, - color: '#10b981', + bgcolor: tint(getHistoryStatusColor(row.status)), + border: `1px solid ${edge(getHistoryStatusColor(row.status))}`, + color: getHistoryStatusColor(row.status), fontWeight: 800, fontSize: 10 }} @@ -841,6 +926,7 @@ const Riders = () => { Substitute Rider Reason Status + Action @@ -908,9 +994,9 @@ const Riders = () => { px: 1.5, py: 0.5, borderRadius: 999, - bgcolor: tint('#10b981'), - border: `1px solid ${edge('#10b981')}`, - color: '#10b981', + bgcolor: tint(getHistoryStatusColor(row.status)), + border: `1px solid ${edge(getHistoryStatusColor(row.status))}`, + color: getHistoryStatusColor(row.status), fontWeight: 800, fontSize: 11, textTransform: 'capitalize' @@ -919,6 +1005,43 @@ const Riders = () => { {row.status || 'scheduled'} + + + + { + setEditingSub(row); + setNewSubRider(null); + }} + > + + + + + { + handleDeleteSubstitution(row); + }} + > + + + + + ))} @@ -930,10 +1053,13 @@ const Riders = () => { { )} + + setEditingSub(null)} + maxWidth="xs" + fullWidth + PaperProps={{ + sx: { + borderRadius: `${DT.radiusCard / 8}px`, + p: 1 + } + }} + > + Update Substitution + + + + Choose a new substitute rider for {editingSub?.absent_rider_name}. + + option?.userid === value?.userid} + getOptionLabel={(option) => `${option.username || option.fullname || ''} (#${option.userid})`} + value={newSubRider} + onChange={(event, newValue) => setNewSubRider(newValue)} + renderInput={(params) => ( + + )} + /> + + + + + + + ); };