diff --git a/src/view/com/notifications/Feed.tsx b/src/view/com/notifications/Feed.tsx index dd439d4755..14ba234418 100644 --- a/src/view/com/notifications/Feed.tsx +++ b/src/view/com/notifications/Feed.tsx @@ -1,36 +1,44 @@ import React from 'react' -import {CenteredView} from '../util/Views' -import {ActivityIndicator, StyleSheet, View} from 'react-native' -import {FeedItem} from './FeedItem' -import {NotificationFeedLoadingPlaceholder} from '../util/LoadingPlaceholder' -import {ErrorMessage} from '../util/error/ErrorMessage' -import {LoadMoreRetryBtn} from '../util/LoadMoreRetryBtn' -import {EmptyState} from '../util/EmptyState' -import {s} from 'lib/styles' +import { + ActivityIndicator, + FlatList, + ScrollView, + StyleSheet, + View, +} from 'react-native' +import {msg} from '@lingui/macro' +import {useLingui} from '@lingui/react' + +import {usePalette} from '#/lib/hooks/usePalette' +import {cleanError} from '#/lib/strings/errors' +import {logger} from '#/logger' import {useNotificationFeedQuery} from '#/state/queries/notifications/feed' import {useUnreadNotificationsApi} from '#/state/queries/notifications/unread' -import {logger} from '#/logger' -import {cleanError} from '#/lib/strings/errors' import {useModerationOpts} from '#/state/queries/preferences' -import {List, ListRef} from '../util/List' -import {useLingui} from '@lingui/react' -import {msg} from '@lingui/macro' -import {usePalette} from '#/lib/hooks/usePalette' +import {s} from 'lib/styles' +import {EmptyState} from '../util/EmptyState' +import {ErrorMessage} from '../util/error/ErrorMessage' +import {List} from '../util/List' +import {NotificationFeedLoadingPlaceholder} from '../util/LoadingPlaceholder' +import {LoadMoreRetryBtn} from '../util/LoadMoreRetryBtn' +import {CenteredView} from '../util/Views' +import {FeedItem} from './FeedItem' const EMPTY_FEED_ITEM = {_reactKey: '__empty__'} const LOAD_MORE_ERROR_ITEM = {_reactKey: '__load_more_error__'} const LOADING_ITEM = {_reactKey: '__loading__'} export function Feed({ - scrollElRef, onPressTryAgain, onScrolledDownChange, ListHeaderComponent, + filterType, }: { - scrollElRef?: ListRef + scrollElRef?: React.RefObject | ScrollView | null> onPressTryAgain?: () => void onScrolledDownChange: (isScrolledDown: boolean) => void ListHeaderComponent?: () => JSX.Element + filterType: string }) { const [isPTRing, setIsPTRing] = React.useState(false) const pal = usePalette('default') @@ -52,22 +60,30 @@ export function Feed({ const items = React.useMemo(() => { let arr: any[] = [] - if (isFetched) { - if (isEmpty) { - arr = arr.concat([EMPTY_FEED_ITEM]) - } else if (data) { - for (const page of data?.pages) { - arr = arr.concat(page.items) + if (isFetched && !isEmpty) { + data?.pages.forEach(page => { + let filteredItems = page.items + if (filterType === 'Mentions') { + let mentions = page.items.filter( + item => + item.type === 'reply' || + item.type === 'quote' || + item.type === 'mention', + ) + filteredItems = mentions } - } - if (isError && !isEmpty) { - arr = arr.concat([LOAD_MORE_ERROR_ITEM]) - } + + arr = arr.concat(filteredItems) + }) + } else if (isEmpty) { + arr.push(EMPTY_FEED_ITEM) + } else if (isError) { + arr.push(LOAD_MORE_ERROR_ITEM) } else { arr.push(LOADING_ITEM) } return arr - }, [isFetched, isError, isEmpty, data]) + }, [isFetched, isError, isEmpty, data, filterType]) const onRefresh = React.useCallback(async () => { try { @@ -155,7 +171,6 @@ export function Feed({ )} item._reactKey} renderItem={renderItem} diff --git a/src/view/screens/Notifications.tsx b/src/view/screens/Notifications.tsx index 48c834a28f..59e879ebb3 100644 --- a/src/view/screens/Notifications.tsx +++ b/src/view/screens/Notifications.tsx @@ -1,37 +1,40 @@ import React from 'react' import {View} from 'react-native' +import {msg, Trans} from '@lingui/macro' +import {useLingui} from '@lingui/react' import {useFocusEffect, useIsFocused} from '@react-navigation/native' import {useQueryClient} from '@tanstack/react-query' -import { - NativeStackScreenProps, - NotificationsTabNavigatorParams, -} from 'lib/routes/types' -import {ViewHeader} from '../com/util/ViewHeader' -import {Feed} from '../com/notifications/Feed' -import {TextLink} from 'view/com/util/Link' -import {ListMethods} from 'view/com/util/List' -import {LoadLatestBtn} from 'view/com/util/load-latest/LoadLatestBtn' -import {MainScrollProvider} from '../com/util/MainScrollProvider' -import {usePalette} from 'lib/hooks/usePalette' -import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries' -import {s, colors} from 'lib/styles' -import {useAnalytics} from 'lib/analytics/analytics' + +import {useNonReactiveCallback} from '#/lib/hooks/useNonReactiveCallback' import {logger} from '#/logger' -import {useSetMinimalShellMode} from '#/state/shell' -import {Trans, msg} from '@lingui/macro' -import {useLingui} from '@lingui/react' +import {isNative} from '#/platform/detection' +import {listenSoftReset} from '#/state/events' +import {RQKEY as NOTIFS_RQKEY} from '#/state/queries/notifications/feed' import { useUnreadNotifications, useUnreadNotificationsApi, } from '#/state/queries/notifications/unread' -import {RQKEY as NOTIFS_RQKEY} from '#/state/queries/notifications/feed' -import {listenSoftReset, emitSoftReset} from '#/state/events' import {truncateAndInvalidate} from '#/state/queries/util' -import {useNonReactiveCallback} from '#/lib/hooks/useNonReactiveCallback' -import {isNative} from '#/platform/detection' -import {FAB} from '../com/util/fab/FAB' -import {ComposeIcon2} from 'lib/icons' +import {useSetMinimalShellMode} from '#/state/shell' import {useComposerControls} from '#/state/shell/composer' +import {useAnalytics} from 'lib/analytics/analytics' +import {usePalette} from 'lib/hooks/usePalette' +import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries' +import {ComposeIcon2} from 'lib/icons' +import { + NativeStackScreenProps, + NotificationsTabNavigatorParams, +} from 'lib/routes/types' +import {s} from 'lib/styles' +import {ListMethods} from 'view/com/util/List' +import {LoadLatestBtn} from 'view/com/util/load-latest/LoadLatestBtn' +import {Text} from 'view/com/util/text/Text' +import {Feed} from '../com/notifications/Feed' +import {PagerRef} from '../com/pager/Pager' +import {PagerWithHeader} from '../com/pager/PagerWithHeader' +import {FAB} from '../com/util/fab/FAB' +import {MainScrollProvider} from '../com/util/MainScrollProvider' +import {SimpleViewHeader} from '../com/util/SimpleViewHeader' type Props = NativeStackScreenProps< NotificationsTabNavigatorParams, @@ -41,16 +44,44 @@ export function NotificationsScreen({}: Props) { const {_} = useLingui() const setMinimalShellMode = useSetMinimalShellMode() const [isScrolledDown, setIsScrolledDown] = React.useState(false) + const [filterType, setFilterType] = React.useState('All') const scrollElRef = React.useRef(null) const {screen} = useAnalytics() const pal = usePalette('default') - const {isDesktop} = useWebMediaQueries() const queryClient = useQueryClient() const unreadNotifs = useUnreadNotifications() const unreadApi = useUnreadNotificationsApi() const hasNew = !!unreadNotifs const isScreenFocused = useIsFocused() const {openComposer} = useComposerControls() + const pagerRef = React.useRef(null) + const {isMobile} = useWebMediaQueries() + + const handleTabChange = React.useCallback( + (index: number) => { + const types = ['All', 'Mentions'] + if (filterType !== types[index]) { + setFilterType(types[index]) + } + }, + [filterType], + ) + + const renderHeader = () => { + return ( + + + + Notifications + + + + ) + } + + const sectionTitles = [_('All'), _('Mentions')] // event handlers // = @@ -101,58 +132,34 @@ export function NotificationsScreen({}: Props) { return listenSoftReset(onPressLoadLatest) }, [onPressLoadLatest, isScreenFocused]) - const ListHeaderComponent = React.useCallback(() => { - if (isDesktop) { - return ( - - - Notifications{' '} - {hasNew && ( - - )} - - } - onPress={emitSoftReset} - /> - - ) - } - return <> - }, [isDesktop, pal, hasNew]) - return ( - - - - + + {({scrollElRef}) => ( + + + + )} + {({scrollElRef}) => ( + + + + )} + {(isScrolledDown || hasNew) && (