Phase 3: closing-overlay fix + goodbye-composer dedupe

Customer chat refreshSessionStatus now clears sessionExpired carryover so the
goodbye composer renders correctly when re-opening a closing session from
history. Backend /api/shared/chat/:id/info returns goodbye_submitted_by_me;
both apps suppress the composer for the side that has already submitted and
render an awaiting-banner view instead.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-27 13:43:19 +08:00
parent 05ab1e10df
commit 6801001b64
6 changed files with 157 additions and 10 deletions

View File

@@ -30,6 +30,7 @@ class ChatConnectedData extends ChatData {
final bool sessionExpired;
final bool sessionPaused;
final bool sessionClosing;
final bool goodbyeSubmitted;
final Map<String, dynamic>? extensionResponse;
const ChatConnectedData({
@@ -39,6 +40,7 @@ class ChatConnectedData extends ChatData {
this.sessionExpired = false,
this.sessionPaused = false,
this.sessionClosing = false,
this.goodbyeSubmitted = false,
this.extensionResponse,
});
@@ -49,6 +51,7 @@ class ChatConnectedData extends ChatData {
bool? sessionExpired,
bool? sessionPaused,
bool? sessionClosing,
bool? goodbyeSubmitted,
Map<String, dynamic>? extensionResponse,
}) {
return ChatConnectedData(
@@ -58,6 +61,7 @@ class ChatConnectedData extends ChatData {
sessionExpired: sessionExpired ?? this.sessionExpired,
sessionPaused: sessionPaused ?? this.sessionPaused,
sessionClosing: sessionClosing ?? this.sessionClosing,
goodbyeSubmitted: goodbyeSubmitted ?? this.goodbyeSubmitted,
extensionResponse: extensionResponse ?? this.extensionResponse,
);
}
@@ -150,8 +154,12 @@ class Chat extends _$Chat {
state = current.copyWith(sessionExpired: true);
return;
}
final goodbyeSubmittedByMe = data?['goodbye_submitted_by_me'] as bool? ?? false;
state = current.copyWith(
sessionClosing: status == SessionStatus.closing,
sessionPaused: status == SessionStatus.extending,
sessionExpired: false,
goodbyeSubmitted: goodbyeSubmittedByMe,
);
} catch (e) {
// ignore: avoid_print
@@ -175,6 +183,7 @@ class Chat extends _$Chat {
}
final isClosing = sessionStatus == SessionStatus.closing;
final goodbyeSubmittedByMe = sessionData?['goodbye_submitted_by_me'] as bool? ?? false;
final response = await _apiClient.get('/api/shared/chat/$sessionId/messages');
final messagesData = response['data'] as List<dynamic>;
@@ -215,6 +224,7 @@ class Chat extends _$Chat {
state = ChatConnectedData(
messages: messages,
sessionClosing: isClosing,
goodbyeSubmitted: goodbyeSubmittedByMe,
);
} catch (e) {
state = const ChatErrorData('Gagal terhubung ke chat.');