Skip to content

Commit 5395fe5

Browse files
committed
feat(account): implement read items deletion for in-app notification center
- Add event handler for deleting read notifications in the current tab - Implement optimistic UI update to remove read items immediately - Perform actual deletion in the background - Handle empty read notifications scenario - Log errors without reverting state to avoid UI flicker
1 parent 206c765 commit 5395fe5

File tree

1 file changed

+52
-0
lines changed

1 file changed

+52
-0
lines changed

lib/account/bloc/in_app_notification_center_bloc.dart

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ class InAppNotificationCenterBloc
4343
_onFetchMoreRequested,
4444
transformer: droppable(),
4545
);
46+
on<InAppNotificationCenterReadItemsDeleted>(_onReadItemsDeleted);
4647
}
4748

4849
/// The number of notifications to fetch per page.
@@ -334,6 +335,57 @@ class InAppNotificationCenterBloc
334335
}
335336
}
336337

338+
/// Handles deleting all read notifications in the current tab.
339+
Future<void> _onReadItemsDeleted(
340+
InAppNotificationCenterReadItemsDeleted event,
341+
Emitter<InAppNotificationCenterState> emit,
342+
) async {
343+
344+
final userId = _appBloc.state.user?.id;
345+
final isBreakingNewsTab = state.currentTabIndex == 0;
346+
final notificationsForTab = isBreakingNewsTab
347+
? state.breakingNewsNotifications
348+
: state.digestNotifications;
349+
350+
final readNotifications =
351+
notificationsForTab.where((n) => n.isRead).toList();
352+
353+
if (readNotifications.isEmpty) {
354+
_logger.info('No read notifications to delete in the current tab.');
355+
return;
356+
}
357+
358+
final idsToDelete = readNotifications.map((n) => n.id).toList();
359+
360+
// Optimistic UI update: remove the read items from the state immediately.
361+
if (isBreakingNewsTab) {
362+
final updatedList =
363+
state.breakingNewsNotifications.where((n) => !n.isRead).toList();
364+
emit(state.copyWith(breakingNewsNotifications: updatedList));
365+
} else {
366+
final updatedList =
367+
state.digestNotifications.where((n) => !n.isRead).toList();
368+
emit(state.copyWith(digestNotifications: updatedList));
369+
}
370+
371+
_logger.info(
372+
'Optimistically removed ${idsToDelete.length} read notifications from UI. '
373+
'Deleting from repository in the background.',
374+
);
375+
376+
// Perform the actual deletion in the background.
377+
try {
378+
await Future.wait(
379+
idsToDelete.map(
380+
(id) => _inAppNotificationRepository.delete(id: id, userId: userId),
381+
),
382+
);
383+
} catch (e, s) {
384+
_logger.severe('Failed to delete one or more notifications.', e, s);
385+
// Do not revert state to avoid UI flicker. The error is logged.
386+
}
387+
}
388+
337389
/// A generic method to fetch notifications based on a filter.
338390
Future<PaginatedResponse<InAppNotification>> _fetchNotifications({
339391
required String userId,

0 commit comments

Comments
 (0)