updats on the dispatch page

This commit is contained in:
2026-09-10 17:57:00 +05:30
parent 79a8f2b234
commit 8b2c4daef8
34 changed files with 6929 additions and 1059 deletions

112
src/api/telemetry.ts Normal file
View File

@@ -0,0 +1,112 @@
/**
* Where a rider is right now, and how their phone is doing.
*
* ── This is a different backend, and that is the whole point ────────────────
*
* `jupiter.nearle.app` — the platform's older API, which the xpress console
* runs against. Fiesta has no equivalent: `getriderperiodiclogs` does not exist
* there under any prefix, and `partners/getriderlogs`, the closest-looking
* Fiesta endpoint, is a heartbeat log that repeats one fixed coordinate per
* rider all day (see `riderShifts`). So this is the ONLY live rider position
* on the platform, and it was missed once already by checking Fiesta alone.
*
* Verified 2026-09-10: rider 852 polled thirty seconds apart moved about 140 m,
* with battery, connection and accuracy all changing. Genuinely live.
*
* Same database as Fiesta underneath — `getallriders` on jupiter and
* `getriders` on Fiesta return identical rosters and identical on-duty state —
* so a userid from one is a userid in the other.
*
* ── One rider per call ──────────────────────────────────────────────────────
*
* There is no fleet form: `?userid=N` answers for that rider, and omitting it
* answers for whichever rider reported most recently, which is not useful. A
* fleet view therefore fans out, which is fine at the sizes involved — a
* merchant's round is a handful of riders.
*
* ── Freshness is the caller's problem, and must be shown ────────────────────
*
* The endpoint always answers, and it answers with the LAST known fix however
* old. Riders 883, 897 and 1111 come back with positions from 5, 3 and 12 days
* ago and nothing in the payload flags them as stale. A map that draws those
* next to a live one is lying, so `logdate` is parsed here and every consumer
* is handed an age rather than a bare position.
*/
const JUPITER_BASE = (
import.meta.env?.['VITE_JUPITER_BASE'] ?? 'https://jupiter.nearle.app'
)
.trim()
.replace(/\/+$/, '');
/** One rider's live snapshot, exactly as jupiter sends it. */
export interface RiderSnapshot {
userid: number;
username?: string;
latitude?: string;
longitude?: string;
/** `2026-09-10 11:25:11` — server local time, no zone. */
logdate?: string;
/** `"95%"`, with the sign. */
battery?: string;
/** `mobile`, `wifi`, `none`. */
connection?: string;
/** Metres of GPS uncertainty, as a string. 100.0 is a poor fix. */
accuracy?: string;
/** Km/h and degrees, both as strings. */
speed?: string;
heading?: string;
/** `idle`, `active`, and whatever else the app decides to send. */
status?: string;
/** The order they are on, when they are on one. */
orderid?: string;
is_charging?: boolean;
is_background?: boolean;
/** `enabled` / `disabled` — a disabled one explains a stale position. */
location_service?: string;
}
export class TelemetryError extends Error {
constructor(message: string) {
super(message);
this.name = 'TelemetryError';
}
}
export const telemetryApi = {
/**
* One rider's latest reported position and phone state.
*
* Never throws for "this rider has never reported" — that answers 200 with an
* empty-ish body, and the caller wants to draw the rider as unreachable
* rather than show an error. It throws only when jupiter itself cannot be
* reached, which is a different thing and worth saying out loud: jupiter can
* be down while Fiesta is fine, and vice versa.
*/
rider: async (userid: number, signal?: AbortSignal): Promise<RiderSnapshot | null> => {
let response: Response;
try {
response = await fetch(
`${JUPITER_BASE}/live/api/v1/utils/getriderperiodiclogs?userid=${userid}`,
{ headers: { Accept: 'application/json' }, signal },
);
} catch (error) {
if ((error as Error)?.name === 'AbortError') throw error;
throw new TelemetryError(
'Could not reach the live rider service. It is a separate backend from the rest of the console, so everything else keeps working.',
);
}
if (!response.ok) {
throw new TelemetryError(`The live rider service answered ${response.status}.`);
}
const payload = (await response.json().catch(() => null)) as
| { data?: RiderSnapshot }
| null;
const data = payload?.data;
// A rider who has never opened the app comes back without coordinates.
// Null rather than an empty object, so "no fix" is one check everywhere.
return data && (data.latitude || data.longitude) ? data : null;
},
};