initialised commit on the ui converted in mui to astryx and changed the design to doormile

This commit is contained in:
2026-08-01 15:38:42 +05:30
parent 403b2cf5e7
commit 79fefda61a
198 changed files with 13757 additions and 31562 deletions

View File

@@ -1,25 +1,6 @@
import React, { useState, useEffect, useRef } from 'react';
import {
Box,
Drawer,
IconButton,
Typography,
useMediaQuery,
useTheme,
Tooltip,
TableCell,
Stack,
TableRow,
TableBody,
TableHead,
Table,
TableContainer,
CircularProgress,
InputBase,
Paper,
Avatar,
ButtonBase
} from '@mui/material';
import { Spinner } from '@astryxdesign/core/Spinner';
import { IconButton } from '@astryxdesign/core/IconButton';
import {
MdMenu,
MdSearch,
@@ -39,19 +20,10 @@ import { fetchOrders1, gettenantlocations } from '../api/api';
import Loader from 'components/Loader';
import CircularLoader from 'components/nearle_components/CircularLoader';
import { Empty, Skeleton } from 'antd';
import {
DT,
BRAND,
BRAND_LIGHT,
tint,
soft,
ring,
edge,
StatusBadge,
AccentAvatar
} from '../_shared/ordersDesign';
import { DT, BRAND, BRAND_LIGHT, tint, soft, ring, edge, StatusBadge, AccentAvatar } from '../_shared/ordersDesign';
import axios from 'axios';
import dayjs from 'dayjs';
import logger from 'utils/logger';
var utc = require('dayjs/plugin/utc');
dayjs.extend(utc);
@@ -60,18 +32,29 @@ const drawerWidth = 300;
// Status filter tabs — colors aligned with STATUS_META in the shared design system
// (blue=created, amber=pending, green=delivered, red=cancelled).
const STATUS_TABS = [
{ label: 'Created', value: 'created', color: '#3b82f6', icon: MdLocalShipping },
{ label: 'Pending', value: 'pending', color: '#f59e0b', icon: MdHourglassEmpty },
{ label: 'Delivered', value: 'delivered', color: '#10b981', icon: MdCheckCircle },
{ label: 'Cancelled', value: 'cancelled', color: '#ef4444', icon: MdCancel }
{ label: 'Created', value: 'created', color: BRAND, icon: MdLocalShipping },
{ label: 'Pending', value: 'pending', color: BRAND, icon: MdHourglassEmpty },
{ label: 'Delivered', value: 'delivered', color: BRAND, icon: MdCheckCircle },
{ label: 'Cancelled', value: 'cancelled', color: BRAND, icon: MdCancel }
];
// Brand-styled scrollbar reused on the sidebar + table.
const scrollbarStyle = `
.rld-scroll::-webkit-scrollbar { width: 8px; height: 8px; }
.rld-scroll::-webkit-scrollbar-thumb { background-color: ${edge(BRAND)}; border-radius: 8px; }
.rld-scroll::-webkit-scrollbar-thumb:hover { background-color: ${BRAND}; }
.rld-scroll::-webkit-scrollbar-track { background-color: ${DT.surfaceAlt}; }
.rld-pill:focus-within { border-color: ${BRAND} !important; box-shadow: 0 0 0 3px ${ring(BRAND)}; }
.rld-toggle:hover { background-color: ${tint(BRAND)}; border-color: ${BRAND}; }
`;
const noWrapStyle = { whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' };
const ResponsiveLocationDrawer = () => {
const loadMoreRef = useRef();
const containerRef = useRef();
const theme = useTheme();
const tenantid = localStorage.getItem('tenantid');
const isDesktop = useMediaQuery('(min-width:900px)');
const [isDesktop, setIsDesktop] = useState(() => (typeof window !== 'undefined' ? window.innerWidth >= 900 : true));
const [open, setOpen] = useState(false);
const [selectedLocation, setSelectedLocation] = useState(null);
const [currentStatus, setCurrentStatus] = useState('created');
@@ -92,6 +75,12 @@ const ResponsiveLocationDrawer = () => {
const [searchword, setSearchword] = useState('');
const [debouncedSearchword, setDebouncedSearchword] = useState('');
useEffect(() => {
const handleResize = () => setIsDesktop(window.innerWidth >= 900);
window.addEventListener('resize', handleResize);
return () => window.removeEventListener('resize', handleResize);
}, []);
// Per-status counts keyed by tab value, so the filter pills can show a badge.
const statusCounts = {
created: createdLenght,
@@ -177,7 +166,7 @@ const ResponsiveLocationDrawer = () => {
}
},
{
root: document.querySelector('.MuiTableContainer-root'),
root: containerRef.current,
rootMargin: '0px',
threshold: 1.0
}
@@ -205,7 +194,7 @@ const ResponsiveLocationDrawer = () => {
`${process.env.REACT_APP_URL}/orders/getordersummary/?tenantid=${tenantid}&locationid=${selectedLocation?.locationid}&fromdate=${startdate}&todate=${enddate}`
)
.then((res) => {
console.log('fetchorderscount', res.data.details);
logger.info('fetchorderscount', res.data.details);
setCreatedLenght(res.data.details.created);
setPendingLenght(res.data.details.pending);
setDeliveredlenght(res.data.details.delivered);
@@ -217,11 +206,11 @@ const ResponsiveLocationDrawer = () => {
setLoading(false);
})
.catch((err) => {
console.log(err);
logger.error(err);
setLoading(false);
});
} catch (err) {
console.log(err);
logger.error(err);
setLoading(false);
}
};
@@ -237,303 +226,320 @@ const ResponsiveLocationDrawer = () => {
const errMessage = locationIsError ? `${locationError.message}` : null;
useEffect(() => {
errMessage && console.log(errMessage);
errMessage && logger.info(errMessage);
}, [errMessage]);
// Brand-styled scrollbar reused on the sidebar + table.
const scrollbarSx = {
'&::-webkit-scrollbar': { width: 8, height: 8 },
'&::-webkit-scrollbar-thumb': {
backgroundColor: edge(BRAND),
borderRadius: 8,
'&:hover': { backgroundColor: BRAND }
},
'&::-webkit-scrollbar-track': { backgroundColor: DT.surfaceAlt }
};
// --------------------------------------------------------------------------
// Sidebar — searchable location list. Shared between the desktop persistent
// drawer and the mobile temporary drawer.
// --------------------------------------------------------------------------
const sidebarContent = (
<Stack sx={{ height: '100%', bgcolor: '#fff' }}>
<div style={{ display: 'flex', flexDirection: 'column', height: '100%', backgroundColor: '#fff' }}>
{/* Sidebar header */}
<Box sx={{ px: 1.5, pt: 1.5, pb: 1 }}>
<Stack direction="row" alignItems="center" spacing={1} sx={{ mb: 1.25 }}>
<Avatar
variant="rounded"
sx={{ width: 30, height: 30, bgcolor: BRAND, color: '#fff', borderRadius: 1.5, boxShadow: `0 4px 12px ${ring(BRAND)}` }}
<div style={{ padding: '12px 12px 8px' }}>
<div style={{ display: 'flex', flexDirection: 'row', alignItems: 'center', gap: 8, marginBottom: 10 }}>
<div
style={{
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
width: 30,
height: 30,
flexShrink: 0,
backgroundColor: BRAND,
color: '#fff',
borderRadius: 12,
boxShadow: `0 4px 12px ${ring(BRAND)}`
}}
>
<MdStorefront size={16} />
</Avatar>
<Stack spacing={0}>
<Typography sx={{ fontSize: 13.5, fontWeight: 800, color: DT.textPrimary, lineHeight: 1.1 }}>Locations</Typography>
<Typography sx={{ fontSize: 10.5, fontWeight: 600, color: DT.textMuted }}>
</div>
<div style={{ display: 'flex', flexDirection: 'column' }}>
<span style={{ fontSize: 13.5, fontWeight: 800, color: DT.textPrimary, lineHeight: 1.1 }}>Locations</span>
<span style={{ fontSize: 10.5, fontWeight: 600, color: DT.textMuted }}>
{Array.isArray(locations) ? `${locations.length} active` : '—'}
</Typography>
</Stack>
</Stack>
</span>
</div>
</div>
{/* Search pill */}
<Box
sx={{
<div
className="rld-pill"
style={{
display: 'flex',
alignItems: 'center',
gap: 0.75,
px: 1.25,
py: 0.75,
gap: 6,
padding: '6px 10px',
borderRadius: 999,
bgcolor: tint(BRAND),
backgroundColor: tint(BRAND),
border: `1.5px solid ${edge(BRAND)}`,
transition: 'all 0.18s',
'&:focus-within': { borderColor: BRAND, boxShadow: `0 0 0 3px ${ring(BRAND)}` }
transition: 'all 0.18s'
}}
>
<MdSearch size={16} style={{ color: BRAND, flexShrink: 0 }} />
<InputBase
<input
placeholder="Search location"
value={searchLocation}
onChange={(e) => setSearchLocation(e.target.value)}
autoComplete="off"
sx={{
flex: 1,
fontSize: 13,
fontWeight: 600,
color: DT.textPrimary,
'& input::placeholder': { color: DT.textMuted, opacity: 1 }
}}
style={{ flex: 1, fontSize: 13, fontWeight: 600, color: DT.textPrimary, border: 'none', outline: 'none', background: 'transparent' }}
/>
{searchLocation && (
<IconButton size="small" onClick={() => setSearchLocation('')} sx={{ p: 0.25, color: BRAND }}>
<MdClear size={14} />
</IconButton>
<IconButton
label="Clear search"
icon={<MdClear size={14} />}
variant="ghost"
size="sm"
onClick={() => setSearchLocation('')}
style={{ color: BRAND }}
/>
)}
</Box>
</Box>
</div>
</div>
{/* Location list */}
<Box sx={{ flex: 1, overflowY: 'auto', px: 1, pb: 1, ...scrollbarSx }}>
<div className="rld-scroll" style={{ flex: 1, overflowY: 'auto', padding: '0 8px 8px' }}>
{locationIsLoading &&
Array.from({ length: 8 }).map((_, i) => (
<Box key={i} sx={{ px: 1, py: 1 }}>
<div key={i} style={{ padding: '8px' }}>
<Skeleton avatar active paragraph={{ rows: 1 }} title={false} />
</Box>
</div>
))}
{!locationIsLoading && Array.isArray(locations) && locations.length === 0 && (
<Box sx={{ py: 5 }}>
<div style={{ padding: '40px 0' }}>
<Empty description="No locations" />
</Box>
</div>
)}
<Stack spacing={0.5}>
<div style={{ display: 'flex', flexDirection: 'column', gap: 4 }}>
{locations?.map((row, index) => {
const isSelected = row.locationid === selectedLocation?.locationid;
return (
<ButtonBase
<button
key={index}
onClick={() => setSelectedLocation(row)}
sx={{
style={{
display: 'flex',
width: '100%',
alignItems: 'center',
justifyContent: 'flex-start',
textAlign: 'left',
gap: 1,
px: 1,
py: 0.875,
borderRadius: 2,
gap: 8,
padding: '7px 8px',
borderRadius: 16,
border: 'none',
position: 'relative',
cursor: 'pointer',
transition: 'background-color 0.14s, box-shadow 0.14s',
bgcolor: isSelected ? tint(BRAND) : 'transparent',
boxShadow: isSelected ? `inset 3px 0 0 ${BRAND}` : 'none',
'&:hover': { bgcolor: isSelected ? tint(BRAND) : DT.surfaceAlt }
backgroundColor: isSelected ? tint(BRAND) : 'transparent',
boxShadow: isSelected ? `inset 3px 0 0 ${BRAND}` : 'none'
}}
>
<AccentAvatar color={BRAND} selected={isSelected} size={36}>
{row.locationname?.[0]?.toUpperCase() || '?'}
</AccentAvatar>
<Stack spacing={0} sx={{ minWidth: 0, flex: 1 }}>
<Typography
sx={{ fontSize: 13, fontWeight: 700, color: isSelected ? BRAND : DT.textPrimary, lineHeight: 1.2 }}
noWrap
>
<div style={{ display: 'flex', flexDirection: 'column', gap: 0, minWidth: 0, flex: 1 }}>
<span style={{ fontSize: 13, fontWeight: 700, color: isSelected ? BRAND : DT.textPrimary, lineHeight: 1.2, ...noWrapStyle }}>
{row.locationname}
</Typography>
<Stack direction="row" alignItems="center" spacing={0.375}>
</span>
<div style={{ display: 'flex', flexDirection: 'row', alignItems: 'center', gap: 3 }}>
<MdPlace size={11} style={{ color: DT.textMuted, flexShrink: 0 }} />
<Typography sx={{ fontSize: 11, fontWeight: 600, color: DT.textSecondary }} noWrap>
{row.suburb || '—'}
</Typography>
</Stack>
</Stack>
</ButtonBase>
<span style={{ fontSize: 11, fontWeight: 600, color: DT.textSecondary, ...noWrapStyle }}>{row.suburb || '—'}</span>
</div>
</div>
</button>
);
})}
</Stack>
</Box>
</Stack>
</div>
</div>
</div>
);
return (
<React.Fragment>
<style>{scrollbarStyle}</style>
{locationIsLoading && (
<>
<Loader /> <CircularLoader />
</>
)}
<Box sx={{ display: 'flex', width: '100%', height: '100%', position: 'relative', bgcolor: DT.surfaceAlt }}>
<div style={{ display: 'flex', width: '100%', height: '100%', position: 'relative', backgroundColor: DT.surfaceAlt }}>
{/* ---------------- LOCATION SIDEBAR ---------------- */}
<Drawer
variant={isDesktop ? 'persistent' : 'temporary'}
open={open}
onClose={() => !isDesktop && toggleDrawer()}
ModalProps={{ keepMounted: true }}
sx={{
'& .MuiDrawer-paper': {
width: drawerWidth,
boxSizing: 'border-box',
position: 'absolute',
left: 0,
top: 0,
height: '100%',
overflow: 'hidden',
borderRight: `1px solid ${DT.borderSubtle}`,
transition: 'transform 0.35s ease-in-out',
zIndex: 10
}
}}
>
{sidebarContent}
</Drawer>
{(isDesktop || open) && (
<>
{!isDesktop && (
<div
role="button"
tabIndex={0}
aria-label="Close locations sidebar"
onClick={toggleDrawer}
onKeyDown={(e) => (e.key === 'Enter' || e.key === ' ') && toggleDrawer()}
style={{ position: 'absolute', inset: 0, backgroundColor: 'rgba(15,23,42,0.35)', zIndex: 9, border: 'none' }}
/>
)}
<div
style={{
width: drawerWidth,
boxSizing: 'border-box',
position: 'absolute',
left: 0,
top: 0,
height: '100%',
overflow: 'hidden',
borderRight: `1px solid ${DT.borderSubtle}`,
transform: open ? 'translateX(0)' : 'translateX(-100%)',
transition: 'transform 0.35s ease-in-out',
zIndex: 10
}}
>
{sidebarContent}
</div>
</>
)}
{/* ---------------- MAIN PANEL ---------------- */}
<Box
sx={{
<div
style={{
flexGrow: 1,
height: '100%',
display: 'flex',
flexDirection: 'column',
overflow: 'hidden',
pl: isDesktop && open ? `${drawerWidth}px` : 0,
paddingLeft: isDesktop && open ? drawerWidth : 0,
transition: 'padding-left 0.3s ease'
}}
>
{/* ---------------- GRADIENT HEADER ---------------- */}
<Paper
elevation={0}
sx={{
<div
style={{
flexShrink: 0,
px: { xs: 1.25, sm: 1.75 },
py: { xs: 1, sm: 1.25 },
borderRadius: 0,
padding: '10px 14px',
borderBottom: `1px solid ${DT.borderSubtle}`,
background: `linear-gradient(135deg, ${tint(BRAND)} 0%, ${tint(BRAND_LIGHT)} 100%)`
}}
>
<Stack
direction={{ xs: 'column', md: 'row' }}
alignItems={{ xs: 'stretch', md: 'center' }}
justifyContent="space-between"
spacing={{ xs: 1, md: 1.5 }}
<div
style={{
display: 'flex',
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'space-between',
gap: 12,
flexWrap: 'wrap'
}}
>
<Stack direction="row" alignItems="center" spacing={1.25}>
<Tooltip title={open ? 'Hide locations' : 'Show locations'} arrow>
<IconButton
onClick={toggleDrawer}
sx={{
width: 34,
height: 34,
borderRadius: 1.5,
bgcolor: '#fff',
border: `1px solid ${DT.borderSubtle}`,
color: BRAND,
'&:hover': { bgcolor: tint(BRAND), borderColor: BRAND }
}}
>
<MdMenu size={18} />
</IconButton>
</Tooltip>
<div style={{ display: 'flex', flexDirection: 'row', alignItems: 'center', gap: 10 }}>
<button
title={open ? 'Hide locations' : 'Show locations'}
onClick={toggleDrawer}
className="rld-toggle"
style={{
width: 34,
height: 34,
borderRadius: 12,
backgroundColor: '#fff',
border: `1px solid ${DT.borderSubtle}`,
color: BRAND,
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
cursor: 'pointer',
transition: 'background-color 0.15s, border-color 0.15s'
}}
>
<MdMenu size={18} />
</button>
<Avatar
variant="rounded"
sx={{ width: 36, height: 36, bgcolor: BRAND, color: '#fff', borderRadius: 1.5, boxShadow: `0 4px 12px ${ring(BRAND)}` }}
<div
style={{
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
width: 36,
height: 36,
flexShrink: 0,
backgroundColor: BRAND,
color: '#fff',
borderRadius: 12,
boxShadow: `0 4px 12px ${ring(BRAND)}`
}}
>
<MdMyLocation size={19} />
</Avatar>
<Stack spacing={0.125}>
<Typography
variant="h3"
sx={{
</div>
<div style={{ display: 'flex', flexDirection: 'column', gap: 1 }}>
<span
style={{
fontWeight: 800,
color: DT.textPrimary,
lineHeight: 1.1,
fontSize: { xs: '1.05rem', sm: '1.2rem', md: '1.3rem' }
fontSize: '1.2rem',
...noWrapStyle
}}
noWrap
>
{selectedLocation?.locationname || 'Select a location'}
</Typography>
<Stack direction="row" alignItems="center" spacing={0.75}>
<Box sx={{ width: 7, height: 7, borderRadius: '50%', bgcolor: '#10b981', boxShadow: '0 0 0 3px rgba(16,185,129,0.18)' }} />
<Typography sx={{ fontSize: 11.5, color: DT.textSecondary, fontWeight: 600 }} noWrap>
</span>
<div style={{ display: 'flex', flexDirection: 'row', alignItems: 'center', gap: 6 }}>
<span style={{ width: 7, height: 7, borderRadius: '50%', backgroundColor: '#10b981', boxShadow: '0 0 0 3px rgba(16,185,129,0.18)' }} />
<span style={{ fontSize: 11.5, color: DT.textSecondary, fontWeight: 600, ...noWrapStyle }}>
{selectedLocation?.suburb ? `${selectedLocation.suburb} · ` : ''}Live · {dayjs(startdate).format('DD MMM YYYY')}
</Typography>
</Stack>
</Stack>
</Stack>
</span>
</div>
</div>
</div>
{/* Order search pill */}
<Box
sx={{
<div
className="rld-pill"
style={{
display: 'flex',
alignItems: 'center',
gap: 0.75,
px: 1.25,
py: 0.75,
gap: 6,
padding: '6px 10px',
borderRadius: 999,
bgcolor: '#fff',
backgroundColor: '#fff',
border: `1.5px solid ${edge(BRAND)}`,
minWidth: { xs: '100%', md: 280 },
maxWidth: { md: 360 },
transition: 'all 0.18s',
'&:focus-within': { borderColor: BRAND, boxShadow: `0 0 0 3px ${ring(BRAND)}` }
minWidth: 280,
maxWidth: 360,
flex: '1 1 280px',
transition: 'all 0.18s'
}}
>
<MdSearch size={16} style={{ color: BRAND, flexShrink: 0 }} />
<InputBase
<input
placeholder="Search order details"
value={searchword}
onChange={(e) => setSearchword(e.target.value)}
autoComplete="off"
sx={{
flex: 1,
fontSize: 13,
fontWeight: 600,
color: DT.textPrimary,
'& input::placeholder': { color: DT.textMuted, opacity: 1 }
}}
style={{ flex: 1, fontSize: 13, fontWeight: 600, color: DT.textPrimary, border: 'none', outline: 'none', background: 'transparent' }}
/>
{searchword && (
<IconButton size="small" onClick={() => setSearchword('')} sx={{ p: 0.25, color: BRAND }}>
<MdClear size={14} />
</IconButton>
<IconButton
label="Clear search"
icon={<MdClear size={14} />}
variant="ghost"
size="sm"
onClick={() => setSearchword('')}
style={{ color: BRAND }}
/>
)}
</Box>
</Stack>
</Paper>
</div>
</div>
</div>
{/* ---------------- STATUS FILTER PILLS ---------------- */}
<Box
sx={{
<div
className="rld-scroll"
style={{
flexShrink: 0,
px: { xs: 1, sm: 1.5 },
py: 1,
bgcolor: '#fff',
padding: '8px 12px',
backgroundColor: '#fff',
borderBottom: `1px solid ${DT.borderSubtle}`,
display: 'flex',
gap: 0.75,
overflowX: 'auto',
...scrollbarSx
gap: 6,
overflowX: 'auto'
}}
>
{STATUS_TABS.map((item, index) => {
@@ -541,229 +547,231 @@ const ResponsiveLocationDrawer = () => {
const Icon = item.icon;
const count = statusCounts[item.value];
return (
<ButtonBase
<button
key={index}
onClick={() => handleChangetab(index)}
sx={{
style={{
flexShrink: 0,
gap: 0.75,
px: 1.25,
py: 0.625,
display: 'flex',
alignItems: 'center',
gap: 6,
padding: '5px 10px',
borderRadius: 999,
fontWeight: 700,
cursor: 'pointer',
transition: 'all 0.15s',
border: `1.5px solid ${isActive ? item.color : DT.borderSubtle}`,
bgcolor: isActive ? item.color : '#fff',
backgroundColor: isActive ? item.color : '#fff',
color: isActive ? '#fff' : DT.textSecondary,
boxShadow: isActive ? `0 4px 12px ${ring(item.color)}` : 'none',
'&:hover': {
borderColor: item.color,
color: isActive ? '#fff' : item.color,
bgcolor: isActive ? item.color : tint(item.color)
}
boxShadow: isActive ? `0 4px 12px ${ring(item.color)}` : 'none'
}}
>
<Icon size={14} />
<Typography sx={{ fontSize: 12.5, fontWeight: 700, lineHeight: 1 }}>{item.label}</Typography>
<Box
sx={{
<span style={{ fontSize: 12.5, fontWeight: 700, lineHeight: 1 }}>{item.label}</span>
<span
style={{
display: 'inline-flex',
alignItems: 'center',
justifyContent: 'center',
minWidth: 20,
height: 18,
px: 0.625,
padding: '0 5px',
borderRadius: 999,
fontSize: 10.5,
fontWeight: 800,
bgcolor: isActive ? 'rgba(255,255,255,0.25)' : soft(item.color),
backgroundColor: isActive ? 'rgba(255,255,255,0.25)' : soft(item.color),
color: isActive ? '#fff' : item.color
}}
>
{count ?? 0}
</Box>
</ButtonBase>
</span>
</button>
);
})}
</Box>
</div>
{/* ---------------- ORDERS TABLE ---------------- */}
<Box sx={{ flex: 1, overflow: 'hidden', p: { xs: 1, sm: 1.5 } }}>
<Paper
elevation={0}
sx={{
<div style={{ flex: 1, overflow: 'hidden', padding: 12 }}>
<div
style={{
height: '100%',
display: 'flex',
flexDirection: 'column',
borderRadius: 2,
borderRadius: 8,
border: `1px solid ${DT.borderSubtle}`,
overflow: 'hidden',
background: '#fff',
boxShadow: DT.shadowSoft
}}
>
<TableContainer
onScroll={handleScroll}
ref={containerRef}
sx={{ flex: 1, overflow: 'auto', ...scrollbarSx }}
>
<Table stickyHeader size="small">
<TableHead>
<TableRow
sx={{
'& th': {
backgroundColor: DT.surfaceAlt,
color: DT.textSecondary,
fontSize: 10.5,
fontWeight: 800,
letterSpacing: 0.5,
textTransform: 'uppercase',
whiteSpace: 'nowrap',
borderBottom: `1px solid ${DT.borderSubtle}`,
py: 0.75,
px: 1
}
}}
>
<TableCell sx={{ width: 36 }}>#</TableCell>
<TableCell sx={{ minWidth: 150 }}>Order</TableCell>
<TableCell sx={{ minWidth: 150 }}>Pickup</TableCell>
<TableCell sx={{ minWidth: 150 }}>Drop</TableCell>
<TableCell sx={{ minWidth: 140 }}>Notes</TableCell>
<TableCell sx={{ width: 120 }}>Status</TableCell>
</TableRow>
</TableHead>
<div className="rld-scroll" onScroll={handleScroll} ref={containerRef} style={{ flex: 1, overflow: 'auto' }}>
<table style={{ width: '100%', borderCollapse: 'collapse', fontSize: 12.5 }}>
<thead style={{ position: 'sticky', top: 0, zIndex: 1 }}>
<tr>
{['#', 'Order', 'Pickup', 'Drop', 'Notes', 'Status'].map((h, i) => (
<th
key={h}
style={{
textAlign: 'left',
backgroundColor: DT.surfaceAlt,
color: DT.textSecondary,
fontSize: 10.5,
fontWeight: 800,
letterSpacing: 0.5,
textTransform: 'uppercase',
whiteSpace: 'nowrap',
borderBottom: `1px solid ${DT.borderSubtle}`,
padding: '6px 8px',
width: i === 0 ? 36 : i === 5 ? 120 : undefined,
minWidth: i > 0 && i < 5 ? 140 : undefined
}}
>
{h}
</th>
))}
</tr>
</thead>
<TableBody>
<tbody>
{/* LOADING STATE */}
{loading &&
Array.from({ length: 10 }).map((_, index) => (
<TableRow key={index}>
<tr key={index}>
{Array.from({ length: 6 }).map((__, i) => (
<TableCell key={i} sx={{ borderBottom: `1px solid ${DT.divider}`, py: 0.625, px: 1 }}>
<td key={i} style={{ borderBottom: `1px solid ${DT.divider}`, padding: '5px 8px' }}>
<Skeleton.Input active size="small" style={{ width: '100%', height: 18 }} />
</TableCell>
</td>
))}
</TableRow>
</tr>
))}
{/* EMPTY STATE */}
{!loading && rows?.length === 0 && (
<TableRow>
<TableCell colSpan={6} sx={{ py: 7, borderBottom: 'none' }}>
<Stack alignItems="center" spacing={1.25}>
<Avatar variant="rounded" sx={{ width: 56, height: 56, bgcolor: soft('#94a3b8'), color: DT.textMuted, borderRadius: 2 }}>
<tr>
<td colSpan={6} style={{ padding: '56px 0', borderBottom: 'none' }}>
<div style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 10 }}>
<div
style={{
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
width: 56,
height: 56,
backgroundColor: soft('#94a3b8'),
color: DT.textMuted,
borderRadius: 16
}}
>
<MdReceiptLong size={26} />
</Avatar>
<Typography sx={{ fontWeight: 700, color: DT.textPrimary, fontSize: 14 }}>No orders found</Typography>
<Typography sx={{ color: DT.textSecondary, fontSize: 12 }}>
</div>
<span style={{ fontWeight: 700, color: DT.textPrimary, fontSize: 14 }}>No orders found</span>
<span style={{ color: DT.textSecondary, fontSize: 12 }}>
{searchword ? 'Try a different keyword or clear the search.' : 'No orders in this status for the selected location.'}
</Typography>
</Stack>
</TableCell>
</TableRow>
</span>
</div>
</td>
</tr>
)}
{/* DATA ROWS */}
{!loading &&
rows?.map((row, index) => (
<TableRow
<tr
key={index}
sx={{
cursor: 'pointer',
transition: 'background-color 0.12s, box-shadow 0.12s',
'& td': { borderBottom: `1px solid ${DT.divider}`, py: 0.75, px: 1, verticalAlign: 'top' },
'&:hover': { backgroundColor: tint(BRAND), boxShadow: `inset 3px 0 0 ${BRAND}` }
}}
className="rld-row"
style={{ cursor: 'pointer', transition: 'background-color 0.12s, box-shadow 0.12s' }}
>
<TableCell>
<Typography sx={{ fontWeight: 700, fontSize: 12, color: DT.textMuted }}>{page * rowsPerPage + index + 1}</Typography>
</TableCell>
<td style={{ borderBottom: `1px solid ${DT.divider}`, padding: '6px 8px', verticalAlign: 'top' }}>
<span style={{ fontWeight: 700, fontSize: 12, color: DT.textMuted }}>{page * rowsPerPage + index + 1}</span>
</td>
{/* Order Info */}
<TableCell>
<Typography sx={{ fontSize: 12.5, fontWeight: 700, color: DT.textPrimary, lineHeight: 1.25 }} noWrap>
<td style={{ borderBottom: `1px solid ${DT.divider}`, padding: '6px 8px', verticalAlign: 'top' }}>
<div style={{ fontSize: 12.5, fontWeight: 700, color: DT.textPrimary, lineHeight: 1.25, ...noWrapStyle }}>
{row.orderid}
</Typography>
<Stack direction="row" alignItems="center" spacing={0.5} sx={{ mt: 0.125 }}>
</div>
<div style={{ display: 'flex', flexDirection: 'row', alignItems: 'center', gap: 4, marginTop: 1 }}>
<MdAccessTime size={10} style={{ color: DT.textMuted, flexShrink: 0 }} />
<Typography sx={{ fontSize: 10.5, color: DT.textSecondary, fontWeight: 700 }} noWrap>
<span style={{ fontSize: 10.5, color: DT.textSecondary, fontWeight: 700, ...noWrapStyle }}>
{dayjs(row.deliverydate).utc().format('hh:mm A')}
</Typography>
<Typography sx={{ fontSize: 10.5, color: DT.textMuted, fontWeight: 600 }} noWrap>
</span>
<span style={{ fontSize: 10.5, color: DT.textMuted, fontWeight: 600, ...noWrapStyle }}>
· {dayjs(row.deliverydate).utc().format('DD MMM YY')}
</Typography>
</Stack>
</TableCell>
</span>
</div>
</td>
{/* Pickup */}
<TableCell>
<Stack spacing={0.125}>
<Typography sx={{ fontSize: 12.5, fontWeight: 700, color: DT.textPrimary, lineHeight: 1.25 }} noWrap>
<td style={{ borderBottom: `1px solid ${DT.divider}`, padding: '6px 8px', verticalAlign: 'top' }}>
<div style={{ display: 'flex', flexDirection: 'column', gap: 1 }}>
<span style={{ fontSize: 12.5, fontWeight: 700, color: DT.textPrimary, lineHeight: 1.25, ...noWrapStyle }}>
{row.pickupcustomer || '—'}
</Typography>
<Typography sx={{ fontSize: 11, color: DT.textSecondary, fontWeight: 600, lineHeight: 1.3 }} noWrap>
</span>
<span style={{ fontSize: 11, color: DT.textSecondary, fontWeight: 600, lineHeight: 1.3, ...noWrapStyle }}>
{row.pickupcontactno}
</Typography>
<Tooltip title={row.pickupaddress || ''}>
<Typography sx={{ fontSize: 10.5, color: DT.textMuted, fontWeight: 600, lineHeight: 1.3 }} noWrap>
{row.pickupsuburb || (row.pickupaddress ? `${row.pickupaddress.slice(0, 20)}` : '—')}
</Typography>
</Tooltip>
</Stack>
</TableCell>
</span>
<span
title={row.pickupaddress || ''}
style={{ fontSize: 10.5, color: DT.textMuted, fontWeight: 600, lineHeight: 1.3, ...noWrapStyle }}
>
{row.pickupsuburb || (row.pickupaddress ? `${row.pickupaddress.slice(0, 20)}` : '—')}
</span>
</div>
</td>
{/* Drop */}
<TableCell>
<Stack spacing={0.125}>
<Typography sx={{ fontSize: 12.5, fontWeight: 700, color: DT.textPrimary, lineHeight: 1.25 }} noWrap>
<td style={{ borderBottom: `1px solid ${DT.divider}`, padding: '6px 8px', verticalAlign: 'top' }}>
<div style={{ display: 'flex', flexDirection: 'column', gap: 1 }}>
<span style={{ fontSize: 12.5, fontWeight: 700, color: DT.textPrimary, lineHeight: 1.25, ...noWrapStyle }}>
{row.deliverycustomer || '—'}
</Typography>
<Typography sx={{ fontSize: 11, color: DT.textSecondary, fontWeight: 600, lineHeight: 1.3 }} noWrap>
</span>
<span style={{ fontSize: 11, color: DT.textSecondary, fontWeight: 600, lineHeight: 1.3, ...noWrapStyle }}>
{row.deliverycontactno}
</Typography>
<Tooltip title={row.deliveryaddress || ''}>
<Typography sx={{ fontSize: 10.5, color: DT.textMuted, fontWeight: 600, lineHeight: 1.3 }} noWrap>
{row.deliverysuburb || (row.deliveryaddress ? `${row.deliveryaddress.slice(0, 20)}` : '—')}
</Typography>
</Tooltip>
</Stack>
</TableCell>
</span>
<span
title={row.deliveryaddress || ''}
style={{ fontSize: 10.5, color: DT.textMuted, fontWeight: 600, lineHeight: 1.3, ...noWrapStyle }}
>
{row.deliverysuburb || (row.deliveryaddress ? `${row.deliveryaddress.slice(0, 20)}` : '—')}
</span>
</div>
</td>
{/* Notes */}
<TableCell>
<Typography sx={{ fontSize: 11.5, color: DT.textSecondary, fontWeight: 600, lineHeight: 1.35 }}>
<td style={{ borderBottom: `1px solid ${DT.divider}`, padding: '6px 8px', verticalAlign: 'top' }}>
<span style={{ fontSize: 11.5, color: DT.textSecondary, fontWeight: 600, lineHeight: 1.35 }}>
{row.ordernotes || '—'}
</Typography>
</TableCell>
</span>
</td>
{/* Status */}
<TableCell>
<td style={{ borderBottom: `1px solid ${DT.divider}`, padding: '6px 8px', verticalAlign: 'top' }}>
<StatusBadge status={row.orderstatus} />
</TableCell>
</TableRow>
</td>
</tr>
))}
{rows?.length != 0 && (
<TableRow>
<TableCell colSpan={6} sx={{ borderBottom: 'none' }}>
<Stack ref={loadMoreRef} alignItems="center" justifyContent="center" sx={{ height: 40 }}>
<tr>
<td colSpan={6} style={{ borderBottom: 'none' }}>
<div ref={loadMoreRef} style={{ display: 'flex', alignItems: 'center', justifyContent: 'center', height: 40 }}>
{isFetchingNextPage || hasNextPage ? (
<CircularProgress size={20} sx={{ color: BRAND }} />
<Spinner size="md" style={{ color: BRAND }} />
) : (
<Typography sx={{ fontSize: 11.5, fontWeight: 700, color: DT.textMuted }}>No more orders</Typography>
<span style={{ fontSize: 11.5, fontWeight: 700, color: DT.textMuted }}>No more orders</span>
)}
</Stack>
</TableCell>
</TableRow>
</div>
</td>
</tr>
)}
</TableBody>
</Table>
</TableContainer>
</Paper>
</Box>
</Box>
</Box>
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
<style>{`.rld-row:hover { background-color: ${tint(BRAND)}; box-shadow: inset 3px 0 0 ${BRAND}; }`}</style>
</React.Fragment>
);
};