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

View File

@@ -2,9 +2,17 @@ import React, { useEffect, useMemo, useState } from 'react';
import { MapContainer, TileLayer, Polyline, Marker, Popup, useMap } from 'react-leaflet';
import L from 'leaflet';
import 'leaflet/dist/leaflet.css';
import { Box, IconButton, Stack, Typography, CircularProgress } from '@mui/material';
import { MdClose, MdRoute } from 'react-icons/md';
import { HStack } from '@astryxdesign/core/HStack';
import { VStack } from '@astryxdesign/core/VStack';
import { Center } from '@astryxdesign/core/Center';
import { Text } from '@astryxdesign/core/Text';
import { IconButton } from '@astryxdesign/core/IconButton';
import { EmptyState } from '@astryxdesign/core/EmptyState';
import LoaderWithImage from 'components/nearle_components/LoaderWithImage';
const containerStyle = { width: '100%', height: '100%' };
// Numbered step icon — brand red to match the planned-route polyline below.
@@ -12,7 +20,7 @@ const containerStyle = { width: '100%', height: '100%' };
// the SVG without juggling external marker assets.
const stepIcon = (n, isFocused) => {
const size = isFocused ? 38 : 32;
const color = isFocused ? '#910E1D' : '#C01227';
const color = isFocused ? '#262626' : '#000000';
const svg = encodeURIComponent(
`<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32" width="${size}" height="${size}">` +
`<circle cx="16" cy="16" r="14" fill="${color}" stroke="white" stroke-width="3"/>` +
@@ -93,48 +101,51 @@ export default function RidersRoutes({ details, loading, riderName, dateRange, o
}, [dropPath]);
const headerBar = (
<Stack
direction="row"
alignItems="center"
spacing={1.5}
sx={{
px: 2,
py: 1.25,
<HStack
gap={3}
vAlign="center"
paddingInline={4}
paddingBlock={3}
style={{
borderBottom: '1px solid rgba(15, 23, 42, 0.08)',
background: 'linear-gradient(135deg, #C01227 0%, #D25463 100%)',
background: 'linear-gradient(135deg, #000000 0%, #3A3A3A 100%)',
color: '#fff',
flexShrink: 0
}}
>
<MdRoute size={20} />
<Stack sx={{ flex: 1, minWidth: 0 }}>
<Typography sx={{ fontWeight: 700, fontSize: 15, lineHeight: 1.2 }}>Planned route{riderName ? ` — ${riderName}` : ''}</Typography>
{dateRange && <Typography sx={{ fontSize: 12, opacity: 0.85 }}>{dateRange}</Typography>}
</Stack>
<VStack gap={0} padding={0} style={{ flex: 1, minWidth: 0 }}>
<Text color="inherit" weight="bold" display="block">
Planned route{riderName ? ` — ${riderName}` : ''}
</Text>
{dateRange && (
<Text color="inherit" size="sm" display="block" style={{ opacity: 0.85 }}>
{dateRange}
</Text>
)}
</VStack>
{details && details.length > 0 && (
<Typography sx={{ fontSize: 12, opacity: 0.9, fontWeight: 600 }}>
<Text color="inherit" size="sm" weight="semibold" style={{ opacity: 0.9 }}>
{details.length} {details.length === 1 ? 'stop' : 'stops'}
{routeLoading ? ' · resolving route…' : ''}
</Typography>
</Text>
)}
{onClose && (
<IconButton size="small" onClick={onClose} sx={{ color: '#fff' }} aria-label="Close">
<MdClose />
</IconButton>
)}
</Stack>
{onClose && <IconButton label="Close" size="sm" variant="ghost" icon={<MdClose />} onClick={onClose} />}
</HStack>
);
// Loading state — parent is still fetching the planned route data.
if (loading) {
return (
<Box sx={{ display: 'flex', flexDirection: 'column', height: '100%' }}>
<VStack gap={0} padding={0} height="100%">
{headerBar}
<Stack alignItems="center" justifyContent="center" sx={{ flex: 1, gap: 1.5 }}>
<CircularProgress size={32} />
<Typography sx={{ color: '#64748b', fontSize: 13 }}>Loading planned route…</Typography>
</Stack>
</Box>
<Center axis="both" style={{ flex: 1 }}>
<VStack gap={3} hAlign="center" padding={0}>
<LoaderWithImage size={44} imgSize={24} />
<Text type="supporting">Loading planned route…</Text>
</VStack>
</Center>
</VStack>
);
}
@@ -142,22 +153,22 @@ export default function RidersRoutes({ details, loading, riderName, dateRange, o
// selected window.
if (!details || details.length === 0) {
return (
<Box sx={{ display: 'flex', flexDirection: 'column', height: '100%' }}>
<VStack gap={0} padding={0} height="100%">
{headerBar}
<Stack alignItems="center" justifyContent="center" sx={{ flex: 1, gap: 1, p: 3 }}>
<Typography sx={{ color: '#1e293b', fontWeight: 700, fontSize: 16 }}>No planned route for this rider</Typography>
<Typography sx={{ color: '#64748b', fontSize: 13, textAlign: 'center', maxWidth: 360 }}>
There are no deliveries with drop coordinates assigned to this rider for the selected date range.
</Typography>
</Stack>
</Box>
<Center axis="both" style={{ flex: 1 }}>
<EmptyState
title="No planned route for this rider"
description="There are no deliveries with drop coordinates assigned to this rider for the selected date range."
/>
</Center>
</VStack>
);
}
return (
<Box sx={{ display: 'flex', flexDirection: 'column', height: '100%' }}>
<VStack gap={0} padding={0} height="100%">
{headerBar}
<Box sx={{ flex: 1, minHeight: 0 }}>
<div style={{ flex: 1, minHeight: 0 }}>
<MapContainer center={dropPath[0]} zoom={14} style={containerStyle} zoomControl={false}>
<TileLayer url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png" attribution="&copy; OpenStreetMap contributors" />
<FitBoundsController dropPath={dropPath} />
@@ -165,14 +176,14 @@ export default function RidersRoutes({ details, loading, riderName, dateRange, o
{routePath.length > 0 ? (
<>
{/* Translucent backdrop so the route stays legible on busy tiles. */}
<Polyline positions={routePath} pathOptions={{ color: '#C01227', opacity: 0.25, weight: 8 }} />
<Polyline positions={routePath} pathOptions={{ color: '#000000', opacity: 0.25, weight: 8 }} />
{/* Road-following planned route from OSRM. */}
<Polyline positions={routePath} pathOptions={{ color: '#C01227', opacity: 0.95, weight: 4 }} />
<Polyline positions={routePath} pathOptions={{ color: '#000000', opacity: 0.95, weight: 4 }} />
</>
) : (
// Fallback while OSRM is in flight (or if it fails) — dashed
// straight-line skeleton between drop pins in step order.
<Polyline positions={dropPath} pathOptions={{ color: '#C01227', opacity: 0.6, weight: 3, dashArray: '2 10', lineCap: 'round' }} />
<Polyline positions={dropPath} pathOptions={{ color: '#000000', opacity: 0.6, weight: 3, dashArray: '2 10', lineCap: 'round' }} />
)}
{details.map((d, i) => {
@@ -189,22 +200,32 @@ export default function RidersRoutes({ details, loading, riderName, dateRange, o
zIndexOffset={isFocused ? 1000 : stepNum}
>
<Popup onClose={() => setFocusedStep(null)}>
<Box sx={{ minWidth: 180, fontFamily: 'inherit' }}>
<Typography sx={{ fontWeight: 800, fontSize: 13, color: '#0f172a' }}>
<VStack gap={0.5} padding={0} minWidth={180}>
<Text weight="bold" size="sm" display="block">
Step {stepNum} · {d.customer}
</Typography>
{d.address && <Typography sx={{ fontSize: 12, color: '#475569', mt: 0.5 }}>{d.address}</Typography>}
{d.expectedTime && (
<Typography sx={{ fontSize: 12, color: '#64748b', mt: 0.5 }}>ETA {String(d.expectedTime).slice(11, 16) || d.expectedTime}</Typography>
</Text>
{d.address && (
<Text type="supporting" size="sm" display="block">
{d.address}
</Text>
)}
{d.orderid && <Typography sx={{ fontSize: 11, color: '#94a3b8', mt: 0.5 }}>Order #{d.orderid}</Typography>}
</Box>
{d.expectedTime && (
<Text type="supporting" size="sm" display="block">
ETA {String(d.expectedTime).slice(11, 16) || d.expectedTime}
</Text>
)}
{d.orderid && (
<Text type="supporting" size="xsm" display="block">
Order #{d.orderid}
</Text>
)}
</VStack>
</Popup>
</Marker>
);
})}
</MapContainer>
</Box>
</Box>
</div>
</VStack>
);
}

View File

@@ -4,8 +4,13 @@ import L from 'leaflet';
import 'leaflet/dist/leaflet.css';
import dayjs from 'dayjs';
import { parseDoormileTimestamp } from 'utils/doormileTimestamp';
import { Chip, Stack, Typography, Box } from '@mui/material';
import { CloseCircleOutlined } from '@ant-design/icons';
import { HStack } from '@astryxdesign/core/HStack';
import { Text } from '@astryxdesign/core/Text';
import { Token } from '@astryxdesign/core/Token';
import { Button } from '@astryxdesign/core/Button';
import CircularLoader from 'components/CircularLoader';
import { DT } from 'themes/dt/tokens';
@@ -122,38 +127,26 @@ const MapWithRoute = ({ coordinates, additionalProps, order, setMapOpen }) => {
const center = coordinates[Math.floor(coordinates.length / 2)];
const InfoItem = ({ label, value }) => (
<Stack direction="row" spacing={1} alignItems="center">
<Typography variant="subtitle1" sx={{ fontWeight: 600 }}>
{label}:
</Typography>
<Chip label={value || '0.00'} color="primary" sx={{ fontWeight: 700 }} />
</Stack>
<HStack gap={1.5} vAlign="center">
<Text weight="semibold">{label}:</Text>
<Token label={String(value || '0.00')} color="red" size="sm" />
</HStack>
);
return (
<Box sx={{ width: '100%', height: '100vh', position: 'relative', overflow: 'hidden' }}>
<div style={{ width: '100%', height: '100vh', position: 'relative', overflow: 'hidden' }}>
{loading && <CircularLoader />}
{/* CLOSE BUTTON */}
<Chip
label="Close"
icon={<CloseCircleOutlined style={{ fontSize: 18 }} />}
onClick={() => setMapOpen(false)}
sx={{
position: 'absolute',
top: 12,
right: 12,
zIndex: 2000,
bgcolor: DT.brand,
color: '#fff',
fontWeight: 600,
borderRadius: DT.radiusInner + 'px',
px: 1.5,
py: 0.5,
boxShadow: DT.shadowMd,
cursor: 'pointer',
'& .MuiChip-icon': { color: '#fff' }
}}
/>
<div style={{ position: 'absolute', top: 12, right: 12, zIndex: 2000 }}>
<Button
label="Close"
variant="primary"
size="sm"
icon={<CloseCircleOutlined style={{ fontSize: 18 }} />}
elevation="low"
onClick={() => setMapOpen(false)}
/>
</div>
{/* MAP */}
<MapContainer center={center} zoom={14} scrollWheelZoom style={{ height: '100%', width: '100%' }} ref={mapRef}>
@@ -174,18 +167,17 @@ const MapWithRoute = ({ coordinates, additionalProps, order, setMapOpen }) => {
</MapContainer>
{/* BOTTOM DETAILS */}
<Box
sx={{
<div
style={{
position: 'absolute',
bottom: 0,
width: '100%',
bgcolor: 'rgba(255,255,255,0.96)',
p: 2,
backgroundColor: 'rgba(255,255,255,0.96)',
boxShadow: DT.shadowPop,
zIndex: 1500
}}
>
<Stack direction="row" flexWrap="wrap" rowGap={1.5} columnGap={3} alignItems="center">
<HStack wrap="wrap" rowGap={2} columnGap={6} vAlign="center" padding={4}>
<InfoItem label="Tenant" value={order?.tenantname} />
<InfoItem label="Rider" value={order?.ridername} />
<InfoItem label="Pickup" value={order?.pickupcustomer} />
@@ -193,9 +185,9 @@ const MapWithRoute = ({ coordinates, additionalProps, order, setMapOpen }) => {
<InfoItem label="Kms" value={order?.kms} />
<InfoItem label="Actual Kms" value={order?.actualkms} />
<InfoItem label="Rider Kms" value={order?.riderkms} />
</Stack>
</Box>
</Box>
</HStack>
</div>
</div>
);
};

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,10 +1,14 @@
import React, { useEffect, useMemo, useState } from 'react';
import { useInfiniteQuery } from '@tanstack/react-query';
// material-ui
import { Box, Paper, TextField, Typography } from '@mui/material';
import { MdCalendarMonth } from 'react-icons/md';
import { Card } from '@astryxdesign/core/Card';
import { HStack } from '@astryxdesign/core/HStack';
import { VStack } from '@astryxdesign/core/VStack';
import { EmptyState } from '@astryxdesign/core/EmptyState';
import { DateInput } from '@astryxdesign/core/DateInput';
import dayjs from 'dayjs';
import { parseDoormileTimestamp } from 'utils/doormileTimestamp';
@@ -37,14 +41,7 @@ import { SKIPPED_STATUSES } from '../dispatch/dispatchShared';
// same pattern as reports/ordersDetails.js and deliveries.js.
// ============================================================================
const DT = {
radiusCard: 14,
shadowSoft: '0 1px 2px rgba(15, 23, 42, 0.04), 0 8px 24px rgba(15, 23, 42, 0.05)',
textSecondary: '#64748b',
borderSubtle: '#e2e8f0',
surface: '#ffffff'
};
const BRAND = '#C01227';
const BRAND = '#000000';
// Profit formulas + batch windows imported from ProfitabilitySection.js
// (the single source of truth) rather than duplicated here — used to total
@@ -142,47 +139,22 @@ const Profitability = () => {
subtitle={`Live · ${dayjs(selectedDate).format('DD MMM YYYY')}`}
live
action={
<Paper
elevation={0}
sx={{
display: 'inline-flex',
alignItems: 'center',
gap: 1,
px: 1.5,
py: 0.75,
borderRadius: DT.radiusCard + 'px',
border: '1px solid',
borderColor: DT.borderSubtle,
boxShadow: DT.shadowSoft,
bgcolor: DT.surface
}}
>
<HStack gap={2} vAlign="center">
<MdCalendarMonth size={16} color={BRAND} />
<TextField
type="date"
size="small"
variant="standard"
value={selectedDate}
onChange={(e) => e.target.value && setSelectedDate(e.target.value)}
InputProps={{ disableUnderline: true }}
sx={{ '& input': { fontWeight: 700, color: DT.textSecondary, p: 0 } }}
/>
</Paper>
<DateInput label="Report date" isLabelHidden size="sm" value={selectedDate} onChange={(v) => v && setSelectedDate(v)} />
</HStack>
}
/>
<Box sx={{ mt: { xs: 1.5, md: 2 } }}>
<VStack gap={0} padding={0} style={{ marginTop: 16 }}>
{!isLoading && riders.length === 0 ? (
<Paper
elevation={0}
sx={{ p: 6, textAlign: 'center', borderRadius: DT.radiusCard + 'px', border: '1px solid', borderColor: DT.borderSubtle }}
>
<Typography sx={{ fontWeight: 700, color: DT.textSecondary }}>No deliveries for {dayjs(selectedDate).format('DD MMM YYYY')}</Typography>
</Paper>
<Card padding={6}>
<EmptyState title={`No deliveries for ${dayjs(selectedDate).format('DD MMM YYYY')}`} />
</Card>
) : (
<ProfitabilitySection riders={riders} totalDailyProfit={totalDailyProfit} selectedDate={selectedDate} />
)}
</Box>
</VStack>
</>
);
};

File diff suppressed because it is too large Load Diff