diff --git a/src/state/queries/notifications/settings.ts b/src/state/queries/notifications/settings.ts index 9661bed1be..986d0b01db 100644 --- a/src/state/queries/notifications/settings.ts +++ b/src/state/queries/notifications/settings.ts @@ -14,7 +14,9 @@ import * as Toast from '#/view/com/util/Toast' const RQKEY_ROOT = 'notification-settings' const RQKEY = [RQKEY_ROOT] -export function useNotificationSettingsQuery() { +export function useNotificationSettingsQuery({ + enabled, +}: {enabled?: boolean} = {}) { const agent = useAgent() return useQuery({ @@ -23,6 +25,7 @@ export function useNotificationSettingsQuery() { const response = await agent.app.bsky.notification.getPreferences() return response.data.preferences }, + enabled, }) } export function useNotificationSettingsUpdateMutation() { diff --git a/src/view/com/notifications/NotificationFeed.tsx b/src/view/com/notifications/NotificationFeed.tsx index 1f87b3186f..bad09929a6 100644 --- a/src/view/com/notifications/NotificationFeed.tsx +++ b/src/view/com/notifications/NotificationFeed.tsx @@ -16,7 +16,7 @@ import {useModerationOpts} from '#/state/preferences/moderation-opts' import {useNotificationFeedQuery} from '#/state/queries/notifications/feed' import {EmptyState} from '#/view/com/util/EmptyState' import {ErrorMessage} from '#/view/com/util/error/ErrorMessage' -import {List, type ListRef} from '#/view/com/util/List' +import {List, type ListProps, type ListRef} from '#/view/com/util/List' import {NotificationFeedLoadingPlaceholder} from '#/view/com/util/LoadingPlaceholder' import {LoadMoreRetryBtn} from '#/view/com/util/LoadMoreRetryBtn' import {NotificationFeedItem} from './NotificationFeedItem' @@ -39,7 +39,7 @@ export function NotificationFeed({ scrollElRef?: ListRef onPressTryAgain?: () => void onScrolledDownChange: (isScrolledDown: boolean) => void - ListHeaderComponent?: () => JSX.Element + ListHeaderComponent?: ListProps['ListHeaderComponent'] refreshNotifications: () => Promise }) { const initialNumToRender = useInitialNumToRender() diff --git a/src/view/screens/Notifications.tsx b/src/view/screens/Notifications.tsx index 528d6be870..5818cc6fc7 100644 --- a/src/view/screens/Notifications.tsx +++ b/src/view/screens/Notifications.tsx @@ -1,4 +1,4 @@ -import React from 'react' +import {useCallback, useEffect, useMemo, useRef, useState} from 'react' import {View} from 'react-native' import {msg, Trans} from '@lingui/macro' import {useLingui} from '@lingui/react' @@ -17,6 +17,7 @@ import {logger} from '#/logger' import {isNative} from '#/platform/detection' import {emitSoftReset, listenSoftReset} from '#/state/events' import {RQKEY as NOTIFS_RQKEY} from '#/state/queries/notifications/feed' +import {useNotificationSettingsQuery} from '#/state/queries/notifications/settings' import { useUnreadNotifications, useUnreadNotificationsApi, @@ -30,8 +31,9 @@ import {FAB} from '#/view/com/util/fab/FAB' import {type ListMethods} from '#/view/com/util/List' import {LoadLatestBtn} from '#/view/com/util/load-latest/LoadLatestBtn' import {MainScrollProvider} from '#/view/com/util/MainScrollProvider' -import {atoms as a} from '#/alf' +import {atoms as a, useTheme} from '#/alf' import {web} from '#/alf' +import {Admonition} from '#/components/Admonition' import {ButtonIcon} from '#/components/Button' import {SettingsGear2_Stroke2_Corner0_Rounded as SettingsIcon} from '#/components/icons/SettingsGear2' import * as Layout from '#/components/Layout' @@ -53,13 +55,13 @@ export function NotificationsScreen({}: Props) { const unreadNotifs = useUnreadNotifications() const hasNew = !!unreadNotifs const {checkUnread: checkUnreadAll} = useUnreadNotificationsApi() - const [isLoadingAll, setIsLoadingAll] = React.useState(false) - const [isLoadingMentions, setIsLoadingMentions] = React.useState(false) + const [isLoadingAll, setIsLoadingAll] = useState(false) + const [isLoadingMentions, setIsLoadingMentions] = useState(false) const initialActiveTab = lastActiveTab - const [activeTab, setActiveTab] = React.useState(initialActiveTab) + const [activeTab, setActiveTab] = useState(initialActiveTab) const isLoading = activeTab === 0 ? isLoadingAll : isLoadingMentions - const onPageSelected = React.useCallback( + const onPageSelected = useCallback( (index: number) => { setActiveTab(index) lastActiveTab = index @@ -68,7 +70,7 @@ export function NotificationsScreen({}: Props) { ) const queryClient = useQueryClient() - const checkUnreadMentions = React.useCallback( + const checkUnreadMentions = useCallback( async ({invalidate}: {invalidate: boolean}) => { if (invalidate) { return truncateAndInvalidate(queryClient, NOTIFS_RQKEY('mentions')) @@ -80,7 +82,7 @@ export function NotificationsScreen({}: Props) { [queryClient], ) - const sections = React.useMemo(() => { + const sections = useMemo(() => { return [ { title: _(msg`All`), @@ -186,20 +188,20 @@ function NotificationsTab({ }) { const {_} = useLingui() const setMinimalShellMode = useSetMinimalShellMode() - const [isScrolledDown, setIsScrolledDown] = React.useState(false) - const scrollElRef = React.useRef(null) + const [isScrolledDown, setIsScrolledDown] = useState(false) + const scrollElRef = useRef(null) const queryClient = useQueryClient() const isScreenFocused = useIsFocused() const isFocusedAndActive = isScreenFocused && isActive // event handlers // = - const scrollToTop = React.useCallback(() => { + const scrollToTop = useCallback(() => { scrollElRef.current?.scrollToOffset({animated: isNative, offset: 0}) setMinimalShellMode(false) }, [scrollElRef, setMinimalShellMode]) - const onPressLoadLatest = React.useCallback(() => { + const onPressLoadLatest = useCallback(() => { scrollToTop() if (hasNew) { // render what we have now @@ -238,7 +240,7 @@ function NotificationsTab({ // on-visible setup // = useFocusEffect( - React.useCallback(() => { + useCallback(() => { if (isFocusedAndActive) { setMinimalShellMode(false) logger.debug('NotificationsScreen: Focus') @@ -246,7 +248,8 @@ function NotificationsTab({ } }, [setMinimalShellMode, onFocusCheckLatest, isFocusedAndActive]), ) - React.useEffect(() => { + + useEffect(() => { if (!isFocusedAndActive) { return } @@ -262,6 +265,11 @@ function NotificationsTab({ refreshNotifications={() => checkUnread({invalidate: true})} onScrolledDownChange={setIsScrolledDown} scrollElRef={scrollElRef} + ListHeaderComponent={ + filter === 'mentions' ? ( + + ) : null + } /> {(isScrolledDown || hasNew) && ( @@ -274,3 +282,26 @@ function NotificationsTab({ ) } + +function DisabledNotificationsWarning({active}: {active: boolean}) { + const t = useTheme() + const [hasBeenActive, setHasBeenActive] = useState(false) + const {data} = useNotificationSettingsQuery({enabled: hasBeenActive}) + + if (active && !hasBeenActive) { + setHasBeenActive(true) + } + + if (!data) return null + + return ( + + + + You have completely disabled reply, quote, and mention notifications, + so this tab will no longer update. + + + + ) +}