payfrit-app/lib/services/order_polling_service.dart
John Mizerek 029c924f41 Fix order status polling and improve notifications
- Reduce polling interval from 30s to 6s for faster updates
- Add global ScaffoldMessengerKey for app-wide snackbar notifications
- Fix notifications showing after cart screen is dismissed
- Add JSON parsing fallback to handle server debug output
- Standardize all gradient heights to 16px

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-01 19:48:42 -08:00

114 lines
3.3 KiB
Dart
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import 'dart:async';
import 'package:flutter/material.dart';
import 'api.dart';
/// Service that polls the backend API for order status updates
/// Uses a simple polling approach with 6-second intervals for responsive updates
class OrderPollingService {
static Timer? _pollingTimer;
static int? _currentOrderId;
static int? _lastKnownStatusId;
static Function(OrderStatusUpdate)? _onStatusUpdate;
/// Start polling for order status updates
static void startPolling({
required int orderId,
required int initialStatusId,
required Function(OrderStatusUpdate) onStatusUpdate,
}) {
print('[OrderPolling] 🔄 Starting polling for OrderID=$orderId, Status=$initialStatusId');
// Stop any existing polling
stopPolling();
_currentOrderId = orderId;
_lastKnownStatusId = initialStatusId;
_onStatusUpdate = onStatusUpdate;
// Poll every 6 seconds for responsive updates
_pollingTimer = Timer.periodic(const Duration(seconds: 6), (_) {
_checkForUpdate();
});
// Also check immediately
_checkForUpdate();
}
/// Stop polling
static void stopPolling() {
print('[OrderPolling] ⏹️ Stopping polling');
_pollingTimer?.cancel();
_pollingTimer = null;
_currentOrderId = null;
_lastKnownStatusId = null;
_onStatusUpdate = null;
}
/// Check if currently polling
static bool get isPolling => _pollingTimer != null && _pollingTimer!.isActive;
/// Get current order ID being polled
static int? get currentOrderId => _currentOrderId;
/// Internal method to check for updates
static Future<void> _checkForUpdate() async {
if (_currentOrderId == null || _lastKnownStatusId == null) {
print('[OrderPolling] ⚠️ No order to poll, stopping');
stopPolling();
return;
}
try {
print('[OrderPolling] 🔍 Checking status for OrderID=$_currentOrderId');
final data = await Api.checkOrderStatus(
orderId: _currentOrderId!,
lastKnownStatusId: _lastKnownStatusId!,
);
if (data['OK'] == true && data['HAS_UPDATE'] == true) {
final orderStatus = data['ORDER_STATUS'];
final newStatusId = (orderStatus['StatusID'] as num).toInt();
final statusName = orderStatus['StatusName'] as String;
final message = orderStatus['Message'] as String;
print('[OrderPolling] ✅ Status update detected: $statusName (ID=$newStatusId)');
// Update last known status
_lastKnownStatusId = newStatusId;
// Notify listener
if (_onStatusUpdate != null) {
_onStatusUpdate!(OrderStatusUpdate(
orderId: _currentOrderId!,
statusId: newStatusId,
statusName: statusName,
message: message,
));
}
} else {
print('[OrderPolling] No status update');
}
} catch (e) {
print('[OrderPolling] ❌ Error checking status: $e');
}
}
}
/// Data class representing an order status update
class OrderStatusUpdate {
final int orderId;
final int statusId;
final String statusName;
final String message;
const OrderStatusUpdate({
required this.orderId,
required this.statusId,
required this.statusName,
required this.message,
});
@override
String toString() => 'OrderStatusUpdate(orderId: $orderId, statusId: $statusId, statusName: $statusName, message: $message)';
}