Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor notifications to use react-query #1878

Merged
merged 10 commits into from
Nov 13, 2023
63 changes: 33 additions & 30 deletions src/App.native.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import {
useSession,
useSessionApi,
} from 'state/session'
import {Provider as UnreadNotifsProvider} from 'state/queries/notifications/unread'
import * as persisted from '#/state/persisted'
import {i18n} from '@lingui/core'
import {I18nProvider} from '@lingui/react'
Expand All @@ -53,7 +54,7 @@ const InnerApp = observer(function AppImpl() {
setupState().then(store => {
setRootStore(store)
analytics.init(store)
notifications.init(store)
notifications.init(store, queryClient)
store.onSessionDropped(() => {
Toast.show('Sorry! Your session expired. Please log in again.')
})
Expand All @@ -72,22 +73,20 @@ const InnerApp = observer(function AppImpl() {
}

return (
<QueryClientProvider client={queryClient}>
<ThemeProvider theme={colorMode}>
<RootSiblingParent>
<analytics.Provider>
<RootStoreProvider value={rootStore}>
<I18nProvider i18n={i18n}>
<GestureHandlerRootView style={s.h100pct}>
<TestCtrls />
<Shell />
</GestureHandlerRootView>
</I18nProvider>
</RootStoreProvider>
</analytics.Provider>
</RootSiblingParent>
</ThemeProvider>
</QueryClientProvider>
<ThemeProvider theme={colorMode}>
<RootSiblingParent>
<analytics.Provider>
<RootStoreProvider value={rootStore}>
<I18nProvider i18n={i18n}>
<GestureHandlerRootView style={s.h100pct}>
<TestCtrls />
<Shell />
</GestureHandlerRootView>
</I18nProvider>
</RootStoreProvider>
</analytics.Provider>
</RootSiblingParent>
</ThemeProvider>
)
})

Expand All @@ -103,19 +102,23 @@ function App() {
}

return (
<SessionProvider>
<ShellStateProvider>
<PrefsStateProvider>
<MutedThreadsProvider>
<InvitesStateProvider>
<ModalStateProvider>
<InnerApp />
</ModalStateProvider>
</InvitesStateProvider>
</MutedThreadsProvider>
</PrefsStateProvider>
</ShellStateProvider>
</SessionProvider>
<QueryClientProvider client={queryClient}>
<SessionProvider>
<ShellStateProvider>
<PrefsStateProvider>
<MutedThreadsProvider>
<UnreadNotifsProvider>
<InvitesStateProvider>
<ModalStateProvider>
<InnerApp />
</ModalStateProvider>
</InvitesStateProvider>
</UnreadNotifsProvider>
</MutedThreadsProvider>
</PrefsStateProvider>
</ShellStateProvider>
</SessionProvider>
</QueryClientProvider>
)
}

Expand Down
61 changes: 32 additions & 29 deletions src/App.web.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import {
useSession,
useSessionApi,
} from 'state/session'
import {Provider as UnreadNotifsProvider} from 'state/queries/notifications/unread'
import * as persisted from '#/state/persisted'

const InnerApp = observer(function AppImpl() {
Expand Down Expand Up @@ -60,22 +61,20 @@ const InnerApp = observer(function AppImpl() {
}

return (
<QueryClientProvider client={queryClient}>
<ThemeProvider theme={colorMode}>
<RootSiblingParent>
<analytics.Provider>
<RootStoreProvider value={rootStore}>
<I18nProvider i18n={i18n}>
<SafeAreaProvider>
<Shell />
</SafeAreaProvider>
</I18nProvider>
<ToastContainer />
</RootStoreProvider>
</analytics.Provider>
</RootSiblingParent>
</ThemeProvider>
</QueryClientProvider>
<ThemeProvider theme={colorMode}>
<RootSiblingParent>
<analytics.Provider>
<RootStoreProvider value={rootStore}>
<I18nProvider i18n={i18n}>
<SafeAreaProvider>
<Shell />
</SafeAreaProvider>
</I18nProvider>
<ToastContainer />
</RootStoreProvider>
</analytics.Provider>
</RootSiblingParent>
</ThemeProvider>
)
})

Expand All @@ -91,19 +90,23 @@ function App() {
}

return (
<SessionProvider>
<ShellStateProvider>
<PrefsStateProvider>
<MutedThreadsProvider>
<InvitesStateProvider>
<ModalStateProvider>
<InnerApp />
</ModalStateProvider>
</InvitesStateProvider>
</MutedThreadsProvider>
</PrefsStateProvider>
</ShellStateProvider>
</SessionProvider>
<QueryClientProvider client={queryClient}>
<SessionProvider>
<ShellStateProvider>
<PrefsStateProvider>
<MutedThreadsProvider>
<UnreadNotifsProvider>
<InvitesStateProvider>
<ModalStateProvider>
<InnerApp />
</ModalStateProvider>
</InvitesStateProvider>
</UnreadNotifsProvider>
</MutedThreadsProvider>
</PrefsStateProvider>
</ShellStateProvider>
</SessionProvider>
</QueryClientProvider>
)
}

Expand Down
18 changes: 8 additions & 10 deletions src/Navigation.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import * as React from 'react'
import {StyleSheet} from 'react-native'
import * as SplashScreen from 'expo-splash-screen'
import {observer} from 'mobx-react-lite'
import {
NavigationContainer,
createNavigationContainerRef,
Expand Down Expand Up @@ -33,10 +32,10 @@ import {isNative} from 'platform/detection'
import {useColorSchemeStyle} from 'lib/hooks/useColorSchemeStyle'
import {router} from './routes'
import {usePalette} from 'lib/hooks/usePalette'
import {useStores} from './state'
import {bskyTitle} from 'lib/strings/headings'
import {JSX} from 'react/jsx-runtime'
import {timeout} from 'lib/async/timeout'
import {useUnreadNotifications} from './state/queries/notifications/unread'

import {HomeScreen} from './view/screens/Home'
import {SearchScreen} from './view/screens/Search'
Expand Down Expand Up @@ -346,7 +345,7 @@ function NotificationsTabNavigator() {
)
}

const MyProfileTabNavigator = observer(function MyProfileTabNavigatorImpl() {
function MyProfileTabNavigator() {
const contentStyle = useColorSchemeStyle(styles.bgLight, styles.bgDark)
return (
<MyProfileTab.Navigator
Expand All @@ -368,18 +367,17 @@ const MyProfileTabNavigator = observer(function MyProfileTabNavigatorImpl() {
{commonScreens(MyProfileTab as typeof HomeTab)}
</MyProfileTab.Navigator>
)
})
}

/**
* The FlatNavigator is used by Web to represent the routes
* in a single ("flat") stack.
*/
const FlatNavigator = observer(function FlatNavigatorImpl() {
const FlatNavigator = () => {
const pal = usePalette('default')
const store = useStores()
const unreadCountLabel = store.me.notifications.unreadCountLabel
const numUnread = useUnreadNotifications()

const title = (page: string) => bskyTitle(page, unreadCountLabel)
const title = (page: string) => bskyTitle(page, numUnread)
return (
<Flat.Navigator
screenOptions={{
Expand Down Expand Up @@ -409,10 +407,10 @@ const FlatNavigator = observer(function FlatNavigatorImpl() {
getComponent={() => NotificationsScreen}
options={{title: title('Notifications')}}
/>
{commonScreens(Flat as typeof HomeTab, unreadCountLabel)}
{commonScreens(Flat as typeof HomeTab, numUnread)}
</Flat.Navigator>
)
})
}

/**
* The RoutesContainer should wrap all components which need access
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,9 @@ export default class BroadcastChannel {
postMessage(_data: any) {}
close() {}
onmessage: (event: MessageEvent) => void = () => {}
addEventListener(_type: string, _listener: (event: MessageEvent) => void) {}
removeEventListener(
_type: string,
_listener: (event: MessageEvent) => void,
) {}
}
12 changes: 4 additions & 8 deletions src/lib/hooks/useSetTitle.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,14 @@ import {useNavigation} from '@react-navigation/native'

import {NavigationProp} from 'lib/routes/types'
import {bskyTitle} from 'lib/strings/headings'
import {useStores} from 'state/index'
import {useUnreadNotifications} from '#/state/queries/notifications/unread'

/**
* Requires consuming component to be wrapped in `observer`:
* https://stackoverflow.com/a/71488009
*/
export function useSetTitle(title?: string) {
const navigation = useNavigation<NavigationProp>()
const {unreadCountLabel} = useStores().me.notifications
const numUnread = useUnreadNotifications()
useEffect(() => {
if (title) {
navigation.setOptions({title: bskyTitle(title, unreadCountLabel)})
navigation.setOptions({title: bskyTitle(title, numUnread)})
}
}, [title, navigation, unreadCountLabel])
}, [title, navigation, numUnread])
}
10 changes: 5 additions & 5 deletions src/lib/notifications/notifications.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
import * as Notifications from 'expo-notifications'
import {QueryClient} from '@tanstack/react-query'
import {RootStoreModel} from '../../state'
import {resetToTab} from '../../Navigation'
import {devicePlatform, isIOS} from 'platform/detection'
import {track} from 'lib/analytics/analytics'
import {logger} from '#/logger'
import {RQKEY as RQKEY_NOTIFS} from '#/state/queries/notifications/feed'

const SERVICE_DID = (serviceUrl?: string) =>
serviceUrl?.includes('staging')
? 'did:web:api.staging.bsky.dev'
: 'did:web:api.bsky.app'

export function init(store: RootStoreModel) {
store.onUnreadNotifications(count => Notifications.setBadgeCountAsync(count))

export function init(store: RootStoreModel, queryClient: QueryClient) {
store.onSessionLoaded(async () => {
// request notifications permission once the user has logged in
const perms = await Notifications.getPermissionsAsync()
Expand Down Expand Up @@ -83,7 +83,7 @@ export function init(store: RootStoreModel) {
)
if (event.request.trigger.type === 'push') {
// refresh notifications in the background
store.me.notifications.syncQueue()
queryClient.invalidateQueries({queryKey: RQKEY_NOTIFS()})
// handle payload-based deeplinks
let payload
if (isIOS) {
Expand Down Expand Up @@ -121,7 +121,7 @@ export function init(store: RootStoreModel) {
logger.DebugContext.notifications,
)
track('Notificatons:OpenApp')
store.me.notifications.refresh() // refresh notifications
queryClient.invalidateQueries({queryKey: RQKEY_NOTIFS()})
resetToTab('NotificationsTab') // open notifications tab
}
},
Expand Down
Loading
Loading