updates on the pricing page and navbar updates

This commit is contained in:
2026-10-07 12:06:49 +05:30
parent 8dca169b83
commit 0d5edf94bf
2 changed files with 29 additions and 13 deletions

View File

@@ -56,6 +56,9 @@ const NAV = [
{ label: 'Deliveries', path: '/doormile/deliveries' }, { label: 'Deliveries', path: '/doormile/deliveries' },
{ label: 'Milers', path: '/doormile/milers' }, { label: 'Milers', path: '/doormile/milers' },
{ label: 'Clients', path: '/doormile/tenants' }, { label: 'Clients', path: '/doormile/tenants' },
// Staff manage every client's rate card here; a client login sees its own,
// read-only (the server scopes the list and refuses a client's changes).
{ label: 'Pricing', path: '/doormile/pricing' },
]; ];
/** Destinations grouped behind a menu, in the order the console lists them. */ /** Destinations grouped behind a menu, in the order the console lists them. */

View File

@@ -11,6 +11,7 @@ import {
useTenants, useUpdatePricing, useTenants, useUpdatePricing,
} from '@/lib/doormileHooks'; } from '@/lib/doormileHooks';
import { currency, matchesQuery, orDash, useDebouncedValue } from '@/lib/doormileFormat'; import { currency, matchesQuery, orDash, useDebouncedValue } from '@/lib/doormileFormat';
import { useAuth } from '@/lib/AuthContext';
/** /**
* Client pricing — the per-tenant rate cards quotes are calculated from. * Client pricing — the per-tenant rate cards quotes are calculated from.
@@ -18,6 +19,11 @@ import { currency, matchesQuery, orDash, useDebouncedValue } from '@/lib/doormil
* This is `/admin/pricing`, the tenant-scoped rules. Doormile's own internal * This is `/admin/pricing`, the tenant-scoped rules. Doormile's own internal
* banding lives on a separate resource with no tenant concept at all and is not * banding lives on a separate resource with no tenant concept at all and is not
* edited here. * edited here.
*
* A client login sees its own rate card read-only: the server scopes the list
* to its tenant and refuses a client's create, edit, delete and quote (the
* quote picks a rule across every tenant, so it would show another client's
* rates).
*/ */
const VEHICLE_TYPES = ['Bike', 'Scooter', 'Bicycle', 'Car', 'Van']; const VEHICLE_TYPES = ['Bike', 'Scooter', 'Bicycle', 'Car', 'Van'];
@@ -48,6 +54,7 @@ const EMPTY_QUOTE = { tenantid: '', applocationid: '', vehicletype: 'Bike', weig
const ALL_ZONES = 'all'; const ALL_ZONES = 'all';
export default function Pricing() { export default function Pricing() {
const { isClient } = useAuth();
const { data: pricing = [], isLoading, isFetching } = usePricing(); const { data: pricing = [], isLoading, isFetching } = usePricing();
const { data: tenants = [] } = useTenants(); const { data: tenants = [] } = useTenants();
const { data: locations = [] } = useAppLocations(); const { data: locations = [] } = useAppLocations();
@@ -234,7 +241,7 @@ export default function Pricing() {
sortable: true, sortable: true,
cell: (row) => <StatusBadge status={row.status} dot size="sm" />, cell: (row) => <StatusBadge status={row.status} dot size="sm" />,
}, },
{ !isClient && {
key: 'actions', key: 'actions',
header: 'Actions', header: 'Actions',
align: 'right', align: 'right',
@@ -245,9 +252,9 @@ export default function Pricing() {
</div> </div>
), ),
}, },
], ].filter(Boolean),
[tenantMap, zoneMap] [tenantMap, zoneMap, isClient]
); );
const quoteResult = simulate.data?.data || simulate.data; const quoteResult = simulate.data?.data || simulate.data;
@@ -282,6 +289,7 @@ export default function Pricing() {
placeholder="Search by client, zone or vehicle" placeholder="Search by client, zone or vehicle"
count={{ shown: rows.length, total: zonePricing.length, noun: 'rules' }} count={{ shown: rows.length, total: zonePricing.length, noun: 'rules' }}
actions={ actions={
isClient ? null : (
<> <>
<Button variant="outline" onClick={() => setQuoteOpen(true)}> <Button variant="outline" onClick={() => setQuoteOpen(true)}>
<Calculator className="mr-1.5 h-4 w-4" /> Get a quote <Calculator className="mr-1.5 h-4 w-4" /> Get a quote
@@ -290,6 +298,7 @@ export default function Pricing() {
<Plus className="mr-1.5 h-4 w-4" /> New rule <Plus className="mr-1.5 h-4 w-4" /> New rule
</Button> </Button>
</> </>
)
} }
> >
<Select value={String(zone)} onValueChange={setZone}> <Select value={String(zone)} onValueChange={setZone}>
@@ -327,8 +336,12 @@ export default function Pricing() {
<EmptyState <EmptyState
icon={Tag} icon={Tag}
title="No pricing rules yet" title="No pricing rules yet"
description="Add a rate card so this client's deliveries can be quoted." description={
action={{ label: 'New rule', icon: Plus, onClick: openCreate }} isClient
? 'Doormile has not set up your rate card yet. Contact your Doormile account manager.'
: "Add a rate card so this client's deliveries can be quoted."
}
action={isClient ? undefined : { label: 'New rule', icon: Plus, onClick: openCreate }}
/> />
) )
} }