updated the ui for the mobile view
This commit is contained in:
@@ -19,6 +19,8 @@ import {
|
||||
} from '@mui/material';
|
||||
import React, { Fragment, useEffect, useMemo, useState } from 'react';
|
||||
import { useTheme } from '@mui/material/styles';
|
||||
import useMediaQuery from '@mui/material/useMediaQuery';
|
||||
import { MobileCard, MobileCardList, MobileField, MobileFieldGrid } from 'components/nearle_components/MobileCard';
|
||||
import { useLocation, useNavigate } from 'react-router-dom';
|
||||
import dayjs from 'dayjs';
|
||||
import MainCard from 'components/MainCard';
|
||||
@@ -38,8 +40,150 @@ import { HiOutlineArrowLeft } from 'react-icons/hi';
|
||||
var utc = require('dayjs/plugin/utc');
|
||||
dayjs.extend(utc);
|
||||
|
||||
// Mobile-only rendering of the optimised-orders preview. Mirrors the exact same
|
||||
// fields, chips and tooltips as the desktop table rows — no behaviour added,
|
||||
// purely a card layout for phones. Renders for both aiMode 1 and normal mode;
|
||||
// the Zone / Rider fields are gated on aiMode just like the table columns.
|
||||
const MobileOrdersList = ({ list, aiMode }) => {
|
||||
if (!list || list.length === 0) {
|
||||
return (
|
||||
<Stack alignItems="center" sx={{ py: 4 }}>
|
||||
<Empty />
|
||||
</Stack>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<MobileCardList>
|
||||
{list.map((val, index) => {
|
||||
const typeColor =
|
||||
val.ordertype == 'Economy' ? 'success' : val.ordertype == 'Risky' ? 'error' : 'primary';
|
||||
return (
|
||||
<MobileCard
|
||||
key={index}
|
||||
header={
|
||||
<Stack direction="row" alignItems="center" justifyContent="space-between" spacing={1}>
|
||||
<Stack direction="row" alignItems="center" spacing={1} sx={{ minWidth: 0 }}>
|
||||
<Typography sx={{ fontWeight: 800, color: '#94a3b8' }}>#{index + 1}</Typography>
|
||||
{aiMode == 1 && <Chip size="small" color="primary" label={val.zone_name} />}
|
||||
</Stack>
|
||||
<Chip size="small" label={val.ordertype} color={typeColor} />
|
||||
</Stack>
|
||||
}
|
||||
>
|
||||
<MobileFieldGrid>
|
||||
<MobileField label="Tenant" full>
|
||||
<Tooltip title={val.tenantaddress}>
|
||||
<Stack>
|
||||
<Typography variant="body1" noWrap>
|
||||
{val.tenantname}
|
||||
</Typography>
|
||||
<Typography noWrap sx={{ fontSize: '11px' }}>
|
||||
{val.tenantsuburb}
|
||||
</Typography>
|
||||
<Typography noWrap variant="body2">
|
||||
{val.applocation}
|
||||
</Typography>
|
||||
</Stack>
|
||||
</Tooltip>
|
||||
</MobileField>
|
||||
|
||||
<MobileField label="Order Location" full>
|
||||
<Tooltip title={val.locationaddress} placement="top">
|
||||
<Typography variant="body1" noWrap>
|
||||
{`${val.locationname}-(${val.locationsuburb})`}
|
||||
</Typography>
|
||||
</Tooltip>
|
||||
<Tooltip title="Order Id">
|
||||
<Typography variant="body2" noWrap>
|
||||
{val.orderid}
|
||||
</Typography>
|
||||
</Tooltip>
|
||||
<Stack display={'flex'} flexDirection={'row'} gap={3}>
|
||||
<Tooltip title="Ordered date">
|
||||
<Stack>
|
||||
<Typography noWrap sx={{ fontSize: '12px' }}>
|
||||
{dayjs(val.orderdate).utc().format('DD/MM/YYYY')}
|
||||
</Typography>
|
||||
<Typography noWrap sx={{ fontSize: '11px' }}>
|
||||
{dayjs(val.orderdate).utc().format('hh:mm A')}
|
||||
</Typography>
|
||||
</Stack>
|
||||
</Tooltip>
|
||||
-
|
||||
<Tooltip title="Delivery date">
|
||||
<Stack>
|
||||
<Typography noWrap sx={{ fontSize: '12px' }}>
|
||||
{dayjs(val.deliverydate).utc().format('DD/MM/YYYY')}
|
||||
</Typography>
|
||||
<Typography noWrap sx={{ fontSize: '11px' }}>
|
||||
{dayjs(val.deliverydate).utc().format('hh:mm A')}
|
||||
</Typography>
|
||||
</Stack>
|
||||
</Tooltip>
|
||||
</Stack>
|
||||
</MobileField>
|
||||
|
||||
<MobileField label="Pickup">
|
||||
<Stack direction="column">
|
||||
<Typography variant="caption">{val.pickupcustomer}</Typography>
|
||||
<Typography variant="caption">{val.pickupcontactno}</Typography>
|
||||
<Tooltip title={val.pickupaddress}>
|
||||
<Typography variant="caption">{val.pickupsuburb || val.pickupaddress.slice(0, 20)}</Typography>
|
||||
</Tooltip>
|
||||
</Stack>
|
||||
</MobileField>
|
||||
|
||||
<MobileField label="Delivery">
|
||||
<Stack direction="column">
|
||||
<Typography variant="caption">{val.deliverycustomer}</Typography>
|
||||
<Typography variant="caption">{val.deliverycontactno}</Typography>
|
||||
<Tooltip title={val.deliveryaddress}>
|
||||
<Typography variant="caption">{val.deliverysuburb || val.deliveryaddress.slice(0, 20)}</Typography>
|
||||
</Tooltip>
|
||||
</Stack>
|
||||
</MobileField>
|
||||
|
||||
{val.ordernotes ? <MobileField label="Notes" value={val.ordernotes} full /> : null}
|
||||
|
||||
{aiMode == 1 && (
|
||||
<MobileField label="Rider" full>
|
||||
<Typography sx={{ whiteSpace: 'nowrap' }}>{val.username}</Typography>
|
||||
<Typography>ID : {val.userid}</Typography>
|
||||
</MobileField>
|
||||
)}
|
||||
|
||||
<MobileField label="Profit">
|
||||
<Stack display={'flex'} flexDirection={'column'} gap={1} sx={{ cursor: 'pointer' }}>
|
||||
<Tooltip title="Charges" placement="top">
|
||||
<Chip size="small" label={`₹ ${val.deliverycharge.toFixed(2)} `} color="error" />
|
||||
</Tooltip>
|
||||
<Tooltip title="Amount" placement="left">
|
||||
<Chip size="small" label={`₹ ${val.deliveryamt.toFixed(2)} `} color="success" />
|
||||
</Tooltip>
|
||||
</Stack>
|
||||
</MobileField>
|
||||
|
||||
<MobileField label="KMS">
|
||||
<Stack display={'flex'} flexDirection={'column'} gap={1} sx={{ cursor: 'pointer' }}>
|
||||
<Tooltip title="KMS" placement="top">
|
||||
<Chip size="small" label={`${val.kms} km`} color="error" />
|
||||
</Tooltip>
|
||||
<Tooltip title="Cumulative Kms" placement="right">
|
||||
<Chip size="small" label={`${val.cumulativekms} km`} color="success" />
|
||||
</Tooltip>
|
||||
</Stack>
|
||||
</MobileField>
|
||||
</MobileFieldGrid>
|
||||
</MobileCard>
|
||||
);
|
||||
})}
|
||||
</MobileCardList>
|
||||
);
|
||||
};
|
||||
|
||||
const OrdersPreview = () => {
|
||||
const theme = useTheme();
|
||||
const isMobile = useMediaQuery(theme.breakpoints.down('md'));
|
||||
const navigate = useNavigate();
|
||||
const location = useLocation();
|
||||
console.log('location.state', location.state);
|
||||
@@ -246,6 +390,9 @@ const OrdersPreview = () => {
|
||||
</Grid>
|
||||
</Stack>
|
||||
)}
|
||||
{isMobile ? (
|
||||
<MobileOrdersList list={finaldeliveryList} aiMode={aiMode} />
|
||||
) : (
|
||||
<TableContainer
|
||||
sx={{
|
||||
maxHeight: 'calc(100vh - 250px)',
|
||||
@@ -549,6 +696,7 @@ const OrdersPreview = () => {
|
||||
</TableBody>
|
||||
</Table>
|
||||
</TableContainer>
|
||||
)}
|
||||
<Divider />
|
||||
{aiMode == 0 && (
|
||||
<Grid container spacing={2} sx={{ p: 2 }}>
|
||||
@@ -600,9 +748,16 @@ const OrdersPreview = () => {
|
||||
</Grid>
|
||||
)}
|
||||
<Divider />
|
||||
<Stack display={'flex'} flexDirection={'row'} gap={2} alignItems={'center'} justifyContent={'end'} sx={{ p: 2 }}>
|
||||
<Stack
|
||||
display={'flex'}
|
||||
flexDirection={{ xs: 'column', sm: 'row' }}
|
||||
gap={2}
|
||||
alignItems={{ xs: 'stretch', sm: 'center' }}
|
||||
justifyContent={'end'}
|
||||
sx={{ p: 2 }}
|
||||
>
|
||||
<Button
|
||||
sx={{}}
|
||||
fullWidth={isMobile}
|
||||
variant="contained"
|
||||
color="secondary"
|
||||
startIcon={<ArrowBackIcon />}
|
||||
@@ -612,7 +767,13 @@ const OrdersPreview = () => {
|
||||
>
|
||||
Back
|
||||
</Button>
|
||||
<Button sx={{ my: 2 }} variant="contained" disabled={aiMode === 0 && (!rider || !payment)} onClick={handleManualCreateDelivery}>
|
||||
<Button
|
||||
fullWidth={isMobile}
|
||||
sx={{ my: { xs: 0, sm: 2 } }}
|
||||
variant="contained"
|
||||
disabled={aiMode === 0 && (!rider || !payment)}
|
||||
onClick={handleManualCreateDelivery}
|
||||
>
|
||||
Assign Orders
|
||||
</Button>
|
||||
</Stack>
|
||||
|
||||
@@ -22,7 +22,8 @@ import {
|
||||
FormGroup,
|
||||
FormControlLabel,
|
||||
Box,
|
||||
Card
|
||||
Card,
|
||||
useMediaQuery
|
||||
} from '@mui/material';
|
||||
import CloseIcon from '@mui/icons-material/Close';
|
||||
import { Empty } from 'antd';
|
||||
@@ -185,6 +186,7 @@ const Createorder1 = () => {
|
||||
const loaded = React.useRef(false);
|
||||
const navigate = useNavigate();
|
||||
const theme = useTheme();
|
||||
const isMobile = useMediaQuery(theme.breakpoints.down('md'));
|
||||
const locationRef = useRef(null);
|
||||
const tenantRef = useRef(null);
|
||||
const [inputValue1, setInputValue1] = React.useState('');
|
||||
@@ -2439,9 +2441,10 @@ const Createorder1 = () => {
|
||||
setSearchCustList('');
|
||||
}}
|
||||
fullWidth
|
||||
fullScreen={isMobile}
|
||||
sx={{
|
||||
'& .MuiDialog-paper': {
|
||||
borderRadius: '16px',
|
||||
borderRadius: { xs: 0, sm: '16px' },
|
||||
overflow: 'hidden'
|
||||
}
|
||||
}}
|
||||
@@ -2567,10 +2570,13 @@ const Createorder1 = () => {
|
||||
onClose={() => {
|
||||
setOpen(false);
|
||||
}}
|
||||
fullWidth
|
||||
sx={{
|
||||
'& .MuiDialog-paper': {
|
||||
borderRadius: '16px',
|
||||
borderRadius: { xs: 3, sm: '16px' },
|
||||
p: 1.5,
|
||||
m: { xs: 1.5, sm: 4 },
|
||||
width: { xs: 'calc(100% - 24px)', sm: 'auto' },
|
||||
maxWidth: '400px'
|
||||
}
|
||||
}}
|
||||
|
||||
@@ -88,6 +88,8 @@ dayjs.extend(utc);
|
||||
// import HeartFilled from '@mui/icons-material/Favorite';
|
||||
|
||||
import { useTheme } from '@mui/material/styles';
|
||||
import useMediaQuery from '@mui/material/useMediaQuery';
|
||||
import { MobileCard, MobileCardList, MobileField, MobileFieldGrid } from 'components/nearle_components/MobileCard';
|
||||
import {
|
||||
CloseOutlined,
|
||||
WarningOutlined,
|
||||
@@ -177,6 +179,7 @@ const Details = () => {
|
||||
}, [state.orderheaderid, state.tenantid]);
|
||||
|
||||
const theme = useTheme();
|
||||
const isMobile = useMediaQuery(theme.breakpoints.down('md'));
|
||||
|
||||
// const fetchorderdetails = async () => {
|
||||
// setLoading(true);
|
||||
@@ -704,7 +707,13 @@ const Details = () => {
|
||||
const [deletepassword, setDeletepassword] = useState('');
|
||||
|
||||
return (
|
||||
<Dialog open={open} onClose={() => handleClose(false)} maxWidth="xs">
|
||||
<Dialog
|
||||
open={open}
|
||||
onClose={() => handleClose(false)}
|
||||
maxWidth="xs"
|
||||
fullScreen={isMobile}
|
||||
PaperProps={{ sx: { borderRadius: { xs: 0, sm: 3 } } }}
|
||||
>
|
||||
<DialogContent sx={{ mt: 2, my: 1 }}>
|
||||
<Stack alignItems="center" spacing={3.5}>
|
||||
<Avatar color="error" sx={{ width: 72, height: 72, fontSize: '1.75rem' }}>
|
||||
@@ -778,7 +787,8 @@ const Details = () => {
|
||||
open={dialogopen}
|
||||
onClose={dialogclose}
|
||||
scroll={'paper'}
|
||||
// fullScreen
|
||||
fullScreen={isMobile}
|
||||
PaperProps={{ sx: { borderRadius: { xs: 0, sm: 3 } } }}
|
||||
TransitionComponent={PopupTransition}
|
||||
>
|
||||
<DialogTitle>
|
||||
@@ -880,6 +890,115 @@ const Details = () => {
|
||||
<Typography>No Staffs Available</Typography>
|
||||
)}
|
||||
</>
|
||||
) : isMobile ? (
|
||||
<MobileCardList>
|
||||
{stafflist.map((val, i) => {
|
||||
const isSelected = staffarr.find((res) => res.userid == val.userid) ? true : false;
|
||||
return (
|
||||
<MobileCard key={i} accent="#662582" selected={isSelected}>
|
||||
<Stack direction="row" justifyContent="space-between" alignItems="flex-start" spacing={1}>
|
||||
<Stack direction="row" alignItems="center" spacing={1}>
|
||||
<Avatar alt="" src={''} sx={{ width: 32, height: 32 }} />
|
||||
<Stack direction="column">
|
||||
<Typography variant="subtitle2">{val.firstname}</Typography>
|
||||
<Typography variant="caption" color="textSecondary">
|
||||
{val.contactno}
|
||||
</Typography>
|
||||
</Stack>
|
||||
</Stack>
|
||||
{val.orderdetailid !== orderdetailid ? (
|
||||
<Checkbox
|
||||
disabled={val.orderdetailid !== 0}
|
||||
checked={isSelected}
|
||||
onClick={(e) => {
|
||||
console.log(currentshiftobj);
|
||||
if (currentshiftobj.remaining >= 0) {
|
||||
if (e.target.checked && currentshiftobj.remaining != 0) {
|
||||
let arr = staffarr;
|
||||
arr.push({
|
||||
userid: val.userid,
|
||||
orderdetailid,
|
||||
productid,
|
||||
shiftid: currentshiftobj.shiftid,
|
||||
userrate: currentshiftobj.price,
|
||||
productrate: val.rolecost,
|
||||
firstname: val.firstname
|
||||
});
|
||||
setStaffarr([...arr]);
|
||||
let obj = currentshiftobj;
|
||||
obj.assigned++;
|
||||
obj.remaining = obj.shifts - obj.assigned;
|
||||
setCurrentshiftobj({ ...obj });
|
||||
} else if (
|
||||
currentshiftobj.assigned != currentshiftobj.shifts ||
|
||||
(currentshiftobj.remaining === 0 && !e.target.checked)
|
||||
) {
|
||||
let arr = staffarr;
|
||||
let index = arr.findIndex((val1) => val1.userid === val.userid);
|
||||
arr.splice(index, 1);
|
||||
setStaffarr([...arr]);
|
||||
let obj = currentshiftobj;
|
||||
obj.assigned--;
|
||||
obj.remaining = obj.shifts - obj.assigned;
|
||||
setCurrentshiftobj({ ...obj });
|
||||
}
|
||||
console.log(staffarr);
|
||||
}
|
||||
}}
|
||||
/>
|
||||
) : (
|
||||
<Stack direction="row" alignItems="center">
|
||||
<Chip label="Assigned" color="success" size="small" sx={{ mr: 1 }} />
|
||||
<Tooltip title="Unassign">
|
||||
<IconButton
|
||||
color="error"
|
||||
onClick={() => {
|
||||
console.log(val);
|
||||
unassign(val);
|
||||
}}
|
||||
>
|
||||
<CloseOutlined />
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
<Tooltip title="Send Notification">
|
||||
<IconButton
|
||||
color="info"
|
||||
onClick={() => {
|
||||
console.log(val);
|
||||
notificationpush(val);
|
||||
}}
|
||||
>
|
||||
<NotificationOutlined />
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
</Stack>
|
||||
)}
|
||||
</Stack>
|
||||
<MobileFieldGrid>
|
||||
<MobileField label="Category">
|
||||
<Stack direction="column" alignItems="flex-start" spacing={0.25}>
|
||||
<Typography variant="caption" color="textSecondary">
|
||||
{val.cateoryname}
|
||||
</Typography>
|
||||
<Chip label={val.subcategoryname} color="info" size="small" variant="light" />
|
||||
</Stack>
|
||||
</MobileField>
|
||||
<MobileField label="Price" value={val.rolecost} />
|
||||
<MobileField label="Experience" value={`${val.experience} Years`} />
|
||||
<MobileField label="Level">
|
||||
<Chip label={val.levelofexperience} size="small" color="primary" variant="light" />
|
||||
</MobileField>
|
||||
<MobileField label="City" value={val.city} />
|
||||
{val.orderid && (
|
||||
<MobileField label="Order">
|
||||
<Chip label={val.orderid} color="warning" size="small" variant="light" />
|
||||
</MobileField>
|
||||
)}
|
||||
</MobileFieldGrid>
|
||||
</MobileCard>
|
||||
);
|
||||
})}
|
||||
</MobileCardList>
|
||||
) : (
|
||||
<TableContainer>
|
||||
<Table>
|
||||
@@ -1081,14 +1200,19 @@ const Details = () => {
|
||||
)}
|
||||
</DialogContent>
|
||||
<DialogActions>
|
||||
<Stack sx={{ mt: 2 }} direction="row" justifyContent="flex-end" spacing={5}>
|
||||
<Stack
|
||||
sx={{ mt: 2, width: { xs: '100%', sm: 'auto' } }}
|
||||
direction={{ xs: 'column', sm: 'row' }}
|
||||
justifyContent="flex-end"
|
||||
spacing={{ xs: 1.5, sm: 5 }}
|
||||
>
|
||||
{stafflist.length > 0 && (
|
||||
<>
|
||||
<Button1 sx={{ width: '130px' }} variant="contained" onClick={assignok}>
|
||||
<Button1 sx={{ width: { xs: '100%', sm: '130px' } }} variant="contained" onClick={assignok}>
|
||||
OK
|
||||
</Button1>
|
||||
<Button1
|
||||
sx={{ width: '130px' }}
|
||||
sx={{ width: { xs: '100%', sm: '130px' } }}
|
||||
color="warning"
|
||||
variant="contained"
|
||||
onClick={() => {
|
||||
@@ -1107,7 +1231,7 @@ const Details = () => {
|
||||
</>
|
||||
)}
|
||||
<Button1
|
||||
sx={{ width: '130px' }}
|
||||
sx={{ width: { xs: '100%', sm: '130px' } }}
|
||||
color="error"
|
||||
variant="contained"
|
||||
onClick={() => {
|
||||
@@ -1195,7 +1319,11 @@ const Details = () => {
|
||||
</Stack>
|
||||
</Stack>
|
||||
|
||||
<Stack direction="row" spacing={2} sx={{ mt: { md: 0, xs: 2 } }}>
|
||||
<Stack
|
||||
direction={{ xs: 'column', sm: 'row' }}
|
||||
spacing={2}
|
||||
sx={{ mt: { md: 0, xs: 2 }, width: { xs: '100%', md: 'auto' } }}
|
||||
>
|
||||
{/* <Typography>{dayjs(startdate).$d.toString()}</Typography> */}
|
||||
{/* <Typography>{startdate}</Typography> */}
|
||||
{/* <Typography> {dayjs().$d.toString()}</Typography> */}
|
||||
@@ -1206,7 +1334,7 @@ const Details = () => {
|
||||
<Button1
|
||||
variant="outlined"
|
||||
color="info"
|
||||
sx={{ borderRadius: '40px' }}
|
||||
sx={{ borderRadius: '40px', width: { xs: '100%', sm: 'auto' } }}
|
||||
startIcon={<BorderColorIcon color="info" />}
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
@@ -1269,7 +1397,7 @@ const Details = () => {
|
||||
setOpen(true);
|
||||
}
|
||||
}}
|
||||
sx={{ borderRadius: '40px', mt: { xs: 2, sm: 0 } }}
|
||||
sx={{ borderRadius: '40px', mt: { xs: 2, sm: 0 }, width: { xs: '100%', sm: 'auto' } }}
|
||||
startIcon={<CancelOutlinedIcon />}
|
||||
>
|
||||
Cancel Order
|
||||
@@ -1418,6 +1546,184 @@ const Details = () => {
|
||||
})}
|
||||
</Stack>
|
||||
</Stack>
|
||||
{isMobile ? (
|
||||
<MobileCardList>
|
||||
{val5.orderdetails.length === 0 && (
|
||||
<MobileCard accent="#662582">
|
||||
<Skeleton animation="wave" />
|
||||
<Skeleton animation="wave" />
|
||||
<Skeleton animation="wave" />
|
||||
</MobileCard>
|
||||
)}
|
||||
{val5.orderdetails.map((row, i) => (
|
||||
<MobileCard key={i + 1} accent="#662582" sx={{ opacity: row.status == 0 ? '' : '0.7' }}>
|
||||
<Stack direction="row" justifyContent="space-between" alignItems="flex-start" spacing={1}>
|
||||
<Stack direction="column">
|
||||
<Typography sx={{ fontSize: 10, fontWeight: 800, color: '#94a3b8' }}>#{i + 1}</Typography>
|
||||
<Typography variant="subtitle1">{row.productname}</Typography>
|
||||
</Stack>
|
||||
<Stack direction="row" alignItems="center">
|
||||
<Tooltip title="Expand">
|
||||
<IconButton
|
||||
aria-label="expand row"
|
||||
style={{ color: theme.palette.primary.main }}
|
||||
onClick={() => {
|
||||
setStafflist([]);
|
||||
setExpandopen(expandopen[0] === j && expandopen[1] === i ? ['', ''] : [j, i]);
|
||||
fetchstafflist(row.orderdetailid);
|
||||
}}
|
||||
>
|
||||
{expandopen[0] === j && expandopen[1] === i ? <KeyboardArrowUp /> : <KeyboardArrowDown />}
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
{orderstatus === 'cancelled' && (
|
||||
<IconButton sx={{ minWidth: '10px !important' }} disabled>
|
||||
<EditTwoTone />
|
||||
</IconButton>
|
||||
)}
|
||||
{row.status === 1 && (
|
||||
<Tooltip title="Cancelled">
|
||||
<IconButton sx={{ minWidth: '10px !important' }}>
|
||||
<CancelOutlinedIcon color="error" />
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
)}
|
||||
{row.supplyqty > row.orderqty && (
|
||||
<Tooltip title="Assigned count is greater than ordered count">
|
||||
<IconButton color="warning">
|
||||
<WarningOutlined />
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
)}
|
||||
</Stack>
|
||||
</Stack>
|
||||
<MobileFieldGrid>
|
||||
<MobileField label="Start Date">
|
||||
<Stack direction="column">
|
||||
<Typography variant="body2">{dayjs(row.starttime).format('MM/DD/YYYY')}</Typography>
|
||||
<Typography variant="caption">{dayjs(row.starttime).format('hh:mm A')}</Typography>
|
||||
</Stack>
|
||||
</MobileField>
|
||||
<MobileField label="End Date">
|
||||
<Stack direction="column">
|
||||
<Typography variant="body2">{dayjs(row.endtime).format('MM/DD/YYYY')}</Typography>
|
||||
<Typography variant="caption">{dayjs(row.endtime).format('hh:mm A')}</Typography>
|
||||
</Stack>
|
||||
</MobileField>
|
||||
<MobileField label="Unpaid Break" value={row.unpaidbreak || 0} />
|
||||
<MobileField label="Count">
|
||||
<Chip label={row.orderqty} color="success" variant="light" size="small" />
|
||||
</MobileField>
|
||||
<MobileField label="Assigned">
|
||||
<Chip
|
||||
label={row.supplyqty}
|
||||
color={row.supplyqty === 0 ? 'error' : 'warning'}
|
||||
variant="light"
|
||||
size="small"
|
||||
/>
|
||||
</MobileField>
|
||||
<MobileField label="Price" value={`$${row.price}`} />
|
||||
<MobileField label="Amount" value={`$${row.landingamount}`} />
|
||||
</MobileFieldGrid>
|
||||
<Collapse in={expandopen[0] === j && expandopen[1] === i} timeout="auto" unmountOnExit>
|
||||
<Divider sx={{ my: 1.5 }} />
|
||||
{stafflist.length === 0 ? (
|
||||
loading ? (
|
||||
<Stack alignItems={'center'}>
|
||||
<CircularProgress />
|
||||
</Stack>
|
||||
) : (
|
||||
<Stack sx={{ p: 1 }}>
|
||||
<Typography>No Staffs has been Assigned</Typography>
|
||||
</Stack>
|
||||
)
|
||||
) : (
|
||||
<Stack spacing={1}>
|
||||
{stafflist.map((val, si) => (
|
||||
<MobileCard key={si} accent="#0ea5e9">
|
||||
<Stack direction="row" justifyContent="space-between" alignItems="flex-start">
|
||||
<Stack direction="column">
|
||||
<Typography variant="subtitle2">{val.staffname}</Typography>
|
||||
<Grid>
|
||||
<Chip label={val.productname} color="info" variant="light" size="small" />
|
||||
</Grid>
|
||||
</Stack>
|
||||
<Stack direction="row">
|
||||
{val.orderstatus === 'pending' && <Chip label="Pending" color="error" size="small" />}
|
||||
{val.orderstatus === 'cancelled' && (
|
||||
<Chip label="Cancelled" color="secondary" size="small" />
|
||||
)}
|
||||
{val.orderstatus === 'completed' && (
|
||||
<Chip label="Completed" color="primary" size="small" />
|
||||
)}
|
||||
{val.orderstatus === 'processing' && (
|
||||
<Chip label="Processing" color="primary" size="small" />
|
||||
)}
|
||||
{val.orderstatus === 'assigned' && <Chip label="Assigned" color="warning" size="small" />}
|
||||
{val.orderstatus === 'confirmed' && (
|
||||
<Chip label="Confirmed" color="success" size="small" />
|
||||
)}
|
||||
{val.orderstatus === 'active' && <Chip label="Active" color="info" size="small" />}
|
||||
{val.orderstatus === 'closed' && <Chip label="Closed" color="info" size="small" />}
|
||||
</Stack>
|
||||
</Stack>
|
||||
<MobileFieldGrid>
|
||||
<MobileField label="Start Time">
|
||||
<Stack direction="column">
|
||||
<Typography variant="body2">{dayjs(val.Starttime).format('MM/DD/YYYY')}</Typography>
|
||||
<Typography variant="caption">{dayjs(val.Starttime).format('hh:mm A')}</Typography>
|
||||
</Stack>
|
||||
</MobileField>
|
||||
<MobileField label="End Time">
|
||||
<Stack direction="column">
|
||||
<Typography variant="body2">{dayjs(val.Endtime).format('MM/DD/YYYY')}</Typography>
|
||||
<Typography variant="caption">{dayjs(val.Endtime).format('hh:mm A')}</Typography>
|
||||
</Stack>
|
||||
</MobileField>
|
||||
<MobileField label="Pay Rate" value={val.rolecost} />
|
||||
<MobileField label="Hours Worked" value={val.hoursworked} />
|
||||
<MobileField label="Clockin">
|
||||
<Stack spacing={0.5} alignItems="flex-start">
|
||||
<Chip
|
||||
label={val.clockin ? dayjs(val.clockin).format('MM/DD/YYYY') : ''}
|
||||
color="primary"
|
||||
variant="light"
|
||||
size="small"
|
||||
/>
|
||||
<Chip
|
||||
label={val.clockin ? dayjs(val.clockin).format('hh:mm A') : ''}
|
||||
color="info"
|
||||
variant="light"
|
||||
size="small"
|
||||
/>
|
||||
</Stack>
|
||||
</MobileField>
|
||||
<MobileField label="Clockout">
|
||||
<Stack spacing={0.5} alignItems="flex-start">
|
||||
<Chip
|
||||
label={val.clockout ? dayjs(val.clockout).format('MM/DD/YYYY') : ''}
|
||||
color="primary"
|
||||
variant="light"
|
||||
size="small"
|
||||
/>
|
||||
<Chip
|
||||
label={val.clockout ? dayjs(val.clockout).format('hh:mm A') : ''}
|
||||
color="info"
|
||||
variant="light"
|
||||
size="small"
|
||||
/>
|
||||
</Stack>
|
||||
</MobileField>
|
||||
</MobileFieldGrid>
|
||||
</MobileCard>
|
||||
))}
|
||||
</Stack>
|
||||
)}
|
||||
</Collapse>
|
||||
</MobileCard>
|
||||
))}
|
||||
</MobileCardList>
|
||||
) : (
|
||||
<TableContainer>
|
||||
<Table>
|
||||
<TableHead>
|
||||
@@ -1870,6 +2176,7 @@ const Details = () => {
|
||||
</TableBody>
|
||||
</Table>
|
||||
</TableContainer>
|
||||
)}
|
||||
</MainCard>
|
||||
</Grid>
|
||||
</Fragment>
|
||||
|
||||
@@ -5,6 +5,7 @@ import * as XLSX from 'xlsx';
|
||||
import dayjs from 'dayjs';
|
||||
import { useNavigate } from 'react-router';
|
||||
import { useTheme } from '@mui/material/styles';
|
||||
import useMediaQuery from '@mui/material/useMediaQuery';
|
||||
import { enqueueSnackbar } from 'notistack';
|
||||
|
||||
import {
|
||||
@@ -65,6 +66,7 @@ import { MdOutlineCloudUpload } from 'react-icons/md';
|
||||
import Loader from 'components/Loader';
|
||||
import CircularLoader from 'components/CircularLoader';
|
||||
import AnimateButton from 'components/@extended/AnimateButton';
|
||||
import { MobileCard, MobileCardList, MobileField, MobileFieldGrid } from 'components/nearle_components/MobileCard';
|
||||
import './OrdersRedesign.css';
|
||||
|
||||
var utc = require('dayjs/plugin/utc');
|
||||
@@ -88,6 +90,7 @@ const cellBodySx = {
|
||||
const MultipleOrders = () => {
|
||||
const navigate = useNavigate();
|
||||
const theme = useTheme();
|
||||
const isMobile = useMediaQuery(theme.breakpoints.down('md'));
|
||||
const locationRef = useRef(null);
|
||||
const tenantRef = useRef(null);
|
||||
const userid = localStorage.getItem('userid');
|
||||
@@ -711,11 +714,12 @@ const MultipleOrders = () => {
|
||||
<Box
|
||||
className="orders-workspace-bg"
|
||||
sx={{
|
||||
height: 'calc(100vh - 64px)',
|
||||
height: { xs: 'auto', md: 'calc(100vh - 64px)' },
|
||||
minHeight: { xs: 'calc(100vh - 64px)', md: 0 },
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
overflow: 'hidden',
|
||||
p: { xs: 1, sm: 1.25 },
|
||||
overflow: { xs: 'visible', md: 'hidden' },
|
||||
p: { xs: 0.75, sm: 1.25 },
|
||||
gap: 1
|
||||
}}
|
||||
>
|
||||
@@ -752,7 +756,7 @@ const MultipleOrders = () => {
|
||||
<Grid
|
||||
container
|
||||
spacing={1.25}
|
||||
sx={{ flex: 1, minHeight: 0, overflow: 'hidden' }}
|
||||
sx={{ flex: 1, minHeight: 0, overflow: { xs: 'visible', md: 'hidden' } }}
|
||||
>
|
||||
{/* ============================== LEFT 50% : Input fields ============================== */}
|
||||
<Grid
|
||||
@@ -760,13 +764,13 @@ const MultipleOrders = () => {
|
||||
xs={12}
|
||||
md={6}
|
||||
sx={{
|
||||
height: '100%',
|
||||
height: { xs: 'auto', md: '100%' },
|
||||
minHeight: 0,
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
gap: 2.25,
|
||||
overflowY: 'auto',
|
||||
pr: 0.75
|
||||
gap: { xs: 1.25, md: 2.25 },
|
||||
overflowY: { xs: 'visible', md: 'auto' },
|
||||
pr: { xs: 0, md: 0.75 }
|
||||
}}
|
||||
>
|
||||
{/* Card: Setup (Location / Client / Business) */}
|
||||
@@ -1283,7 +1287,7 @@ const MultipleOrders = () => {
|
||||
item
|
||||
xs={12}
|
||||
md={6}
|
||||
sx={{ height: '100%', minHeight: 0, display: 'flex', flexDirection: 'column' }}
|
||||
sx={{ height: { xs: 'auto', md: '100%' }, minHeight: 0, display: 'flex', flexDirection: 'column' }}
|
||||
>
|
||||
<Card
|
||||
className="orders-card"
|
||||
@@ -1293,7 +1297,7 @@ const MultipleOrders = () => {
|
||||
flexDirection: 'column',
|
||||
overflow: 'hidden',
|
||||
p: 1.25,
|
||||
maxHeight: 685
|
||||
maxHeight: { xs: 'none', md: 685 }
|
||||
}}
|
||||
>
|
||||
{/* Preview header (sticky inside card) */}
|
||||
@@ -1483,7 +1487,101 @@ const MultipleOrders = () => {
|
||||
|
||||
{/* Scrollable preview body */}
|
||||
<Box sx={{ flex: 1, minHeight: 0, overflow: 'auto' }}>
|
||||
{previewMode === 'drops' && (
|
||||
{previewMode === 'drops' && isMobile && (
|
||||
<MobileCardList sx={{ p: 0 }}>
|
||||
{dropCust.map((customer, index) => (
|
||||
<MobileCard
|
||||
key={customer.customerid || customer.firstname || index}
|
||||
accent="#65387a"
|
||||
header={
|
||||
<Stack direction="row" alignItems="flex-start" justifyContent="space-between" spacing={1}>
|
||||
<Box sx={{ minWidth: 0, flex: 1 }}>
|
||||
<Typography sx={{ fontSize: 14, fontWeight: 700, color: '#1e293b', lineHeight: 1.2 }}>
|
||||
{index + 1}. {customer.firstname}
|
||||
</Typography>
|
||||
<Typography sx={{ fontSize: 12, color: '#64748b', mt: 0.25 }}>
|
||||
{customer.address}
|
||||
</Typography>
|
||||
</Box>
|
||||
<Tooltip title="Remove">
|
||||
<IconButton
|
||||
size="small"
|
||||
onClick={() => handleCheckboxChange1(customer)}
|
||||
sx={{ color: '#ef4444', p: 0.5, flexShrink: 0 }}
|
||||
>
|
||||
<CloseOutlined style={{ fontSize: 14 }} />
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
</Stack>
|
||||
}
|
||||
>
|
||||
<MobileFieldGrid columns={2}>
|
||||
<MobileField label="Qty">
|
||||
{uploadType === 0 ? (
|
||||
<Typography sx={{ fontSize: 13, fontWeight: 600, color: '#0f172a' }}>
|
||||
{customer.quantity ?? '—'}
|
||||
</Typography>
|
||||
) : (
|
||||
<TextField
|
||||
size="small"
|
||||
type="number"
|
||||
value={customer.quantity || ''}
|
||||
onChange={(e) => handleQuantityChange(customer.customerid, e.target.value)}
|
||||
inputProps={{ min: 0 }}
|
||||
fullWidth
|
||||
sx={{ '& .MuiOutlinedInput-root': { borderRadius: '8px', height: 34 } }}
|
||||
/>
|
||||
)}
|
||||
</MobileField>
|
||||
<MobileField label="Cash">
|
||||
{uploadType === 0 ? (
|
||||
<Typography sx={{ fontSize: 13, fontWeight: 600, color: '#0f172a' }}>
|
||||
{`₹${Number(customer.collectionamt || 0).toFixed(2)}`}
|
||||
</Typography>
|
||||
) : (
|
||||
<TextField
|
||||
size="small"
|
||||
type="number"
|
||||
value={customer.collectionamt ? customer.collectionamt : ''}
|
||||
placeholder="0"
|
||||
onChange={(e) => {
|
||||
const v = Number(e.target.value);
|
||||
handleCollectionAmtChange(customer.customerid, v > 0 ? v : 0);
|
||||
}}
|
||||
inputProps={{ min: 0 }}
|
||||
InputProps={{
|
||||
startAdornment: <InputAdornment position="start">₹</InputAdornment>
|
||||
}}
|
||||
fullWidth
|
||||
sx={{ '& .MuiOutlinedInput-root': { borderRadius: '8px', height: 34 } }}
|
||||
/>
|
||||
)}
|
||||
</MobileField>
|
||||
<MobileField label="Km" value={customer.distance} />
|
||||
<MobileField label="Charge" align="right">
|
||||
<Typography sx={{ fontSize: 13, fontWeight: 700, color: '#1e293b' }}>
|
||||
₹{Number(customer?.totalcharge || 0).toFixed(2)}
|
||||
</Typography>
|
||||
</MobileField>
|
||||
</MobileFieldGrid>
|
||||
</MobileCard>
|
||||
))}
|
||||
<MobileCard accent="#65387a" sx={{ bgcolor: '#fafbfc' }}>
|
||||
<MobileFieldGrid columns={2}>
|
||||
<MobileField label="Total Qty" value={totalQty} />
|
||||
<MobileField label="Total Cash" value={`₹${Number(totalCash).toFixed(2)}`} />
|
||||
<MobileField label="Total Km" value={totaldist} />
|
||||
<MobileField label="Total Charge" align="right">
|
||||
<Typography sx={{ fontSize: 14, fontWeight: 800, color: '#65387a' }}>
|
||||
₹{Number(totalAmt).toFixed(2)}
|
||||
</Typography>
|
||||
</MobileField>
|
||||
</MobileFieldGrid>
|
||||
</MobileCard>
|
||||
</MobileCardList>
|
||||
)}
|
||||
|
||||
{previewMode === 'drops' && !isMobile && (
|
||||
<TableContainer
|
||||
component={Paper}
|
||||
sx={{ borderRadius: '10px', border: '1px solid #eef2f6', boxShadow: 'none' }}
|
||||
@@ -1604,7 +1702,37 @@ const MultipleOrders = () => {
|
||||
</TableContainer>
|
||||
)}
|
||||
|
||||
{previewMode === 'preview' && (
|
||||
{previewMode === 'preview' && isMobile && (
|
||||
<MobileCardList sx={{ p: 0 }}>
|
||||
{users.map((u, i) => (
|
||||
<MobileCard
|
||||
key={i}
|
||||
accent="#d97706"
|
||||
header={
|
||||
<Box sx={{ minWidth: 0 }}>
|
||||
<Typography sx={{ fontSize: 14, fontWeight: 700, color: '#1e293b', lineHeight: 1.2 }}>
|
||||
{i + 1}. {u.firstname || '—'}
|
||||
</Typography>
|
||||
<Typography sx={{ fontSize: 12, color: '#64748b', mt: 0.25 }}>
|
||||
{u.address || '—'}
|
||||
</Typography>
|
||||
</Box>
|
||||
}
|
||||
>
|
||||
<MobileFieldGrid columns={2}>
|
||||
<MobileField label="Contact" value={u.contactno || '—'} />
|
||||
<MobileField label="Qty" value={u.quantity ?? '—'} />
|
||||
<MobileField
|
||||
label="Cash"
|
||||
value={u.collectionamt != null ? `₹${Number(u.collectionamt).toFixed(2)}` : '—'}
|
||||
/>
|
||||
</MobileFieldGrid>
|
||||
</MobileCard>
|
||||
))}
|
||||
</MobileCardList>
|
||||
)}
|
||||
|
||||
{previewMode === 'preview' && !isMobile && (
|
||||
<TableContainer
|
||||
component={Paper}
|
||||
sx={{ borderRadius: '10px', border: '1px solid #eef2f6', boxShadow: 'none' }}
|
||||
@@ -1819,9 +1947,10 @@ const MultipleOrders = () => {
|
||||
open={isCustomerOpen}
|
||||
onClose={() => setIsCustomerOpen(false)}
|
||||
fullWidth
|
||||
fullScreen={isMobile}
|
||||
sx={{
|
||||
'& .MuiDialog-paper': {
|
||||
borderRadius: '16px',
|
||||
borderRadius: { xs: 0, sm: '16px' },
|
||||
overflow: 'hidden'
|
||||
}
|
||||
}}
|
||||
@@ -1863,7 +1992,7 @@ const MultipleOrders = () => {
|
||||
</Stack>
|
||||
</DialogTitle>
|
||||
<Divider />
|
||||
<DialogContent sx={{ p: 2.5, bgcolor: '#fafbfc', minHeight: 400, maxHeight: 600 }}>
|
||||
<DialogContent sx={{ p: 2.5, bgcolor: '#fafbfc', minHeight: 400, maxHeight: { xs: 'none', sm: 600 } }}>
|
||||
{customerlist?.length === 0 ? (
|
||||
<Stack alignItems="center" justifyContent="center" sx={{ minHeight: 300 }}>
|
||||
<Empty description="No saved customers found for this client" />
|
||||
|
||||
@@ -20,10 +20,12 @@ import {
|
||||
Accordion,
|
||||
AccordionSummary,
|
||||
AccordionActions,
|
||||
AccordionDetails
|
||||
AccordionDetails,
|
||||
useMediaQuery
|
||||
} from '@mui/material';
|
||||
import React, { Fragment, useEffect, useMemo, useState } from 'react';
|
||||
import { useTheme } from '@mui/material/styles';
|
||||
import { MobileCard, MobileCardList, MobileField, MobileFieldGrid } from 'components/nearle_components/MobileCard';
|
||||
import { useLocation, useNavigate } from 'react-router-dom';
|
||||
import dayjs from 'dayjs';
|
||||
import MainCard from 'components/MainCard';
|
||||
@@ -60,6 +62,7 @@ dayjs.extend(utc);
|
||||
|
||||
const OptimisedOrderPreview = () => {
|
||||
const theme = useTheme();
|
||||
const isMobile = useMediaQuery(theme.breakpoints.down('md'));
|
||||
const navigate = useNavigate();
|
||||
const location = useLocation();
|
||||
console.log('location.state', location.state);
|
||||
@@ -266,7 +269,13 @@ const OptimisedOrderPreview = () => {
|
||||
<CircularLoader />
|
||||
</>
|
||||
)}
|
||||
<Stack direction="row" alignItems="center" justifyContent="space-between" sx={{}}>
|
||||
<Stack
|
||||
direction={{ xs: 'column', md: 'row' }}
|
||||
alignItems={{ xs: 'stretch', md: 'center' }}
|
||||
justifyContent="space-between"
|
||||
spacing={{ xs: 1.5, md: 0 }}
|
||||
sx={{}}
|
||||
>
|
||||
<Stack direction="row" alignItems="center" spacing={1}>
|
||||
<Tooltip title="Back to orders" placement="top">
|
||||
<IconButton
|
||||
@@ -312,7 +321,7 @@ const OptimisedOrderPreview = () => {
|
||||
</li>
|
||||
);
|
||||
}}
|
||||
style={{ width: 400 }}
|
||||
sx={{ width: { xs: '100%', md: 400 } }}
|
||||
renderInput={(params) => (
|
||||
<TextField
|
||||
{...params}
|
||||
@@ -405,8 +414,117 @@ const OptimisedOrderPreview = () => {
|
||||
</Tooltip>
|
||||
</Stack>
|
||||
</AccordionSummary>
|
||||
<AccordionDetails>
|
||||
<TableContainer sx={{ p: 0, m: 0 }}>
|
||||
<AccordionDetails sx={{ p: { xs: 0, md: 1 } }}>
|
||||
{isMobile ? (
|
||||
<MobileCardList>
|
||||
{orders.map((val, i) => {
|
||||
const typeAccent =
|
||||
val.ordertype === 'Economy' ? '#10b981' : val.ordertype === 'Risky' ? '#ef4444' : '#662582';
|
||||
return (
|
||||
<MobileCard key={i} accent={typeAccent}>
|
||||
<Stack direction="row" alignItems="center" justifyContent="space-between" spacing={1}>
|
||||
<Stack direction="row" alignItems="center" spacing={1} sx={{ minWidth: 0 }}>
|
||||
<Chip size="small" label={`#${i + 1}`} variant="light" color="primary" />
|
||||
<Typography variant="subtitle2" noWrap sx={{ minWidth: 0 }}>
|
||||
{`${val.locationname}-(${val.locationsuburb})`}
|
||||
</Typography>
|
||||
</Stack>
|
||||
<Chip
|
||||
size="small"
|
||||
label={val.ordertype}
|
||||
icon={
|
||||
val.ordertype === 'Economy' ? (
|
||||
<EnergySavingsLeafIcon />
|
||||
) : val.ordertype === 'Risky' ? (
|
||||
<WarningIcon />
|
||||
) : (
|
||||
<BoltIcon />
|
||||
)
|
||||
}
|
||||
color={val.ordertype === 'Economy' ? 'success' : val.ordertype === 'Risky' ? 'error' : 'primary'}
|
||||
variant="light"
|
||||
/>
|
||||
</Stack>
|
||||
<MobileFieldGrid>
|
||||
<MobileField label="Order Id" value={val.orderid} />
|
||||
<MobileField label="Rider">
|
||||
<Typography sx={{ fontSize: 13, fontWeight: 600 }} noWrap>
|
||||
{val.rider}
|
||||
</Typography>
|
||||
<Typography variant="caption">ID : {val.userid}</Typography>
|
||||
</MobileField>
|
||||
<MobileField label="Pickup">
|
||||
<Stack spacing={0.25} sx={{ minWidth: 0 }}>
|
||||
<Typography variant="caption" noWrap>
|
||||
{val.pickupcustomer}
|
||||
</Typography>
|
||||
<Typography variant="caption" noWrap>
|
||||
{val.pickupcontactno}
|
||||
</Typography>
|
||||
<Tooltip title={val.pickupaddress}>
|
||||
<Typography variant="caption" noWrap sx={{ cursor: 'pointer' }}>
|
||||
{val.pickupsuburb || val.pickupaddress.slice(0, 20)}
|
||||
</Typography>
|
||||
</Tooltip>
|
||||
<Chip
|
||||
size="small"
|
||||
label={dayjs(val.pickupslot).format('DD/MM/YYYY hh:mm A')}
|
||||
variant="light"
|
||||
sx={{ color: '#0a803b', bgcolor: '#c3f3c7', alignSelf: 'flex-start' }}
|
||||
/>
|
||||
</Stack>
|
||||
</MobileField>
|
||||
<MobileField label="Delivery">
|
||||
<Stack spacing={0.25} sx={{ minWidth: 0 }}>
|
||||
<Typography variant="caption" noWrap>
|
||||
{val.deliverycustomer}
|
||||
</Typography>
|
||||
<Typography variant="caption" noWrap>
|
||||
{val.deliverycontactno}
|
||||
</Typography>
|
||||
<Tooltip title={val.deliveryaddress}>
|
||||
<Typography variant="caption" noWrap sx={{ cursor: 'pointer' }}>
|
||||
{val.deliverysuburb || val.deliveryaddress.slice(0, 20)}
|
||||
</Typography>
|
||||
</Tooltip>
|
||||
<Chip
|
||||
size="small"
|
||||
label={dayjs(val.expecteddeliverytime).format('DD/MM/YYYY hh:mm A')}
|
||||
variant="light"
|
||||
sx={{ color: '#DD2C00', background: '#FBE9E7', alignSelf: 'flex-start' }}
|
||||
/>
|
||||
</Stack>
|
||||
</MobileField>
|
||||
{val.ordernotes ? <MobileField full label="Notes" value={val.ordernotes} /> : null}
|
||||
<MobileField label="Profit">
|
||||
<Chip
|
||||
size="small"
|
||||
label={`₹ ${parseFloat(val?.profit).toFixed(2)}`}
|
||||
variant="light"
|
||||
sx={{ color: '#009688', bgcolor: '#b2dfdb' }}
|
||||
/>
|
||||
</MobileField>
|
||||
<MobileField label="Charges">
|
||||
<Chip
|
||||
size="small"
|
||||
label={`₹ ${val.deliverycharge.toFixed(2)} `}
|
||||
variant="light"
|
||||
sx={{ color: '#0074e7', bgcolor: '#cce3fa' }}
|
||||
/>
|
||||
</MobileField>
|
||||
<MobileField label="KMS">
|
||||
<Chip size="small" label={`${val.kms} km`} color="error" variant="light" />
|
||||
</MobileField>
|
||||
<MobileField label="Cumulative KMS">
|
||||
<Chip size="small" label={`${val.cumulativekms} km`} color="success" variant="light" />
|
||||
</MobileField>
|
||||
</MobileFieldGrid>
|
||||
</MobileCard>
|
||||
);
|
||||
})}
|
||||
</MobileCardList>
|
||||
) : (
|
||||
<TableContainer sx={{ p: 0, m: 0 }}>
|
||||
<Table stickyHeader>
|
||||
<TableHead>
|
||||
<TableRow>
|
||||
@@ -579,16 +697,24 @@ const OptimisedOrderPreview = () => {
|
||||
))}
|
||||
</TableBody>
|
||||
</Table>
|
||||
</TableContainer>
|
||||
</TableContainer>
|
||||
)}
|
||||
</AccordionDetails>
|
||||
</Accordion>
|
||||
);
|
||||
})}
|
||||
|
||||
<Divider />
|
||||
<Stack display={'flex'} flexDirection={'row'} gap={2} alignItems={'center'} justifyContent={'end'} sx={{ p: 2 }}>
|
||||
<Stack
|
||||
display={'flex'}
|
||||
flexDirection={{ xs: 'column', sm: 'row' }}
|
||||
gap={2}
|
||||
alignItems={{ xs: 'stretch', sm: 'center' }}
|
||||
justifyContent={'end'}
|
||||
sx={{ p: 2 }}
|
||||
>
|
||||
<Button
|
||||
sx={{}}
|
||||
sx={{ width: { xs: '100%', sm: 'auto' } }}
|
||||
variant="contained"
|
||||
color="secondary"
|
||||
startIcon={<ArrowBackIcon />}
|
||||
@@ -598,7 +724,12 @@ const OptimisedOrderPreview = () => {
|
||||
>
|
||||
Back
|
||||
</Button>
|
||||
<Button sx={{ my: 2 }} variant="contained" disabled={aiMode === 0 && (!rider || !payment)} onClick={handleFinalCreateDelivery}>
|
||||
<Button
|
||||
sx={{ my: { xs: 0, sm: 2 }, width: { xs: '100%', sm: 'auto' } }}
|
||||
variant="contained"
|
||||
disabled={aiMode === 0 && (!rider || !payment)}
|
||||
onClick={handleFinalCreateDelivery}
|
||||
>
|
||||
Assign Orders
|
||||
</Button>
|
||||
</Stack>
|
||||
|
||||
@@ -110,6 +110,7 @@ import {
|
||||
getallriders
|
||||
} from '../../api/api';
|
||||
import LoaderWithImage from 'components/nearle_components/LoaderWithImage';
|
||||
import { MobileCard, MobileCardList, MobileField, MobileFieldGrid } from 'components/nearle_components/MobileCard';
|
||||
import { useNavigate } from 'react-router';
|
||||
import CSVExport from 'components/third-party/ReactTable';
|
||||
import Dispatch from '../dispatch/Dispatch';
|
||||
@@ -204,6 +205,7 @@ const ORDERS_STATUS_TABS = [
|
||||
|
||||
const Orders = () => {
|
||||
const theme = useTheme();
|
||||
const isMobile = useMediaQuery(theme.breakpoints.down('md'));
|
||||
const navigate = useNavigate();
|
||||
const loadMoreRef = useRef();
|
||||
const containerRef = useRef();
|
||||
@@ -1419,6 +1421,233 @@ const Orders = () => {
|
||||
'&::-webkit-scrollbar-track': { backgroundColor: DT.surfaceAlt }
|
||||
}}
|
||||
>
|
||||
{isMobile ? (
|
||||
/* ===================== MOBILE: card list ===================== */
|
||||
<MobileCardList sx={{ p: 1.25 }}>
|
||||
{rows?.length === 0 && !fetchOrdersIsLoading && (
|
||||
<Stack alignItems="center" spacing={1.5} sx={{ py: 6 }}>
|
||||
<Avatar sx={{ width: 64, height: 64, bgcolor: dtSoft('#94a3b8'), color: DT.textMuted }}>
|
||||
<MdLocalShipping size={28} />
|
||||
</Avatar>
|
||||
<Typography variant="subtitle1" sx={{ fontWeight: 700, color: DT.textPrimary }}>
|
||||
No {currentStatus} orders
|
||||
</Typography>
|
||||
<Typography variant="caption" sx={{ color: DT.textSecondary, textAlign: 'center', px: 2 }}>
|
||||
{searchword ? 'Try a different keyword.' : 'Adjust the filters above to load orders.'}
|
||||
</Typography>
|
||||
</Stack>
|
||||
)}
|
||||
{fetchOrdersIsLoading && (
|
||||
<Stack alignItems="center" sx={{ py: 6 }}>
|
||||
<LoaderWithImage />
|
||||
<Typography variant="caption" color="text.secondary" sx={{ mt: 1 }}>
|
||||
Loading orders…
|
||||
</Typography>
|
||||
</Stack>
|
||||
)}
|
||||
{rows?.map((row, index) => {
|
||||
const isItemSelected = !!deliverylist.find((res) => res.orderheaderid === row.orderheaderid);
|
||||
const handleCheckbox = (e) => {
|
||||
if (!appId) {
|
||||
OpenToast('Please select a location first!', 'warning', 2000);
|
||||
locationRef.current?.focus();
|
||||
return;
|
||||
}
|
||||
if (e.target.checked) {
|
||||
setDeliverylist((prev) => [...prev, { ...row, sno: prev.length + 1 }]);
|
||||
} else {
|
||||
setDeliverylist((prev) =>
|
||||
prev.filter((item) => item.orderheaderid !== row.orderheaderid).map((item, i) => ({ ...item, sno: i + 1 }))
|
||||
);
|
||||
}
|
||||
};
|
||||
const meta = ROW_STATUS_META[String(row.orderstatus || '').toLowerCase()] || {
|
||||
label: row.orderstatus || '—',
|
||||
color: BRAND,
|
||||
icon: MdHistoryToggleOff
|
||||
};
|
||||
const StatusIcon = meta.icon;
|
||||
const chipSx = (c) => ({
|
||||
display: 'inline-flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
px: 1,
|
||||
py: 0.25,
|
||||
borderRadius: 999,
|
||||
bgcolor: dtTint(c),
|
||||
color: c,
|
||||
fontWeight: 700,
|
||||
fontSize: 11,
|
||||
border: `1px solid ${dtEdge(c)}`,
|
||||
whiteSpace: 'nowrap'
|
||||
});
|
||||
return (
|
||||
<MobileCard
|
||||
key={row.sno}
|
||||
accent={meta.color}
|
||||
selected={isItemSelected}
|
||||
header={
|
||||
<Stack spacing={1.25}>
|
||||
<Stack direction="row" alignItems="center" justifyContent="space-between" spacing={1}>
|
||||
<Stack direction="row" alignItems="center" spacing={0.75} sx={{ minWidth: 0 }}>
|
||||
{currentStatus === 'created' && (
|
||||
<Checkbox
|
||||
size="small"
|
||||
sx={{ p: 0.25, color: dtEdge(BRAND), '&.Mui-checked': { color: BRAND } }}
|
||||
onChange={handleCheckbox}
|
||||
checked={isItemSelected}
|
||||
/>
|
||||
)}
|
||||
<Typography variant="caption" sx={{ fontWeight: 700, color: DT.textMuted }}>
|
||||
{String(page * rowsPerPage + index + 1).padStart(2, '0')}
|
||||
</Typography>
|
||||
<Box
|
||||
sx={{
|
||||
display: 'inline-flex',
|
||||
alignItems: 'center',
|
||||
gap: 0.5,
|
||||
px: 1,
|
||||
py: 0.375,
|
||||
borderRadius: 999,
|
||||
bgcolor: dtTint(meta.color),
|
||||
border: `1px solid ${dtEdge(meta.color)}`,
|
||||
color: meta.color,
|
||||
fontSize: 10.5,
|
||||
fontWeight: 800,
|
||||
whiteSpace: 'nowrap'
|
||||
}}
|
||||
>
|
||||
<StatusIcon size={11} /> {meta.label}
|
||||
</Box>
|
||||
</Stack>
|
||||
{row.orderstatus === 'created' && (
|
||||
<Stack direction="row" spacing={0.75} sx={{ flexShrink: 0 }}>
|
||||
{row.deliverytype === 'C' && (
|
||||
<IconButton
|
||||
size="small"
|
||||
onClick={() => {
|
||||
if (productCollapse?.orderid === row.orderid) {
|
||||
setProductCollapse(null);
|
||||
} else {
|
||||
setProductCollapse(row);
|
||||
}
|
||||
}}
|
||||
sx={{
|
||||
borderRadius: 999,
|
||||
bgcolor: dtTint('#06b6d4'),
|
||||
color: '#06b6d4',
|
||||
border: `1px solid ${dtEdge('#06b6d4')}`,
|
||||
'&:hover': { bgcolor: dtSoft('#06b6d4') }
|
||||
}}
|
||||
>
|
||||
{productCollapse?.orderid === row.orderid ? (
|
||||
<KeyboardArrowUpOutlined fontSize="small" />
|
||||
) : (
|
||||
<KeyboardArrowDownOutlined fontSize="small" />
|
||||
)}
|
||||
</IconButton>
|
||||
)}
|
||||
<IconButton
|
||||
size="small"
|
||||
disabled={isItemSelected}
|
||||
onClick={() => {
|
||||
setCancelDialog(true);
|
||||
setOrderheaderid(row.orderheaderid);
|
||||
}}
|
||||
sx={{
|
||||
borderRadius: 999,
|
||||
bgcolor: dtTint('#ef4444'),
|
||||
color: '#ef4444',
|
||||
border: `1px solid ${dtEdge('#ef4444')}`,
|
||||
'&:hover': { bgcolor: dtSoft('#ef4444') },
|
||||
'&.Mui-disabled': { color: theme.palette.secondary.main }
|
||||
}}
|
||||
>
|
||||
<CloseOutlined />
|
||||
</IconButton>
|
||||
</Stack>
|
||||
)}
|
||||
</Stack>
|
||||
<Box sx={{ minWidth: 0 }}>
|
||||
<Typography sx={{ fontWeight: 800, color: DT.textPrimary, fontSize: 15 }} noWrap>
|
||||
{row.tenantname}
|
||||
</Typography>
|
||||
<Typography variant="caption" sx={{ color: DT.textSecondary }} noWrap>
|
||||
{[row.tenantsuburb, row.applocation].filter(Boolean).join(' · ') || '—'}
|
||||
</Typography>
|
||||
</Box>
|
||||
</Stack>
|
||||
}
|
||||
>
|
||||
<MobileFieldGrid>
|
||||
<MobileField label="Order / Location" full>
|
||||
<Typography sx={{ fontSize: 13, fontWeight: 600, color: DT.textPrimary }} noWrap>
|
||||
{`${row.locationname}-(${row.locationsuburb})`}
|
||||
</Typography>
|
||||
<Typography variant="caption" sx={{ color: DT.textSecondary }}>
|
||||
{row.orderid} · {dayjs(row.pickupslot).utc().format('DD/MM/YYYY')} {dayjs(row.pickupslot).format('hh:mm A')}
|
||||
</Typography>
|
||||
</MobileField>
|
||||
<MobileField label="Pickup">
|
||||
<Typography sx={{ fontSize: 13, fontWeight: 600, color: DT.textPrimary }} noWrap>
|
||||
{row.pickupcustomer || '—'}
|
||||
</Typography>
|
||||
<Typography variant="caption" sx={{ color: DT.textSecondary }} noWrap>
|
||||
{row.pickupcontactno}
|
||||
</Typography>
|
||||
<Typography variant="caption" sx={{ color: DT.textSecondary }} noWrap>
|
||||
{row.pickupsuburb || row.pickupaddress}
|
||||
</Typography>
|
||||
</MobileField>
|
||||
<MobileField label="Drop">
|
||||
<Typography sx={{ fontSize: 13, fontWeight: 600, color: DT.textPrimary }} noWrap>
|
||||
{row.deliverycustomer || '—'}
|
||||
</Typography>
|
||||
<Typography variant="caption" sx={{ color: DT.textSecondary }} noWrap>
|
||||
{row.deliverycontactno}
|
||||
</Typography>
|
||||
<Typography variant="caption" sx={{ color: DT.textSecondary }} noWrap>
|
||||
{row.deliverysuburb || row.deliveryaddress}
|
||||
</Typography>
|
||||
</MobileField>
|
||||
<MobileField label="Qty" value={row.quantity || '—'} />
|
||||
<MobileField label="KMS">
|
||||
<Box sx={chipSx('#06b6d4')}>{row.kms || 0} km</Box>
|
||||
</MobileField>
|
||||
<MobileField label="COD">
|
||||
<Typography sx={{ fontSize: 13, fontWeight: 800, color: row.collectionamt ? '#ef4444' : DT.textMuted }}>
|
||||
{row.collectionamt ? `₹ ${row.collectionamt.toFixed(2)}` : '—'}
|
||||
</Typography>
|
||||
</MobileField>
|
||||
<MobileField label="Charges">
|
||||
<Typography sx={{ fontSize: 13, fontWeight: 800, color: row.deliverycharge ? '#ef4444' : DT.textMuted }}>
|
||||
{row.deliverycharge ? `₹ ${row.deliverycharge.toFixed(2)}` : '—'}
|
||||
</Typography>
|
||||
</MobileField>
|
||||
{row.ordernotes && (
|
||||
<MobileField label="Notes" full>
|
||||
<Typography variant="caption" sx={{ color: DT.textSecondary }}>
|
||||
{row.ordernotes}
|
||||
</Typography>
|
||||
</MobileField>
|
||||
)}
|
||||
</MobileFieldGrid>
|
||||
</MobileCard>
|
||||
);
|
||||
})}
|
||||
{rows?.length != 0 && (
|
||||
<div ref={loadMoreRef} style={{ height: 40, textAlign: 'center' }}>
|
||||
{isFetchingNextPage || hasNextPage ? (
|
||||
<LoaderWithImage />
|
||||
) : (
|
||||
<Typography variant="caption" sx={{ color: DT.textMuted, fontWeight: 600 }}>
|
||||
No more orders
|
||||
</Typography>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</MobileCardList>
|
||||
) : (
|
||||
<Table stickyHeader sx={{ minWidth: { xs: 960, md: 1180 } }}>
|
||||
<TableHead>
|
||||
<TableRow
|
||||
@@ -1770,6 +1999,7 @@ const Orders = () => {
|
||||
)}
|
||||
</TableBody>
|
||||
</Table>
|
||||
)}
|
||||
</TableContainer>
|
||||
</Paper>
|
||||
{/* ============================================= || Orders Preview Dialog | ============================================= */}
|
||||
|
||||
Reference in New Issue
Block a user