diff --git a/src/screens/Messages/ChatList.tsx b/src/screens/Messages/ChatList.tsx index 906fcb017a1..58e7d2d5e88 100644 --- a/src/screens/Messages/ChatList.tsx +++ b/src/screens/Messages/ChatList.tsx @@ -17,7 +17,6 @@ import {isNative} from '#/platform/detection' import {listenSoftReset} from '#/state/events' import {MESSAGE_SCREEN_POLL_INTERVAL} from '#/state/messages/convo/const' import {useMessagesEventBus} from '#/state/messages/events' -import {useLeftConvos} from '#/state/queries/messages/leave-conversation' import {useListConvosQuery} from '#/state/queries/messages/list-conversations' import {useSession} from '#/state/session' import {List, type ListRef} from '#/view/com/util/List' @@ -149,14 +148,11 @@ export function MessagesScreenInner({navigation, route}: Props) { useRefreshOnFocus(refetch) useRefreshOnFocus(refetchInbox) - const leftConvos = useLeftConvos() - const inboxAllConvos = inboxData?.pages .flatMap(page => page.convos) .filter( convo => - !leftConvos.includes(convo.id) && !convo.muted && convo.members.every(member => member.handle !== 'missing.invalid'), ) ?? [] @@ -172,10 +168,7 @@ export function MessagesScreenInner({navigation, route}: Props) { const conversations = useMemo(() => { if (data?.pages) { - const conversations = data.pages - .flatMap(page => page.convos) - // filter out convos that are actively being left - .filter(convo => !leftConvos.includes(convo.id)) + const flattenedConvos = data.pages.flatMap(page => page.convos) return [ ...(hasInboxConvos @@ -187,13 +180,13 @@ export function MessagesScreenInner({navigation, route}: Props) { }, ] : []), - ...conversations.map( + ...flattenedConvos.map( convo => ({type: 'CONVERSATION', conversation: convo}) as const, ), ] satisfies ListItem[] } return [] - }, [data, leftConvos, hasInboxConvos, inboxUnreadConvoMembers]) + }, [data, hasInboxConvos, inboxUnreadConvoMembers]) const onRefresh = useCallback(async () => { setIsPTRing(true) diff --git a/src/screens/Messages/Inbox.tsx b/src/screens/Messages/Inbox.tsx index 6d2fc1cd82a..aadc54b065a 100644 --- a/src/screens/Messages/Inbox.tsx +++ b/src/screens/Messages/Inbox.tsx @@ -24,7 +24,6 @@ import {logger} from '#/logger' import {isNative} from '#/platform/detection' import {MESSAGE_SCREEN_POLL_INTERVAL} from '#/state/messages/convo/const' import {useMessagesEventBus} from '#/state/messages/events' -import {useLeftConvos} from '#/state/queries/messages/leave-conversation' import {useListConvosQuery} from '#/state/queries/messages/list-conversations' import {useUpdateAllRead} from '#/state/queries/messages/update-all-read' import {FAB} from '#/view/com/util/fab/FAB' @@ -66,19 +65,13 @@ export function MessagesInboxScreenInner({}: Props) { const listConvosQuery = useListConvosQuery({status: 'request'}) const {data} = listConvosQuery - const leftConvos = useLeftConvos() - const conversations = useMemo(() => { if (data?.pages) { - const convos = data.pages - .flatMap(page => page.convos) - // filter out convos that are actively being left - .filter(convo => !leftConvos.includes(convo.id)) - + const convos = data.pages.flatMap(page => page.convos) return convos } return [] - }, [data, leftConvos]) + }, [data]) const hasUnreadConvos = useMemo(() => { return conversations.some( diff --git a/src/state/queries/messages/leave-conversation.ts b/src/state/queries/messages/leave-conversation.ts index 986351a072b..133c18fe47b 100644 --- a/src/state/queries/messages/leave-conversation.ts +++ b/src/state/queries/messages/leave-conversation.ts @@ -1,33 +1,24 @@ -import {useMemo} from 'react' -import { - type ChatBskyConvoLeaveConvo, - type ChatBskyConvoListConvos, -} from '@atproto/api' -import { - useMutation, - useMutationState, - useQueryClient, -} from '@tanstack/react-query' +import {type ChatBskyConvoListConvos} from '@atproto/api' +import {useMutation, useQueryClient} from '@tanstack/react-query' import {DM_SERVICE_HEADERS} from '#/lib/constants' import {logger} from '#/logger' import {useAgent} from '#/state/session' import {RQKEY_ROOT as CONVO_LIST_KEY} from './list-conversations' -const RQKEY_ROOT = 'leave-convo' -export function RQKEY(convoId: string | undefined) { - return [RQKEY_ROOT, convoId] +export const RQKEY_ROOT = 'leave-convo' + +export function RQKEY(convoId: string) { + return [RQKEY_ROOT, convoId] as const } export function useLeaveConvo( - convoId: string | undefined, + convoId: string, { - onSuccess, onMutate, onError, }: { onMutate?: () => void - onSuccess?: (data: ChatBskyConvoLeaveConvo.OutputSchema) => void onError?: (error: Error) => void }, ) { @@ -46,7 +37,8 @@ export function useLeaveConvo( return data }, - onMutate: () => { + onMutate: async () => { + await queryClient.cancelQueries({queryKey: [CONVO_LIST_KEY]}) let prevPages: ChatBskyConvoListConvos.OutputSchema[] = [] queryClient.setQueryData( [CONVO_LIST_KEY], @@ -70,10 +62,6 @@ export function useLeaveConvo( onMutate?.() return {prevPages} }, - onSuccess: data => { - queryClient.invalidateQueries({queryKey: [CONVO_LIST_KEY]}) - onSuccess?.(data) - }, onError: (error, _, context) => { logger.error(error) queryClient.setQueryData( @@ -89,28 +77,12 @@ export function useLeaveConvo( } }, ) - queryClient.invalidateQueries({queryKey: [CONVO_LIST_KEY]}) onError?.(error) }, + onSettled: () => { + if (queryClient.isMutating({mutationKey: RQKEY(convoId)}) === 1) { + queryClient.invalidateQueries({queryKey: [CONVO_LIST_KEY]}) + } + }, }) } - -/** - * Gets currently pending and successful leave convo mutations - * - * @returns Array of `convoId` - */ -export function useLeftConvos() { - const pending = useMutationState({ - filters: {mutationKey: [RQKEY_ROOT], status: 'pending'}, - select: mutation => mutation.options.mutationKey?.[1] as string | undefined, - }) - const success = useMutationState({ - filters: {mutationKey: [RQKEY_ROOT], status: 'success'}, - select: mutation => mutation.options.mutationKey?.[1] as string | undefined, - }) - return useMemo( - () => [...pending, ...success].filter(id => id !== undefined), - [pending, success], - ) -} diff --git a/src/state/queries/messages/list-conversations.tsx b/src/state/queries/messages/list-conversations.tsx index c5457d1cb8b..b040ae042a8 100644 --- a/src/state/queries/messages/list-conversations.tsx +++ b/src/state/queries/messages/list-conversations.tsx @@ -9,6 +9,7 @@ import { type InfiniteData, type QueryClient, useInfiniteQuery, + useMutationState, useQueryClient, } from '@tanstack/react-query' import throttle from 'lodash.throttle' @@ -17,8 +18,8 @@ import {DM_SERVICE_HEADERS} from '#/lib/constants' import {useCurrentConvoId} from '#/state/messages/current-convo-id' import {useMessagesEventBus} from '#/state/messages/events' import {useModerationOpts} from '#/state/preferences/moderation-opts' +import {RQKEY_ROOT as LEAVE_CONVO_RQKEY_ROOT} from '#/state/queries/messages/leave-conversation' import {useAgent, useSession} from '#/state/session' -import {useLeftConvos} from './leave-conversation' export const RQKEY_ROOT = 'convo-list' export const RQKEY = ( @@ -38,8 +39,17 @@ export function useListConvosQuery({ } = {}) { const agent = useAgent() + const leaveConvoMutationStates = useMutationState({ + filters: { + mutationKey: [LEAVE_CONVO_RQKEY_ROOT], + status: 'pending', + }, + }) + return useInfiniteQuery({ - enabled, + // Stop refetching if leaving conversation is pending, we + // do not want to override the optimistic update. + enabled: enabled && leaveConvoMutationStates.length === 0, queryKey: RQKEY(status ?? 'all', readState), queryFn: async ({pageParam}) => { const {data} = await agent.chat.bsky.convo.listConvos( @@ -97,7 +107,6 @@ export function ListConvosProviderInner({ const queryClient = useQueryClient() const {currentConvoId} = useCurrentConvoId() const {currentAccount} = useSession() - const leftConvos = useLeftConvos() const debouncedRefetch = useMemo(() => { const refetchAndInvalidate = () => { @@ -376,15 +385,12 @@ export function ListConvosProviderInner({ ]) const ctx = useMemo(() => { - const convos = - data?.pages - .flatMap(page => page.convos) - .filter(convo => !leftConvos.includes(convo.id)) ?? [] + const convos = data?.pages.flatMap(page => page.convos) ?? [] return { accepted: convos.filter(conv => conv.status === 'accepted'), request: convos.filter(conv => conv.status === 'request'), } - }, [data, leftConvos]) + }, [data]) return (