import React, { useMemo, useRef, useState } from 'react';
import {
Avatar,
Box,
Grid,
Paper,
Stack,
Table,
TableBody,
TableCell,
TableContainer,
TableHead,
TableRow,
Typography,
useMediaQuery,
useTheme
} from '@mui/material';
import {
MdLocalOffer,
MdMyLocation,
MdAttachMoney,
MdGroups,
MdPlace,
MdSpeed,
MdPriceCheck,
MdStraighten,
MdReceiptLong,
MdOutlineLocalOffer,
MdOutlineGroups,
MdOutlineAttachMoney,
MdOutlinePlace
} from 'react-icons/md';
import { useQuery } from '@tanstack/react-query';
import Loader from 'components/Loader';
import DebounceSearchBar from 'components/nearle_components/DebounceSearchBar';
import LocationAutocomplete from 'components/nearle_components/LocationAutocomplete';
import PageHeader from 'components/nearle_components/PageHeader';
import StatCard from 'components/nearle_components/StatCard';
import { MobileCard, MobileCardList, MobileField, MobileFieldGrid } from 'components/nearle_components/MobileCard';
import { OrdersTableSkeleton } from '../orders/OrdersTableSkeleton';
import { getallpricing } from 'pages/api/api';
// ============================================================================
// Design tokens — shared with the deliveries / tenants / customers pages so every
// surface (header, KPI tiles, table, badges) speaks the same visual language.
// Keep this block in sync with customers.js / deliveries.js.
// ============================================================================
const DT = {
radiusPill: 999,
radiusCard: 14,
radiusField: 10,
shadowSoft: '0 1px 2px rgba(15, 23, 42, 0.04), 0 8px 24px rgba(15, 23, 42, 0.05)',
shadowMd: '0 1px 3px rgba(15, 23, 42, 0.06)',
shadowPop: '0 12px 32px rgba(15, 23, 42, 0.12)',
textPrimary: '#0f172a',
textSecondary: '#64748b',
textMuted: '#94a3b8',
borderSubtle: '#e2e8f0',
borderHover: '#cbd5e1',
divider: '#f1f5f9',
surface: '#ffffff',
surfaceAlt: '#f8fafc',
brand: '#C01227'
};
const a = (c, suffix) => `${c}${suffix}`;
const tint = (c) => a(c, '08');
const soft = (c) => a(c, '18');
const ring = (c) => a(c, '26');
const edge = (c) => a(c, '55');
const BRAND = '#C01227';
const SoftPaper = (props) => (
);
const AccentAvatar = ({ color, selected, size = 24, children }) => (
{children}
);
const formatRupees = (value) =>
new Intl.NumberFormat('en-IN', {
style: 'currency',
currency: 'INR',
minimumFractionDigits: 2
}).format(Number(value) || 0);
const formatDecimal = (value) =>
new Intl.NumberFormat('en-IN', { minimumFractionDigits: 2 }).format(Number(value) || 0);
// Numeric table value — plain, strong, right-readable text. The old version
// wrapped every cell in a coloured bordered pill, which made the table read
// like a rainbow; corporate data tables keep figures as quiet typography and
// let the column header carry the meaning.
const MetricPill = ({ label }) => (
{label}
);
// Subtle neutral category chip (zone / slab) — one quiet style, muted icon.
const CategoryChip = ({ icon, label }) => (
{icon}
{label}
);
// ==============================|| Pricing page ||============================== //
const ClientsPricing = () => {
const theme = useTheme();
const isMobile = useMediaQuery(theme.breakpoints.down('md'));
const containerRef = useRef();
const [appId, setAppId] = useState(0);
const [locaName, setLocoName] = useState('All');
const [searchword, setSearchword] = useState('');
const [debouncedSearch, setDebouncedSearch] = useState('');
const {
data: pricing = [],
isLoading
} = useQuery({
queryKey: ['getallpricing', appId],
queryFn: getallpricing,
keepPreviousData: true
});
const rows = useMemo(() => {
if (!debouncedSearch) return pricing;
const q = debouncedSearch.toLowerCase().trim();
return pricing.filter((row) =>
[row.applocation, row.appname, row.slab, String(row.pricingid)]
.filter(Boolean)
.some((field) => String(field).toLowerCase().includes(q))
);
}, [pricing, debouncedSearch]);
const stats = useMemo(() => {
const total = pricing.length;
const tenants = new Set(pricing.map((r) => r.appname).filter(Boolean)).size;
const avgBase = total
? pricing.reduce((sum, r) => sum + (Number(r.baseprice) || 0), 0) / total
: 0;
return { total, tenants, avgBase };
}, [pricing]);
const KPI_META = [
{ key: 'total', label: 'Total Pricing Slabs', color: BRAND, icon: MdOutlineLocalOffer, value: stats.total },
{ key: 'tenants', label: 'Tenants Priced', color: '#0ea5e9', icon: MdOutlineGroups, value: stats.tenants },
{ key: 'avg', label: 'Avg Base Price', color: '#f59e0b', icon: MdOutlineAttachMoney, value: formatRupees(stats.avgBase) },
{ key: 'zone', label: 'Active Zone', color: '#10b981', icon: MdOutlinePlace, value: locaName || 'All Zones' }
];
return (
<>
{isLoading && }
{/* ============================================= || Header || ============================================= */}
}
placeholder="Select Zone"
paperComponent={SoftPaper}
sx={{ width: { xs: '100%', sm: 280 }, zIndex: 100 }}
/>
}
/>
{/* ============================================= || KPI Cards || ============================================= */}
{KPI_META.map((item) => {
const Icon = item.icon;
return (
} color={item.color} />
);
})}
{/* ============================================= || Search Header || ============================================= */}
Pricing Catalog
{pricing.length} total · {rows.length} shown
{/* ============================================= || Table || ============================================= */}
{isMobile ? (
rows.length === 0 && !isLoading ? (
No pricing to show
{searchword ? 'Try a different keyword.' : 'Pick a zone above to load the catalog.'}
) : (
{rows.map((row, index) => (
{row.appname || '—'}
ID #{row.pricingid}
{String(index + 1).padStart(2, '0')}
}
>
{row.applocation ? (
{row.applocation}
) : null}
{row.slab || '—'}
}
label={formatRupees(row.baseprice)}
/>
}
label={formatRupees(row.priceperkm)}
/>
}
label={`${formatDecimal(row.minkm)} km`}
/>
}
label={`${formatDecimal(row.maxkm)} km`}
/>
{row.minorder ?? '—'}
))}
)
) : (
#
Tenant
Zone
Slab
Base Price
Min KM
Price / KM
Max KM
Min Orders
{isLoading && }
{rows.length === 0 && !isLoading ? (
No pricing to show
{searchword ? 'Try a different keyword.' : 'Pick a zone above to load the catalog.'}
) : (
rows.map((row, index) => (
{String(index + 1).padStart(2, '0')}
{row.appname || '—'}
ID #{row.pricingid}
{row.applocation ? (
} label={row.applocation} />
) : (
—
)}
} label={row.slab || '—'} />
}
label={formatRupees(row.baseprice)}
width={110}
/>
}
label={`${formatDecimal(row.minkm)} km`}
width={90}
/>
}
label={formatRupees(row.priceperkm)}
width={110}
/>
}
label={`${formatDecimal(row.maxkm)} km`}
width={90}
/>
{row.minorder ?? '—'}
))
)}
)}
>
);
};
export default ClientsPricing;