[SDK] Migrate group chat and join links to the chat client (#11358)

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Samuel Newman
2026-08-13 22:26:16 +03:00
committed by GitHub
parent 0e8e0b2ab4
commit ea4f70fb1e
21 changed files with 263 additions and 259 deletions
+21 -24
View File
@@ -1,5 +1,4 @@
import {useCallback} from 'react' import {useCallback} from 'react'
import {ChatBskyGroupCreateGroup} from '@atproto/api'
import {Trans, useLingui} from '@lingui/react/macro' import {Trans, useLingui} from '@lingui/react/macro'
import {useRequireEmailVerification} from '#/lib/hooks/useRequireEmailVerification' import {useRequireEmailVerification} from '#/lib/hooks/useRequireEmailVerification'
@@ -88,29 +87,27 @@ export function NewChat({
let errorMessage = l`An issue occurred starting the group chat, please try again.` let errorMessage = l`An issue occurred starting the group chat, please try again.`
if (isNetworkError(error)) { if (isNetworkError(error)) {
errorMessage = l`A network error occurred. Please check your internet connection.` errorMessage = l`A network error occurred. Please check your internet connection.`
} else if ( } else {
error instanceof ChatBskyGroupCreateGroup.AccountSuspendedError switch (matchXrpcError(error, chat.bsky.group.createGroup)) {
) { case 'AccountSuspended':
errorMessage = l`Suspended accounts cannot participate in a group chat.` errorMessage = l`Suspended accounts cannot participate in a group chat.`
} else if (error instanceof ChatBskyGroupCreateGroup.BlockedActorError) { break
errorMessage = l`One of the selected recipients has blocked you and cannot be messaged.` case 'BlockedActor':
} else if ( errorMessage = l`One of the selected recipients has blocked you and cannot be messaged.`
error instanceof break
ChatBskyGroupCreateGroup.NewAccountCannotCreateGroupError case 'NewAccountCannotCreateGroup':
) { errorMessage = l`You cannot create a group chat yet.`
errorMessage = l`You cannot create a group chat yet.` break
} else if ( case 'NotFollowedBySender':
error instanceof ChatBskyGroupCreateGroup.NotFollowedBySenderError errorMessage = l`A selected recipient is not followed by the sender.`
) { break
errorMessage = l`A selected recipient is not followed by the sender.` case 'RecipientNotFound':
} else if ( errorMessage = l`Unable to find a selected recipient.`
error instanceof ChatBskyGroupCreateGroup.RecipientNotFoundError break
) { case 'UserForbidsGroups':
errorMessage = l`Unable to find a selected recipient.` errorMessage = l`One of the selected recipients does not allow group chats.`
} else if ( break
error instanceof ChatBskyGroupCreateGroup.UserForbidsGroupsError }
) {
errorMessage = l`One of the selected recipients does not allow group chats.`
} }
Toast.show(errorMessage, { Toast.show(errorMessage, {
type: 'error', type: 'error',
@@ -1,5 +1,4 @@
import {useCallback, useState} from 'react' import {useCallback, useState} from 'react'
import {ChatBskyGroupCreateGroup} from '@atproto/api'
import {useLingui} from '@lingui/react/macro' import {useLingui} from '@lingui/react/macro'
import {isNetworkError} from '#/lib/strings/errors' import {isNetworkError} from '#/lib/strings/errors'
@@ -104,29 +103,27 @@ function SendViaChatDialogInner({
let errorMessage = l`An issue occurred starting the group chat, please try again.` let errorMessage = l`An issue occurred starting the group chat, please try again.`
if (isNetworkError(error)) { if (isNetworkError(error)) {
errorMessage = l`A network error occurred. Please check your internet connection.` errorMessage = l`A network error occurred. Please check your internet connection.`
} else if ( } else {
error instanceof ChatBskyGroupCreateGroup.AccountSuspendedError switch (matchXrpcError(error, chat.bsky.group.createGroup)) {
) { case 'AccountSuspended':
errorMessage = l`Suspended accounts cannot participate in a group chat.` errorMessage = l`Suspended accounts cannot participate in a group chat.`
} else if (error instanceof ChatBskyGroupCreateGroup.BlockedActorError) { break
errorMessage = l`One of the selected recipients has blocked you and cannot be messaged.` case 'BlockedActor':
} else if ( errorMessage = l`One of the selected recipients has blocked you and cannot be messaged.`
error instanceof break
ChatBskyGroupCreateGroup.NewAccountCannotCreateGroupError case 'NewAccountCannotCreateGroup':
) { errorMessage = l`You cannot create a group chat yet.`
errorMessage = l`You cannot create a group chat yet.` break
} else if ( case 'NotFollowedBySender':
error instanceof ChatBskyGroupCreateGroup.NotFollowedBySenderError errorMessage = l`A selected recipient is not followed by the sender.`
) { break
errorMessage = l`A selected recipient is not followed by the sender.` case 'RecipientNotFound':
} else if ( errorMessage = l`Unable to find a selected recipient.`
error instanceof ChatBskyGroupCreateGroup.RecipientNotFoundError break
) { case 'UserForbidsGroups':
errorMessage = l`Unable to find a selected recipient.` errorMessage = l`One of the selected recipients does not allow group chats.`
} else if ( break
error instanceof ChatBskyGroupCreateGroup.UserForbidsGroupsError }
) {
errorMessage = l`One of the selected recipients does not allow group chats.`
} }
Toast.show(errorMessage, { Toast.show(errorMessage, {
type: 'error', type: 'error',
+35 -34
View File
@@ -1,11 +1,6 @@
import {useEffect} from 'react' import {useEffect} from 'react'
import {View} from 'react-native' import {View} from 'react-native'
import { import {ChatBskyGroupDefs, moderateProfile} from '@atproto/api'
ChatBskyGroupDefs,
ChatBskyGroupRequestJoin,
ChatBskyGroupWithdrawJoinRequest,
moderateProfile,
} from '@atproto/api'
import {Plural, Trans, useLingui} from '@lingui/react/macro' import {Plural, Trans, useLingui} from '@lingui/react/macro'
import {useNavigation} from '@react-navigation/native' import {useNavigation} from '@react-navigation/native'
import {useQueryClient} from '@tanstack/react-query' import {useQueryClient} from '@tanstack/react-query'
@@ -16,6 +11,7 @@ import {makeProfileLink} from '#/lib/routes/links'
import {type NavigationProp} from '#/lib/routes/types' import {type NavigationProp} from '#/lib/routes/types'
import {isNetworkError} from '#/lib/strings/errors' import {isNetworkError} from '#/lib/strings/errors'
import {sanitizeHandle} from '#/lib/strings/handles' import {sanitizeHandle} from '#/lib/strings/handles'
import {matchXrpcError} from '#/lib/xrpc-error'
import {logger} from '#/logger' import {logger} from '#/logger'
import {useModerationOpts} from '#/state/preferences/moderation-opts' import {useModerationOpts} from '#/state/preferences/moderation-opts'
import { import {
@@ -49,6 +45,7 @@ import {Loader} from '#/components/Loader'
import * as Toast from '#/components/Toast' import * as Toast from '#/components/Toast'
import {Text} from '#/components/Typography' import {Text} from '#/components/Typography'
import {useAnalytics} from '#/analytics' import {useAnalytics} from '#/analytics'
import {chat} from '#/lexicons'
import {ProfileBadges} from '../ProfileBadges' import {ProfileBadges} from '../ProfileBadges'
export function GroupChatJoinDialog() { export function GroupChatJoinDialog() {
@@ -147,33 +144,37 @@ function GroupChatJoinDialogContent({code}: {code?: string}) {
let errorMessage = l`Failed to join the group chat. Please try again.` let errorMessage = l`Failed to join the group chat. Please try again.`
if (isNetworkError(error)) { if (isNetworkError(error)) {
errorMessage = l`There was a problem with your internet connection, please try again` errorMessage = l`There was a problem with your internet connection, please try again`
} else if (error instanceof ChatBskyGroupRequestJoin.ConvoLockedError) { } else {
errorMessage = l`This conversation is locked.` switch (matchXrpcError(error, chat.bsky.group.requestJoin)) {
} else if ( case 'ConvoLocked':
error instanceof ChatBskyGroupRequestJoin.FollowRequiredError errorMessage = l`This conversation is locked.`
) { break
errorMessage = l`Only followers can join this group chat.` case 'FollowRequired':
} else if (error instanceof ChatBskyGroupRequestJoin.InvalidCodeError) { errorMessage = l`Only followers can join this group chat.`
errorMessage = l`Invalid group chat code.` break
} else if ( case 'InvalidCode':
error instanceof ChatBskyGroupRequestJoin.LinkDisabledError errorMessage = l`Invalid group chat code.`
) { break
errorMessage = l`This invite link has been disabled.` case 'LinkDisabled':
} else if ( errorMessage = l`This invite link has been disabled.`
error instanceof ChatBskyGroupRequestJoin.MemberLimitReachedError break
) { case 'MemberLimitReached': {
errorMessage = l`The member limit has been reached.` errorMessage = l`The member limit has been reached.`
const preview = data?.joinLinkPreviews[0] const preview = data?.joinLinkPreviews[0]
if ( if (
ChatBskyGroupDefs.isJoinLinkPreviewView(preview) && ChatBskyGroupDefs.isJoinLinkPreviewView(preview) &&
preview.convo?.id preview.convo?.id
) { ) {
ax.metric('groupchat:join:memberLimitReached', { ax.metric('groupchat:join:memberLimitReached', {
convoId: preview.convo.id, convoId: preview.convo.id,
}) })
}
break
}
case 'UserKicked':
errorMessage = l`You have been previously removed from this group and cant join it using this link.`
break
} }
} else if (error instanceof ChatBskyGroupRequestJoin.UserKickedError) {
errorMessage = l`You have been previously removed from this group and cant join it using this link.`
} }
Toast.show(errorMessage) Toast.show(errorMessage)
}, },
@@ -194,8 +195,8 @@ function GroupChatJoinDialogContent({code}: {code?: string}) {
if (isNetworkError(error)) { if (isNetworkError(error)) {
errorMessage = l`There was a problem with your internet connection, please try again` errorMessage = l`There was a problem with your internet connection, please try again`
} else if ( } else if (
error instanceof matchXrpcError(error, chat.bsky.group.withdrawJoinRequest) ===
ChatBskyGroupWithdrawJoinRequest.InvalidJoinRequestError 'InvalidJoinRequest'
) { ) {
errorMessage = l`Invalid rescind request.` errorMessage = l`Invalid rescind request.`
} }
+10 -9
View File
@@ -1,6 +1,6 @@
import {useState} from 'react' import {useState} from 'react'
import {View} from 'react-native' import {View} from 'react-native'
import {type ChatBskyConvoDefs, ChatBskyGroupRemoveMembers} from '@atproto/api' import {type ChatBskyConvoDefs} from '@atproto/api'
import {Trans, useLingui} from '@lingui/react/macro' import {Trans, useLingui} from '@lingui/react/macro'
import {useQueryClient} from '@tanstack/react-query' import {useQueryClient} from '@tanstack/react-query'
@@ -309,14 +309,15 @@ function MutualGroupChat({
let errorMessage = l`Could not remove member.` let errorMessage = l`Could not remove member.`
if (isNetworkError(error)) { if (isNetworkError(error)) {
errorMessage = l`A network error occurred. Please check your internet connection.` errorMessage = l`A network error occurred. Please check your internet connection.`
} else if ( } else {
error instanceof ChatBskyGroupRemoveMembers.InvalidConvoError switch (matchXrpcError(error, chat.bsky.group.removeMembers)) {
) { case 'InvalidConvo':
errorMessage = l`Chat not found.` errorMessage = l`Chat not found.`
} else if ( break
error instanceof ChatBskyGroupRemoveMembers.InsufficientRoleError case 'InsufficientRole':
) { errorMessage = l`You must be a chat owner to remove a member.`
errorMessage = l`You must be a chat owner to remove a member.` break
}
} }
Toast.show(errorMessage, {type: 'error'}) Toast.show(errorMessage, {type: 'error'})
}, },
+24 -26
View File
@@ -1,10 +1,6 @@
import {useState} from 'react' import {useState} from 'react'
import {View} from 'react-native' import {View} from 'react-native'
import { import {type ChatBskyGroupListJoinRequests} from '@atproto/api'
ChatBskyGroupApproveJoinRequest,
type ChatBskyGroupListJoinRequests,
ChatBskyGroupRejectJoinRequest,
} from '@atproto/api'
import {Plural, Trans, useLingui} from '@lingui/react/macro' import {Plural, Trans, useLingui} from '@lingui/react/macro'
import {useNavigation} from '@react-navigation/native' import {useNavigation} from '@react-navigation/native'
import {type InfiniteData, useQueryClient} from '@tanstack/react-query' import {type InfiniteData, useQueryClient} from '@tanstack/react-query'
@@ -16,6 +12,7 @@ import {
type NativeStackScreenProps, type NativeStackScreenProps,
type NavigationProp, type NavigationProp,
} from '#/lib/routes/types' } from '#/lib/routes/types'
import {matchXrpcError} from '#/lib/xrpc-error'
import {logger} from '#/logger' import {logger} from '#/logger'
import {ConvoProvider, useConvo} from '#/state/messages/convo' import {ConvoProvider, useConvo} from '#/state/messages/convo'
import {ConvoStatus} from '#/state/messages/convo/types' import {ConvoStatus} from '#/state/messages/convo/types'
@@ -43,6 +40,7 @@ import * as ProfileCard from '#/components/ProfileCard'
import * as Toast from '#/components/Toast' import * as Toast from '#/components/Toast'
import {Text} from '#/components/Typography' import {Text} from '#/components/Typography'
import {useAnalytics} from '#/analytics' import {useAnalytics} from '#/analytics'
import {chat} from '#/lexicons'
import type * as bsky from '#/types/bsky' import type * as bsky from '#/types/bsky'
import {InviteLinkDialog} from './components/InviteLinkDialog' import {InviteLinkDialog} from './components/InviteLinkDialog'
@@ -190,19 +188,18 @@ function JoinRequestsList({
let errorMessage = l`Failed to accept join request` let errorMessage = l`Failed to accept join request`
if (isNetworkError(error)) { if (isNetworkError(error)) {
errorMessage = l`A network error occurred. Please check your internet connection.` errorMessage = l`A network error occurred. Please check your internet connection.`
} else if ( } else {
error instanceof ChatBskyGroupApproveJoinRequest.InvalidConvoError switch (matchXrpcError(error, chat.bsky.group.approveJoinRequest)) {
) { case 'InvalidConvo':
errorMessage = l`Conversation not found.` errorMessage = l`Conversation not found.`
} else if ( break
error instanceof ChatBskyGroupApproveJoinRequest.InsufficientRoleError case 'InsufficientRole':
) { errorMessage = l`Only admins can accept join requests.`
errorMessage = l`Only admins can accept join requests.` break
} else if ( case 'MemberLimitReached':
error instanceof errorMessage = l`The member limit has been reached.`
ChatBskyGroupApproveJoinRequest.MemberLimitReachedError break
) { }
errorMessage = l`The member limit has been reached.`
} }
Toast.show(errorMessage, {type: 'error'}) Toast.show(errorMessage, {type: 'error'})
}, },
@@ -223,14 +220,15 @@ function JoinRequestsList({
let errorMessage = l`Failed to reject join request` let errorMessage = l`Failed to reject join request`
if (isNetworkError(error)) { if (isNetworkError(error)) {
errorMessage = l`A network error occurred. Please check your internet connection.` errorMessage = l`A network error occurred. Please check your internet connection.`
} else if ( } else {
error instanceof ChatBskyGroupRejectJoinRequest.InvalidConvoError switch (matchXrpcError(error, chat.bsky.group.rejectJoinRequest)) {
) { case 'InvalidConvo':
errorMessage = l`Conversation not found.` errorMessage = l`Conversation not found.`
} else if ( break
error instanceof ChatBskyGroupRejectJoinRequest.InsufficientRoleError case 'InsufficientRole':
) { errorMessage = l`Only admins can reject join requests.`
errorMessage = l`Only admins can reject join requests.` break
}
} }
Toast.show(errorMessage, {type: 'error'}) Toast.show(errorMessage, {type: 'error'})
}, },
@@ -1,11 +1,9 @@
import {View} from 'react-native' import {View} from 'react-native'
import { import {type ChatBskyGroupDefs} from '@atproto/api'
type ChatBskyGroupDefs,
ChatBskyGroupWithdrawJoinRequest,
} from '@atproto/api'
import {Trans, useLingui} from '@lingui/react/macro' import {Trans, useLingui} from '@lingui/react/macro'
import {isNetworkError} from '#/lib/strings/errors' import {isNetworkError} from '#/lib/strings/errors'
import {matchXrpcError} from '#/lib/xrpc-error'
import {useWithdrawJoinGroupChatRequest} from '#/state/queries/messages/withdraw-join-group-chat' import {useWithdrawJoinGroupChatRequest} from '#/state/queries/messages/withdraw-join-group-chat'
import {TimeElapsed} from '#/view/com/util/TimeElapsed' import {TimeElapsed} from '#/view/com/util/TimeElapsed'
import {atoms as a, useTheme, web} from '#/alf' import {atoms as a, useTheme, web} from '#/alf'
@@ -14,6 +12,7 @@ import {createStaticClick, Link} from '#/components/Link'
import * as Prompt from '#/components/Prompt' import * as Prompt from '#/components/Prompt'
import * as Toast from '#/components/Toast' import * as Toast from '#/components/Toast'
import {Text} from '#/components/Typography' import {Text} from '#/components/Typography'
import {chat} from '#/lexicons'
export function OutgoingRequestListItem({ export function OutgoingRequestListItem({
convo: convoView, convo: convoView,
@@ -35,8 +34,8 @@ export function OutgoingRequestListItem({
if (isNetworkError(error)) { if (isNetworkError(error)) {
errorMessage = l`There was a problem with your internet connection, please try again` errorMessage = l`There was a problem with your internet connection, please try again`
} else if ( } else if (
error instanceof matchXrpcError(error, chat.bsky.group.withdrawJoinRequest) ===
ChatBskyGroupWithdrawJoinRequest.InvalidJoinRequestError 'InvalidJoinRequest'
) { ) {
errorMessage = l`Invalid rescind request.` errorMessage = l`Invalid rescind request.`
} }
+38 -20
View File
@@ -1,17 +1,19 @@
import {useCallback} from 'react' import {useCallback} from 'react'
import { import {
type $Typed, type $Typed,
AtpAgent,
ChatBskyGroupDefs, ChatBskyGroupDefs,
type ChatBskyGroupGetJoinLinkPreviews, type ChatBskyGroupGetJoinLinkPreviews,
} from '@atproto/api' } from '@atproto/api'
import {type Client} from '@atproto/lex'
import {type QueryClient, useQuery, useQueryClient} from '@tanstack/react-query' import {type QueryClient, useQuery, useQueryClient} from '@tanstack/react-query'
import {CHAT_SERVICE, DM_SERVICE_HEADERS} from '#/lib/constants' import {CHAT_SERVICE} from '#/lib/constants'
import {createLexClient} from '#/lib/lexClient'
import {logger} from '#/logger' import {logger} from '#/logger'
import {STALE} from '#/state/queries/index' import {STALE} from '#/state/queries/index'
import {createQueryKey, type StructuredQueryKey} from '#/state/queries/util' import {createQueryKey, type StructuredQueryKey} from '#/state/queries/util'
import {useAgent} from '#/state/session' import {useChatClient} from '#/state/session'
import {chat} from '#/lexicons'
/** /**
* The three preview shapes we currently support. Excludes the `{$type: string}` * The three preview shapes we currently support. Excludes the `{$type: string}`
@@ -154,23 +156,39 @@ export function invalidateJoinLinkPreviewsForConvo(
}) })
} }
let publicChatClient: Client | undefined
/**
* The unauthenticated {@link Client} for the chat service, used to resolve join
* links before the viewer has a session.
*
* It talks to {@link CHAT_SERVICE} directly rather than proxying through a PDS,
* so no `atproto-proxy` header is involved. A single module-level instance,
* because there is no session to scope it to and reconstructing it per call
* would be waste.
*
* Unlike the public appview client this does NOT wrap `networkAwareFetch`,
* matching the plain-fetch behavior of the ad-hoc agent it replaces: a
* logged-out link resolution failing says nothing useful about the session's
* reachability, so it should not move the app-wide network signal.
*/
function getPublicChatClient(): Client {
return (publicChatClient ??= createLexClient({service: CHAT_SERVICE}))
}
async function fetchJoinLinkPreviews({ async function fetchJoinLinkPreviews({
agent, client,
codes, codes,
hasSession, hasSession,
}: { }: {
agent: AtpAgent client: Client
codes: string[] codes: string[]
hasSession: boolean hasSession: boolean
}) { }) {
const previewAgent = new AtpAgent({service: CHAT_SERVICE}) return await (hasSession ? client : getPublicChatClient()).call(
const res = hasSession chat.bsky.group.getJoinLinkPreviews,
? await agent.chat.bsky.group.getJoinLinkPreviews( {codes},
{codes}, )
{headers: DM_SERVICE_HEADERS},
)
: await previewAgent.chat.bsky.group.getJoinLinkPreviews({codes})
return res.data
} }
export function useJoinLinkPreviewsQuery({ export function useJoinLinkPreviewsQuery({
@@ -188,14 +206,14 @@ export function useJoinLinkPreviewsQuery({
*/ */
initialData?: ChatBskyGroupGetJoinLinkPreviews.OutputSchema initialData?: ChatBskyGroupGetJoinLinkPreviews.OutputSchema
}) { }) {
const agent = useAgent() const client = useChatClient()
return useQuery({ return useQuery({
queryKey: createJoinLinkPreviewQueryKey({codes: codes ?? [], hasSession}), queryKey: createJoinLinkPreviewQueryKey({codes: codes ?? [], hasSession}),
queryFn: async () => { queryFn: async () => {
if (!codes) throw new Error('No invite code') if (!codes) throw new Error('No invite code')
try { try {
return await fetchJoinLinkPreviews({agent, codes, hasSession}) return await fetchJoinLinkPreviews({client, codes, hasSession})
} catch (error) { } catch (error) {
logger.error('Failed to fetch join link preview', {safeMessage: error}) logger.error('Failed to fetch join link preview', {safeMessage: error})
throw error throw error
@@ -208,13 +226,13 @@ export function useJoinLinkPreviewsQuery({
} }
export function usePrefetchJoinLinkPreviews() { export function usePrefetchJoinLinkPreviews() {
const agent = useAgent() const client = useChatClient()
const queryClient = useQueryClient() const queryClient = useQueryClient()
return ({codes, hasSession}: {codes: string[]; hasSession: boolean}) => { return ({codes, hasSession}: {codes: string[]; hasSession: boolean}) => {
return queryClient.prefetchQuery({ return queryClient.prefetchQuery({
queryKey: createJoinLinkPreviewQueryKey({codes, hasSession}), queryKey: createJoinLinkPreviewQueryKey({codes, hasSession}),
queryFn: () => fetchJoinLinkPreviews({agent, codes, hasSession}), queryFn: () => fetchJoinLinkPreviews({client, codes, hasSession}),
staleTime: STALE.SECONDS.FIFTEEN, staleTime: STALE.SECONDS.FIFTEEN,
}) })
} }
@@ -226,7 +244,7 @@ export function usePrefetchJoinLinkPreviews() {
* Returns undefined if the preview can't be resolved. * Returns undefined if the preview can't be resolved.
*/ */
export function useGetJoinLinkPreview() { export function useGetJoinLinkPreview() {
const agent = useAgent() const client = useChatClient()
const queryClient = useQueryClient() const queryClient = useQueryClient()
return useCallback( return useCallback(
@@ -241,7 +259,7 @@ export function useGetJoinLinkPreview() {
const data = await queryClient.fetchQuery({ const data = await queryClient.fetchQuery({
queryKey: createJoinLinkPreviewQueryKey({codes: [code], hasSession}), queryKey: createJoinLinkPreviewQueryKey({codes: [code], hasSession}),
queryFn: () => queryFn: () =>
fetchJoinLinkPreviews({agent, codes: [code], hasSession}), fetchJoinLinkPreviews({client, codes: [code], hasSession}),
staleTime: STALE.SECONDS.FIFTEEN, staleTime: STALE.SECONDS.FIFTEEN,
}) })
const found = data.joinLinkPreviews[0] const found = data.joinLinkPreviews[0]
@@ -251,6 +269,6 @@ export function useGetJoinLinkPreview() {
return undefined return undefined
} }
}, },
[agent, queryClient], [client, queryClient],
) )
} }
@@ -4,16 +4,17 @@ import {
type ChatBskyConvoListConvos, type ChatBskyConvoListConvos,
type ChatBskyGroupAddMembers, type ChatBskyGroupAddMembers,
} from '@atproto/api' } from '@atproto/api'
import {type DidString} from '@atproto/syntax'
import { import {
type InfiniteData, type InfiniteData,
useMutation, useMutation,
useQueryClient, useQueryClient,
} from '@tanstack/react-query' } from '@tanstack/react-query'
import {DM_SERVICE_HEADERS} from '#/lib/constants'
import {logger} from '#/logger' import {logger} from '#/logger'
import {useProfileQuery} from '#/state/queries/profile' import {useProfileQuery} from '#/state/queries/profile'
import {useAgent, useSession} from '#/state/session' import {useChatClient, useSession} from '#/state/session'
import {chat} from '#/lexicons'
import type * as bsky from '#/types/bsky' import type * as bsky from '#/types/bsky'
import {RQKEY as CONVO_KEY} from './conversation' import {RQKEY as CONVO_KEY} from './conversation'
import {RQKEY_ROOT as CONVO_LIST_KEY} from './list-conversations' import {RQKEY_ROOT as CONVO_LIST_KEY} from './list-conversations'
@@ -30,7 +31,7 @@ export function useAddGroupMembers(
}, },
) { ) {
const queryClient = useQueryClient() const queryClient = useQueryClient()
const agent = useAgent() const client = useChatClient()
const {currentAccount} = useSession() const {currentAccount} = useSession()
const {data: myProfile} = useProfileQuery({did: currentAccount?.did}) const {data: myProfile} = useProfileQuery({did: currentAccount?.did})
@@ -42,11 +43,11 @@ export function useAddGroupMembers(
profiles: bsky.profile.AnyProfileView[] profiles: bsky.profile.AnyProfileView[]
}) => { }) => {
if (!convoId) throw new Error('No convoId provided') if (!convoId) throw new Error('No convoId provided')
const {data} = await agent.chat.bsky.group.addMembers( return await client.call(chat.bsky.group.addMembers, {
{convoId, members}, convoId,
{headers: DM_SERVICE_HEADERS, encoding: 'application/json'}, // callers pass already-resolved actor dids
) members: members as DidString[],
return data })
}, },
onMutate: ({profiles}) => { onMutate: ({profiles}) => {
if (!convoId) return if (!convoId) return
@@ -1,9 +1,10 @@
import {type ChatBskyGroupCreateGroup} from '@atproto/api' import {type ChatBskyGroupCreateGroup} from '@atproto/api'
import {type DidString} from '@atproto/syntax'
import {useMutation, useQueryClient} from '@tanstack/react-query' import {useMutation, useQueryClient} from '@tanstack/react-query'
import {DM_SERVICE_HEADERS} from '#/lib/constants'
import {logger} from '#/logger' import {logger} from '#/logger'
import {useAgent} from '#/state/session' import {useChatClient} from '#/state/session'
import {chat} from '#/lexicons'
import {precacheConvoQuery} from './conversation' import {precacheConvoQuery} from './conversation'
export function useCreateGroupChat({ export function useCreateGroupChat({
@@ -14,16 +15,15 @@ export function useCreateGroupChat({
onError?: (error: Error) => void onError?: (error: Error) => void
}) { }) {
const queryClient = useQueryClient() const queryClient = useQueryClient()
const agent = useAgent() const client = useChatClient()
return useMutation({ return useMutation({
mutationFn: async ({name, members}: {name: string; members: string[]}) => { mutationFn: async ({name, members}: {name: string; members: string[]}) => {
const {data} = await agent.chat.bsky.group.createGroup( return await client.call(chat.bsky.group.createGroup, {
{name, members}, name,
{headers: DM_SERVICE_HEADERS}, // callers pass already-resolved actor dids
) members: members as DidString[],
})
return data
}, },
onSuccess: data => { onSuccess: data => {
precacheConvoQuery(queryClient, data.convo) precacheConvoQuery(queryClient, data.convo)
@@ -5,9 +5,9 @@ import {
} from '@atproto/api' } from '@atproto/api'
import {useMutation, useQueryClient} from '@tanstack/react-query' import {useMutation, useQueryClient} from '@tanstack/react-query'
import {DM_SERVICE_HEADERS} from '#/lib/constants'
import {logger} from '#/logger' import {logger} from '#/logger'
import {useAgent} from '#/state/session' import {useChatClient} from '#/state/session'
import {chat} from '#/lexicons'
import { import {
rollbackConvoOptimistic, rollbackConvoOptimistic,
updateConvoOptimistic, updateConvoOptimistic,
@@ -24,7 +24,7 @@ export function useCreateJoinLink(
}, },
) { ) {
const queryClient = useQueryClient() const queryClient = useQueryClient()
const agent = useAgent() const client = useChatClient()
return useMutation({ return useMutation({
mutationFn: async ({ mutationFn: async ({
@@ -35,11 +35,11 @@ export function useCreateJoinLink(
requireApproval: boolean requireApproval: boolean
}) => { }) => {
if (!convoId) throw new Error('No convoId provided') if (!convoId) throw new Error('No convoId provided')
const {data} = await agent.chat.bsky.group.createJoinLink( return await client.call(chat.bsky.group.createJoinLink, {
{convoId, joinRule, requireApproval}, convoId,
{headers: DM_SERVICE_HEADERS, encoding: 'application/json'}, joinRule,
) requireApproval,
return data })
}, },
onMutate: ({joinRule, requireApproval}) => { onMutate: ({joinRule, requireApproval}) => {
if (!convoId) return if (!convoId) return
@@ -4,10 +4,10 @@ import {
} from '@atproto/api' } from '@atproto/api'
import {useMutation, useQueryClient} from '@tanstack/react-query' import {useMutation, useQueryClient} from '@tanstack/react-query'
import {DM_SERVICE_HEADERS} from '#/lib/constants'
import {logger} from '#/logger' import {logger} from '#/logger'
import {invalidateJoinLinkPreviewsForCode} from '#/state/queries/join-links' import {invalidateJoinLinkPreviewsForCode} from '#/state/queries/join-links'
import {useAgent} from '#/state/session' import {useChatClient} from '#/state/session'
import {chat} from '#/lexicons'
import { import {
rollbackConvoOptimistic, rollbackConvoOptimistic,
updateConvoOptimistic, updateConvoOptimistic,
@@ -24,16 +24,12 @@ export function useDisableJoinLink(
}, },
) { ) {
const queryClient = useQueryClient() const queryClient = useQueryClient()
const agent = useAgent() const client = useChatClient()
return useMutation({ return useMutation({
mutationFn: async () => { mutationFn: async () => {
if (!convoId) throw new Error('No convoId provided') if (!convoId) throw new Error('No convoId provided')
const {data} = await agent.chat.bsky.group.disableJoinLink( return await client.call(chat.bsky.group.disableJoinLink, {convoId})
{convoId},
{headers: DM_SERVICE_HEADERS, encoding: 'application/json'},
)
return data
}, },
onMutate: () => { onMutate: () => {
if (!convoId) return if (!convoId) return
@@ -1,9 +1,9 @@
import {ChatBskyConvoDefs, type ChatBskyGroupEditGroup} from '@atproto/api' import {ChatBskyConvoDefs, type ChatBskyGroupEditGroup} from '@atproto/api'
import {useMutation, useQueryClient} from '@tanstack/react-query' import {useMutation, useQueryClient} from '@tanstack/react-query'
import {DM_SERVICE_HEADERS} from '#/lib/constants'
import {logger} from '#/logger' import {logger} from '#/logger'
import {useAgent} from '#/state/session' import {useChatClient} from '#/state/session'
import {chat} from '#/lexicons'
import { import {
rollbackConvoOptimistic, rollbackConvoOptimistic,
updateConvoOptimistic, updateConvoOptimistic,
@@ -20,16 +20,15 @@ export function useEditGroupChatName(
}, },
) { ) {
const queryClient = useQueryClient() const queryClient = useQueryClient()
const agent = useAgent() const client = useChatClient()
return useMutation({ return useMutation({
mutationFn: async ({name: groupName}: {name: string}) => { mutationFn: async ({name: groupName}: {name: string}) => {
if (!convoId) throw new Error('No convoId provided') if (!convoId) throw new Error('No convoId provided')
const {data} = await agent.chat.bsky.group.editGroup( return await client.call(chat.bsky.group.editGroup, {
{convoId, name: groupName}, convoId,
{headers: DM_SERVICE_HEADERS, encoding: 'application/json'}, name: groupName,
) })
return data
}, },
onMutate: ({name: groupName}) => { onMutate: ({name: groupName}) => {
if (!convoId) return if (!convoId) return
+8 -8
View File
@@ -5,9 +5,9 @@ import {
} from '@atproto/api' } from '@atproto/api'
import {useMutation, useQueryClient} from '@tanstack/react-query' import {useMutation, useQueryClient} from '@tanstack/react-query'
import {DM_SERVICE_HEADERS} from '#/lib/constants'
import {logger} from '#/logger' import {logger} from '#/logger'
import {useAgent} from '#/state/session' import {useChatClient} from '#/state/session'
import {chat} from '#/lexicons'
import { import {
rollbackConvoOptimistic, rollbackConvoOptimistic,
updateConvoOptimistic, updateConvoOptimistic,
@@ -24,7 +24,7 @@ export function useEditJoinLink(
}, },
) { ) {
const queryClient = useQueryClient() const queryClient = useQueryClient()
const agent = useAgent() const client = useChatClient()
return useMutation({ return useMutation({
mutationFn: async ({ mutationFn: async ({
@@ -35,11 +35,11 @@ export function useEditJoinLink(
requireApproval: boolean requireApproval: boolean
}) => { }) => {
if (!convoId) throw new Error('No convoId provided') if (!convoId) throw new Error('No convoId provided')
const {data} = await agent.chat.bsky.group.editJoinLink( return await client.call(chat.bsky.group.editJoinLink, {
{convoId, joinRule, requireApproval}, convoId,
{headers: DM_SERVICE_HEADERS, encoding: 'application/json'}, joinRule,
) requireApproval,
return data })
}, },
onMutate: ({joinRule, requireApproval}) => { onMutate: ({joinRule, requireApproval}) => {
if (!convoId) return if (!convoId) return
@@ -1,10 +1,10 @@
import {ChatBskyConvoDefs, type ChatBskyGroupEnableJoinLink} from '@atproto/api' import {ChatBskyConvoDefs, type ChatBskyGroupEnableJoinLink} from '@atproto/api'
import {useMutation, useQueryClient} from '@tanstack/react-query' import {useMutation, useQueryClient} from '@tanstack/react-query'
import {DM_SERVICE_HEADERS} from '#/lib/constants'
import {logger} from '#/logger' import {logger} from '#/logger'
import {invalidateJoinLinkPreviewsForCode} from '#/state/queries/join-links' import {invalidateJoinLinkPreviewsForCode} from '#/state/queries/join-links'
import {useAgent} from '#/state/session' import {useChatClient} from '#/state/session'
import {chat} from '#/lexicons'
import { import {
rollbackConvoOptimistic, rollbackConvoOptimistic,
updateConvoOptimistic, updateConvoOptimistic,
@@ -21,16 +21,12 @@ export function useEnableJoinLink(
}, },
) { ) {
const queryClient = useQueryClient() const queryClient = useQueryClient()
const agent = useAgent() const client = useChatClient()
return useMutation({ return useMutation({
mutationFn: async () => { mutationFn: async () => {
if (!convoId) throw new Error('No convoId provided') if (!convoId) throw new Error('No convoId provided')
const {data} = await agent.chat.bsky.group.enableJoinLink( return await client.call(chat.bsky.group.enableJoinLink, {convoId})
{convoId},
{headers: DM_SERVICE_HEADERS, encoding: 'application/json'},
)
return data
}, },
onMutate: () => { onMutate: () => {
if (!convoId) return if (!convoId) return
+20 -12
View File
@@ -4,15 +4,16 @@ import {
type ChatBskyGroupListJoinRequests, type ChatBskyGroupListJoinRequests,
type ChatBskyGroupRejectJoinRequest, type ChatBskyGroupRejectJoinRequest,
} from '@atproto/api' } from '@atproto/api'
import {type DidString} from '@atproto/syntax'
import { import {
type InfiniteData, type InfiniteData,
useMutation, useMutation,
useQueryClient, useQueryClient,
} from '@tanstack/react-query' } from '@tanstack/react-query'
import {DM_SERVICE_HEADERS} from '#/lib/constants'
import {logger} from '#/logger' import {logger} from '#/logger'
import {useAgent} from '#/state/session' import {useChatClient} from '#/state/session'
import {chat} from '#/lexicons'
import {listConvoMembersQueryKey} from './list-convo-members' import {listConvoMembersQueryKey} from './list-convo-members'
import {createListJoinRequestsQueryKey} from './list-join-requests' import {createListJoinRequestsQueryKey} from './list-join-requests'
@@ -34,21 +35,28 @@ export function useJoinRequestMutation<A extends JoinRequestAction>(
}, },
) { ) {
const queryClient = useQueryClient() const queryClient = useQueryClient()
const agent = useAgent() const client = useChatClient()
return useMutation({ return useMutation({
mutationFn: async ({member}: {member: string}) => { mutationFn: async ({member}: {member: string}) => {
if (!convoId) throw new Error('No convoId provided') if (!convoId) throw new Error('No convoId provided')
const {data} = // callers pass an already-resolved actor did
const memberDid = member as DidString
const data =
action === 'approve' action === 'approve'
? await agent.chat.bsky.group.approveJoinRequest( ? await client.call(chat.bsky.group.approveJoinRequest, {
{convoId, member}, convoId,
{headers: DM_SERVICE_HEADERS, encoding: 'application/json'}, member: memberDid,
) })
: await agent.chat.bsky.group.rejectJoinRequest( : await client.call(chat.bsky.group.rejectJoinRequest, {
{convoId, member}, convoId,
{headers: DM_SERVICE_HEADERS, encoding: 'application/json'}, member: memberDid,
) })
/*
* The two branches have different output schemas, so the union cannot be
* narrowed from the `action` value alone - the cast carries the generic's
* mapping through, exactly as the pre-migration code did.
*/
return data as JoinRequestOutput<A> return data as JoinRequestOutput<A>
}, },
onMutate: ({member}) => { onMutate: ({member}) => {
@@ -2,10 +2,10 @@ import {useEffect} from 'react'
import {ChatBskyConvoDefs} from '@atproto/api' import {ChatBskyConvoDefs} from '@atproto/api'
import {useInfiniteQuery, useQueryClient} from '@tanstack/react-query' import {useInfiniteQuery, useQueryClient} from '@tanstack/react-query'
import {DM_SERVICE_HEADERS} from '#/lib/constants'
import {useMessagesEventBus} from '#/state/messages/events' import {useMessagesEventBus} from '#/state/messages/events'
import {createQueryKey} from '#/state/queries/util' import {createQueryKey} from '#/state/queries/util'
import {useAgent} from '#/state/session' import {useChatClient} from '#/state/session'
import {chat} from '#/lexicons'
import {STALE} from '..' import {STALE} from '..'
export const JOIN_REQUESTS_THRESHOLD = 20 export const JOIN_REQUESTS_THRESHOLD = 20
@@ -22,7 +22,7 @@ export function useListJoinRequestsQuery({
convoId: string | undefined convoId: string | undefined
enabled?: boolean enabled?: boolean
}) { }) {
const agent = useAgent() const client = useChatClient()
const queryClient = useQueryClient() const queryClient = useQueryClient()
const messagesBus = useMessagesEventBus() const messagesBus = useMessagesEventBus()
const isEnabled = enabled !== false && !!convoId const isEnabled = enabled !== false && !!convoId
@@ -54,11 +54,12 @@ export function useListJoinRequestsQuery({
enabled: isEnabled, enabled: isEnabled,
queryKey: createListJoinRequestsQueryKey({convoId: convoId ?? ''}), queryKey: createListJoinRequestsQueryKey({convoId: convoId ?? ''}),
queryFn: async ({pageParam}) => { queryFn: async ({pageParam}) => {
const {data} = await agent.chat.bsky.group.listJoinRequests( return await client.call(chat.bsky.group.listJoinRequests, {
{convoId: convoId!, cursor: pageParam, limit: JOIN_REQUESTS_THRESHOLD}, // guarded by `isEnabled`
{headers: DM_SERVICE_HEADERS}, convoId: convoId!,
) cursor: pageParam,
return data limit: JOIN_REQUESTS_THRESHOLD,
})
}, },
initialPageParam: undefined as string | undefined, initialPageParam: undefined as string | undefined,
getNextPageParam: page => page.cursor, getNextPageParam: page => page.cursor,
@@ -1,8 +1,9 @@
import {type DidString} from '@atproto/syntax'
import {useInfiniteQuery} from '@tanstack/react-query' import {useInfiniteQuery} from '@tanstack/react-query'
import {DM_SERVICE_HEADERS} from '#/lib/constants'
import {createQueryKey} from '#/state/queries/util' import {createQueryKey} from '#/state/queries/util'
import {useAgent} from '#/state/session' import {useChatClient} from '#/state/session'
import {chat} from '#/lexicons'
const listMutualGroupsQueryKeyRoot = 'list-mutual-groups' const listMutualGroupsQueryKeyRoot = 'list-mutual-groups'
@@ -18,7 +19,7 @@ export function useListMutualGroupsQuery({
enabled?: boolean enabled?: boolean
limit?: number limit?: number
}) { }) {
const agent = useAgent() const client = useChatClient()
const isEnabled = enabled !== false && !!subject const isEnabled = enabled !== false && !!subject
return useInfiniteQuery({ return useInfiniteQuery({
@@ -27,11 +28,12 @@ export function useListMutualGroupsQuery({
enabled: isEnabled, enabled: isEnabled,
queryKey: createListMutualGroupsQueryKey({subject: subject ?? ''}), queryKey: createListMutualGroupsQueryKey({subject: subject ?? ''}),
queryFn: async ({pageParam}) => { queryFn: async ({pageParam}) => {
const {data} = await agent.chat.bsky.group.listMutualGroups( return await client.call(chat.bsky.group.listMutualGroups, {
{subject: subject!, cursor: pageParam, limit}, // guarded by `enabled`, and callers pass a resolved actor did
{headers: DM_SERVICE_HEADERS}, subject: subject as DidString,
) cursor: pageParam,
return data limit,
})
}, },
initialPageParam: undefined as string | undefined, initialPageParam: undefined as string | undefined,
getNextPageParam: page => page.cursor, getNextPageParam: page => page.cursor,
@@ -1,9 +1,9 @@
import {ChatBskyConvoDefs} from '@atproto/api' import {ChatBskyConvoDefs} from '@atproto/api'
import {useMutation, useQueryClient} from '@tanstack/react-query' import {useMutation, useQueryClient} from '@tanstack/react-query'
import {DM_SERVICE_HEADERS} from '#/lib/constants'
import {logger} from '#/logger' import {logger} from '#/logger'
import {useAgent} from '#/state/session' import {useChatClient} from '#/state/session'
import {chat} from '#/lexicons'
import {RQKEY as CONVO_KEY} from './conversation' import {RQKEY as CONVO_KEY} from './conversation'
import { import {
type ConvoListQueryData, type ConvoListQueryData,
@@ -12,15 +12,12 @@ import {
export function useMarkJoinRequestsRead(convoId: string | undefined) { export function useMarkJoinRequestsRead(convoId: string | undefined) {
const queryClient = useQueryClient() const queryClient = useQueryClient()
const agent = useAgent() const client = useChatClient()
return useMutation({ return useMutation({
mutationFn: async () => { mutationFn: async () => {
if (!convoId) throw new Error('No convoId provided') if (!convoId) throw new Error('No convoId provided')
await agent.chat.bsky.group.updateJoinRequestsRead( await client.call(chat.bsky.group.updateJoinRequestsRead, {convoId})
{convoId},
{headers: DM_SERVICE_HEADERS, encoding: 'application/json'},
)
}, },
onMutate: () => { onMutate: () => {
if (!convoId) return if (!convoId) return
@@ -4,15 +4,16 @@ import {
type ChatBskyConvoListConvos, type ChatBskyConvoListConvos,
type ChatBskyGroupRemoveMembers, type ChatBskyGroupRemoveMembers,
} from '@atproto/api' } from '@atproto/api'
import {type DidString} from '@atproto/syntax'
import { import {
type InfiniteData, type InfiniteData,
useMutation, useMutation,
useQueryClient, useQueryClient,
} from '@tanstack/react-query' } from '@tanstack/react-query'
import {DM_SERVICE_HEADERS} from '#/lib/constants'
import {logger} from '#/logger' import {logger} from '#/logger'
import {useAgent} from '#/state/session' import {useChatClient} from '#/state/session'
import {chat} from '#/lexicons'
import {RQKEY as CONVO_KEY} from './conversation' import {RQKEY as CONVO_KEY} from './conversation'
import {RQKEY_ROOT as CONVO_LIST_KEY} from './list-conversations' import {RQKEY_ROOT as CONVO_LIST_KEY} from './list-conversations'
import {listConvoMembersQueryKey} from './list-convo-members' import {listConvoMembersQueryKey} from './list-convo-members'
@@ -28,16 +29,16 @@ export function useRemoveFromGroupChat(
}, },
) { ) {
const queryClient = useQueryClient() const queryClient = useQueryClient()
const agent = useAgent() const client = useChatClient()
return useMutation({ return useMutation({
mutationFn: async ({members}: {members: string[]}) => { mutationFn: async ({members}: {members: string[]}) => {
if (!convoId) throw new Error('No convoId provided') if (!convoId) throw new Error('No convoId provided')
const {data} = await agent.chat.bsky.group.removeMembers( return await client.call(chat.bsky.group.removeMembers, {
{convoId, members}, convoId,
{headers: DM_SERVICE_HEADERS, encoding: 'application/json'}, // callers pass already-resolved actor dids
) members: members as DidString[],
return data })
}, },
onMutate: ({members}) => { onMutate: ({members}) => {
if (!convoId) return if (!convoId) return
@@ -1,9 +1,9 @@
import {type ChatBskyGroupRequestJoin} from '@atproto/api' import {type ChatBskyGroupRequestJoin} from '@atproto/api'
import {useMutation, useQueryClient} from '@tanstack/react-query' import {useMutation, useQueryClient} from '@tanstack/react-query'
import {DM_SERVICE_HEADERS} from '#/lib/constants'
import {logger} from '#/logger' import {logger} from '#/logger'
import {useAgent, useSession} from '#/state/session' import {useChatClient, useSession} from '#/state/session'
import {chat} from '#/lexicons'
import {RQKEY_ROOT as REQUESTS_RQKEY_ROOT} from './list-conversation-requests' import {RQKEY_ROOT as REQUESTS_RQKEY_ROOT} from './list-conversation-requests'
export function useRequestJoinGroupChat({ export function useRequestJoinGroupChat({
@@ -13,7 +13,7 @@ export function useRequestJoinGroupChat({
onSuccess?: (data: ChatBskyGroupRequestJoin.OutputSchema) => void onSuccess?: (data: ChatBskyGroupRequestJoin.OutputSchema) => void
onError?: (error: Error) => void onError?: (error: Error) => void
} = {}) { } = {}) {
const agent = useAgent() const client = useChatClient()
const queryClient = useQueryClient() const queryClient = useQueryClient()
const {hasSession} = useSession() const {hasSession} = useSession()
@@ -22,11 +22,7 @@ export function useRequestJoinGroupChat({
if (!hasSession) throw new Error('Must be logged in to join') if (!hasSession) throw new Error('Must be logged in to join')
if (!code) throw new Error('No invite code') if (!code) throw new Error('No invite code')
const res = await agent.chat.bsky.group.requestJoin( return await client.call(chat.bsky.group.requestJoin, {code})
{code},
{headers: DM_SERVICE_HEADERS},
)
return res.data
}, },
onSuccess: data => { onSuccess: data => {
void queryClient.invalidateQueries({queryKey: [REQUESTS_RQKEY_ROOT]}) void queryClient.invalidateQueries({queryKey: [REQUESTS_RQKEY_ROOT]})
@@ -1,9 +1,9 @@
import {type ChatBskyGroupWithdrawJoinRequest} from '@atproto/api' import {type ChatBskyGroupWithdrawJoinRequest} from '@atproto/api'
import {useMutation, useQueryClient} from '@tanstack/react-query' import {useMutation, useQueryClient} from '@tanstack/react-query'
import {DM_SERVICE_HEADERS} from '#/lib/constants'
import {logger} from '#/logger' import {logger} from '#/logger'
import {useAgent, useSession} from '#/state/session' import {useChatClient, useSession} from '#/state/session'
import {chat} from '#/lexicons'
import { import {
type ConvoRequestListQueryData, type ConvoRequestListQueryData,
optimisticDeleteJoinRequest, optimisticDeleteJoinRequest,
@@ -17,7 +17,7 @@ export function useWithdrawJoinGroupChatRequest({
onSuccess?: (data: ChatBskyGroupWithdrawJoinRequest.OutputSchema) => void onSuccess?: (data: ChatBskyGroupWithdrawJoinRequest.OutputSchema) => void
onError?: (error: Error) => void onError?: (error: Error) => void
} = {}) { } = {}) {
const agent = useAgent() const client = useChatClient()
const queryClient = useQueryClient() const queryClient = useQueryClient()
const {hasSession} = useSession() const {hasSession} = useSession()
@@ -27,11 +27,7 @@ export function useWithdrawJoinGroupChatRequest({
throw new Error('Must be logged in to withdraw a join request') throw new Error('Must be logged in to withdraw a join request')
if (!convoId) throw new Error('No convoId provided') if (!convoId) throw new Error('No convoId provided')
const res = await agent.chat.bsky.group.withdrawJoinRequest( return await client.call(chat.bsky.group.withdrawJoinRequest, {convoId})
{convoId},
{headers: DM_SERVICE_HEADERS},
)
return res.data
}, },
onSuccess: (data, {convoId}) => { onSuccess: (data, {convoId}) => {
queryClient.setQueriesData<ConvoRequestListQueryData>( queryClient.setQueriesData<ConvoRequestListQueryData>(