A group of notifications fixes (#227)

* Fix: don't group together notifications that can't visually be grouped (close #221)

* Mark all notifications read on PTR

* Small optimization: useCallback and useMemo in posts feed

* Add loading spinner to footer of notifications (close #222)
This commit is contained in:
Paul Frazee
2023-02-21 10:32:29 -06:00
committed by GitHub
parent 1861f95a1f
commit f55fbe73c7
3 changed files with 112 additions and 69 deletions
+2 -2
View File
@@ -14,7 +14,7 @@ import {RootStoreModel} from './root-store'
import {PostThreadViewModel} from './post-thread-view'
import {cleanError} from '../../lib/strings'
const UNGROUPABLE_REASONS = ['assertion']
const GROUPABLE_REASONS = ['vote', 'repost', 'follow']
const PAGE_SIZE = 30
const MS_1HR = 1e3 * 60 * 60
const MS_2DAY = MS_1HR * 48
@@ -539,7 +539,7 @@ function groupNotifications(
for (const item of items) {
const ts = +new Date(item.indexedAt)
let grouped = false
if (!UNGROUPABLE_REASONS.includes(item.reason)) {
if (GROUPABLE_REASONS.includes(item.reason)) {
for (const item2 of items2) {
const ts2 = +new Date(item2.indexedAt)
if (
+46 -25
View File
@@ -1,6 +1,6 @@
import React, {MutableRefObject} from 'react'
import {observer} from 'mobx-react-lite'
import {FlatList, StyleSheet, View} from 'react-native'
import {ActivityIndicator, FlatList, StyleSheet, View} from 'react-native'
import {NotificationsViewModel} from '../../../state/models/notifications-view'
import {FeedItem} from './FeedItem'
import {NotificationFeedLoadingPlaceholder} from '../util/LoadingPlaceholder'
@@ -22,11 +22,39 @@ export const Feed = observer(function Feed({
onPressTryAgain?: () => void
onScroll?: OnScrollCb
}) {
const data = React.useMemo(() => {
let feedItems
if (view.hasLoaded) {
if (view.isEmpty) {
feedItems = [EMPTY_FEED_ITEM]
} else {
feedItems = view.notifications
}
}
return feedItems
}, [view.hasLoaded, view.isEmpty, view.notifications])
const onRefresh = React.useCallback(async () => {
try {
await view.refresh()
await view.markAllRead()
} catch (err) {
view.rootStore.log.error('Failed to refresh notifications feed', err)
}
}, [view])
const onEndReached = React.useCallback(async () => {
try {
await view.loadMore()
} catch (err) {
view.rootStore.log.error('Failed to load more notifications', err)
}
}, [view])
// TODO optimize renderItem or FeedItem, we're getting this notice from RN: -prf
// VirtualizedList: You have a large list that is slow to update - make sure your
// renderItem function renders components that follow React performance best practices
// like PureComponent, shouldComponentUpdate, etc
const renderItem = ({item}: {item: any}) => {
const renderItem = React.useCallback(({item}: {item: any}) => {
if (item === EMPTY_FEED_ITEM) {
return (
<EmptyState
@@ -37,29 +65,20 @@ export const Feed = observer(function Feed({
)
}
return <FeedItem item={item} />
}
const onRefresh = async () => {
try {
await view.refresh()
} catch (err) {
view.rootStore.log.error('Failed to refresh notifications feed', err)
}
}
const onEndReached = async () => {
try {
await view.loadMore()
} catch (err) {
view.rootStore.log.error('Failed to load more notifications', err)
}
}
let data
if (view.hasLoaded) {
if (view.isEmpty) {
data = [EMPTY_FEED_ITEM]
} else {
data = view.notifications
}
}
}, [])
const FeedFooter = React.useCallback(
() =>
view.isLoading ? (
<View style={styles.feedFooter}>
<ActivityIndicator />
</View>
) : (
<View />
),
[view],
)
return (
<View style={s.h100pct}>
{view.isLoading && !data && <NotificationFeedLoadingPlaceholder />}
@@ -72,6 +91,7 @@ export const Feed = observer(function Feed({
data={data}
keyExtractor={item => item._reactKey}
renderItem={renderItem}
ListFooterComponent={FeedFooter}
refreshing={view.isRefreshing}
onRefresh={onRefresh}
onEndReached={onEndReached}
@@ -84,5 +104,6 @@ export const Feed = observer(function Feed({
})
const styles = StyleSheet.create({
feedFooter: {paddingTop: 20},
emptyState: {paddingVertical: 40},
})
+64 -42
View File
@@ -40,27 +40,25 @@ export const Feed = observer(function Feed({
const {track} = useAnalytics()
const [isRefreshing, setIsRefreshing] = React.useState(false)
// TODO optimize renderItem or FeedItem, we're getting this notice from RN: -prf
// VirtualizedList: You have a large list that is slow to update - make sure your
// renderItem function renders components that follow React performance best practices
// like PureComponent, shouldComponentUpdate, etc
const renderItem = ({item}: {item: any}) => {
if (item === EMPTY_FEED_ITEM) {
return (
<EmptyState
icon="bars"
message="This feed is empty!"
style={styles.emptyState}
/>
)
} else if (item === ERROR_FEED_ITEM) {
return (
<ErrorMessage message={feed.error} onPressTryAgain={onPressTryAgain} />
)
const data = React.useMemo(() => {
let feedItems: any[] = []
if (feed.hasError) {
feedItems = feedItems.concat([ERROR_FEED_ITEM])
}
return <FeedItem item={item} />
}
const onRefresh = async () => {
if (feed.hasLoaded) {
if (feed.isEmpty) {
feedItems = feedItems.concat([EMPTY_FEED_ITEM])
} else {
feedItems = feedItems.concat(feed.feed)
}
}
return feedItems
}, [feed.hasError, feed.hasLoaded, feed.isEmpty, feed.feed])
// events
// =
const onRefresh = React.useCallback(async () => {
track('Feed:onRefresh')
setIsRefreshing(true)
try {
@@ -69,34 +67,58 @@ export const Feed = observer(function Feed({
feed.rootStore.log.error('Failed to refresh posts feed', err)
}
setIsRefreshing(false)
}
const onEndReached = async () => {
}, [feed, track, setIsRefreshing])
const onEndReached = React.useCallback(async () => {
track('Feed:onEndReached')
try {
await feed.loadMore()
} catch (err) {
feed.rootStore.log.error('Failed to load more posts', err)
}
}
let data: any[] = []
if (feed.hasError) {
data = data.concat([ERROR_FEED_ITEM])
}
if (feed.hasLoaded) {
if (feed.isEmpty) {
data = data.concat([EMPTY_FEED_ITEM])
} else {
data = data.concat(feed.feed)
}
}
const FeedFooter = () =>
feed.isLoading ? (
<View style={styles.feedFooter}>
<ActivityIndicator />
</View>
) : (
<View />
)
}, [feed, track])
// rendering
// =
// TODO optimize renderItem or FeedItem, we're getting this notice from RN: -prf
// VirtualizedList: You have a large list that is slow to update - make sure your
// renderItem function renders components that follow React performance best practices
// like PureComponent, shouldComponentUpdate, etc
const renderItem = React.useCallback(
({item}: {item: any}) => {
if (item === EMPTY_FEED_ITEM) {
return (
<EmptyState
icon="bars"
message="This feed is empty!"
style={styles.emptyState}
/>
)
} else if (item === ERROR_FEED_ITEM) {
return (
<ErrorMessage
message={feed.error}
onPressTryAgain={onPressTryAgain}
/>
)
}
return <FeedItem item={item} />
},
[feed, onPressTryAgain],
)
const FeedFooter = React.useCallback(
() =>
feed.isLoading ? (
<View style={styles.feedFooter}>
<ActivityIndicator />
</View>
) : (
<View />
),
[feed],
)
return (
<View testID={testID} style={style}>
{feed.isLoading && data.length === 0 && (