Handle blocks in list and chat
This commit is contained in:
@@ -12,6 +12,10 @@ import {
|
||||
} from '#/state/queries/messages/conversation'
|
||||
import {useLeaveConvo} from '#/state/queries/messages/leave-conversation'
|
||||
import {useMuteConvo} from '#/state/queries/messages/mute-conversation'
|
||||
import {
|
||||
useAwaitedProfileBlockMutation,
|
||||
useAwaitedProfileUnblockMutation,
|
||||
} from '#/state/queries/profile'
|
||||
import * as Toast from '#/view/com/util/Toast'
|
||||
import {atoms as a, useTheme} from '#/alf'
|
||||
import {ArrowBoxLeft_Stroke2_Corner0_Rounded as ArrowBoxLeft} from '#/components/icons/ArrowBoxLeft'
|
||||
@@ -34,10 +38,11 @@ let ConvoMenu = ({
|
||||
showMarkAsRead,
|
||||
hideTrigger,
|
||||
triggerOpacity,
|
||||
onUpdateConvo,
|
||||
}: {
|
||||
convo: ChatBskyConvoDefs.ConvoView
|
||||
profile: AppBskyActorDefs.ProfileViewBasic
|
||||
onUpdateConvo?: (convo: ChatBskyConvoDefs.ConvoView) => void
|
||||
onUpdateConvo?: () => void
|
||||
control?: Menu.MenuControlProps
|
||||
currentScreen: 'list' | 'conversation'
|
||||
showMarkAsRead?: boolean
|
||||
@@ -64,12 +69,41 @@ let ConvoMenu = ({
|
||||
} else {
|
||||
Toast.show(_(msg`Chat unmuted`))
|
||||
}
|
||||
onUpdateConvo?.()
|
||||
},
|
||||
onError: () => {
|
||||
Toast.show(_(msg`Could not mute chat`))
|
||||
},
|
||||
})
|
||||
|
||||
const {mutateAsync: blockProfile, isPending: isBlockPending} =
|
||||
useAwaitedProfileBlockMutation()
|
||||
const {mutateAsync: unblockProfile, isPending: isUnblockPending} =
|
||||
useAwaitedProfileUnblockMutation()
|
||||
const isBlockMutationPending = isBlockPending || isUnblockPending
|
||||
const isBlocking = Boolean(profile.viewer?.blocking)
|
||||
|
||||
const toggleBlock = useCallback(async () => {
|
||||
if (isBlockMutationPending) return
|
||||
|
||||
if (profile.viewer?.blocking) {
|
||||
await unblockProfile({
|
||||
subject: profile.did,
|
||||
blockUri: profile.viewer?.blocking,
|
||||
})
|
||||
} else {
|
||||
await blockProfile({subject: profile.did})
|
||||
}
|
||||
|
||||
onUpdateConvo?.()
|
||||
}, [
|
||||
profile,
|
||||
isBlockMutationPending,
|
||||
blockProfile,
|
||||
unblockProfile,
|
||||
onUpdateConvo,
|
||||
])
|
||||
|
||||
const {mutate: leaveConvo} = useLeaveConvo(convo?.id, {
|
||||
onSuccess: () => {
|
||||
if (currentScreen === 'conversation') {
|
||||
@@ -146,18 +180,17 @@ let ConvoMenu = ({
|
||||
</Menu.Item>
|
||||
</Menu.Group>
|
||||
<Menu.Divider />
|
||||
{/* TODO(samuel): implement this */}
|
||||
<Menu.Group>
|
||||
<Menu.Item
|
||||
label={_(msg`Block account`)}
|
||||
onPress={() => {}}
|
||||
disabled>
|
||||
disabled={isBlockMutationPending}
|
||||
label={
|
||||
isBlocking ? _(msg`Unblock account`) : _(msg`Block account`)
|
||||
}
|
||||
onPress={toggleBlock}>
|
||||
<Menu.ItemText>
|
||||
<Trans>Block account</Trans>
|
||||
{isBlocking ? _(msg`Unblock account`) : _(msg`Block account`)}
|
||||
</Menu.ItemText>
|
||||
<Menu.ItemIcon
|
||||
icon={profile.viewer?.blocking ? PersonCheck : PersonX}
|
||||
/>
|
||||
<Menu.ItemIcon icon={isBlocking ? PersonX : PersonCheck} />
|
||||
</Menu.Item>
|
||||
<Menu.Item
|
||||
label={_(msg`Report conversation`)}
|
||||
|
||||
@@ -98,6 +98,7 @@ function Inner() {
|
||||
* Any other convo states (atm) are "ready" states
|
||||
*/
|
||||
|
||||
console.log(convoState.blocks)
|
||||
return (
|
||||
<KeyboardProvider>
|
||||
<KeyboardAvoidingView
|
||||
@@ -242,6 +243,7 @@ let Header = ({
|
||||
convo={convoState.convo}
|
||||
profile={profile}
|
||||
currentScreen="conversation"
|
||||
onUpdateConvo={convoState.revalidateConvo}
|
||||
/>
|
||||
) : (
|
||||
<View style={{width: 30}} />
|
||||
|
||||
@@ -4,9 +4,11 @@ import {ChatBskyConvoDefs} from '@atproto/api'
|
||||
import {msg} from '@lingui/macro'
|
||||
import {useLingui} from '@lingui/react'
|
||||
import {useNavigation} from '@react-navigation/native'
|
||||
import {useQueryClient} from '@tanstack/react-query'
|
||||
|
||||
import {NavigationProp} from '#/lib/routes/types'
|
||||
import {isNative} from '#/platform/detection'
|
||||
import {RQKEY as ListConvosQueryKey} from '#/state/queries/messages/list-converations'
|
||||
import {useSession} from '#/state/session'
|
||||
import {TimeElapsed} from '#/view/com/util/TimeElapsed'
|
||||
import {UserAvatar} from '#/view/com/util/UserAvatar'
|
||||
@@ -36,6 +38,7 @@ export function ChatListItem({
|
||||
const displayName = isDeletedAccount
|
||||
? 'Deleted Account'
|
||||
: otherUser?.displayName || otherUser?.handle
|
||||
const queryClient = useQueryClient()
|
||||
|
||||
let lastMessage = _(msg`No messages yet`)
|
||||
let lastMessageSentAt: string | null = null
|
||||
@@ -73,6 +76,10 @@ export function ChatListItem({
|
||||
})
|
||||
}, [convo.id, navigation])
|
||||
|
||||
const onUpdateConvo = React.useCallback(() => {
|
||||
queryClient.invalidateQueries({queryKey: ListConvosQueryKey})
|
||||
}, [queryClient])
|
||||
|
||||
if (!otherUser) {
|
||||
return null
|
||||
}
|
||||
@@ -204,6 +211,7 @@ export function ChatListItem({
|
||||
triggerOpacity={
|
||||
!gtMobile || showActions || menuControl.isOpen ? 1 : 0
|
||||
}
|
||||
onUpdateConvo={onUpdateConvo}
|
||||
/>
|
||||
</View>
|
||||
</View>
|
||||
|
||||
@@ -384,6 +384,9 @@ function useProfileUnmuteMutation() {
|
||||
|
||||
export function useProfileBlockMutationQueue(
|
||||
profile: Shadow<AppBskyActorDefs.ProfileViewDetailed>,
|
||||
options?: {
|
||||
onSuccess?: () => void
|
||||
},
|
||||
) {
|
||||
const queryClient = useQueryClient()
|
||||
const did = profile.did
|
||||
@@ -414,6 +417,7 @@ export function useProfileBlockMutationQueue(
|
||||
updateProfileShadow(queryClient, did, {
|
||||
blockingUri: finalBlockingUri,
|
||||
})
|
||||
options?.onSuccess?.()
|
||||
},
|
||||
})
|
||||
|
||||
@@ -478,6 +482,60 @@ function useProfileUnblockMutation() {
|
||||
})
|
||||
}
|
||||
|
||||
export function useAwaitedProfileBlockMutation() {
|
||||
const {currentAccount} = useSession()
|
||||
const {getAgent} = useAgent()
|
||||
const queryClient = useQueryClient()
|
||||
|
||||
return useMutation({
|
||||
mutationFn: async ({subject}: {subject: string}) => {
|
||||
if (!currentAccount) {
|
||||
throw new Error('Not signed in')
|
||||
}
|
||||
await getAgent().app.bsky.graph.block.create(
|
||||
{repo: currentAccount.did},
|
||||
{subject: subject, createdAt: new Date().toISOString()},
|
||||
)
|
||||
await whenAppViewReady(
|
||||
getAgent,
|
||||
subject,
|
||||
res => !!res.data.viewer?.blocking,
|
||||
)
|
||||
},
|
||||
onSuccess(_, {subject}) {
|
||||
queryClient.invalidateQueries({queryKey: RQKEY_MY_BLOCKED()})
|
||||
resetProfilePostsQueries(queryClient, subject, 1000)
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
export function useAwaitedProfileUnblockMutation() {
|
||||
const {currentAccount} = useSession()
|
||||
const {getAgent} = useAgent()
|
||||
const queryClient = useQueryClient()
|
||||
|
||||
return useMutation<void, Error, {subject: string; blockUri: string}>({
|
||||
mutationFn: async ({blockUri, subject}) => {
|
||||
if (!currentAccount) {
|
||||
throw new Error('Not signed in')
|
||||
}
|
||||
const {rkey} = new AtUri(blockUri)
|
||||
await getAgent().app.bsky.graph.block.delete({
|
||||
repo: currentAccount.did,
|
||||
rkey,
|
||||
})
|
||||
await whenAppViewReady(
|
||||
getAgent,
|
||||
subject,
|
||||
res => !res.data.viewer?.blocking,
|
||||
)
|
||||
},
|
||||
onSuccess(_, {subject}) {
|
||||
resetProfilePostsQueries(queryClient, subject, 1000)
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
export function precacheProfile(
|
||||
queryClient: QueryClient,
|
||||
profile: AppBskyActorDefs.ProfileViewBasic,
|
||||
|
||||
Reference in New Issue
Block a user