Session expiry, arrival geofence guard, multi-destination stops
Three fixes found by running the app on a real handset against production. 1. An expired token left the app looking signed in and unable to work. MilerApi.onUnauthorized was declared and called on every 401 but never assigned, so the token was dropped and nothing else happened: the profile stayed on disk, logged_out stayed false, and the rider saw his own name over a dashboard whose every call returned 401. He reads that as "no work today". The teardown now lives in endSession() and both ways out of a session — the Log out button and the 401 path — use it. 2. Arrived was written locally even when the rider was not there. updateArrivedStatus answers false for three different things and the caller treated all of them as "the write did not land", which is only true of one. A geofence refusal and a server refusal now stop the rung and hand back the reason; a dead network still advances, as it should. 3. A multi-destination customer pickup collapsed onto one stop. GET /miler/bookings returns a row per destination once collected, all with the same bookingid and reference. Every local store keys on that id, so the accepted store deduped two of three drops away and their consignment ids were unrecoverable. orderid is now the stop key; bookingreference stays the booking's name. Cards show "Stop 2 of 3" and the receiver's own name and number rather than the sender's. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EqVJPB9B4QuieZnBAAKgYQ
This commit is contained in:
@@ -35,6 +35,7 @@ import 'package:miler/controllers/profile_controller.dart';
|
||||
import 'package:miler/data/service_profile.dart';
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
import 'package:miler/data/accepted_store.dart';
|
||||
import 'package:miler/data/session.dart';
|
||||
import 'package:miler/data/proof_store.dart';
|
||||
import 'package:miler/controllers/rewards_controller.dart';
|
||||
import 'package:miler/controllers/summary_controller.dart';
|
||||
@@ -866,8 +867,32 @@ void _showLogoutDialog(BuildContext context) {
|
||||
// Doorstep photos are exactly the kind of record that must
|
||||
// not outlive the session that took them.
|
||||
await ProofStore.clearScope();
|
||||
final prefs = await SharedPreferences.getInstance();
|
||||
await prefs.setBool('logged_out', true);
|
||||
|
||||
// ── The session ends here, not at the next sign-in ──
|
||||
//
|
||||
// This did not clear the bearer token. The rider was sent
|
||||
// to the sign-in screen and `logged_out` kept him there, so
|
||||
// it *looked* finished — but the token stayed in
|
||||
// SharedPreferences under `authtoken`, still valid, until
|
||||
// the next `verifyPinWithServer` happened to overwrite it.
|
||||
//
|
||||
// Two things followed. Anything that reads the token
|
||||
// without checking the flag — a background isolate, the
|
||||
// notification handler, a heartbeat that outlives the
|
||||
// route change — could go on making authenticated calls as
|
||||
// the rider who just left. And a handset handed to the next
|
||||
// rider carried the previous one's credential on disk.
|
||||
//
|
||||
// Logging out is the one moment the app is certain the
|
||||
// session is over. The credential goes then.
|
||||
// Everything above plus the token, the in-flight guard, the
|
||||
// cached fix and the `logged_out` flag now live in one
|
||||
// place — see [endSession]. The other caller is the 401
|
||||
// handler in `main.dart`: a session the server has stopped
|
||||
// accepting has to end exactly as thoroughly as one the
|
||||
// rider chose to end, and when the two were written out
|
||||
// separately only this one existed.
|
||||
await endSession();
|
||||
Get.offAll(() => const SignIn());
|
||||
},
|
||||
height: ButtonSizes.secondary,
|
||||
|
||||
Reference in New Issue
Block a user