Phase 3: session-end UX overhaul + closing-grace cleanup
Promotes the customer-side chat WebSocket to active-session-scoped (driven by a new `activeSessionProvider`) so home reflects session state in real time without a per-screen connection. Backend now auto-completes sessions left in `closing` after a 5-minute grace window so abandoned goodbye flows don't leave the customer's home permanently locked. Customer: - New `activeSessionProvider` (replaces `unread_notifier`) — single source of truth for the active session + unread count; polled every 15s. - Chat WS lifecycle moved to `main.dart` listener on activeSessionProvider. Chat screen joins via `connectIfNotConnected`; the new `refreshSessionStatus` reconciles flags from the server when re-entering an already-connected session (covers missed `sessionClosing`/`sessionExpired` WS events). - Home filters `closing` from the "Sesi Aktif" CTA so a session pending goodbye doesn't block "Mulai Curhat". - Timer-expired UX is a non-dismissible modal (Tutup / Perpanjang) instead of an inline bar. - Early-end goodbye composer gets an amber "Sesi telah ditutup oleh Bestie" banner. Goodbye TextEditingController lifted to state so focus changes no longer wipe the message. - Closure provider reset on chat_screen mount to avoid stale `ClosureCompleteData` from a previous session leaking into a new view. - Chat history now lists `closing` sessions with a "Belum ditutup" badge that routes to the live chat (goodbye composer) instead of the transcript. Mitra: - Same goodbye-controller fix as customer. - Same chat-history badge + routing for `closing` items. Backend: - New `EndedBy.SYSTEM_AUTO_CLOSE` constant. - `startClosureGraceTimer` extracted in `session-timer.service.js`; wired in from `closure.initiateEarlyEnd`, `extension.rejectExtension`, and `extension.handleExtensionTimeout`. Cancelled when customer submits goodbye. - Restart recovery (`restoreActiveTimers`) re-arms grace timers and stamps any orphaned `closing` rows with `system_auto_close`. - `getCustomerHistory` / `getMitraHistory` include `closing` alongside `completed`; ordering uses `COALESCE(ended_at, created_at)`. Removed: dead `session_active_screen.dart` (no router entry). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -4,6 +4,8 @@ import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'core/api/api_client_provider.dart';
|
||||
import 'core/auth/auth_notifier.dart';
|
||||
import 'core/chat/active_session_notifier.dart';
|
||||
import 'core/chat/chat_notifier.dart';
|
||||
import 'core/notifications/notification_service.dart';
|
||||
import 'firebase_options.dart';
|
||||
import 'router.dart';
|
||||
@@ -45,10 +47,33 @@ class _AppState extends ConsumerState<App> {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
// FCM registration on auth.
|
||||
ref.listen(authProvider, (prev, next) {
|
||||
final data = next.valueOrNull;
|
||||
if (data is AuthAuthenticatedData || data is AuthAnonymousData) {
|
||||
_registerFcmToken();
|
||||
} else {
|
||||
// Logged out (or initial) — ensure the chat WS is closed.
|
||||
ref.read(chatProvider.notifier).disconnect();
|
||||
}
|
||||
});
|
||||
|
||||
// Global chat WebSocket lifecycle: connect whenever the user has an
|
||||
// active session, regardless of which screen is mounted. The chat screen
|
||||
// only joins this connection — it doesn't own it. FCM remains the
|
||||
// background-only fallback.
|
||||
ref.listen(activeSessionProvider, (prev, next) {
|
||||
final snapshot = next.valueOrNull;
|
||||
final notifier = ref.read(chatProvider.notifier);
|
||||
if (snapshot == null || !snapshot.hasSession) {
|
||||
if (notifier.connectedSessionId != null) {
|
||||
notifier.disconnect();
|
||||
}
|
||||
return;
|
||||
}
|
||||
final sessionId = snapshot.sessionId;
|
||||
if (sessionId != null && notifier.connectedSessionId != sessionId) {
|
||||
notifier.connectIfNotConnected(sessionId);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user