Add pending chat requests CTA on mitra home screen

- Backend: new GET /api/mitra/chat-requests/pending endpoint
- Backend: getPendingRequestsForMitra() queries unresponded notifications
  for sessions still in pending_acceptance status
- Mitra app: loadPendingRequests() fetches on screen load + status toggle
- Mitra app: activeRequestCount getter exposes queue size
- Mitra app: _PendingRequestsBanner widget shows count with tap-to-view

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-10 21:21:00 +08:00
parent b043b92b57
commit 1920507ec5
4 changed files with 124 additions and 1 deletions

View File

@@ -72,9 +72,54 @@ class ChatRequest extends _$ChatRequest {
ApiClient get _apiClient => ref.read(apiClientProvider);
/// Number of active requests (currently displayed + queued).
int get activeRequestCount {
final current = state is ChatRequestIncomingData ? 1 : 0;
return current + _pendingQueue.length;
}
@override
ChatRequestData build() => const ChatRequestIdleData();
/// Fetch pending requests from backend and populate the queue.
Future<void> loadPendingRequests() async {
try {
final response = await _apiClient.get('/api/mitra/chat-requests/pending');
final requests = response['data'] as List<dynamic>;
if (requests.isEmpty) return;
for (final r in requests) {
final sessionId = r['session_id'] as String;
// Skip if already showing or queued
if (state is ChatRequestIncomingData &&
(state as ChatRequestIncomingData).sessionId == sessionId) continue;
if (_pendingQueue.any((q) => q['session_id'] == sessionId)) continue;
final data = {
'session_id': sessionId,
'duration_minutes': r['duration_minutes'],
'is_free_trial': r['is_free_trial'],
'created_at': r['created_at'],
};
if (state is ChatRequestIncomingData ||
state is ChatRequestStaleData ||
state is ChatRequestAcceptingData) {
_pendingQueue.add(data);
} else {
state = ChatRequestIncomingData(
sessionId,
durationMinutes: r['duration_minutes'] as int?,
isFreeTrial: r['is_free_trial'] as bool?,
createdAt: r['created_at'] != null
? DateTime.tryParse(r['created_at'] as String)
: null,
);
}
}
} catch (_) {}
}
Future<void> startListening() async {
// Don't reset state if showing a request, stale message, or actively accepting
if (state is ChatRequestIncomingData ||