import { type ChatBskyActorDefs, ChatBskyConvoDefs, type ChatBskyConvoListConvos, type ChatBskyGroupRemoveMembers, } from '@atproto/api' import { type InfiniteData, useMutation, useQueryClient, } from '@tanstack/react-query' import {DM_SERVICE_HEADERS} from '#/lib/constants' import {logger} from '#/logger' import {useAgent} from '#/state/session' import {RQKEY as CONVO_KEY} from './conversation' import {RQKEY_ROOT as CONVO_LIST_KEY} from './list-conversations' import {listConvoMembersQueryKey} from './list-convo-members' export function useRemoveFromGroupChat( convoId: string | undefined, { onSuccess, onError, }: { onSuccess?: (data: ChatBskyGroupRemoveMembers.OutputSchema) => void onError?: (error: Error) => void }, ) { const queryClient = useQueryClient() const agent = useAgent() return useMutation({ mutationFn: async ({members}: {members: string[]}) => { if (!convoId) throw new Error('No convoId provided') const {data} = await agent.chat.bsky.group.removeMembers( {convoId, members}, {headers: DM_SERVICE_HEADERS, encoding: 'application/json'}, ) return data }, onMutate: ({members}) => { if (!convoId) return const prevConvo = queryClient.getQueryData( CONVO_KEY(convoId), ) const prevListEntries = queryClient.getQueriesData< InfiniteData >({queryKey: [CONVO_LIST_KEY]}) const prevMemberList = queryClient.getQueryData< ChatBskyActorDefs.ProfileViewBasic[] >(listConvoMembersQueryKey(convoId)) queryClient.setQueryData( CONVO_KEY(convoId), prev => { if (!prev) return const nextMembers = prev.members.filter(m => !members.includes(m.did)) const removed = prev.members.length - nextMembers.length if (!ChatBskyConvoDefs.isGroupConvo(prev.kind)) { return {...prev, members: nextMembers} } return { ...prev, members: nextMembers, kind: { ...prev.kind, memberCount: Math.max(0, prev.kind.memberCount - removed), }, } }, ) queryClient.setQueriesData< InfiniteData >({queryKey: [CONVO_LIST_KEY]}, prev => { if (!prev?.pages) return return { ...prev, pages: prev.pages.map(page => ({ ...page, convos: page.convos.map(convo => { if (convo.id !== convoId) return convo const nextMembers = convo.members.filter( m => !members.includes(m.did), ) const removed = convo.members.length - nextMembers.length if (!ChatBskyConvoDefs.isGroupConvo(convo.kind)) { return {...convo, members: nextMembers} } return { ...convo, members: nextMembers, kind: { ...convo.kind, memberCount: Math.max(0, convo.kind.memberCount - removed), }, } }), })), } }) queryClient.setQueryData( listConvoMembersQueryKey(convoId), prev => { if (!prev) return return prev.filter(m => !members.includes(m.did)) }, ) return {prevConvo, prevListEntries, prevMemberList} }, onSuccess: data => { onSuccess?.(data) }, onError: (e, _variables, context) => { logger.error(e) if (context?.prevConvo && convoId) { queryClient.setQueryData(CONVO_KEY(convoId), context.prevConvo) } if (context?.prevListEntries) { for (const [key, data] of context.prevListEntries) { queryClient.setQueryData(key, data) } } if (context?.prevMemberList && convoId) { queryClient.setQueryData( listConvoMembersQueryKey(convoId), context.prevMemberList, ) } onError?.(e) }, }) }