Phase 3.2 docs + Phase 3.1 testing fixes
- Add phase3.2.md requirement: overlay UX, mitra activity log - Add phase3.2-plan.md implementation plan - Fix stale request validation: add GET /:sessionId/status endpoint - Fix notification tap flow: setIncomingFromNotification + onChatRequestTapped - IncomingRequestSheet shows stale message instead of auto-dismiss - Home screen validates on resume, shows immediately on fresh WS Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -130,19 +130,26 @@ class ChatRequest extends _$ChatRequest {
|
||||
}
|
||||
}
|
||||
|
||||
/// Called when user taps a chat_request notification. Sets the incoming state
|
||||
/// with the given session and validates it's still pending.
|
||||
Future<void> setIncomingFromNotification(String sessionId) async {
|
||||
state = ChatRequestIncomingData(sessionId);
|
||||
await validateIncomingRequest();
|
||||
}
|
||||
|
||||
/// Check if the current incoming request is still valid (pending_acceptance).
|
||||
/// If stale, reset to listening state.
|
||||
Future<void> validateIncomingRequest() async {
|
||||
if (state is! ChatRequestIncomingData) return;
|
||||
final sessionId = (state as ChatRequestIncomingData).sessionId;
|
||||
try {
|
||||
final response = await _apiClient.get('/api/shared/chat/$sessionId/info');
|
||||
final response = await _apiClient.get('/api/mitra/chat-requests/$sessionId/status');
|
||||
final status = response['data']?['status'] as String?;
|
||||
if (status != 'pending_acceptance') {
|
||||
state = const ChatRequestListeningData();
|
||||
}
|
||||
} catch (_) {
|
||||
state = const ChatRequestListeningData();
|
||||
// On error, keep current state — don't dismiss valid requests
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -8,6 +8,10 @@ class NotificationService {
|
||||
static final _localNotifications = FlutterLocalNotificationsPlugin();
|
||||
static GoRouter? _router;
|
||||
|
||||
/// Callback for when a chat request notification is tapped.
|
||||
/// Set this from the app to bridge notifications → Riverpod state.
|
||||
static void Function(String sessionId)? onChatRequestTapped;
|
||||
|
||||
static const _channel = AndroidNotificationChannel(
|
||||
'chat_messages',
|
||||
'Chat Messages',
|
||||
@@ -119,8 +123,9 @@ class NotificationService {
|
||||
final type = data['type'] as String?;
|
||||
final action = data['action'] as String?;
|
||||
|
||||
if (type == 'chat_request' && action == 'open_accept') {
|
||||
// Navigate to home where incoming request sheet will show
|
||||
if (type == 'chat_request' && action == 'open_accept' && sessionId != null) {
|
||||
// Update the notifier state with this session, then navigate
|
||||
onChatRequestTapped?.call(sessionId);
|
||||
_router!.go('/home');
|
||||
} else if (type == 'session_closing' || type == 'session_expired') {
|
||||
// Navigate to the chat session closure screen
|
||||
|
||||
@@ -68,16 +68,10 @@ class _HomeScreenState extends ConsumerState<HomeScreen> with WidgetsBindingObse
|
||||
}
|
||||
});
|
||||
|
||||
// Listen for incoming chat requests
|
||||
// Listen for incoming chat requests — fresh from WS, show immediately
|
||||
ref.listen(chatRequestProvider, (prev, next) {
|
||||
if (next is ChatRequestIncomingData) {
|
||||
// Validate request is still pending before showing sheet
|
||||
ref.read(chatRequestProvider.notifier).validateIncomingRequest().then((_) {
|
||||
final current = ref.read(chatRequestProvider);
|
||||
if (current is ChatRequestIncomingData) {
|
||||
_showIncomingRequest(current.sessionId);
|
||||
}
|
||||
});
|
||||
_showIncomingRequest(next.sessionId);
|
||||
} else if (next is ChatRequestAcceptedData) {
|
||||
final session = next.session;
|
||||
final sessionId = session['session_id'] as String? ?? session['id'] as String;
|
||||
|
||||
@@ -5,6 +5,7 @@ import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'core/api/api_client_provider.dart';
|
||||
import 'core/auth/auth_notifier.dart';
|
||||
import 'core/status/status_notifier.dart';
|
||||
import 'core/chat/chat_request_notifier.dart';
|
||||
import 'core/notifications/notification_service.dart';
|
||||
import 'firebase_options.dart';
|
||||
import 'router.dart';
|
||||
@@ -78,6 +79,9 @@ class _AppState extends ConsumerState<App> with WidgetsBindingObserver {
|
||||
|
||||
final router = ref.watch(routerProvider);
|
||||
NotificationService.initialize(router);
|
||||
NotificationService.onChatRequestTapped = (sessionId) {
|
||||
ref.read(chatRequestProvider.notifier).setIncomingFromNotification(sessionId);
|
||||
};
|
||||
|
||||
return MaterialApp.router(
|
||||
title: 'Halo Bestie Mitra',
|
||||
|
||||
Reference in New Issue
Block a user