[Glitch] Reload notifications when accepted notifications are merged (streaming only)
Port 53c183f899 to glitch-soc
Signed-off-by: Claire <claire.github-309c@sitedethib.com>
			
			
This commit is contained in:
		
							parent
							
								
									99ffae7d44
								
							
						
					
					
						commit
						bfd01110d8
					
				|  | @ -138,8 +138,18 @@ export const processNewNotificationForGroups = createAppAsyncThunk( | ||||||
| 
 | 
 | ||||||
| export const loadPending = createAction('notificationGroups/loadPending'); | export const loadPending = createAction('notificationGroups/loadPending'); | ||||||
| 
 | 
 | ||||||
| export const updateScrollPosition = createAction<{ top: boolean }>( | export const updateScrollPosition = createAppAsyncThunk( | ||||||
|   'notificationGroups/updateScrollPosition', |   'notificationGroups/updateScrollPosition', | ||||||
|  |   ({ top }: { top: boolean }, { dispatch, getState }) => { | ||||||
|  |     if ( | ||||||
|  |       top && | ||||||
|  |       getState().notificationGroups.mergedNotifications === 'needs-reload' | ||||||
|  |     ) { | ||||||
|  |       void dispatch(fetchNotifications()); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     return { top }; | ||||||
|  |   }, | ||||||
| ); | ); | ||||||
| 
 | 
 | ||||||
| export const setNotificationsFilter = createAppAsyncThunk( | export const setNotificationsFilter = createAppAsyncThunk( | ||||||
|  | @ -165,5 +175,34 @@ export const markNotificationsAsRead = createAction( | ||||||
|   'notificationGroups/markAsRead', |   'notificationGroups/markAsRead', | ||||||
| ); | ); | ||||||
| 
 | 
 | ||||||
| export const mountNotifications = createAction('notificationGroups/mount'); | export const mountNotifications = createAppAsyncThunk( | ||||||
|  |   'notificationGroups/mount', | ||||||
|  |   (_, { dispatch, getState }) => { | ||||||
|  |     const state = getState(); | ||||||
|  | 
 | ||||||
|  |     if ( | ||||||
|  |       state.notificationGroups.mounted === 0 && | ||||||
|  |       state.notificationGroups.mergedNotifications === 'needs-reload' | ||||||
|  |     ) { | ||||||
|  |       void dispatch(fetchNotifications()); | ||||||
|  |     } | ||||||
|  |   }, | ||||||
|  | ); | ||||||
|  | 
 | ||||||
| export const unmountNotifications = createAction('notificationGroups/unmount'); | export const unmountNotifications = createAction('notificationGroups/unmount'); | ||||||
|  | 
 | ||||||
|  | export const refreshStaleNotificationGroups = createAppAsyncThunk<{ | ||||||
|  |   deferredRefresh: boolean; | ||||||
|  | }>('notificationGroups/refreshStale', (_, { dispatch, getState }) => { | ||||||
|  |   const state = getState(); | ||||||
|  | 
 | ||||||
|  |   if ( | ||||||
|  |     state.notificationGroups.scrolledToTop || | ||||||
|  |     !state.notificationGroups.mounted | ||||||
|  |   ) { | ||||||
|  |     void dispatch(fetchNotifications()); | ||||||
|  |     return { deferredRefresh: false }; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   return { deferredRefresh: true }; | ||||||
|  | }); | ||||||
|  |  | ||||||
|  | @ -10,7 +10,7 @@ import { | ||||||
|   deleteAnnouncement, |   deleteAnnouncement, | ||||||
| } from './announcements'; | } from './announcements'; | ||||||
| import { updateConversations } from './conversations'; | import { updateConversations } from './conversations'; | ||||||
| import { processNewNotificationForGroups } from './notification_groups'; | import { processNewNotificationForGroups, refreshStaleNotificationGroups } from './notification_groups'; | ||||||
| import { updateNotifications, expandNotifications } from './notifications'; | import { updateNotifications, expandNotifications } from './notifications'; | ||||||
| import { updateStatus } from './statuses'; | import { updateStatus } from './statuses'; | ||||||
| import { | import { | ||||||
|  | @ -108,6 +108,14 @@ export const connectTimelineStream = (timelineId, channelName, params = {}, opti | ||||||
|           } |           } | ||||||
|           break; |           break; | ||||||
|         } |         } | ||||||
|  |         case 'notifications_merged': | ||||||
|  |           const state = getState(); | ||||||
|  |           if (state.notifications.top || !state.notifications.mounted) | ||||||
|  |             dispatch(expandNotifications({ forceLoad: true, maxId: undefined })); | ||||||
|  |           if(state.settings.getIn(['notifications', 'groupingBeta'], false)) { | ||||||
|  |             dispatch(refreshStaleNotificationGroups()); | ||||||
|  |           } | ||||||
|  |           break; | ||||||
|         case 'conversation': |         case 'conversation': | ||||||
|           // @ts-expect-error
 |           // @ts-expect-error
 | ||||||
|           dispatch(updateConversations(JSON.parse(data.payload))); |           dispatch(updateConversations(JSON.parse(data.payload))); | ||||||
|  |  | ||||||
|  | @ -81,7 +81,11 @@ export const Notifications: React.FC<{ | ||||||
| 
 | 
 | ||||||
|   const anyPendingNotification = useAppSelector(selectAnyPendingNotification); |   const anyPendingNotification = useAppSelector(selectAnyPendingNotification); | ||||||
| 
 | 
 | ||||||
|   const isUnread = unreadNotificationsCount > 0; |   const needsReload = useAppSelector( | ||||||
|  |     (state) => state.notificationGroups.mergedNotifications === 'needs-reload', | ||||||
|  |   ); | ||||||
|  | 
 | ||||||
|  |   const isUnread = unreadNotificationsCount > 0 || needsReload; | ||||||
| 
 | 
 | ||||||
|   const canMarkAsRead = |   const canMarkAsRead = | ||||||
|     useAppSelector(selectSettingsNotificationsShowUnread) && |     useAppSelector(selectSettingsNotificationsShowUnread) && | ||||||
|  | @ -118,11 +122,11 @@ export const Notifications: React.FC<{ | ||||||
| 
 | 
 | ||||||
|   // Keep track of mounted components for unread notification handling
 |   // Keep track of mounted components for unread notification handling
 | ||||||
|   useEffect(() => { |   useEffect(() => { | ||||||
|     dispatch(mountNotifications()); |     void dispatch(mountNotifications()); | ||||||
| 
 | 
 | ||||||
|     return () => { |     return () => { | ||||||
|       dispatch(unmountNotifications()); |       dispatch(unmountNotifications()); | ||||||
|       dispatch(updateScrollPosition({ top: false })); |       void dispatch(updateScrollPosition({ top: false })); | ||||||
|     }; |     }; | ||||||
|   }, [dispatch]); |   }, [dispatch]); | ||||||
| 
 | 
 | ||||||
|  | @ -147,11 +151,11 @@ export const Notifications: React.FC<{ | ||||||
|   }, [dispatch]); |   }, [dispatch]); | ||||||
| 
 | 
 | ||||||
|   const handleScrollToTop = useDebouncedCallback(() => { |   const handleScrollToTop = useDebouncedCallback(() => { | ||||||
|     dispatch(updateScrollPosition({ top: true })); |     void dispatch(updateScrollPosition({ top: true })); | ||||||
|   }, 100); |   }, 100); | ||||||
| 
 | 
 | ||||||
|   const handleScroll = useDebouncedCallback(() => { |   const handleScroll = useDebouncedCallback(() => { | ||||||
|     dispatch(updateScrollPosition({ top: false })); |     void dispatch(updateScrollPosition({ top: false })); | ||||||
|   }, 100); |   }, 100); | ||||||
| 
 | 
 | ||||||
|   useEffect(() => { |   useEffect(() => { | ||||||
|  |  | ||||||
|  | @ -19,6 +19,7 @@ import { | ||||||
|   markNotificationsAsRead, |   markNotificationsAsRead, | ||||||
|   mountNotifications, |   mountNotifications, | ||||||
|   unmountNotifications, |   unmountNotifications, | ||||||
|  |   refreshStaleNotificationGroups, | ||||||
| } from 'flavours/glitch/actions/notification_groups'; | } from 'flavours/glitch/actions/notification_groups'; | ||||||
| import { | import { | ||||||
|   disconnectTimeline, |   disconnectTimeline, | ||||||
|  | @ -51,6 +52,7 @@ interface NotificationGroupsState { | ||||||
|   readMarkerId: string; |   readMarkerId: string; | ||||||
|   mounted: number; |   mounted: number; | ||||||
|   isTabVisible: boolean; |   isTabVisible: boolean; | ||||||
|  |   mergedNotifications: 'ok' | 'pending' | 'needs-reload'; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| const initialState: NotificationGroupsState = { | const initialState: NotificationGroupsState = { | ||||||
|  | @ -58,6 +60,8 @@ const initialState: NotificationGroupsState = { | ||||||
|   pendingGroups: [], // holds pending groups in slow mode
 |   pendingGroups: [], // holds pending groups in slow mode
 | ||||||
|   scrolledToTop: false, |   scrolledToTop: false, | ||||||
|   isLoading: false, |   isLoading: false, | ||||||
|  |   // this is used to track whether we need to refresh notifications after accepting requests
 | ||||||
|  |   mergedNotifications: 'ok', | ||||||
|   // The following properties are used to track unread notifications
 |   // The following properties are used to track unread notifications
 | ||||||
|   lastReadId: '0', // used internally for unread notifications
 |   lastReadId: '0', // used internally for unread notifications
 | ||||||
|   readMarkerId: '0', // user-facing and updated when focus changes
 |   readMarkerId: '0', // user-facing and updated when focus changes
 | ||||||
|  | @ -301,6 +305,7 @@ export const notificationGroupsReducer = createReducer<NotificationGroupsState>( | ||||||
|           json.type === 'gap' ? json : createNotificationGroupFromJSON(json), |           json.type === 'gap' ? json : createNotificationGroupFromJSON(json), | ||||||
|         ); |         ); | ||||||
|         state.isLoading = false; |         state.isLoading = false; | ||||||
|  |         state.mergedNotifications = 'ok'; | ||||||
|         updateLastReadId(state); |         updateLastReadId(state); | ||||||
|       }) |       }) | ||||||
|       .addCase(fetchNotificationsGap.fulfilled, (state, action) => { |       .addCase(fetchNotificationsGap.fulfilled, (state, action) => { | ||||||
|  | @ -455,7 +460,7 @@ export const notificationGroupsReducer = createReducer<NotificationGroupsState>( | ||||||
|         state.groups = state.pendingGroups.concat(state.groups); |         state.groups = state.pendingGroups.concat(state.groups); | ||||||
|         state.pendingGroups = []; |         state.pendingGroups = []; | ||||||
|       }) |       }) | ||||||
|       .addCase(updateScrollPosition, (state, action) => { |       .addCase(updateScrollPosition.fulfilled, (state, action) => { | ||||||
|         state.scrolledToTop = action.payload.top; |         state.scrolledToTop = action.payload.top; | ||||||
|         updateLastReadId(state); |         updateLastReadId(state); | ||||||
|         trimNotifications(state); |         trimNotifications(state); | ||||||
|  | @ -482,7 +487,7 @@ export const notificationGroupsReducer = createReducer<NotificationGroupsState>( | ||||||
|             action.payload.markers.notifications.last_read_id; |             action.payload.markers.notifications.last_read_id; | ||||||
|         } |         } | ||||||
|       }) |       }) | ||||||
|       .addCase(mountNotifications, (state) => { |       .addCase(mountNotifications.fulfilled, (state) => { | ||||||
|         state.mounted += 1; |         state.mounted += 1; | ||||||
|         commitLastReadId(state); |         commitLastReadId(state); | ||||||
|         updateLastReadId(state); |         updateLastReadId(state); | ||||||
|  | @ -498,6 +503,10 @@ export const notificationGroupsReducer = createReducer<NotificationGroupsState>( | ||||||
|       .addCase(unfocusApp, (state) => { |       .addCase(unfocusApp, (state) => { | ||||||
|         state.isTabVisible = false; |         state.isTabVisible = false; | ||||||
|       }) |       }) | ||||||
|  |       .addCase(refreshStaleNotificationGroups.fulfilled, (state, action) => { | ||||||
|  |         if (action.payload.deferredRefresh) | ||||||
|  |           state.mergedNotifications = 'needs-reload'; | ||||||
|  |       }) | ||||||
|       .addMatcher( |       .addMatcher( | ||||||
|         isAnyOf(authorizeFollowRequestSuccess, rejectFollowRequestSuccess), |         isAnyOf(authorizeFollowRequestSuccess, rejectFollowRequestSuccess), | ||||||
|         (state, action) => { |         (state, action) => { | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue