From b47c68b63a7a92a9ada7b09fdbdeebaff208bb20 Mon Sep 17 00:00:00 2001 From: John Mizerek Date: Fri, 23 Jan 2026 21:08:39 -0800 Subject: [PATCH] Fix type casting in order history and order detail models Handle string/int/null values safely in JSON parsing Co-Authored-By: Claude Opus 4.5 --- lib/models/order_detail.dart | 55 +++++++++++++++++----------- lib/models/order_history.dart | 30 ++++++++------- lib/screens/address_list_screen.dart | 2 + lib/screens/cart_view_screen.dart | 2 +- 4 files changed, 53 insertions(+), 36 deletions(-) diff --git a/lib/models/order_detail.dart b/lib/models/order_detail.dart index b0a5a34..20beed0 100644 --- a/lib/models/order_detail.dart +++ b/lib/models/order_detail.dart @@ -43,22 +43,23 @@ class OrderDetail { }); factory OrderDetail.fromJson(Map json) { + String safeStr(dynamic v) => v?.toString() ?? ''; final lineItemsJson = json['LineItems'] as List? ?? []; final staffJson = json['Staff'] as List? ?? []; return OrderDetail( orderId: _parseInt(json['OrderID']) ?? 0, businessId: _parseInt(json['BusinessID']) ?? 0, - businessName: (json['BusinessName'] as String?) ?? '', + businessName: safeStr(json['BusinessName']), status: _parseInt(json['Status']) ?? 0, - statusText: (json['StatusText'] as String?) ?? '', + statusText: safeStr(json['StatusText']), orderTypeId: _parseInt(json['OrderTypeID']) ?? 0, - orderTypeName: (json['OrderTypeName'] as String?) ?? '', + orderTypeName: safeStr(json['OrderTypeName']), subtotal: _parseDouble(json['Subtotal']) ?? 0.0, tax: _parseDouble(json['Tax']) ?? 0.0, tip: _parseDouble(json['Tip']) ?? 0.0, total: _parseDouble(json['Total']) ?? 0.0, - notes: (json['Notes'] as String?) ?? '', + notes: safeStr(json['Notes']), createdOn: _parseDateTime(json['CreatedOn']), submittedOn: _parseDateTimeNullable(json['SubmittedOn']), updatedOn: _parseDateTimeNullable(json['UpdatedOn']), @@ -135,14 +136,17 @@ class OrderCustomer { factory OrderCustomer.fromJson(Map json) { return OrderCustomer( - userId: (json['UserID'] as num?)?.toInt() ?? 0, - firstName: (json['FirstName'] as String?) ?? '', - lastName: (json['LastName'] as String?) ?? '', - phone: (json['Phone'] as String?) ?? '', - email: (json['Email'] as String?) ?? '', + userId: _safeInt(json['UserID']), + firstName: _safeStr(json['FirstName']), + lastName: _safeStr(json['LastName']), + phone: _safeStr(json['Phone']), + email: _safeStr(json['Email']), ); } + static int _safeInt(dynamic v) => v is int ? v : int.tryParse(v?.toString() ?? '') ?? 0; + static String _safeStr(dynamic v) => v?.toString() ?? ''; + String get fullName { final parts = [firstName, lastName].where((s) => s.isNotEmpty); return parts.isEmpty ? 'Guest' : parts.join(' '); @@ -161,10 +165,12 @@ class OrderServicePoint { }); factory OrderServicePoint.fromJson(Map json) { + int safeInt(dynamic v) => v is int ? v : int.tryParse(v?.toString() ?? '') ?? 0; + String safeStr(dynamic v) => v?.toString() ?? ''; return OrderServicePoint( - servicePointId: (json['ServicePointID'] as num?)?.toInt() ?? 0, - name: (json['Name'] as String?) ?? '', - typeId: (json['TypeID'] as num?)?.toInt() ?? 0, + servicePointId: safeInt(json['ServicePointID']), + name: safeStr(json['Name']), + typeId: safeInt(json['TypeID']), ); } } @@ -181,10 +187,12 @@ class OrderStaff { }); factory OrderStaff.fromJson(Map json) { + int safeInt(dynamic v) => v is int ? v : int.tryParse(v?.toString() ?? '') ?? 0; + String safeStr(dynamic v) => v?.toString() ?? ''; return OrderStaff( - userId: (json['UserID'] as num?)?.toInt() ?? 0, - firstName: (json['FirstName'] as String?) ?? '', - avatarUrl: (json['AvatarUrl'] as String?) ?? '', + userId: safeInt(json['UserID']), + firstName: safeStr(json['FirstName']), + avatarUrl: safeStr(json['AvatarUrl']), ); } } @@ -213,16 +221,19 @@ class OrderLineItemDetail { }); factory OrderLineItemDetail.fromJson(Map json) { + int safeInt(dynamic v) => v is int ? v : int.tryParse(v?.toString() ?? '') ?? 0; + double safeDouble(dynamic v) => v is num ? v.toDouble() : double.tryParse(v?.toString() ?? '') ?? 0.0; + String safeStr(dynamic v) => v?.toString() ?? ''; final modifiersJson = json['Modifiers'] as List? ?? []; return OrderLineItemDetail( - lineItemId: (json['LineItemID'] as num?)?.toInt() ?? 0, - itemId: (json['ItemID'] as num?)?.toInt() ?? 0, - parentLineItemId: (json['ParentLineItemID'] as num?)?.toInt() ?? 0, - itemName: (json['ItemName'] as String?) ?? '', - quantity: (json['Quantity'] as num?)?.toInt() ?? 1, - unitPrice: (json['UnitPrice'] as num?)?.toDouble() ?? 0.0, - remarks: (json['Remarks'] as String?) ?? '', + lineItemId: safeInt(json['LineItemID']), + itemId: safeInt(json['ItemID']), + parentLineItemId: safeInt(json['ParentLineItemID']), + itemName: safeStr(json['ItemName']), + quantity: safeInt(json['Quantity']), + unitPrice: safeDouble(json['UnitPrice']), + remarks: safeStr(json['Remarks']), isDefault: json['IsDefault'] == true, modifiers: modifiersJson .map((e) => OrderLineItemDetail.fromJson(e as Map)) diff --git a/lib/models/order_history.dart b/lib/models/order_history.dart index 35f73c1..847f027 100644 --- a/lib/models/order_history.dart +++ b/lib/models/order_history.dart @@ -28,20 +28,24 @@ class OrderHistoryItem { }); factory OrderHistoryItem.fromJson(Map json) { + int parseId(dynamic val) => val is int ? val : int.tryParse(val.toString()) ?? 0; + double parseDouble(dynamic val) => val is num ? val.toDouble() : double.tryParse(val.toString()) ?? 0.0; + String parseStr(dynamic val) => val?.toString() ?? ""; + return OrderHistoryItem( - orderId: (json["OrderID"] as num).toInt(), - orderUuid: json["OrderUUID"] as String? ?? "", - businessId: (json["BusinessID"] as num).toInt(), - businessName: json["BusinessName"] as String? ?? "Unknown", - total: (json["OrderTotal"] as num?)?.toDouble() ?? 0.0, - statusId: (json["OrderStatusID"] as num).toInt(), - statusName: json["StatusName"] as String? ?? "Unknown", - orderTypeId: (json["OrderTypeID"] as num?)?.toInt() ?? 0, - typeName: json["TypeName"] as String? ?? "Unknown", - itemCount: (json["ItemCount"] as num?)?.toInt() ?? 0, - createdAt: DateTime.tryParse(json["CreatedAt"] as String? ?? "") ?? DateTime.now(), - completedAt: json["CompletedAt"] != null && (json["CompletedAt"] as String).isNotEmpty - ? DateTime.tryParse(json["CompletedAt"] as String) + orderId: parseId(json["OrderID"]), + orderUuid: parseStr(json["OrderUUID"]), + businessId: parseId(json["BusinessID"]), + businessName: parseStr(json["BusinessName"]).isEmpty ? "Unknown" : parseStr(json["BusinessName"]), + total: parseDouble(json["OrderTotal"]), + statusId: parseId(json["OrderStatusID"]), + statusName: parseStr(json["StatusName"]).isEmpty ? "Unknown" : parseStr(json["StatusName"]), + orderTypeId: parseId(json["OrderTypeID"]), + typeName: parseStr(json["TypeName"]).isEmpty ? "Unknown" : parseStr(json["TypeName"]), + itemCount: parseId(json["ItemCount"]), + createdAt: DateTime.tryParse(parseStr(json["CreatedAt"])) ?? DateTime.now(), + completedAt: parseStr(json["CompletedAt"]).isNotEmpty + ? DateTime.tryParse(parseStr(json["CompletedAt"])) : null, ); } diff --git a/lib/screens/address_list_screen.dart b/lib/screens/address_list_screen.dart index 42fc95a..313eaf3 100644 --- a/lib/screens/address_list_screen.dart +++ b/lib/screens/address_list_screen.dart @@ -183,6 +183,8 @@ class _AddressListScreenState extends State { _error!, textAlign: TextAlign.center, style: Theme.of(context).textTheme.bodySmall, + maxLines: 3, + overflow: TextOverflow.ellipsis, ), const SizedBox(height: 24), FilledButton.icon( diff --git a/lib/screens/cart_view_screen.dart b/lib/screens/cart_view_screen.dart index 519db2b..cfac4d9 100644 --- a/lib/screens/cart_view_screen.dart +++ b/lib/screens/cart_view_screen.dart @@ -561,7 +561,7 @@ class _CartViewScreenState extends State { style: Theme.of(context).textTheme.titleLarge, ), const SizedBox(height: 8), - Text(_error!, textAlign: TextAlign.center), + Text(_error!, textAlign: TextAlign.center, maxLines: 3, overflow: TextOverflow.ellipsis), const SizedBox(height: 16), ElevatedButton( onPressed: _loadCart,