my fork of the bluesky client

Add ability to block account from post dropdown menu (#6091)

Co-authored-by: Hailey <me@haileyok.com>
Co-authored-by: Hailey <hailey@blueskyweb.xyz>

authored by

rshigg
Hailey
Hailey
and committed by
GitHub
ced67876 247bc100

+49 -9
+1 -1
src/state/queries/profile.ts
··· 409 } 410 411 export function useProfileBlockMutationQueue( 412 - profile: Shadow<AppBskyActorDefs.ProfileViewDetailed>, 413 ) { 414 const queryClient = useQueryClient() 415 const did = profile.did
··· 409 } 410 411 export function useProfileBlockMutationQueue( 412 + profile: Shadow<AppBskyActorDefs.ProfileViewBasic>, 413 ) { 414 const queryClient = useQueryClient() 415 const did = profile.did
+48 -8
src/view/com/util/forms/PostDropdownBtnMenuItems.tsx
··· 29 import {logger} from '#/logger' 30 import {isWeb} from '#/platform/detection' 31 import {Shadow} from '#/state/cache/post-shadow' 32 import {useFeedFeedbackContext} from '#/state/feed-feedback' 33 import {useLanguagePrefs} from '#/state/preferences' 34 import {useHiddenPosts, useHiddenPostsApi} from '#/state/preferences' ··· 39 } from '#/state/queries/post' 40 import {useToggleQuoteDetachmentMutation} from '#/state/queries/postgate' 41 import {getMaybeDetachedQuoteEmbed} from '#/state/queries/postgate/util' 42 import {useToggleReplyVisibilityMutation} from '#/state/queries/threadgate' 43 import {useSession} from '#/state/session' 44 import {useMergedThreadgateHiddenReplies} from '#/state/threadgate-hidden-replies' ··· 64 import {Filter_Stroke2_Corner0_Rounded as Filter} from '#/components/icons/Filter' 65 import {Mute_Stroke2_Corner0_Rounded as Mute} from '#/components/icons/Mute' 66 import {PaperPlane_Stroke2_Corner0_Rounded as Send} from '#/components/icons/PaperPlane' 67 import {Pin_Stroke2_Corner0_Rounded as PinIcon} from '#/components/icons/Pin' 68 import {SettingsGear2_Stroke2_Corner0_Rounded as Gear} from '#/components/icons/SettingsGear2' 69 import {SpeakerVolumeFull_Stroke2_Corner0_Rounded as Unmute} from '#/components/icons/Speaker' ··· 107 const openLink = useOpenLink() 108 const navigation = useNavigation<NavigationProp>() 109 const {mutedWordsDialogControl} = useGlobalDialogsControlContext() 110 const reportDialogControl = useReportDialogControl() 111 const deletePromptControl = useDialogControl() 112 const hidePromptControl = useDialogControl() ··· 121 122 const postUri = post.uri 123 const postCid = post.cid 124 - const postAuthor = post.author 125 const quoteEmbed = React.useMemo(() => { 126 if (!currentAccount || !post.embed) return 127 return getMaybeDetachedQuoteEmbed({ ··· 147 148 const {mutateAsync: toggleQuoteDetachment, isPending: isDetachPending} = 149 useToggleQuoteDetachmentMutation() 150 151 const prefetchPostInteractionSettings = usePrefetchPostInteractionSettings({ 152 postUri: post.uri, ··· 348 }) 349 }, [isPinned, pinPostMutate, postCid, postUri]) 350 351 return ( 352 <> 353 <Menu.Outer> ··· 578 <Menu.Divider /> 579 <Menu.Group> 580 {!isAuthor && ( 581 - <Menu.Item 582 - testID="postDropdownReportBtn" 583 - label={_(msg`Report post`)} 584 - onPress={() => reportDialogControl.open()}> 585 - <Menu.ItemText>{_(msg`Report post`)}</Menu.ItemText> 586 - <Menu.ItemIcon icon={Warning} position="right" /> 587 - </Menu.Item> 588 )} 589 590 {isAuthor && ( ··· 703 )} 704 onConfirm={onToggleReplyVisibility} 705 confirmButtonCta={_(msg`Yes, hide`)} 706 /> 707 </> 708 )
··· 29 import {logger} from '#/logger' 30 import {isWeb} from '#/platform/detection' 31 import {Shadow} from '#/state/cache/post-shadow' 32 + import {useProfileShadow} from '#/state/cache/profile-shadow' 33 import {useFeedFeedbackContext} from '#/state/feed-feedback' 34 import {useLanguagePrefs} from '#/state/preferences' 35 import {useHiddenPosts, useHiddenPostsApi} from '#/state/preferences' ··· 40 } from '#/state/queries/post' 41 import {useToggleQuoteDetachmentMutation} from '#/state/queries/postgate' 42 import {getMaybeDetachedQuoteEmbed} from '#/state/queries/postgate/util' 43 + import {useProfileBlockMutationQueue} from '#/state/queries/profile' 44 import {useToggleReplyVisibilityMutation} from '#/state/queries/threadgate' 45 import {useSession} from '#/state/session' 46 import {useMergedThreadgateHiddenReplies} from '#/state/threadgate-hidden-replies' ··· 66 import {Filter_Stroke2_Corner0_Rounded as Filter} from '#/components/icons/Filter' 67 import {Mute_Stroke2_Corner0_Rounded as Mute} from '#/components/icons/Mute' 68 import {PaperPlane_Stroke2_Corner0_Rounded as Send} from '#/components/icons/PaperPlane' 69 + import {PersonX_Stroke2_Corner0_Rounded as PersonX} from '#/components/icons/Person' 70 import {Pin_Stroke2_Corner0_Rounded as PinIcon} from '#/components/icons/Pin' 71 import {SettingsGear2_Stroke2_Corner0_Rounded as Gear} from '#/components/icons/SettingsGear2' 72 import {SpeakerVolumeFull_Stroke2_Corner0_Rounded as Unmute} from '#/components/icons/Speaker' ··· 110 const openLink = useOpenLink() 111 const navigation = useNavigation<NavigationProp>() 112 const {mutedWordsDialogControl} = useGlobalDialogsControlContext() 113 + const blockPromptControl = useDialogControl() 114 const reportDialogControl = useReportDialogControl() 115 const deletePromptControl = useDialogControl() 116 const hidePromptControl = useDialogControl() ··· 125 126 const postUri = post.uri 127 const postCid = post.cid 128 + const postAuthor = useProfileShadow(post.author) 129 const quoteEmbed = React.useMemo(() => { 130 if (!currentAccount || !post.embed) return 131 return getMaybeDetachedQuoteEmbed({ ··· 151 152 const {mutateAsync: toggleQuoteDetachment, isPending: isDetachPending} = 153 useToggleQuoteDetachmentMutation() 154 + 155 + const [queueBlock] = useProfileBlockMutationQueue(postAuthor) 156 157 const prefetchPostInteractionSettings = usePrefetchPostInteractionSettings({ 158 postUri: post.uri, ··· 354 }) 355 }, [isPinned, pinPostMutate, postCid, postUri]) 356 357 + const onBlockAuthor = useCallback(async () => { 358 + try { 359 + await queueBlock() 360 + Toast.show(_(msg`Account blocked`)) 361 + } catch (e: any) { 362 + if (e?.name !== 'AbortError') { 363 + logger.error('Failed to block account', {message: e}) 364 + Toast.show(_(msg`There was an issue! ${e.toString()}`), 'xmark') 365 + } 366 + } 367 + }, [_, queueBlock]) 368 + 369 return ( 370 <> 371 <Menu.Outer> ··· 596 <Menu.Divider /> 597 <Menu.Group> 598 {!isAuthor && ( 599 + <> 600 + {!postAuthor.viewer?.blocking && ( 601 + <Menu.Item 602 + testID="postDropdownBlockBtn" 603 + label={_(msg`Block account`)} 604 + onPress={() => blockPromptControl.open()}> 605 + <Menu.ItemText>{_(msg`Block account`)}</Menu.ItemText> 606 + <Menu.ItemIcon icon={PersonX} position="right" /> 607 + </Menu.Item> 608 + )} 609 + <Menu.Item 610 + testID="postDropdownReportBtn" 611 + label={_(msg`Report post`)} 612 + onPress={() => reportDialogControl.open()}> 613 + <Menu.ItemText>{_(msg`Report post`)}</Menu.ItemText> 614 + <Menu.ItemIcon icon={Warning} position="right" /> 615 + </Menu.Item> 616 + </> 617 )} 618 619 {isAuthor && ( ··· 732 )} 733 onConfirm={onToggleReplyVisibility} 734 confirmButtonCta={_(msg`Yes, hide`)} 735 + /> 736 + 737 + <Prompt.Basic 738 + control={blockPromptControl} 739 + title={_(msg`Block Account?`)} 740 + description={_( 741 + msg`Blocked accounts cannot reply in your threads, mention you, or otherwise interact with you.`, 742 + )} 743 + onConfirm={onBlockAuthor} 744 + confirmButtonCta={_(msg`Block`)} 745 + confirmButtonColor="negative" 746 /> 747 </> 748 )