Migrate console off jupiter.nearle.app to the Doormile Express API

Retires REACT_APP_URL/URL2/URL3 in favor of REACT_APP_DOORMILE_URL across
every page (orders, deliveries, riders, tenants, pricing, profile, reports,
dispatch). Fixes several field-mapping and envelope-check bugs found along
the way, most notably that /admin/milers/:id routes (block, assign-vehicle,
edit, notify) key off milerprofileid, not userid, and that a miler's real
fields are phone/availabilitystatus/displayname, not contactno/status/
firstname+lastname (confirmed against a live read-only session).

Also fixes several silent-failure bugs uncovered during that audit: order
creation and order cancellation showed a success toast but gave no feedback
at all on failure (createorder1.js had a dead notifyadmin() call that left
the loading spinner stuck forever on every failed submit), and Tenants.js's
pricing/profile updates never surfaced a failed response to the operator.

The AI dispatch optimiser (routes.workolik.com/routemate.workolik.com) and
its jupiter.nearle.app delivery-commit call remain untouched by design —
separate solver service with no equivalent in the new API.
This commit is contained in:
2026-08-06 19:26:23 +05:30
parent 0a36212ac8
commit 59f31c8adf
39 changed files with 7006 additions and 9170 deletions

View File

@@ -0,0 +1,38 @@
import axios from 'axios';
// Client for the new Doormile Express admin API (api.doormile.com/api/v1/admin/*).
// Separate instance from utils/axios.js and the raw axios calls in pages/api/api.js
// because this backend requires a JWT Bearer token on every request and uses its
// own token lifecycle — it does not share the `authname` gate in App.js.
// See express-console-api.md at the repo root for the full endpoint reference.
export const DOORMILE_TOKEN_KEY = 'doormileToken';
export const DOORMILE_USER_KEY = 'doormileUser';
const doormileAxios = axios.create({
baseURL: process.env.REACT_APP_DOORMILE_URL || 'https://api.doormile.com/api/v1'
});
doormileAxios.interceptors.request.use((config) => {
const token = localStorage.getItem(DOORMILE_TOKEN_KEY);
if (token) {
config.headers.Authorization = `Bearer ${token}`;
}
return config;
});
doormileAxios.interceptors.response.use(
(response) => response,
(error) => {
// Mirror utils/session.js's performSessionLogout contract (full localStorage
// wipe + hard navigate) so an expired doormile token logs the console out the
// same way inactivity/manual logout does, instead of leaving a half-authed state.
if (error.response?.status === 401 && !window.location.href.includes('/login')) {
localStorage.clear();
window.location.replace('/login');
}
return Promise.reject(error.response?.data || error);
}
);
export default doormileAxios;

View File

@@ -14,5 +14,13 @@
"ordersummary": "Orders Summary",
"ordersdetails": "Orders Details",
"riderssummary": "Riders Summary",
"dispatch": "Dispatch"
"dispatch": "Dispatch",
"customers": "Customers",
"fleetops": "Fleet & Ops",
"hubs": "Hubs",
"vehicles": "Vehicles",
"tripsheets": "Tripsheets",
"exceptions": "Exceptions",
"competitiveintel": "Competitive Intel",
"appusers": "App Users"
}