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;