updates on the ui changes and frully removed the mui and converted into astryx and color change

This commit is contained in:
2026-08-13 18:24:04 +05:30
parent 498bb7cbc0
commit 8cd8e34b11
122 changed files with 15111 additions and 22411 deletions

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,750 +0,0 @@
/* eslint-disable no-unused-vars */
import {
Autocomplete,
Button,
Chip,
Divider,
Grid,
Stack,
Table,
TableBody,
TableCell,
TableContainer,
TableHead,
TableRow,
TextField,
Tooltip,
Typography,
Backdrop,
IconButton,
Badge,
Accordion,
AccordionSummary,
AccordionActions,
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';
import ArrowBackIcon from '@mui/icons-material/ArrowBack';
import { createAutomationDeliveries, fetchPaymentType, fetchRidersList, finalCreatedeliveries, notifyRider } from 'pages/api/api';
import { OpenToast } from 'components/third-party/OpenToast';
import { useMutation, useQuery } from '@tanstack/react-query';
import Loader from 'components/Loader';
import CircularLoader from 'components/CircularLoader';
import { Empty } from 'antd';
import HoverSocialCard from 'components/cards/statistics/HoverSocialCard';
import { DashboardFilled, DashboardOutlined, OpenAIFilled } from '@ant-design/icons';
import { MdDirectionsBike } from 'react-icons/md';
import { FaMapLocationDot } from 'react-icons/fa6';
import { HiOutlineArrowLeft } from 'react-icons/hi';
import { IoReload } from 'react-icons/io5';
import CheckBoxOutlineBlankIcon from '@mui/icons-material/CheckBoxOutlineBlank';
import CheckBoxIcon from '@mui/icons-material/CheckBox';
import { GiProfit } from 'react-icons/gi';
import { ArrowRightAltOutlined } from '@mui/icons-material';
import LocalShippingIcon from '@mui/icons-material/LocalShipping';
import WarningIcon from '@mui/icons-material/Warning';
import BoltIcon from '@mui/icons-material/Bolt';
import CurrencyRupeeIcon from '@mui/icons-material/CurrencyRupee';
import SavingsIcon from '@mui/icons-material/Savings';
import EnergySavingsLeafIcon from '@mui/icons-material/EnergySavingsLeaf';
import DirectionsBikeOutlinedIcon from '@mui/icons-material/DirectionsBikeOutlined';
import DownloadOutlinedIcon from '@mui/icons-material/DownloadOutlined';
import { exportToExcel } from 'components/exportToExcel';
import CSVExport from 'components/third-party/ReactTable';
var utc = require('dayjs/plugin/utc');
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);
const [rider, setRider] = useState(null);
const [payment, setPayment] = useState(null);
const [finaldeliveryList, setFinalDeliveryList] = useState([]);
const [isLoading, setIsLoading] = useState(false);
const [deliverylist, setDeliverylist] = useState(location.state?.deliverylist);
const [zoneData, setZoneData] = useState(location?.state?.zoneData);
const [metaData, setMetaData] = useState(location.state?.metaData);
const riderToken = location.state?.riderToken;
const appId = location.state?.appId;
const aiMode = location.state?.aiMode;
const reassignOrders = location.state?.reassignOrders;
const [csvExportData, setCsvExportData] = useState([]);
useEffect(() => {
console.log('called');
console.log('aiMode', aiMode);
console.log('riderToken', riderToken);
console.log('zoneData', zoneData);
console.log('metaData', metaData);
console.log('reassignOrders', reassignOrders);
}, [zoneData, metaData, deliverylist]);
useEffect(() => {
const filtered = finaldeliveryList.map((item) => ({
zone_name: item.zone_name,
ordernotes: item.ordernotes,
rider: item.rider,
step: item.step,
ordertype: item.ordertype,
orderamount: item.orderamount,
riderkms: item.riderkms,
cumulativekms: item.cumulativekms,
baseprice: item.baseprice,
minkm: item.minkm,
priceperkm: item.priceperkm,
kms: item.kms,
actualkms: item.actualkms,
rider_charge: item.rider_charge,
deliveryamt: item.deliveryamt,
deliverycharges: item.deliverycharges,
profit: item.profit
}));
setCsvExportData(filtered);
console.log('csvExportData', filtered);
}, [finaldeliveryList]);
useEffect(() => {
if (!deliverylist?.length) return;
const updateDeliveryAmtList = deliverylist.map((list) => {
const cumulativeKms = Number(list.cumulativekms || 0);
const minKm = Number(list.minkm || 0);
const basePrice = Number(list.baseprice || 0);
const pricePerKm = Number(list.priceperkm || 0);
if (cumulativeKms <= minKm) {
return {
...list,
deliveryamt: basePrice
};
}
return {
...list,
deliveryamt: (cumulativeKms - minKm) * pricePerKm + basePrice
};
});
setFinalDeliveryList(updateDeliveryAmtList);
}, [deliverylist]);
// ==============================|| fetchPaymentType ||============================== //
const {
data: paymentModes = [],
isLoading: paymentModesLoading,
isError: paymentModesError,
error: paymentModesErrorMessage
} = useQuery({
queryKey: ['paymentmodes'],
queryFn: fetchPaymentType
});
// ==============================|| fetchRidersList ||============================== //
const {
data: ridersList = [],
isLoading: ridersListLoading,
isError: ridersListError,
error: ridersListErrorMessage,
refetch: ridersListRefetch
} = useQuery({
queryKey: ['ridersList', appId], // Unique key for caching & re-fetching
queryFn: fetchRidersList,
enabled: appId !== 0 // Ensures query runs only when appId is valid
});
const getRiderName = async (userid) => {
await ridersList.map((rider) => {
if (rider.userid == userid) {
return rider.firstname;
}
});
};
// ======================================================= || notifyRiderMutation || =======================================================
const notifyRiderMutation = useMutation({
mutationFn: notifyRider, // Using the separate function
onSuccess: () => {
OpenToast('Notification sent Successfully', 'success', 2000);
},
onError: (error) => {
OpenToast(error.message, 'error', 2000);
}
});
const createFinalDeliveryMutation = useMutation({
mutationFn: finalCreatedeliveries, // for optimised delivery create
onSuccess: (data) => {
// rider state here is never set (no setRider call anywhere in this
// file), so rider.userfcmtoken threw on every success — also the
// wrong argument type regardless (notifyRider needs a milerprofileid,
// not an FCM token; see dispatch/Preview.js's identical fix). Notify
// every rider actually present in the committed deliveries instead.
const notifiedRiderIds = new Set();
(finaldeliveryList || []).forEach((order) => {
const riderId = order.userid;
if (riderId == null || notifiedRiderIds.has(String(riderId))) return;
notifiedRiderIds.add(String(riderId));
notifyRiderMutation.mutate(riderId);
});
if (data.status == 'accepted') {
OpenToast('Delivery Created Successfully', 'success', 2000);
}
},
onError: (error) => {
OpenToast(error.message, 'error', 4000);
},
onSettled: () => {
setTimeout(() => {
setIsLoading(false);
navigate('/doormile/deliveries');
}, 2000);
}
});
const handleFinalCreateDelivery = async () => {
// console.log('Final delivery list:', finaldeliveryList);
setIsLoading(true);
createFinalDeliveryMutation.mutate({
deliveries: finaldeliveryList
});
};
const createDeliveryMutation = useMutation({
// 0 -> manual rider assign 1 -> ai rider assign
mutationFn: createAutomationDeliveries,
onSuccess: (data, variables) => {
console.log('data', data);
console.log('varialbles', variables);
OpenToast('Orders Optimised Successfully', 'success', 2000);
// notifyRiderMutation.mutate(variables?.riderToken); // Call notifyRider after success
setZoneData(data?.zones);
setDeliverylist(data?.details);
setMetaData(data?.meta);
setIsLoading(false);
},
onError: (error) => {
OpenToast(error.message, 'error', 4000);
setIsLoading(false);
},
onSettled: () => {
setIsLoading(false);
}
});
const tuningTypes = [
{
tuneid: 1,
type: 'Rider'
},
{
tuneid: 2,
type: 'Pickup'
},
{
tuneid: 3,
type: 'Zone'
}
];
return (
<Fragment>
{
<Backdrop
sx={{
color: '#fff',
zIndex: (theme) => theme.zIndex.drawer + 1
}}
open={paymentModesLoading || ridersListLoading || isLoading} // when loader = true, backdrop covers the page
>
<CircularLoader color="inherit" />
</Backdrop>
}
{(paymentModesLoading || ridersListLoading || isLoading) && (
<>
<Loader />
<CircularLoader />
</>
)}
<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
onClick={() => navigate('/doormile/orders')}
sx={{
bgcolor: 'action.hover',
'&:hover': { bgcolor: 'action.selected' }
}}
>
<HiOutlineArrowLeft size={20} />
</IconButton>
</Tooltip>
<Typography variant="h3" fontWeight={600}>
Assign Orders
</Typography>
</Stack>
{/* <Button
variant="contained"
color="primary"
startIcon={<IoReload />}
onClick={() => {
setIsLoading(true);
createDeliveryMutation.mutate({ deliveries: reassignOrders });
}}
>
Tuning
</Button> */}
<Autocomplete
multiple
id="checkboxes-tags-demo"
options={tuningTypes}
disableCloseOnSelect
getOptionLabel={(option) => option.type}
renderOption={(props, option, { selected }) => {
const { id, ...optionProps } = props;
const SelectionIcon = selected ? CheckBoxIcon : CheckBoxOutlineBlankIcon;
return (
<li key={id} {...optionProps}>
<SelectionIcon fontSize="small" style={{ marginRight: 8, padding: 9, boxSizing: 'content-box' }} />
{option.type}
</li>
);
}}
sx={{ width: { xs: '100%', md: 400 } }}
renderInput={(params) => (
<TextField
{...params}
sx={{
'& .MuiInputBase-input': {
lineHeight: '1.5' // 👈 important
}
}}
label="Hyper Tuning"
// placeholder="Favorites"
/>
)}
/>
{/* <Button
variant="outlined"
size="small"
startIcon={<DownloadOutlinedIcon />}
onClick={() => {
exportToExcel(finaldeliveryList, 'users', 'UsersData');
}}
>
Export Report
</Button> */}
<CSVExport
data={csvExportData}
filename={`Orders_Detail_${dayjs().format('YYYY-MM-DD_HHmmss')}.csv`}
label=" CSV"
style={{ m: 1 }}
/>
</Stack>
<Stack sx={{ my: 2 }}>
<Grid container spacing={2}>
<Grid item xs={6} sm={6} md={3}>
<HoverSocialCard
secondary={metaData?.total_orders}
primary={'Orders'}
percentage={<DashboardFilled />}
color={theme.palette.success.main}
sx={{ cursor: 'pointer' }}
/>
</Grid>
<Grid item xs={6} sm={6} md={3}>
<HoverSocialCard
secondary={metaData?.utilized_riders}
primary={'Riders'}
percentage={<MdDirectionsBike />}
color={theme.palette.warning.main}
/>
</Grid>
<Grid item xs={6} sm={6} md={3}>
<HoverSocialCard
secondary={zoneData?.length}
primary={'Zones'}
percentage={<FaMapLocationDot />}
color={theme.palette.info.main}
/>
</Grid>
<Grid item xs={6} sm={6} md={3}>
<HoverSocialCard
secondary={metaData?.total_profit}
primary={'Profit'}
percentage={<GiProfit />}
color={theme.palette.error.main}
/>
</Grid>
</Grid>
</Stack>
<MainCard content={false}>
{zoneData?.map((zone, index) => {
const riders = zone?.riders.flatMap((rider) => rider);
const orders = zone?.riders?.flatMap((rider) => rider.orders);
return (
<Accordion key={index}>
<AccordionSummary>
<Stack direction="row" alignItems="center" spacing={2} sx={{ m: 2 }}>
<Typography variant="h5" fontWeight={1000}>
Zone {index + 1} :
</Typography>
<Chip label={zone.zone_name} color="primary" variant="light" size="small" sx={{ minWidth: 100 }} />
<Tooltip title={`Orders`} placement="top">
<Badge badgeContent={zone.total_orders} color="secondary">
<DashboardOutlined style={{ fontSize: 20 }} />
</Badge>
</Tooltip>
<Tooltip title={`Riders`} placement="top">
<Badge color="secondary" badgeContent={zone.active_riders_count}>
<DirectionsBikeOutlinedIcon style={{ fontSize: 20 }} />
</Badge>
</Tooltip>
</Stack>
</AccordionSummary>
<AccordionDetails sx={{ p: { xs: 0, md: 1 } }}>
{isMobile ? (
<MobileCardList>
{orders.map((val, i) => {
const typeAccent =
val.ordertype === 'Economy' ? '#10b981' : val.ordertype === 'Risky' ? '#ef4444' : '#C01227';
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>
<TableCell>#</TableCell>
{/* <TableCell>Tenant</TableCell> */}
<TableCell>Order Location</TableCell>
<TableCell>Pickup</TableCell>
<TableCell>Delivery</TableCell>
<TableCell>Notes</TableCell>
<TableCell>Rider</TableCell>
<TableCell align="center">Type</TableCell>
<TableCell align="center">Profit</TableCell>
<TableCell align="center">Charges</TableCell>
<TableCell align="center">KMS</TableCell>
</TableRow>
</TableHead>
<TableBody>
{orders.map((val, i) => (
<Fragment key={i}>
<TableRow sx={{}}>
<TableCell>
<Typography> {i + 1}</Typography>
</TableCell>
{/* <TableCell>
<Tooltip title={val.tenantaddress}>
<Typography variant="body1" noWrap>
{val.tenantname}
</Typography>
<Typography noWrap sx={{ fontSize: '11px' }}>
{val.tenantsuburb}
<br />
</Typography>
<Typography noWrap variant="body2">
{val.applocation}
</Typography>
</Tooltip>
</TableCell> */}
<TableCell align="left">
<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} sx={{ cursor: 'pointer' }}>
<Tooltip title="Pickup Time">
<Typography noWrap sx={{ fontSize: '12px' }}>
{dayjs(val.pickupslot).format('DD/MM/YYYY')}
</Typography>
<Chip
size="small"
label={dayjs(val.pickupslot).format('hh:mm A')}
variant="light"
sx={{ color: '#0a803b', bgcolor: '#c3f3c7' }}
/>
</Tooltip>
<ArrowRightAltOutlined />
<Tooltip title="Estimated Delivery time">
<Typography noWrap sx={{ fontSize: '12px' }}>
{dayjs(val.expecteddeliverytime).format('DD/MM/YYYY')}
</Typography>
<Chip
size="small"
label={dayjs(val.expecteddeliverytime).format('hh:mm A')}
variant="light"
sx={{ color: '#DD2C00', background: '#FBE9E7' }}
/>
</Tooltip>
</Stack>
</TableCell>
<TableCell align="left">
<Stack direction={'row'} spacing={1}>
<Stack direction="column">
<Typography variant="caption">{val.pickupcustomer}</Typography>
<Typography variant="caption">{val.pickupcontactno}</Typography>
<Tooltip title={val.pickupaddress}>
<Typography sx={{ cursor: 'pointer' }} variant="caption">
{val.pickupsuburb || val.pickupaddress.slice(0, 20)}
</Typography>
</Tooltip>
</Stack>
</Stack>
</TableCell>
<TableCell align="left">
<Stack direction={'row'} spacing={1}>
<Stack direction="column">
<Typography variant="caption">{val.deliverycustomer}</Typography>
<Typography variant="caption">{val.deliverycontactno}</Typography>
<Tooltip title={val.deliveryaddress}>
<Typography sx={{ cursor: 'pointer' }} variant="caption">
{val.deliverysuburb || val.deliveryaddress.slice(0, 20)}
</Typography>
</Tooltip>
</Stack>
</Stack>
</TableCell>
<TableCell align="left">
<Typography variant="caption" sx={{ whiteSpace: 'nowrap' }}>
{val.ordernotes}
</Typography>
</TableCell>
<TableCell align="left">
<Typography variant="caption" sx={{ whiteSpace: 'nowrap' }}>
{val.rider}
</Typography>
<br />
<Typography variant="caption">ID : {val.userid}</Typography>
</TableCell>
<TableCell align="center">
<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"
/>
</TableCell>
<TableCell align="center">
<Chip
size="small"
label={`₹ ${parseFloat(val?.profit).toFixed(2)}`}
variant="light"
sx={{ color: '#009688', bgcolor: '#b2dfdb' }}
/>
</TableCell>
<TableCell align="center">
<Stack display={'flex'} flexDirection={'column'} gap={1} sx={{ cursor: 'pointer' }}>
<Tooltip title="Charges" placement="top">
<Chip
size="small"
label={`₹ ${val.deliverycharge.toFixed(2)} `}
variant="light"
sx={{ color: '#0074e7', bgcolor: '#cce3fa' }}
/>
</Tooltip>
{/* <Tooltip title="Amount" placement="left">
<Chip size="small" label={`₹ ${val.deliveryamt.toFixed(2)} `} color="success" variant="light" />
</Tooltip> */}
</Stack>
</TableCell>
<TableCell align="center">
<Stack display={'flex'} flexDirection={'column'} gap={1} sx={{ cursor: 'pointer' }}>
<Tooltip title="KMS" placement="top">
<Chip size="small" label={`${val.kms} km`} color="error" variant="light" />
</Tooltip>
<Tooltip title="Cumulative Kms" placement="right">
<Chip size="small" label={`${val.cumulativekms} km`} color="success" variant="light" />
</Tooltip>
</Stack>
</TableCell>
</TableRow>
</Fragment>
))}
</TableBody>
</Table>
</TableContainer>
)}
</AccordionDetails>
</Accordion>
);
})}
<Divider />
<Stack
display={'flex'}
flexDirection={{ xs: 'column', sm: 'row' }}
gap={2}
alignItems={{ xs: 'stretch', sm: 'center' }}
justifyContent={'end'}
sx={{ p: 2 }}
>
<Button
sx={{ width: { xs: '100%', sm: 'auto' } }}
variant="contained"
color="secondary"
startIcon={<ArrowBackIcon />}
onClick={() => {
navigate('/doormile/orders');
}}
>
Back
</Button>
<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>
</MainCard>
</Fragment>
);
};
export default OptimisedOrderPreview;

View File

@@ -67,37 +67,16 @@ import { useNavigate, useLocation } from 'react-router-dom';
import { fetchPercentageData, createAutomationDeliveries, getallriders, buildMilerLookup, notifyRider } from '../../api/api';
import { getBookings, cancelBooking, getAdminCustomers, getBookingTrack, batchAssignBookings, getMilers } from 'pages/api/doormileApi';
import { parseDoormileTimestamp } from 'utils/doormileTimestamp';
import { DT, a, tint, soft, ring, edge } from 'themes/dt/tokens';
// ============================================================================
// Design tokens — shared with the rest of the redesigned operator pages.
// ============================================================================
const DT = {
radiusPill: 999,
radiusCard: 16,
shadowSoft: '0 14px 40px rgba(15, 23, 42, 0.10)',
shadowMd: '0 8px 24px rgba(15, 23, 42, 0.08)',
shadowPop: '0 18px 50px rgba(15, 23, 42, 0.18)',
textPrimary: '#0f172a',
textSecondary: '#64748b',
textMuted: '#94a3b8',
borderSubtle: '#e2e8f0',
divider: '#f1f5f9',
surface: '#ffffff',
surfaceAlt: '#f8fafc'
};
const dtA = (c, suffix) => `${c}${suffix}`;
const tint = (c) => dtA(c, '08');
const soft = (c) => dtA(c, '18');
const ring = (c) => dtA(c, '26');
const edge = (c) => dtA(c, '55');
const dtTint = tint;
const dtSoft = soft;
const dtRing = ring;
const dtEdge = edge;
const BRAND = '#C01227';
const BRAND_LIGHT = '#D25463';
const BRAND = '#000000';
const BRAND_LIGHT = '#3A3A3A';
// Semantic per-row status palette, keyed by GET /admin/bookings' real `status`
// enum (lowercased — StatusBadge lowercases before lookup). pending_pickup,
@@ -455,7 +434,9 @@ const Orders = () => {
}
},
{
root: null,
// MainLayout's AppShell scrolls content inside `.astryx-layout-content`
// (height="fill"), not the window — root: null would never intersect.
root: document.querySelector('.astryx-layout-content'),
rootMargin: '0px 0px 400px 0px',
threshold: 0
}
@@ -830,46 +811,51 @@ const Orders = () => {
py: 0.5,
flexShrink: 0,
cursor: 'pointer',
borderRadius: 999,
border: `1.5px solid ${active ? t.color : edge(t.color)}`,
bgcolor: active ? t.color : tint(t.color),
color: active ? '#fff' : t.color,
fontWeight: 700,
boxShadow: active ? `0 6px 18px ${ring(t.color)}` : 'none',
transition: 'all 0.18s',
borderRadius: DT.radiusField + 'px',
// Selected tab always shows the brand red, not the status's own
// semantic color (pending=amber, delivered=emerald, etc.) — the
// status color survives on the avatar below, which is where
// operators actually read it. Shape/weight/hover match
// deliveries.js, the design reference for every list page.
border: `1px solid ${active ? BRAND : DT.borderSubtle}`,
bgcolor: active ? BRAND : DT.surface,
color: active ? '#fff' : DT.textSecondary,
fontWeight: 600,
boxShadow: 'none',
transition: 'background-color 0.15s, border-color 0.15s, color 0.15s',
'&:hover': {
borderColor: t.color,
boxShadow: active ? `0 6px 18px ${ring(t.color)}` : `0 0 0 3px ${ring(t.color)}`
borderColor: active ? BRAND : DT.borderHover,
bgcolor: active ? BRAND : DT.surfaceAlt
}
}}
>
<Avatar
sx={{
width: { xs: 22, md: 26 },
height: { xs: 22, md: 26 },
width: { xs: 20, md: 22 },
height: { xs: 20, md: 22 },
bgcolor: active ? 'rgba(255,255,255,0.22)' : soft(t.color),
color: active ? '#fff' : t.color
}}
>
<Icon size={13} />
<Icon size={12} />
</Avatar>
<Typography variant="caption" sx={{ fontWeight: 800, fontSize: { xs: 11.5, md: 13 }, lineHeight: 1 }}>
<Typography variant="caption" sx={{ fontWeight: 600, fontSize: { xs: 11.5, md: 13 }, lineHeight: 1 }}>
{t.label}
</Typography>
<Box
sx={{
minWidth: { xs: 22, md: 26 },
height: { xs: 18, md: 22 },
minWidth: { xs: 20, md: 24 },
height: { xs: 18, md: 20 },
px: 0.625,
display: 'inline-flex',
alignItems: 'center',
justifyContent: 'center',
borderRadius: 999,
fontSize: { xs: 10, md: 11 },
fontWeight: 800,
bgcolor: active ? 'rgba(255,255,255,0.22)' : '#fff',
color: active ? '#fff' : t.color,
border: active ? 'none' : `1px solid ${edge(t.color)}`
fontWeight: 700,
bgcolor: active ? 'rgba(255,255,255,0.22)' : DT.surfaceAlt,
color: active ? '#fff' : DT.textSecondary,
border: 'none'
}}
>
{count ?? 0}