Improve notification load behaviors (#1943)
* Dont use the stale cache for notifs-feed * Add a delay to marking all read to avoid marking upcoming posts as read * Trigger automatic notifications refresh when navigating to the tab, in certain conditionszio/stable
parent
357c752a21
commit
e358c3cc30
|
@ -12,7 +12,6 @@ import {getAgent} from '../../session'
|
||||||
import {useModerationOpts} from '../preferences'
|
import {useModerationOpts} from '../preferences'
|
||||||
import {shouldFilterNotif} from './util'
|
import {shouldFilterNotif} from './util'
|
||||||
import {useMutedThreads} from '#/state/muted-threads'
|
import {useMutedThreads} from '#/state/muted-threads'
|
||||||
import {STALE} from '#/state/queries'
|
|
||||||
|
|
||||||
const GROUPABLE_REASONS = ['like', 'repost', 'follow']
|
const GROUPABLE_REASONS = ['like', 'repost', 'follow']
|
||||||
const PAGE_SIZE = 30
|
const PAGE_SIZE = 30
|
||||||
|
@ -60,7 +59,6 @@ export function useNotificationFeedQuery(opts?: {enabled?: boolean}) {
|
||||||
QueryKey,
|
QueryKey,
|
||||||
RQPageParam
|
RQPageParam
|
||||||
>({
|
>({
|
||||||
staleTime: STALE.INFINITY,
|
|
||||||
queryKey: RQKEY(),
|
queryKey: RQKEY(),
|
||||||
async queryFn({pageParam}: {pageParam: RQPageParam}) {
|
async queryFn({pageParam}: {pageParam: RQPageParam}) {
|
||||||
const res = await getAgent().listNotifications({
|
const res = await getAgent().listNotifications({
|
||||||
|
|
|
@ -54,9 +54,12 @@ export function Feed({
|
||||||
|
|
||||||
// mark all read on fresh data
|
// mark all read on fresh data
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
|
let cleanup
|
||||||
if (firstItem) {
|
if (firstItem) {
|
||||||
markAllRead()
|
const to = setTimeout(() => markAllRead(), 250)
|
||||||
|
cleanup = () => clearTimeout(to)
|
||||||
}
|
}
|
||||||
|
return cleanup
|
||||||
}, [firstItem, markAllRead])
|
}, [firstItem, markAllRead])
|
||||||
|
|
||||||
const items = React.useMemo(() => {
|
const items = React.useMemo(() => {
|
||||||
|
|
|
@ -14,6 +14,7 @@ import {
|
||||||
FontAwesomeIcon,
|
FontAwesomeIcon,
|
||||||
FontAwesomeIconStyle,
|
FontAwesomeIconStyle,
|
||||||
} from '@fortawesome/react-native-fontawesome'
|
} from '@fortawesome/react-native-fontawesome'
|
||||||
|
import {useQueryClient} from '@tanstack/react-query'
|
||||||
import {s, colors} from 'lib/styles'
|
import {s, colors} from 'lib/styles'
|
||||||
import {FEEDBACK_FORM_URL, HELP_DESK_URL} from 'lib/constants'
|
import {FEEDBACK_FORM_URL, HELP_DESK_URL} from 'lib/constants'
|
||||||
import {
|
import {
|
||||||
|
@ -50,6 +51,7 @@ import {useProfileQuery} from '#/state/queries/profile'
|
||||||
import {useUnreadNotifications} from '#/state/queries/notifications/unread'
|
import {useUnreadNotifications} from '#/state/queries/notifications/unread'
|
||||||
import {emitSoftReset} from '#/state/events'
|
import {emitSoftReset} from '#/state/events'
|
||||||
import {useInviteCodesQuery} from '#/state/queries/invites'
|
import {useInviteCodesQuery} from '#/state/queries/invites'
|
||||||
|
import {RQKEY as NOTIFS_RQKEY} from '#/state/queries/notifications/feed'
|
||||||
|
|
||||||
export function DrawerProfileCard({
|
export function DrawerProfileCard({
|
||||||
account,
|
account,
|
||||||
|
@ -104,6 +106,7 @@ export function DrawerContent() {
|
||||||
const theme = useTheme()
|
const theme = useTheme()
|
||||||
const pal = usePalette('default')
|
const pal = usePalette('default')
|
||||||
const {_} = useLingui()
|
const {_} = useLingui()
|
||||||
|
const queryClient = useQueryClient()
|
||||||
const setDrawerOpen = useSetDrawerOpen()
|
const setDrawerOpen = useSetDrawerOpen()
|
||||||
const navigation = useNavigation<NavigationProp>()
|
const navigation = useNavigation<NavigationProp>()
|
||||||
const {track} = useAnalytics()
|
const {track} = useAnalytics()
|
||||||
|
@ -135,12 +138,18 @@ export function DrawerContent() {
|
||||||
} else if (tabState === TabState.Inside) {
|
} else if (tabState === TabState.Inside) {
|
||||||
navigation.dispatch(StackActions.popToTop())
|
navigation.dispatch(StackActions.popToTop())
|
||||||
} else {
|
} else {
|
||||||
|
if (tab === 'Notifications') {
|
||||||
|
// fetch new notifs on view
|
||||||
|
queryClient.invalidateQueries({
|
||||||
|
queryKey: NOTIFS_RQKEY(),
|
||||||
|
})
|
||||||
|
}
|
||||||
// @ts-ignore must be Home, Search, Notifications, or MyProfile
|
// @ts-ignore must be Home, Search, Notifications, or MyProfile
|
||||||
navigation.navigate(`${tab}Tab`)
|
navigation.navigate(`${tab}Tab`)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[track, navigation, setDrawerOpen, currentAccount],
|
[track, navigation, setDrawerOpen, currentAccount, queryClient],
|
||||||
)
|
)
|
||||||
|
|
||||||
const onPressHome = React.useCallback(() => onPressTab('Home'), [onPressTab])
|
const onPressHome = React.useCallback(() => onPressTab('Home'), [onPressTab])
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import React, {ComponentProps} from 'react'
|
import React, {ComponentProps} from 'react'
|
||||||
import {GestureResponderEvent, TouchableOpacity, View} from 'react-native'
|
import {GestureResponderEvent, TouchableOpacity, View} from 'react-native'
|
||||||
import Animated from 'react-native-reanimated'
|
import Animated from 'react-native-reanimated'
|
||||||
|
import {useQueryClient} from '@tanstack/react-query'
|
||||||
import {StackActions} from '@react-navigation/native'
|
import {StackActions} from '@react-navigation/native'
|
||||||
import {BottomTabBarProps} from '@react-navigation/bottom-tabs'
|
import {BottomTabBarProps} from '@react-navigation/bottom-tabs'
|
||||||
import {useSafeAreaInsets} from 'react-native-safe-area-context'
|
import {useSafeAreaInsets} from 'react-native-safe-area-context'
|
||||||
|
@ -30,6 +31,7 @@ import {useUnreadNotifications} from '#/state/queries/notifications/unread'
|
||||||
import {emitSoftReset} from '#/state/events'
|
import {emitSoftReset} from '#/state/events'
|
||||||
import {useSession} from '#/state/session'
|
import {useSession} from '#/state/session'
|
||||||
import {useProfileQuery} from '#/state/queries/profile'
|
import {useProfileQuery} from '#/state/queries/profile'
|
||||||
|
import {RQKEY as NOTIFS_RQKEY} from '#/state/queries/notifications/feed'
|
||||||
|
|
||||||
type TabOptions = 'Home' | 'Search' | 'Notifications' | 'MyProfile' | 'Feeds'
|
type TabOptions = 'Home' | 'Search' | 'Notifications' | 'MyProfile' | 'Feeds'
|
||||||
|
|
||||||
|
@ -38,6 +40,7 @@ export function BottomBar({navigation}: BottomTabBarProps) {
|
||||||
const {currentAccount} = useSession()
|
const {currentAccount} = useSession()
|
||||||
const pal = usePalette('default')
|
const pal = usePalette('default')
|
||||||
const {_} = useLingui()
|
const {_} = useLingui()
|
||||||
|
const queryClient = useQueryClient()
|
||||||
const safeAreaInsets = useSafeAreaInsets()
|
const safeAreaInsets = useSafeAreaInsets()
|
||||||
const {track} = useAnalytics()
|
const {track} = useAnalytics()
|
||||||
const {footerHeight} = useShellLayout()
|
const {footerHeight} = useShellLayout()
|
||||||
|
@ -57,10 +60,16 @@ export function BottomBar({navigation}: BottomTabBarProps) {
|
||||||
} else if (tabState === TabState.Inside) {
|
} else if (tabState === TabState.Inside) {
|
||||||
navigation.dispatch(StackActions.popToTop())
|
navigation.dispatch(StackActions.popToTop())
|
||||||
} else {
|
} else {
|
||||||
|
if (tab === 'Notifications') {
|
||||||
|
// fetch new notifs on view
|
||||||
|
queryClient.invalidateQueries({
|
||||||
|
queryKey: NOTIFS_RQKEY(),
|
||||||
|
})
|
||||||
|
}
|
||||||
navigation.navigate(`${tab}Tab`)
|
navigation.navigate(`${tab}Tab`)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[track, navigation],
|
[track, navigation, queryClient],
|
||||||
)
|
)
|
||||||
const onPressHome = React.useCallback(() => onPressTab('Home'), [onPressTab])
|
const onPressHome = React.useCallback(() => onPressTab('Home'), [onPressTab])
|
||||||
const onPressSearch = React.useCallback(
|
const onPressSearch = React.useCallback(
|
||||||
|
|
|
@ -45,6 +45,8 @@ import {useUnreadNotifications} from '#/state/queries/notifications/unread'
|
||||||
import {useComposerControls} from '#/state/shell/composer'
|
import {useComposerControls} from '#/state/shell/composer'
|
||||||
import {useFetchHandle} from '#/state/queries/handle'
|
import {useFetchHandle} from '#/state/queries/handle'
|
||||||
import {emitSoftReset} from '#/state/events'
|
import {emitSoftReset} from '#/state/events'
|
||||||
|
import {useQueryClient} from '@tanstack/react-query'
|
||||||
|
import {RQKEY as NOTIFS_RQKEY} from '#/state/queries/notifications/feed'
|
||||||
|
|
||||||
function ProfileCard() {
|
function ProfileCard() {
|
||||||
const {currentAccount} = useSession()
|
const {currentAccount} = useSession()
|
||||||
|
@ -118,6 +120,7 @@ interface NavItemProps {
|
||||||
}
|
}
|
||||||
function NavItem({count, href, icon, iconFilled, label}: NavItemProps) {
|
function NavItem({count, href, icon, iconFilled, label}: NavItemProps) {
|
||||||
const pal = usePalette('default')
|
const pal = usePalette('default')
|
||||||
|
const queryClient = useQueryClient()
|
||||||
const {currentAccount} = useSession()
|
const {currentAccount} = useSession()
|
||||||
const {isDesktop, isTablet} = useWebMediaQueries()
|
const {isDesktop, isTablet} = useWebMediaQueries()
|
||||||
const [pathName] = React.useMemo(() => router.matchPath(href), [href])
|
const [pathName] = React.useMemo(() => router.matchPath(href), [href])
|
||||||
|
@ -143,10 +146,16 @@ function NavItem({count, href, icon, iconFilled, label}: NavItemProps) {
|
||||||
if (isCurrent) {
|
if (isCurrent) {
|
||||||
emitSoftReset()
|
emitSoftReset()
|
||||||
} else {
|
} else {
|
||||||
|
if (href === '/notifications') {
|
||||||
|
// fetch new notifs on view
|
||||||
|
queryClient.invalidateQueries({
|
||||||
|
queryKey: NOTIFS_RQKEY(),
|
||||||
|
})
|
||||||
|
}
|
||||||
onPress()
|
onPress()
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[onPress, isCurrent],
|
[onPress, isCurrent, queryClient, href],
|
||||||
)
|
)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
Loading…
Reference in New Issue