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:
@@ -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 (
|
||||
|
||||
@@ -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
@@ -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 && (
|
||||
|
||||
Reference in New Issue
Block a user