Files
Doormilexpress_app/src/pages/nearle/locations/ResponsiveLocationDrawer.js

778 lines
31 KiB
JavaScript

import React, { useState, useEffect, useRef } from 'react';
import { Spinner } from '@astryxdesign/core/Spinner';
import { IconButton } from '@astryxdesign/core/IconButton';
import {
MdMenu,
MdSearch,
MdClear,
MdPlace,
MdStorefront,
MdMyLocation,
MdAccessTime,
MdLocalShipping,
MdHourglassEmpty,
MdCheckCircle,
MdCancel,
MdReceiptLong
} from 'react-icons/md';
import { useInfiniteQuery, useQuery } from '@tanstack/react-query';
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 axios from 'axios';
import dayjs from 'dayjs';
import logger from 'utils/logger';
var utc = require('dayjs/plugin/utc');
dayjs.extend(utc);
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: 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 tenantid = localStorage.getItem('tenantid');
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');
const [tabvalue, setTabvalue] = useState(0);
const [createdLenght, setCreatedLenght] = useState();
const [pendingLenght, setPendingLenght] = useState();
const [deliveredlenght, setDeliveredlenght] = useState();
const [cancelledLenght, setCancelledLenght] = useState();
const [loading, setLoading] = useState(false);
const [page, setPage] = React.useState(0);
const [rowsPerPage, setRowsPerPage] = React.useState(10);
const [, setPageCount] = React.useState(0);
const [startdate] = useState(dayjs().format('YYYY-MM-DD'));
const [enddate] = useState(dayjs().format('YYYY-MM-DD'));
const [searchLocation, setSearchLocation] = useState('');
const [debouncedSearchLocation, setDebouncedSearchLocation] = useState('');
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,
pending: pendingLenght,
delivered: deliveredlenght,
cancelled: cancelledLenght
};
useEffect(() => {
const handler = setTimeout(() => {
setDebouncedSearchLocation(searchLocation);
}, 400);
return () => clearTimeout(handler);
}, [searchLocation]);
useEffect(() => {
const handler = setTimeout(() => {
setDebouncedSearchword(searchword);
}, 400);
return () => clearTimeout(handler);
}, [searchword]);
const handleChangetab = (i) => {
setSearchword('');
setRowsPerPage(10);
setTabvalue(i);
setCurrentStatus(STATUS_TABS[i].value);
setPage(0);
};
const {
data: locations,
isLoading: locationIsLoading,
isError: locationIsError,
error: locationError
} = useQuery({
queryKey: ['locations', debouncedSearchLocation],
queryFn: gettenantlocations
});
// Auto-pick a sensible default whenever the locations list changes:
// • Nothing selected yet → pick the first item.
// • Current selection has been filtered out → also pick the first item
// (otherwise the orders panel queries a locationid that's no longer
// in the visible list, returning nothing and confusing the operator).
useEffect(() => {
if (!Array.isArray(locations) || locations.length === 0) return;
const stillVisible = selectedLocation && locations.some((l) => l.locationid === selectedLocation.locationid);
if (!stillVisible) setSelectedLocation(locations[0]);
}, [locations]);
const {
data: ordersData,
fetchNextPage,
hasNextPage,
isFetchingNextPage
} = useInfiniteQuery({
queryKey: [
'orders',
tenantid,
selectedLocation?.locationid ?? null, // stable
currentStatus,
startdate,
enddate,
debouncedSearchword,
rowsPerPage
],
queryFn: fetchOrders1,
getNextPageParam: (lastPage) => lastPage.nextPage
});
const rows = ordersData?.pages?.flatMap((page) => page.details) || [];
useEffect(() => {
if (!hasNextPage) return;
const observer = new IntersectionObserver(
(entries) => {
if (entries[0].isIntersecting) {
fetchNextPage();
}
},
{
root: containerRef.current,
rootMargin: '0px',
threshold: 1.0
}
);
if (loadMoreRef.current) observer.observe(loadMoreRef.current);
return () => {
if (loadMoreRef.current) observer.unobserve(loadMoreRef.current);
};
}, [hasNextPage, fetchNextPage]);
const handleScroll = (event) => {
const { scrollTop, scrollHeight, clientHeight } = event.currentTarget;
if (scrollTop + clientHeight >= scrollHeight - 50) {
if (hasNextPage && !isFetchingNextPage) {
fetchNextPage();
}
}
};
const fetchorderscount = async () => {
setLoading(true);
try {
await axios
.get(
`${process.env.REACT_APP_URL}/orders/getordersummary/?tenantid=${tenantid}&locationid=${selectedLocation?.locationid}&fromdate=${startdate}&todate=${enddate}`
)
.then((res) => {
logger.info('fetchorderscount', res.data.details);
setCreatedLenght(res.data.details.created);
setPendingLenght(res.data.details.pending);
setDeliveredlenght(res.data.details.delivered);
setCancelledLenght(res.data.details.cancelled);
tabvalue === 0 && setPageCount(res.data.details.created);
tabvalue === 1 && setPageCount(res.data.details.pending);
tabvalue === 2 && setPageCount(res.data.details.delivered);
tabvalue === 3 && setPageCount(res.data.details.cancelled);
setLoading(false);
})
.catch((err) => {
logger.error(err);
setLoading(false);
});
} catch (err) {
logger.error(err);
setLoading(false);
}
};
useEffect(() => {
fetchorderscount();
}, [currentStatus, selectedLocation, startdate, enddate]);
useEffect(() => {
setOpen(isDesktop);
}, [isDesktop]);
const toggleDrawer = () => setOpen(!open);
const errMessage = locationIsError ? `${locationError.message}` : null;
useEffect(() => {
errMessage && logger.info(errMessage);
}, [errMessage]);
// --------------------------------------------------------------------------
// Sidebar — searchable location list. Shared between the desktop persistent
// drawer and the mobile temporary drawer.
// --------------------------------------------------------------------------
const sidebarContent = (
<div style={{ display: 'flex', flexDirection: 'column', height: '100%', backgroundColor: '#fff' }}>
{/* Sidebar header */}
<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} />
</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` : '—'}
</span>
</div>
</div>
{/* Search pill */}
<div
className="rld-pill"
style={{
display: 'flex',
alignItems: 'center',
gap: 6,
padding: '6px 10px',
borderRadius: 999,
backgroundColor: tint(BRAND),
border: `1.5px solid ${edge(BRAND)}`,
transition: 'all 0.18s'
}}
>
<MdSearch size={16} style={{ color: BRAND, flexShrink: 0 }} />
<input
placeholder="Search location"
value={searchLocation}
onChange={(e) => setSearchLocation(e.target.value)}
autoComplete="off"
style={{ flex: 1, fontSize: 13, fontWeight: 600, color: DT.textPrimary, border: 'none', outline: 'none', background: 'transparent' }}
/>
{searchLocation && (
<IconButton
label="Clear search"
icon={<MdClear size={14} />}
variant="ghost"
size="sm"
onClick={() => setSearchLocation('')}
style={{ color: BRAND }}
/>
)}
</div>
</div>
{/* Location list */}
<div className="rld-scroll" style={{ flex: 1, overflowY: 'auto', padding: '0 8px 8px' }}>
{locationIsLoading &&
Array.from({ length: 8 }).map((_, i) => (
<div key={i} style={{ padding: '8px' }}>
<Skeleton avatar active paragraph={{ rows: 1 }} title={false} />
</div>
))}
{!locationIsLoading && Array.isArray(locations) && locations.length === 0 && (
<div style={{ padding: '40px 0' }}>
<Empty description="No locations" />
</div>
)}
<div style={{ display: 'flex', flexDirection: 'column', gap: 4 }}>
{locations?.map((row, index) => {
const isSelected = row.locationid === selectedLocation?.locationid;
return (
<button
key={index}
onClick={() => setSelectedLocation(row)}
style={{
display: 'flex',
width: '100%',
alignItems: 'center',
justifyContent: 'flex-start',
textAlign: 'left',
gap: 8,
padding: '7px 8px',
borderRadius: 16,
border: 'none',
position: 'relative',
cursor: 'pointer',
transition: 'background-color 0.14s, box-shadow 0.14s',
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>
<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}
</span>
<div style={{ display: 'flex', flexDirection: 'row', alignItems: 'center', gap: 3 }}>
<MdPlace size={11} style={{ color: DT.textMuted, flexShrink: 0 }} />
<span style={{ fontSize: 11, fontWeight: 600, color: DT.textSecondary, ...noWrapStyle }}>{row.suburb || '—'}</span>
</div>
</div>
</button>
);
})}
</div>
</div>
</div>
);
return (
<React.Fragment>
<style>{scrollbarStyle}</style>
{locationIsLoading && (
<>
<Loader /> <CircularLoader />
</>
)}
<div style={{ display: 'flex', width: '100%', height: '100%', position: 'relative', backgroundColor: DT.surfaceAlt }}>
{/* ---------------- LOCATION SIDEBAR ---------------- */}
{(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 ---------------- */}
<div
style={{
flexGrow: 1,
height: '100%',
display: 'flex',
flexDirection: 'column',
overflow: 'hidden',
paddingLeft: isDesktop && open ? drawerWidth : 0,
transition: 'padding-left 0.3s ease'
}}
>
{/* ---------------- GRADIENT HEADER ---------------- */}
<div
style={{
flexShrink: 0,
padding: '10px 14px',
borderBottom: `1px solid ${DT.borderSubtle}`,
background: `linear-gradient(135deg, ${tint(BRAND)} 0%, ${tint(BRAND_LIGHT)} 100%)`
}}
>
<div
style={{
display: 'flex',
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'space-between',
gap: 12,
flexWrap: 'wrap'
}}
>
<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>
<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} />
</div>
<div style={{ display: 'flex', flexDirection: 'column', gap: 1 }}>
<span
style={{
fontWeight: 800,
color: DT.textPrimary,
lineHeight: 1.1,
fontSize: '1.2rem',
...noWrapStyle
}}
>
{selectedLocation?.locationname || 'Select a location'}
</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')}
</span>
</div>
</div>
</div>
{/* Order search pill */}
<div
className="rld-pill"
style={{
display: 'flex',
alignItems: 'center',
gap: 6,
padding: '6px 10px',
borderRadius: 999,
backgroundColor: '#fff',
border: `1.5px solid ${edge(BRAND)}`,
minWidth: 280,
maxWidth: 360,
flex: '1 1 280px',
transition: 'all 0.18s'
}}
>
<MdSearch size={16} style={{ color: BRAND, flexShrink: 0 }} />
<input
placeholder="Search order details"
value={searchword}
onChange={(e) => setSearchword(e.target.value)}
autoComplete="off"
style={{ flex: 1, fontSize: 13, fontWeight: 600, color: DT.textPrimary, border: 'none', outline: 'none', background: 'transparent' }}
/>
{searchword && (
<IconButton
label="Clear search"
icon={<MdClear size={14} />}
variant="ghost"
size="sm"
onClick={() => setSearchword('')}
style={{ color: BRAND }}
/>
)}
</div>
</div>
</div>
{/* ---------------- STATUS FILTER PILLS ---------------- */}
<div
className="rld-scroll"
style={{
flexShrink: 0,
padding: '8px 12px',
backgroundColor: '#fff',
borderBottom: `1px solid ${DT.borderSubtle}`,
display: 'flex',
gap: 6,
overflowX: 'auto'
}}
>
{STATUS_TABS.map((item, index) => {
const isActive = tabvalue === index;
const Icon = item.icon;
const count = statusCounts[item.value];
return (
<button
key={index}
onClick={() => handleChangetab(index)}
style={{
flexShrink: 0,
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}`,
backgroundColor: isActive ? item.color : '#fff',
color: isActive ? '#fff' : DT.textSecondary,
boxShadow: isActive ? `0 4px 12px ${ring(item.color)}` : 'none'
}}
>
<Icon size={14} />
<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,
padding: '0 5px',
borderRadius: 999,
fontSize: 10.5,
fontWeight: 800,
backgroundColor: isActive ? 'rgba(255,255,255,0.25)' : soft(item.color),
color: isActive ? '#fff' : item.color
}}
>
{count ?? 0}
</span>
</button>
);
})}
</div>
{/* ---------------- ORDERS TABLE ---------------- */}
<div style={{ flex: 1, overflow: 'hidden', padding: 12 }}>
<div
style={{
height: '100%',
display: 'flex',
flexDirection: 'column',
borderRadius: 8,
border: `1px solid ${DT.borderSubtle}`,
overflow: 'hidden',
background: '#fff',
boxShadow: DT.shadowSoft
}}
>
<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>
<tbody>
{/* LOADING STATE */}
{loading &&
Array.from({ length: 10 }).map((_, index) => (
<tr key={index}>
{Array.from({ length: 6 }).map((__, i) => (
<td key={i} style={{ borderBottom: `1px solid ${DT.divider}`, padding: '5px 8px' }}>
<Skeleton.Input active size="small" style={{ width: '100%', height: 18 }} />
</td>
))}
</tr>
))}
{/* EMPTY STATE */}
{!loading && rows?.length === 0 && (
<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} />
</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.'}
</span>
</div>
</td>
</tr>
)}
{/* DATA ROWS */}
{!loading &&
rows?.map((row, index) => (
<tr
key={index}
className="rld-row"
style={{ cursor: 'pointer', transition: 'background-color 0.12s, box-shadow 0.12s' }}
>
<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 */}
<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}
</div>
<div style={{ display: 'flex', flexDirection: 'row', alignItems: 'center', gap: 4, marginTop: 1 }}>
<MdAccessTime size={10} style={{ color: DT.textMuted, flexShrink: 0 }} />
<span style={{ fontSize: 10.5, color: DT.textSecondary, fontWeight: 700, ...noWrapStyle }}>
{dayjs(row.deliverydate).utc().format('hh:mm A')}
</span>
<span style={{ fontSize: 10.5, color: DT.textMuted, fontWeight: 600, ...noWrapStyle }}>
· {dayjs(row.deliverydate).utc().format('DD MMM YY')}
</span>
</div>
</td>
{/* Pickup */}
<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 || '—'}
</span>
<span style={{ fontSize: 11, color: DT.textSecondary, fontWeight: 600, lineHeight: 1.3, ...noWrapStyle }}>
{row.pickupcontactno}
</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 */}
<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 || '—'}
</span>
<span style={{ fontSize: 11, color: DT.textSecondary, fontWeight: 600, lineHeight: 1.3, ...noWrapStyle }}>
{row.deliverycontactno}
</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 */}
<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 || '—'}
</span>
</td>
{/* Status */}
<td style={{ borderBottom: `1px solid ${DT.divider}`, padding: '6px 8px', verticalAlign: 'top' }}>
<StatusBadge status={row.orderstatus} />
</td>
</tr>
))}
{rows?.length != 0 && (
<tr>
<td colSpan={6} style={{ borderBottom: 'none' }}>
<div ref={loadMoreRef} style={{ display: 'flex', alignItems: 'center', justifyContent: 'center', height: 40 }}>
{isFetchingNextPage || hasNextPage ? (
<Spinner size="md" style={{ color: BRAND }} />
) : (
<span style={{ fontSize: 11.5, fontWeight: 700, color: DT.textMuted }}>No more orders</span>
)}
</div>
</td>
</tr>
)}
</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>
);
};
export default ResponsiveLocationDrawer;