rider partner page

This commit is contained in:
2026-09-09 15:43:23 +05:30
parent 32c612a10d
commit b760c1a078
18 changed files with 1802 additions and 63 deletions

View File

@@ -16,6 +16,7 @@ import { productsApi } from '@/api/products';
import { posUsersApi, staffApi } from '@/api/people';
import { stockApi, type StockRequestQuery } from '@/api/stock';
import { tenantsApi, utilsApi, type TenantListQuery } from '@/api/tenants';
import { partnersApi } from '@/api/deliveries';
import { customersApi, type CustomerQuery } from '@/api/customers';
import { uploadsApi } from '@/api/uploads';
import { APP_BROWSE_CATEGORY } from '@/features/catalogue/tenantCategories';
@@ -138,6 +139,93 @@ export function useImportedRefs(tenantid: number | undefined) {
/* ── Products ────────────────────────────────────────────────────────────── */
/**
* Every delivery partner across every region.
*
* `getpartners` takes one region at a time and refuses 0, so the whole list is
* the regions fanned out and flattened. Three regions today — Coimbatore,
* Madurai, Nagercoil — so this is three requests, not a page of them.
*/
export function useAllPartners() {
const regions = useAppRegions();
const ids = (regions.data ?? []).map((region) => region.applocationid);
const results = useQueries({
queries: ids.map((applocationid) => ({
queryKey: queryKeys.partners.inRegion(applocationid),
queryFn: () => partnersApi.list(applocationid),
...stable,
})),
});
return {
data: results.flatMap((result) => result.data ?? []),
isLoading: regions.isLoading || results.some((result) => result.isLoading),
};
}
/** The delivery regions. `0` asks for all of them — see `utilsApi.appLocations`. */
export function useAppRegions() {
return useQuery({
queryKey: queryKeys.regions.all,
queryFn: () => utilsApi.appLocations(0),
...stable,
});
}
/**
* One delivery partner's riders.
*
* The roster, not `getriders`: the second wants a clock-in stamped today, so a
* rider added five minutes ago is absent from it — which reads as a failed
* save. The directory shows everybody and reports duty as a state.
*/
export function usePartnerRiders(partnerid: number | undefined) {
return useQuery({
queryKey: [...queryKeys.partners.all, 'riders', partnerid ?? 0] as const,
queryFn: () => ridersApi.partnerRoster(partnerid as number),
enabled: typeof partnerid === 'number' && partnerid > 0,
...stable,
});
}
/**
* How many riders each partner has, keyed by partnerid.
*
* Fanned out because `getriderroster` takes one partner at a time. Five
* partners today, so five requests — and the count is what makes the Riders
* button worth pressing, since "Riders" alone asks you to open a drawer to find
* out whether there are any.
*/
export function usePartnerRiderCounts(partnerids: readonly number[]) {
const ids = [...new Set(partnerids)].filter((id) => id > 0);
const results = useQueries({
queries: ids.map((partnerid) => ({
queryKey: [...queryKeys.partners.all, 'riders', partnerid] as const,
queryFn: () => ridersApi.partnerRoster(partnerid),
...stable,
})),
});
const counts = new Map<number, number>();
results.forEach((result, index) => {
const id = ids[index];
if (id !== undefined && result.data) counts.set(id, result.data.length);
});
return counts;
}
/** The regions one partner covers. */
export function usePartnerLocations(partnerid: number | undefined) {
return useQuery({
queryKey: queryKeys.partners.locations(partnerid ?? 0),
queryFn: () => partnersApi.locations(partnerid as number),
enabled: typeof partnerid === 'number' && partnerid > 0,
...stable,
});
}
/**
* The ten aisles the customer app groups products into.
*
@@ -356,11 +444,21 @@ export function useDeliveries(query: OrderQuery | undefined) {
* Scoped by `applocationid`. Passing a tenant instead returns an empty list
* with a 200 — see `deliveriesApi.riders`.
*/
export function useRiders(applocationid: number | undefined) {
export function useRiders(scope: {
/** The merchant's own riders. */
tenantid?: number | undefined;
/** A delivery partner's riders. */
partnerid?: number | undefined;
/** Only used when neither of the above is given. */
applocationid?: number | undefined;
}) {
const { tenantid, partnerid, applocationid } = scope;
return useQuery({
queryKey: queryKeys.insights.riders(applocationid ?? 0),
queryFn: () => deliveriesApi.riders({ applocationid: applocationid as number }),
enabled: Boolean(applocationid),
// The scope is part of the key, or one fleet's riders would be served to
// the other after a toggle.
queryKey: [...queryKeys.insights.all, 'riders', tenantid ?? 0, partnerid ?? 0, applocationid ?? 0] as const,
queryFn: () => deliveriesApi.riders({ tenantid, partnerid, applocationid }),
enabled: Boolean(tenantid || partnerid || applocationid),
...live,
});
}

View File

@@ -8,6 +8,14 @@
*/
export const queryKeys = {
/** Delivery partners — the companies that supply riders. */
partners: {
all: ['partners'] as const,
inRegion: (applocationid: number) => ['partners', 'region', applocationid] as const,
locations: (partnerid: number) => ['partners', 'locations', partnerid] as const,
},
/** The delivery regions a partner can cover. */
regions: { all: ['regions'] as const },
uploads: {
all: ['uploads'] as const,
list: (tenantid: number, locationid: number) =>