import React, {useMemo, useState} from 'react' import {observer} from 'mobx-react-lite' import {StyleSheet, Text, View} from 'react-native' import {AtUri} from '../../../third-party/uri' import * as PostType from '../../../third-party/api/src/client/types/app/bsky/feed/post' import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome' import {PostThreadViewPostModel} from '../../../state/models/post-thread-view' import {Link} from '../util/Link' import {RichText} from '../util/RichText' import {PostDropdownBtn} from '../util/DropdownBtn' import Toast from '../util/Toast' import {UserAvatar} from '../util/UserAvatar' import {s, colors} from '../../lib/styles' import {ago, pluralize} from '../../../lib/strings' import {useStores} from '../../../state' import {PostMeta} from '../util/PostMeta' import {PostCtrls} from '../util/PostCtrls' const PARENT_REPLY_LINE_LENGTH = 8 export const PostThreadItem = observer(function PostThreadItem({ item, onPostReply, }: { item: PostThreadViewPostModel onPostReply: () => void }) { const store = useStores() const [deleted, setDeleted] = useState(false) const record = item.record as unknown as PostType.Record const hasEngagement = item.upvoteCount || item.repostCount const itemHref = useMemo(() => { const urip = new AtUri(item.uri) return `/profile/${item.author.handle}/post/${urip.rkey}` }, [item.uri, item.author.handle]) const itemTitle = `Post by ${item.author.handle}` const authorHref = `/profile/${item.author.handle}` const authorTitle = item.author.handle const upvotesHref = useMemo(() => { const urip = new AtUri(item.uri) return `/profile/${item.author.handle}/post/${urip.rkey}/upvoted-by` }, [item.uri, item.author.handle]) const upvotesTitle = 'Upvotes on this post' const repostsHref = useMemo(() => { const urip = new AtUri(item.uri) return `/profile/${item.author.handle}/post/${urip.rkey}/reposted-by` }, [item.uri, item.author.handle]) const repostsTitle = 'Reposts of this post' const onPressReply = () => { store.shell.openComposer({ replyTo: { uri: item.uri, cid: item.cid, text: item.record.text as string, author: { handle: item.author.handle, displayName: item.author.displayName, }, }, onPost: onPostReply, }) } const onPressToggleRepost = () => { item .toggleRepost() .catch(e => console.error('Failed to toggle repost', record, e)) } const onPressToggleUpvote = () => { item .toggleUpvote() .catch(e => console.error('Failed to toggle upvote', record, e)) } const onDeletePost = () => { item.delete().then( () => { setDeleted(true) Toast.show('Post deleted', { position: Toast.positions.TOP, }) }, e => { console.error(e) Toast.show('Failed to delete post, please try again', { position: Toast.positions.TOP, }) }, ) } if (item._isHighlightedPost) { return ( {item.author.displayName || item.author.handle} · {ago(item.indexedAt)} @{item.author.handle} {item._isHighlightedPost && hasEngagement ? ( {item.repostCount ? ( {item.repostCount} {' '} {pluralize(item.repostCount, 'repost')} ) : ( <> )} {item.upvoteCount ? ( {item.upvoteCount} {' '} {pluralize(item.upvoteCount, 'upvote')} ) : ( <> )} ) : ( <> )} ) } else { return ( {!!item.replyingToAuthor && } {item.replies?.length !== 0 && } {item.replyingToAuthor && item.replyingToAuthor !== item.author.handle && ( Replying to @{item.replyingToAuthor} )} ) } }) const styles = StyleSheet.create({ outer: { backgroundColor: colors.white, borderRadius: 6, margin: 2, marginBottom: 0, }, parentReplyLine: { position: 'absolute', left: 34, top: -1 * PARENT_REPLY_LINE_LENGTH + 6, height: PARENT_REPLY_LINE_LENGTH, borderLeftWidth: 2, borderLeftColor: colors.gray2, }, childReplyLine: { position: 'absolute', left: 34, top: 65, bottom: 0, borderLeftWidth: 2, borderLeftColor: colors.gray2, }, layout: { flexDirection: 'row', }, layoutAvi: { width: 70, paddingLeft: 10, paddingTop: 10, paddingBottom: 10, }, layoutContent: { flex: 1, paddingRight: 10, paddingTop: 10, paddingBottom: 10, }, meta: { flexDirection: 'row', paddingTop: 2, paddingBottom: 2, }, metaItem: { paddingRight: 5, maxWidth: 240, }, postText: { fontFamily: 'Helvetica Neue', fontSize: 17, lineHeight: 22.1, // 1.3 of 17px }, postTextContainer: { flexDirection: 'row', alignItems: 'center', flexWrap: 'wrap', paddingBottom: 8, minHeight: 36, }, postTextLarge: { fontSize: 24, lineHeight: 32, fontWeight: '300', }, postTextLargeContainer: { paddingLeft: 4, paddingBottom: 20, }, expandedInfo: { flexDirection: 'row', padding: 10, borderColor: colors.gray2, borderTopWidth: 1, borderBottomWidth: 1, marginTop: 5, marginBottom: 10, }, expandedInfoItem: { marginRight: 10, }, })