diff options
Diffstat (limited to 'src/view/com/notifications/FeedItem.tsx')
-rw-r--r-- | src/view/com/notifications/FeedItem.tsx | 167 |
1 files changed, 79 insertions, 88 deletions
diff --git a/src/view/com/notifications/FeedItem.tsx b/src/view/com/notifications/FeedItem.tsx index 0387ed38d..dd785a682 100644 --- a/src/view/com/notifications/FeedItem.tsx +++ b/src/view/com/notifications/FeedItem.tsx @@ -1,5 +1,4 @@ import React, {useMemo, useState, useEffect} from 'react' -import {observer} from 'mobx-react-lite' import { Animated, TouchableOpacity, @@ -9,6 +8,9 @@ import { } from 'react-native' import { AppBskyEmbedImages, + AppBskyFeedDefs, + AppBskyFeedPost, + ModerationOpts, ProfileModeration, moderateProfile, AppBskyEmbedRecordWithMedia, @@ -19,8 +21,7 @@ import { FontAwesomeIconStyle, Props, } from '@fortawesome/react-native-fontawesome' -import {NotificationsFeedItemModel} from 'state/models/feeds/notifications' -import {PostThreadModel} from 'state/models/content/post-thread' +import {FeedNotification} from '#/state/queries/notifications/feed' import {s, colors} from 'lib/styles' import {niceDate} from 'lib/strings/time' import {sanitizeDisplayName} from 'lib/strings/display-names' @@ -33,7 +34,6 @@ import {UserPreviewLink} from '../util/UserPreviewLink' import {ImageHorzList} from '../util/images/ImageHorzList' import {Post} from '../post/Post' import {Link, TextLink} from '../util/Link' -import {useStores} from 'state/index' import {usePalette} from 'lib/hooks/usePalette' import {useAnimatedValue} from 'lib/hooks/useAnimatedValue' import {formatCount} from '../util/numeric/format' @@ -56,40 +56,36 @@ interface Author { moderation: ProfileModeration } -export const FeedItem = observer(function FeedItemImpl({ +export function FeedItem({ item, + dataUpdatedAt, + moderationOpts, }: { - item: NotificationsFeedItemModel + item: FeedNotification + dataUpdatedAt: number + moderationOpts: ModerationOpts }) { - const store = useStores() const pal = usePalette('default') const [isAuthorsExpanded, setAuthorsExpanded] = useState<boolean>(false) const itemHref = useMemo(() => { - if (item.isLike || item.isRepost) { - const urip = new AtUri(item.subjectUri) - return `/profile/${urip.host}/post/${urip.rkey}` - } else if (item.isFollow) { - return makeProfileLink(item.author) - } else if (item.isReply) { - const urip = new AtUri(item.uri) + if (item.type === 'post-like' || item.type === 'repost') { + if (item.subjectUri) { + const urip = new AtUri(item.subjectUri) + return `/profile/${urip.host}/post/${urip.rkey}` + } + } else if (item.type === 'follow') { + return makeProfileLink(item.notification.author) + } else if (item.type === 'reply') { + const urip = new AtUri(item.notification.uri) return `/profile/${urip.host}/post/${urip.rkey}` - } else if (item.isCustomFeedLike) { - const urip = new AtUri(item.subjectUri) - return `/profile/${urip.host}/feed/${urip.rkey}` + } else if (item.type === 'feedgen-like') { + if (item.subjectUri) { + const urip = new AtUri(item.subjectUri) + return `/profile/${urip.host}/feed/${urip.rkey}` + } } return '' }, [item]) - const itemTitle = useMemo(() => { - if (item.isLike || item.isRepost) { - return 'Post' - } else if (item.isFollow) { - return item.author.handle - } else if (item.isReply) { - return 'Post' - } else if (item.isCustomFeedLike) { - return 'Custom Feed' - } - }, [item]) const onToggleAuthorsExpanded = () => { setAuthorsExpanded(currentlyExpanded => !currentlyExpanded) @@ -98,15 +94,12 @@ export const FeedItem = observer(function FeedItemImpl({ const authors: Author[] = useMemo(() => { return [ { - href: makeProfileLink(item.author), - did: item.author.did, - handle: item.author.handle, - displayName: item.author.displayName, - avatar: item.author.avatar, - moderation: moderateProfile( - item.author, - store.preferences.moderationOpts, - ), + href: makeProfileLink(item.notification.author), + did: item.notification.author.did, + handle: item.notification.author.handle, + displayName: item.notification.author.displayName, + avatar: item.notification.author.avatar, + moderation: moderateProfile(item.notification.author, moderationOpts), }, ...(item.additional?.map(({author}) => { return { @@ -115,33 +108,36 @@ export const FeedItem = observer(function FeedItemImpl({ handle: author.handle, displayName: author.displayName, avatar: author.avatar, - moderation: moderateProfile(author, store.preferences.moderationOpts), + moderation: moderateProfile(author, moderationOpts), } }) || []), ] - }, [store, item.additional, item.author]) + }, [item, moderationOpts]) - if (item.additionalPost?.notFound) { + if (item.subjectUri && !item.subject) { // don't render anything if the target post was deleted or unfindable return <View /> } - if (item.isReply || item.isMention || item.isQuote) { - if (!item.additionalPost || item.additionalPost?.error) { - // hide errors - it doesnt help the user to show them - return <View /> + if ( + item.type === 'reply' || + item.type === 'mention' || + item.type === 'quote' + ) { + if (!item.subject) { + return null } return ( <Link - testID={`feedItem-by-${item.author.handle}`} + testID={`feedItem-by-${item.notification.author.handle}`} href={itemHref} - title={itemTitle} noFeedback accessible={false}> <Post - view={item.additionalPost} + post={item.subject} + dataUpdatedAt={dataUpdatedAt} style={ - item.isRead + item.notification.isRead ? undefined : { backgroundColor: pal.colors.unreadNotifBg, @@ -156,23 +152,25 @@ export const FeedItem = observer(function FeedItemImpl({ let action = '' let icon: Props['icon'] | 'HeartIconSolid' let iconStyle: Props['style'] = [] - if (item.isLike) { + if (item.type === 'post-like') { action = 'liked your post' icon = 'HeartIconSolid' iconStyle = [ s.likeColor as FontAwesomeIconStyle, {position: 'relative', top: -4}, ] - } else if (item.isRepost) { + } else if (item.type === 'repost') { action = 'reposted your post' icon = 'retweet' iconStyle = [s.green3 as FontAwesomeIconStyle] - } else if (item.isFollow) { + } else if (item.type === 'follow') { action = 'followed you' icon = 'user-plus' iconStyle = [s.blue3 as FontAwesomeIconStyle] - } else if (item.isCustomFeedLike) { - action = `liked your custom feed '${new AtUri(item.subjectUri).rkey}'` + } else if (item.type === 'feedgen-like') { + action = `liked your custom feed${ + item.subjectUri ? ` '${new AtUri(item.subjectUri).rkey}}'` : '' + }` icon = 'HeartIconSolid' iconStyle = [ s.likeColor as FontAwesomeIconStyle, @@ -184,12 +182,12 @@ export const FeedItem = observer(function FeedItemImpl({ return ( <Link - testID={`feedItem-by-${item.author.handle}`} + testID={`feedItem-by-${item.notification.author.handle}`} style={[ styles.outer, pal.view, pal.border, - item.isRead + item.notification.isRead ? undefined : { backgroundColor: pal.colors.unreadNotifBg, @@ -197,9 +195,11 @@ export const FeedItem = observer(function FeedItemImpl({ }, ]} href={itemHref} - title={itemTitle} noFeedback - accessible={(item.isLike && authors.length === 1) || item.isRepost}> + accessible={ + (item.type === 'post-like' && authors.length === 1) || + item.type === 'repost' + }> <View style={styles.layoutIcon}> {/* TODO: Prevent conditional rendering and move toward composable notifications for clearer accessibility labeling */} @@ -244,24 +244,24 @@ export const FeedItem = observer(function FeedItemImpl({ </> ) : undefined} <Text style={[pal.text]}> {action}</Text> - <TimeElapsed timestamp={item.indexedAt}> + <TimeElapsed timestamp={item.notification.indexedAt}> {({timeElapsed}) => ( <Text style={[pal.textLight, styles.pointer]} - title={niceDate(item.indexedAt)}> + title={niceDate(item.notification.indexedAt)}> {' ' + timeElapsed} </Text> )} </TimeElapsed> </Text> </ExpandListPressable> - {item.isLike || item.isRepost || item.isQuote ? ( - <AdditionalPostText additionalPost={item.additionalPost} /> + {item.type === 'post-like' || item.type === 'repost' ? ( + <AdditionalPostText post={item.subject} /> ) : null} </View> </Link> ) -}) +} function ExpandListPressable({ hasMultipleAuthors, @@ -423,34 +423,25 @@ function ExpandedAuthorsList({ ) } -function AdditionalPostText({ - additionalPost, -}: { - additionalPost?: PostThreadModel -}) { +function AdditionalPostText({post}: {post?: AppBskyFeedDefs.PostView}) { const pal = usePalette('default') - if ( - !additionalPost || - !additionalPost.thread?.postRecord || - additionalPost.error - ) { - return <View /> + if (post && AppBskyFeedPost.isRecord(post?.record)) { + const text = post.record.text + const images = AppBskyEmbedImages.isView(post.embed) + ? post.embed.images + : AppBskyEmbedRecordWithMedia.isView(post.embed) && + AppBskyEmbedImages.isView(post.embed.media) + ? post.embed.media.images + : undefined + return ( + <> + {text?.length > 0 && <Text style={pal.textLight}>{text}</Text>} + {images && images?.length > 0 && ( + <ImageHorzList images={images} style={styles.additionalPostImages} /> + )} + </> + ) } - const text = additionalPost.thread?.postRecord.text - const images = AppBskyEmbedImages.isView(additionalPost.thread.post.embed) - ? additionalPost.thread.post.embed.images - : AppBskyEmbedRecordWithMedia.isView(additionalPost.thread.post.embed) && - AppBskyEmbedImages.isView(additionalPost.thread.post.embed.media) - ? additionalPost.thread.post.embed.media.images - : undefined - return ( - <> - {text?.length > 0 && <Text style={pal.textLight}>{text}</Text>} - {images && images?.length > 0 && ( - <ImageHorzList images={images} style={styles.additionalPostImages} /> - )} - </> - ) } const styles = StyleSheet.create({ |