diff options
Diffstat (limited to 'src/view')
-rw-r--r-- | src/view/com/post-thread/PostThreadItem.tsx | 22 | ||||
-rw-r--r-- | src/view/com/post/Post.tsx | 27 | ||||
-rw-r--r-- | src/view/com/posts/FeedItem.tsx | 28 | ||||
-rw-r--r-- | src/view/com/util/DropdownBtn.tsx | 23 | ||||
-rw-r--r-- | src/view/com/util/PostMeta.tsx | 6 | ||||
-rw-r--r-- | src/view/index.ts | 2 |
6 files changed, 99 insertions, 9 deletions
diff --git a/src/view/com/post-thread/PostThreadItem.tsx b/src/view/com/post-thread/PostThreadItem.tsx index c63364ecb..0ee52660b 100644 --- a/src/view/com/post-thread/PostThreadItem.tsx +++ b/src/view/com/post-thread/PostThreadItem.tsx @@ -1,4 +1,4 @@ -import React, {useMemo} from 'react' +import React, {useMemo, useState} from 'react' import {observer} from 'mobx-react-lite' import {StyleSheet, Text, View} from 'react-native' import Svg, {Line} from 'react-native-svg' @@ -9,6 +9,7 @@ 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' @@ -28,6 +29,7 @@ export const PostThreadItem = observer(function PostThreadItem({ onPostReply: () => void }) { const store = useStores() + const [deleted, setDeleted] = useState(false) const record = item.record as unknown as PostType.Record const hasEngagement = item.upvoteCount || item.downvoteCount || item.repostCount @@ -76,6 +78,22 @@ export const PostThreadItem = observer(function PostThreadItem({ .toggleDownvote() .catch(e => console.error('Failed to toggle downvote', 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 ( @@ -250,6 +268,8 @@ export const PostThreadItem = observer(function PostThreadItem({ authorHandle={item.author.handle} authorDisplayName={item.author.displayName} timestamp={item.indexedAt} + isAuthor={item.author.did === store.me.did} + onDeletePost={onDeletePost} /> {item.replyingToAuthor && item.replyingToAuthor !== item.author.handle && ( diff --git a/src/view/com/post/Post.tsx b/src/view/com/post/Post.tsx index 83bf8bed8..7d2edff4c 100644 --- a/src/view/com/post/Post.tsx +++ b/src/view/com/post/Post.tsx @@ -10,14 +10,15 @@ import {UserInfoText} from '../util/UserInfoText' import {PostMeta} from '../util/PostMeta' import {PostCtrls} from '../util/PostCtrls' import {RichText} from '../util/RichText' +import Toast from '../util/Toast' import {UserAvatar} from '../util/UserAvatar' import {useStores} from '../../../state' import {s, colors} from '../../lib/styles' -import {ago} from '../../lib/strings' export const Post = observer(function Post({uri}: {uri: string}) { const store = useStores() const [view, setView] = useState<PostThreadViewModel | undefined>() + const [deleted, setDeleted] = useState(false) useEffect(() => { if (view?.params.uri === uri) { @@ -28,6 +29,12 @@ export const Post = observer(function Post({uri}: {uri: string}) { newView.setup().catch(err => console.error('Failed to fetch post', err)) }, [uri, view?.params.uri, store]) + // deleted + // = + if (deleted) { + return <View /> + } + // loading // = if (!view || view.isLoading || view.params.uri !== uri) { @@ -83,6 +90,22 @@ export const Post = observer(function Post({uri}: {uri: string}) { .toggleDownvote() .catch(e => console.error('Failed to toggle downvote', 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, + }) + }, + ) + } return ( <Link style={styles.outer} href={itemHref} title={itemTitle}> @@ -102,6 +125,8 @@ export const Post = observer(function Post({uri}: {uri: string}) { authorHandle={item.author.handle} authorDisplayName={item.author.displayName} timestamp={item.indexedAt} + isAuthor={item.author.did === store.me.did} + onDeletePost={onDeletePost} /> {replyHref !== '' && ( <View style={[s.flexRow, s.mb2, {alignItems: 'center'}]}> diff --git a/src/view/com/posts/FeedItem.tsx b/src/view/com/posts/FeedItem.tsx index d1e891d62..e4c54b32a 100644 --- a/src/view/com/posts/FeedItem.tsx +++ b/src/view/com/posts/FeedItem.tsx @@ -1,16 +1,16 @@ -import React, {useMemo} from 'react' +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 {FeedItemModel} from '../../../state/models/feed-view' -import {SharePostModel} from '../../../state/models/shell-ui' import {Link} from '../util/Link' import {UserInfoText} from '../util/UserInfoText' import {PostMeta} from '../util/PostMeta' import {PostCtrls} from '../util/PostCtrls' import {RichText} from '../util/RichText' +import Toast from '../util/Toast' import {UserAvatar} from '../util/UserAvatar' import {s, colors} from '../../lib/styles' import {useStores} from '../../../state' @@ -21,6 +21,7 @@ export const FeedItem = observer(function FeedItem({ item: FeedItemModel }) { const store = useStores() + const [deleted, setDeleted] = useState(false) const record = item.record as unknown as PostType.Record const itemHref = useMemo(() => { const urip = new AtUri(item.uri) @@ -57,8 +58,25 @@ export const FeedItem = observer(function FeedItem({ .toggleDownvote() .catch(e => console.error('Failed to toggle downvote', record, e)) } - const onPressShare = (uri: string) => { - store.shell.openModal(new SharePostModel(uri)) + 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 (deleted) { + return <View /> } return ( @@ -107,6 +125,8 @@ export const FeedItem = observer(function FeedItem({ authorHandle={item.author.handle} authorDisplayName={item.author.displayName} timestamp={item.indexedAt} + isAuthor={item.author.did === store.me.did} + onDeletePost={onDeletePost} /> {replyHref !== '' && ( <View style={[s.flexRow, s.mb5, {alignItems: 'center'}]}> diff --git a/src/view/com/util/DropdownBtn.tsx b/src/view/com/util/DropdownBtn.tsx index 960293320..bef193f1d 100644 --- a/src/view/com/util/DropdownBtn.tsx +++ b/src/view/com/util/DropdownBtn.tsx @@ -13,7 +13,7 @@ import RootSiblings from 'react-native-root-siblings' import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome' import {colors} from '../../lib/styles' import {useStores} from '../../../state' -import {SharePostModel} from '../../../state/models/shell-ui' +import {SharePostModel, ConfirmModel} from '../../../state/models/shell-ui' export interface DropdownItem { icon?: IconProp @@ -69,11 +69,15 @@ export function PostDropdownBtn({ children, itemHref, itemTitle, + isAuthor, + onDeletePost, }: { style?: StyleProp<ViewStyle> children?: React.ReactNode itemHref: string itemTitle: string + isAuthor: boolean + onDeletePost: () => void }) { const store = useStores() @@ -92,7 +96,22 @@ export function PostDropdownBtn({ store.shell.openModal(new SharePostModel(itemHref)) }, }, - ] + isAuthor + ? { + icon: ['far', 'trash-can'], + label: 'Delete post', + onPress() { + store.shell.openModal( + new ConfirmModel( + 'Delete this post?', + 'Are you sure? This can not be undone.', + onDeletePost, + ), + ) + }, + } + : undefined, + ].filter(Boolean) as DropdownItem[] return ( <DropdownBtn style={style} items={dropdownItems} menuWidth={200}> diff --git a/src/view/com/util/PostMeta.tsx b/src/view/com/util/PostMeta.tsx index 95dfcbd64..840de8709 100644 --- a/src/view/com/util/PostMeta.tsx +++ b/src/view/com/util/PostMeta.tsx @@ -13,6 +13,8 @@ interface PostMetaOpts { authorHandle: string authorDisplayName: string | undefined timestamp: string + isAuthor: boolean + onDeletePost: () => void } export function PostMeta(opts: PostMetaOpts) { @@ -48,7 +50,9 @@ export function PostMeta(opts: PostMetaOpts) { <PostDropdownBtn style={styles.metaItem} itemHref={opts.itemHref} - itemTitle={opts.itemTitle}> + itemTitle={opts.itemTitle} + isAuthor={opts.isAuthor} + onDeletePost={opts.onDeletePost}> <FontAwesomeIcon icon="ellipsis-h" size={14} style={[s.mt2, s.mr5]} /> </PostDropdownBtn> </View> diff --git a/src/view/index.ts b/src/view/index.ts index 78361e75b..69078dae9 100644 --- a/src/view/index.ts +++ b/src/view/index.ts @@ -52,6 +52,7 @@ import {faUserCheck} from '@fortawesome/free-solid-svg-icons/faUserCheck' import {faUserPlus} from '@fortawesome/free-solid-svg-icons/faUserPlus' import {faUserXmark} from '@fortawesome/free-solid-svg-icons/faUserXmark' import {faTicket} from '@fortawesome/free-solid-svg-icons/faTicket' +import {faTrashCan} from '@fortawesome/free-regular-svg-icons/faTrashCan' import {faX} from '@fortawesome/free-solid-svg-icons/faX' export function setup() { @@ -108,6 +109,7 @@ export function setup() { faUserPlus, faUserXmark, faTicket, + faTrashCan, faX, ) } |