114 lines
3.9 KiB
Dart
114 lines
3.9 KiB
Dart
/// Canonical lifecycle status for a booking/stop, parsed from the backend's
|
|
/// free-form `orderstatus` string.
|
|
///
|
|
/// Status used to be compared as raw string literals in ~90 places, with
|
|
/// case-sensitivity landmines (`'active'` vs `'ACTIVE'`) and variant spellings
|
|
/// (`'picked'` / `'picked up'` / `'pickuped'`). This normalizes all of that in
|
|
/// one place so filters agree everywhere.
|
|
///
|
|
/// NOTE: this is the *read* side. The status-change API still sends its own
|
|
/// protocol verbs (`ACCEPTED`/`ARRIVED`/`PICKED`/`REJECTED`/`CANCELLED`) — see
|
|
/// [OrderAction] for those canonical write values.
|
|
enum StopStatus {
|
|
newStop,
|
|
assigned,
|
|
accepted,
|
|
active,
|
|
arrived,
|
|
picked,
|
|
skipped,
|
|
cancelled,
|
|
rejected,
|
|
unknown,
|
|
}
|
|
|
|
/// Normalizes any raw `orderstatus` value (case-insensitive, trimmed, variant
|
|
/// spellings folded) into a [StopStatus].
|
|
StopStatus stopStatusFromRaw(dynamic raw) {
|
|
final s = (raw?.toString() ?? '').trim().toLowerCase();
|
|
switch (s) {
|
|
case 'new':
|
|
return StopStatus.newStop;
|
|
case 'assigned':
|
|
case 'miler_assigned':
|
|
case 'pending':
|
|
return StopStatus.assigned;
|
|
case 'accepted':
|
|
return StopStatus.accepted;
|
|
case 'active':
|
|
return StopStatus.active;
|
|
case 'arrived':
|
|
return StopStatus.arrived;
|
|
case 'picked':
|
|
case 'picked up':
|
|
case 'pickuped':
|
|
case 'pickedup':
|
|
return StopStatus.picked;
|
|
case 'skipped':
|
|
return StopStatus.skipped;
|
|
case 'cancelled':
|
|
case 'canceled':
|
|
return StopStatus.cancelled;
|
|
case 'rejected':
|
|
return StopStatus.rejected;
|
|
default:
|
|
return StopStatus.unknown;
|
|
}
|
|
}
|
|
|
|
/// Parse straight from a booking map's `orderstatus`.
|
|
StopStatus stopStatusOf(Map<String, dynamic> booking) =>
|
|
stopStatusFromRaw(booking['orderstatus']);
|
|
|
|
extension StopStatusX on StopStatus {
|
|
bool get isPicked => this == StopStatus.picked;
|
|
bool get isCancelled => this == StopStatus.cancelled;
|
|
bool get isSkipped => this == StopStatus.skipped;
|
|
bool get isActive => this == StopStatus.active;
|
|
bool get isRejected => this == StopStatus.rejected;
|
|
|
|
/// A completed pickup — picked up or cancelled. (Matches the long-standing
|
|
/// `!= 'picked' && != 'picked up' && != 'cancelled'` filter used to build the
|
|
/// "next stops" and remaining-pickups lists.)
|
|
bool get isFinishedPickup =>
|
|
this == StopStatus.picked || this == StopStatus.cancelled;
|
|
|
|
/// Still awaiting the rider's acceptance — belongs on Home, not Bookings.
|
|
bool get isPending =>
|
|
this == StopStatus.newStop || this == StopStatus.assigned;
|
|
|
|
/// What this state is *called*, in the rider's words.
|
|
///
|
|
/// The status vocabulary had been re-invented per widget: the live banner had
|
|
/// its own switch over raw `orderstatus` strings returning "At pickup" and
|
|
/// "In progress", the trip card wrote 'Accepted' as a literal, and the two
|
|
/// disagreed about the same backend state. A rider moving between Home, the
|
|
/// banner and Bookings was reading three vocabularies for one lifecycle and
|
|
/// re-learning the app at each stop.
|
|
///
|
|
/// One list, here, next to the parser that produces the states — so a new
|
|
/// status cannot be added without someone deciding what to call it.
|
|
String get label => switch (this) {
|
|
StopStatus.newStop => 'New',
|
|
StopStatus.assigned => 'Assigned',
|
|
StopStatus.accepted => 'Accepted',
|
|
StopStatus.active => 'In progress',
|
|
StopStatus.arrived => 'At the stop',
|
|
StopStatus.picked => 'Completed',
|
|
StopStatus.skipped => 'Skipped',
|
|
StopStatus.cancelled => 'Cancelled',
|
|
StopStatus.rejected => 'Rejected',
|
|
StopStatus.unknown => 'Active',
|
|
};
|
|
}
|
|
|
|
/// Canonical protocol verbs sent to the status-change API (the *write* side).
|
|
class OrderAction {
|
|
static const String accept = 'ACCEPT';
|
|
static const String accepted = 'ACCEPTED';
|
|
static const String arrived = 'ARRIVED';
|
|
static const String picked = 'PICKED';
|
|
static const String rejected = 'REJECTED';
|
|
static const String cancelled = 'CANCELLED';
|
|
}
|