Phase 3.1: Local notification for WS chat requests, router fix, cleanup

- Show local notification (sound + vibrate) when chat_request arrives
  via WebSocket while mitra app is backgrounded
- Add NotificationService.showLocalNotification() for programmatic use
- Fix router redirect: don't redirect auth routes to splash during loading
- Handle binary/string WebSocket frames in ChatRequestNotifier
- Remove debug logging from backend and Flutter
- Control center: mitra ping config UI
- Both apps: dynamic ping, FCM deep-linking, unread badges

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-09 14:57:36 +08:00
parent 1b249e34b0
commit 2e80434e9b
2 changed files with 45 additions and 4 deletions

View File

@@ -7,6 +7,7 @@ import 'package:web_socket_channel/web_socket_channel.dart';
import '../api/api_client.dart';
import '../api/api_client_provider.dart';
import '../constants.dart';
import '../notifications/notification_service.dart';
part 'chat_request_notifier.g.dart';
@@ -77,9 +78,12 @@ class ChatRequest extends _$ChatRequest {
_wsSubscription = _channel!.stream.listen(
(raw) {
final data = jsonDecode(raw as String) as Map<String, dynamic>;
if (data['type'] == WsMessage.authOk) return;
_onRequestReceived(data);
try {
final text = raw is String ? raw : String.fromCharCodes(raw as List<int>);
final data = jsonDecode(text) as Map<String, dynamic>;
if (data['type'] == WsMessage.authOk) return;
_onRequestReceived(data);
} catch (_) {}
},
onError: (_) => _onConnectionError(),
onDone: () => _onConnectionError(),
@@ -105,7 +109,14 @@ class ChatRequest extends _$ChatRequest {
final type = data['type'] as String?;
if (type == WsMessage.chatRequest) {
state = ChatRequestIncomingData(data['session_id'] as String);
final sessionId = data['session_id'] as String;
state = ChatRequestIncomingData(sessionId);
// Show local notification so mitra is alerted even when app is backgrounded
NotificationService.showLocalNotification(
title: 'Permintaan Chat Baru',
body: 'Ada pelanggan yang ingin curhat! Ketuk untuk menerima.',
data: {'type': 'chat_request', 'session_id': sessionId, 'action': 'open_accept'},
);
} else if (type == WsMessage.chatRequestClosed) {
if (state is ChatRequestIncomingData) {
state = const ChatRequestListeningData();