From e1f072611e20cce7f34bfb07ecf7a8078c9a6f6b Mon Sep 17 00:00:00 2001 From: Umberto Pepato Date: Mon, 29 Jan 2024 21:51:24 +0100 Subject: [PATCH] feat(notifications): ensure course files notifs cleared on screen blur --- src/core/hooks/useOnLeaveScreen.ts | 38 +++++++++++++++++++ .../courses/components/CourseFileListItem.tsx | 2 +- .../courses/screens/CourseDirectoryScreen.tsx | 2 +- .../courses/screens/CourseFilesScreen.tsx | 10 ++++- 4 files changed, 48 insertions(+), 4 deletions(-) create mode 100644 src/core/hooks/useOnLeaveScreen.ts diff --git a/src/core/hooks/useOnLeaveScreen.ts b/src/core/hooks/useOnLeaveScreen.ts new file mode 100644 index 00000000..48d449eb --- /dev/null +++ b/src/core/hooks/useOnLeaveScreen.ts @@ -0,0 +1,38 @@ +import { useCallback, useEffect, useState } from 'react'; + +import { useFocusEffect, useNavigation } from '@react-navigation/native'; + +/** + * Runs `onLeave` when the user leaves the current screen, optionally checking + * if the user spent at least `delay` ms in the screen + */ +export const useOnLeaveScreen = ( + /** + * Callback + */ + onLeave: () => void, + /** + * Don't fire the event if the user stayed in the page less than `delay` ms + */ + delay = 2000, +) => { + const { addListener } = useNavigation(); + const [focusedAt, setFocusedAt] = useState(); + + useFocusEffect( + useCallback(() => { + if (!focusedAt) { + setFocusedAt(+new Date()); + } + }, [focusedAt]), + ); + + useEffect(() => { + return addListener('beforeRemove', () => { + if (!delay || +new Date() - focusedAt! >= delay) { + onLeave(); + setFocusedAt(undefined); + } + }); + }, [addListener, delay, focusedAt, onLeave]); +}; diff --git a/src/features/courses/components/CourseFileListItem.tsx b/src/features/courses/components/CourseFileListItem.tsx index fc700bd4..97ab3186 100644 --- a/src/features/courses/components/CourseFileListItem.tsx +++ b/src/features/courses/components/CourseFileListItem.tsx @@ -245,7 +245,7 @@ export const CourseFileListItem = ({ onPress={downloadFile} isDownloaded={isDownloaded} downloadProgress={downloadProgress} - title={item.name ?? t('common.unnamedFile')} + title={`#${item.id} ` + item.name ?? t('common.unnamedFile')} subtitle={metrics} trailingItem={trailingItem} mimeType={item.mimeType} diff --git a/src/features/courses/screens/CourseDirectoryScreen.tsx b/src/features/courses/screens/CourseDirectoryScreen.tsx index b04bd8d0..70db3ca5 100644 --- a/src/features/courses/screens/CourseDirectoryScreen.tsx +++ b/src/features/courses/screens/CourseDirectoryScreen.tsx @@ -60,7 +60,7 @@ export const CourseDirectoryScreen = ({ route, navigation }: Props) => { onChangeText: e => setSearchFilter(e.nativeEvent.text), }, }); - }, [directoryName]); + }, [directoryName, navigation, t]); return ( diff --git a/src/features/courses/screens/CourseFilesScreen.tsx b/src/features/courses/screens/CourseFilesScreen.tsx index c1a76333..574d126d 100644 --- a/src/features/courses/screens/CourseFilesScreen.tsx +++ b/src/features/courses/screens/CourseFilesScreen.tsx @@ -12,6 +12,8 @@ import { MaterialTopTabScreenProps } from '@react-navigation/material-top-tabs'; import { useFocusEffect } from '@react-navigation/native'; import { BottomBarSpacer } from '../../../core/components/BottomBarSpacer'; +import { useNotifications } from '../../../core/hooks/useNotifications'; +import { useOnLeaveScreen } from '../../../core/hooks/useOnLeaveScreen'; import { useSafeAreaSpacing } from '../../../core/hooks/useSafeAreaSpacing'; import { useVisibleFlatListItems } from '../../../core/hooks/useVisibleFlatListItems'; import { useGetCourseFilesRecent } from '../../../core/queries/courseHooks'; @@ -34,12 +36,16 @@ export const CourseFilesScreen = ({ navigation }: Props) => { const { paddingHorizontal } = useSafeAreaSpacing(); const { visibleItemsIndexes, ...visibleItemsFlatListProps } = useVisibleFlatListItems(); + const { clearNotificationScope } = useNotifications(); + + useOnLeaveScreen(() => { + clearNotificationScope(['teaching', 'courses', courseId, 'files']); + }); useFocusEffect( useCallback(() => { refresh(); - // eslint-disable-next-line react-hooks/exhaustive-deps - }, []), + }, [refresh]), ); return (