diff options
author | Hailey <me@haileyok.com> | 2024-05-10 08:46:51 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-05-10 08:46:51 -0700 |
commit | f928e0a54736803a8650c084b5a0977ff1881ecf (patch) | |
tree | c9675d304e3bc30a3148f8a164f07b4662d9e1ae /src | |
parent | 8f56f79c6c94a7adf1de304097067f5aed0a111a (diff) | |
download | voidsky-f928e0a54736803a8650c084b5a0977ff1881ecf.tar.zst |
[🐴] Mutate data instead of invalidating queries when muting or unmuting (#3946)
* mutate for mutes * mutate data for mutes * add initial data, `useConvoQuery` in `ConvoMenu` * `useInitialData` * don't use `identifier` for notifications, use `dates` instead * better implementation * simplify * simplify * fix types
Diffstat (limited to 'src')
-rw-r--r-- | src/components/dms/ConvoMenu.tsx | 43 | ||||
-rw-r--r-- | src/screens/Messages/Conversation/index.tsx | 27 | ||||
-rw-r--r-- | src/state/queries/messages/conversation.ts | 13 | ||||
-rw-r--r-- | src/state/queries/messages/leave-conversation.ts | 5 | ||||
-rw-r--r-- | src/state/queries/messages/mute-conversation.ts | 101 |
5 files changed, 92 insertions, 97 deletions
diff --git a/src/components/dms/ConvoMenu.tsx b/src/components/dms/ConvoMenu.tsx index cac4eb4d9..8c8e7ed48 100644 --- a/src/components/dms/ConvoMenu.tsx +++ b/src/components/dms/ConvoMenu.tsx @@ -2,17 +2,18 @@ import React, {useCallback} from 'react' import {Keyboard, Pressable, View} from 'react-native' import {AppBskyActorDefs} from '@atproto/api' import {ChatBskyConvoDefs} from '@atproto-labs/api' +import {ConvoView} from '@atproto-labs/api/dist/client/types/chat/bsky/convo/defs' import {msg, Trans} from '@lingui/macro' import {useLingui} from '@lingui/react' import {useNavigation} from '@react-navigation/native' import {NavigationProp} from '#/lib/routes/types' -import {useMarkAsReadMutation} from '#/state/queries/messages/conversation' -import {useLeaveConvo} from '#/state/queries/messages/leave-conversation' import { - useMuteConvo, - useUnmuteConvo, -} from '#/state/queries/messages/mute-conversation' + useConvoQuery, + useMarkAsReadMutation, +} from '#/state/queries/messages/conversation' +import {useLeaveConvo} from '#/state/queries/messages/leave-conversation' +import {useMuteConvo} from '#/state/queries/messages/mute-conversation' 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' @@ -28,16 +29,15 @@ import * as Prompt from '#/components/Prompt' import {Bubble_Stroke2_Corner2_Rounded as Bubble} from '../icons/Bubble' let ConvoMenu = ({ - convo, + convo: initialConvo, profile, - onUpdateConvo, control, currentScreen, showMarkAsRead, hideTrigger, triggerOpacity, }: { - convo: ChatBskyConvoDefs.ConvoView + convo: ConvoView profile: AppBskyActorDefs.ProfileViewBasic onUpdateConvo?: (convo: ChatBskyConvoDefs.ConvoView) => void control?: Menu.MenuControlProps @@ -52,31 +52,26 @@ let ConvoMenu = ({ const leaveConvoControl = Prompt.usePromptControl() const {mutate: markAsRead} = useMarkAsReadMutation() + const {data: convo} = useConvoQuery(initialConvo) + const onNavigateToProfile = useCallback(() => { navigation.navigate('Profile', {name: profile.did}) }, [navigation, profile.did]) - const {mutate: muteConvo} = useMuteConvo(convo.id, { + const {mutate: muteConvo} = useMuteConvo(convo?.id, { onSuccess: data => { - onUpdateConvo?.(data.convo) - Toast.show(_(msg`Chat muted`)) + if (data.convo.muted) { + Toast.show(_(msg`Chat muted`)) + } else { + Toast.show(_(msg`Chat unmuted`)) + } }, onError: () => { Toast.show(_(msg`Could not mute chat`)) }, }) - const {mutate: unmuteConvo} = useUnmuteConvo(convo.id, { - onSuccess: data => { - onUpdateConvo?.(data.convo) - Toast.show(_(msg`Chat unmuted`)) - }, - onError: () => { - Toast.show(_(msg`Could not unmute chat`)) - }, - }) - - const {mutate: leaveConvo} = useLeaveConvo(convo.id, { + const {mutate: leaveConvo} = useLeaveConvo(convo?.id, { onSuccess: () => { if (currentScreen === 'conversation') { navigation.replace('Messages') @@ -121,7 +116,7 @@ let ConvoMenu = ({ label={_(msg`Mark as read`)} onPress={() => markAsRead({ - convoId: convo.id, + convoId: convo?.id, }) }> <Menu.ItemText> @@ -140,7 +135,7 @@ let ConvoMenu = ({ </Menu.Item> <Menu.Item label={_(msg`Mute notifications`)} - onPress={() => (convo?.muted ? unmuteConvo() : muteConvo())}> + onPress={() => muteConvo({mute: !convo?.muted})}> <Menu.ItemText> {convo?.muted ? ( <Trans>Unmute notifications</Trans> diff --git a/src/screens/Messages/Conversation/index.tsx b/src/screens/Messages/Conversation/index.tsx index fc4df0a24..a783a0bd6 100644 --- a/src/screens/Messages/Conversation/index.tsx +++ b/src/screens/Messages/Conversation/index.tsx @@ -56,7 +56,7 @@ export function MessagesConversationScreen({route}: Props) { function Inner() { const t = useTheme() - const convo = useConvo() + const convoState = useConvo() const {_} = useLingui() const [hasInitiallyRendered, setHasInitiallyRendered] = React.useState(false) @@ -72,23 +72,23 @@ function Inner() { React.useEffect(() => { if ( !hasInitiallyRendered && - convo.status === ConvoStatus.Ready && - !convo.isFetchingHistory + convoState.status === ConvoStatus.Ready && + !convoState.isFetchingHistory ) { setTimeout(() => { setHasInitiallyRendered(true) }, 15) } - }, [convo.isFetchingHistory, convo.items, convo.status, hasInitiallyRendered]) + }, [convoState.isFetchingHistory, convoState.status, hasInitiallyRendered]) - if (convo.status === ConvoStatus.Error) { + if (convoState.status === ConvoStatus.Error) { return ( <CenteredView style={a.flex_1} sideBorders> <Header /> <Error title={_(msg`Something went wrong`)} message={_(msg`We couldn't load this conversation`)} - onRetry={() => convo.error.retry()} + onRetry={() => convoState.error.retry()} /> </CenteredView> ) @@ -106,9 +106,9 @@ function Inner() { behavior="padding" contentContainerStyle={a.flex_1}> <CenteredView style={a.flex_1} sideBorders> - <Header profile={convo.recipients?.[0]} /> + <Header profile={convoState.recipients?.[0]} /> <View style={[a.flex_1]}> - {convo.status !== ConvoStatus.Ready ? ( + {convoState.status !== ConvoStatus.Ready ? ( <ListMaybePlaceholder isLoading /> ) : ( <MessagesList /> @@ -145,7 +145,7 @@ let Header = ({ const {_} = useLingui() const {gtTablet} = useBreakpoints() const navigation = useNavigation<NavigationProp>() - const convo = useConvo() + const convoState = useConvo() const onPressBack = useCallback(() => { if (isWeb) { @@ -155,10 +155,6 @@ let Header = ({ } }, [navigation]) - const onUpdateConvo = useCallback(() => { - // TODO eric update muted state - }, []) - return ( <View style={[ @@ -234,11 +230,10 @@ let Header = ({ </> )} </View> - {convo.status === ConvoStatus.Ready && profile ? ( + {convoState.status === ConvoStatus.Ready && profile ? ( <ConvoMenu - convo={convo.convo} + convo={convoState.convo} profile={profile} - onUpdateConvo={onUpdateConvo} currentScreen="conversation" /> ) : ( diff --git a/src/state/queries/messages/conversation.ts b/src/state/queries/messages/conversation.ts index b4861b572..e420ba736 100644 --- a/src/state/queries/messages/conversation.ts +++ b/src/state/queries/messages/conversation.ts @@ -1,4 +1,5 @@ import {BskyAgent} from '@atproto-labs/api' +import {ConvoView} from '@atproto-labs/api/dist/client/types/chat/bsky/convo/defs' import {useMutation, useQuery, useQueryClient} from '@tanstack/react-query' import {useOnMarkAsRead} from '#/state/queries/messages/list-converations' @@ -9,20 +10,21 @@ import {useHeaders} from './temp-headers' const RQKEY_ROOT = 'convo' export const RQKEY = (convoId: string) => [RQKEY_ROOT, convoId] -export function useConvoQuery(convoId: string) { +export function useConvoQuery(convo: ConvoView) { const headers = useHeaders() const {serviceUrl} = useDmServiceUrlStorage() return useQuery({ - queryKey: RQKEY(convoId), + queryKey: RQKEY(convo.id), queryFn: async () => { const agent = new BskyAgent({service: serviceUrl}) const {data} = await agent.api.chat.bsky.convo.getConvo( - {convoId}, + {convoId: convo.id}, {headers}, ) return data.convo }, + initialData: convo, }) } @@ -37,9 +39,11 @@ export function useMarkAsReadMutation() { convoId, messageId, }: { - convoId: string + convoId?: string messageId?: string }) => { + if (!convoId) throw new Error('No convoId provided') + const agent = new BskyAgent({service: serviceUrl}) await agent.api.chat.bsky.convo.updateRead( { @@ -53,6 +57,7 @@ export function useMarkAsReadMutation() { ) }, onMutate({convoId}) { + if (!convoId) throw new Error('No convoId provided') optimisticUpdate(convoId) }, onSettled() { diff --git a/src/state/queries/messages/leave-conversation.ts b/src/state/queries/messages/leave-conversation.ts index 0dd67fa0b..5d5c64c5b 100644 --- a/src/state/queries/messages/leave-conversation.ts +++ b/src/state/queries/messages/leave-conversation.ts @@ -11,7 +11,7 @@ import {RQKEY as CONVO_LIST_KEY} from './list-converations' import {useHeaders} from './temp-headers' export function useLeaveConvo( - convoId: string, + convoId: string | undefined, { onSuccess, onError, @@ -26,6 +26,8 @@ export function useLeaveConvo( return useMutation({ mutationFn: async () => { + if (!convoId) throw new Error('No convoId provided') + const agent = new BskyAgent({service: serviceUrl}) const {data} = await agent.api.chat.bsky.convo.leaveConvo( {convoId}, @@ -41,7 +43,6 @@ export function useLeaveConvo( pageParams: Array<string | undefined> pages: Array<ChatBskyConvoListConvos.OutputSchema> }) => { - console.log('old', old) if (!old) return old return { ...old, diff --git a/src/state/queries/messages/mute-conversation.ts b/src/state/queries/messages/mute-conversation.ts index 4840c65ad..f30612c73 100644 --- a/src/state/queries/messages/mute-conversation.ts +++ b/src/state/queries/messages/mute-conversation.ts @@ -1,18 +1,18 @@ import { BskyAgent, + ChatBskyConvoDefs, + ChatBskyConvoListConvos, ChatBskyConvoMuteConvo, - ChatBskyConvoUnmuteConvo, } from '@atproto-labs/api' -import {useMutation, useQueryClient} from '@tanstack/react-query' +import {InfiniteData, useMutation, useQueryClient} from '@tanstack/react-query' -import {logger} from '#/logger' import {useDmServiceUrlStorage} from '#/screens/Messages/Temp/useDmServiceUrlStorage' import {RQKEY as CONVO_KEY} from './conversation' import {RQKEY as CONVO_LIST_KEY} from './list-converations' import {useHeaders} from './temp-headers' export function useMuteConvo( - convoId: string, + convoId: string | undefined, { onSuccess, onError, @@ -26,59 +26,58 @@ export function useMuteConvo( const {serviceUrl} = useDmServiceUrlStorage() return useMutation({ - mutationFn: async () => { - const agent = new BskyAgent({service: serviceUrl}) - const {data} = await agent.api.chat.bsky.convo.muteConvo( - {convoId}, - {headers, encoding: 'application/json'}, - ) - - return data - }, - onSuccess: data => { - queryClient.invalidateQueries({queryKey: CONVO_LIST_KEY}) - queryClient.invalidateQueries({queryKey: CONVO_KEY(convoId)}) - onSuccess?.(data) - }, - onError: error => { - logger.error(error) - onError?.(error) - }, - }) -} + mutationFn: async ({mute}: {mute: boolean}) => { + if (!convoId) throw new Error('No convoId provided') -export function useUnmuteConvo( - convoId: string, - { - onSuccess, - onError, - }: { - onSuccess?: (data: ChatBskyConvoUnmuteConvo.OutputSchema) => void - onError?: (error: Error) => void - }, -) { - const queryClient = useQueryClient() - const headers = useHeaders() - const {serviceUrl} = useDmServiceUrlStorage() - - return useMutation({ - mutationFn: async () => { const agent = new BskyAgent({service: serviceUrl}) - const {data} = await agent.api.chat.bsky.convo.unmuteConvo( - {convoId}, - {headers, encoding: 'application/json'}, + if (mute) { + const {data} = await agent.api.chat.bsky.convo.muteConvo( + {convoId}, + {headers, encoding: 'application/json'}, + ) + return data + } else { + const {data} = await agent.api.chat.bsky.convo.unmuteConvo( + {convoId}, + {headers, encoding: 'application/json'}, + ) + return data + } + }, + onSuccess: (data, params) => { + queryClient.setQueryData<ChatBskyConvoDefs.ConvoView>( + CONVO_KEY(data.convo.id), + prev => { + if (!prev) return + return { + ...prev, + muted: params.mute, + } + }, ) + queryClient.setQueryData< + InfiniteData<ChatBskyConvoListConvos.OutputSchema> + >(CONVO_LIST_KEY, prev => { + if (!prev?.pages) return + return { + ...prev, + pages: prev.pages.map(page => ({ + ...page, + convos: page.convos.map(convo => { + if (convo.id !== data.convo.id) return convo + return { + ...convo, + muted: params.mute, + } + }), + })), + } + }) - return data - }, - onSuccess: data => { - queryClient.invalidateQueries({queryKey: CONVO_LIST_KEY}) - queryClient.invalidateQueries({queryKey: CONVO_KEY(convoId)}) onSuccess?.(data) }, - onError: error => { - logger.error(error) - onError?.(error) + onError: e => { + onError?.(e) }, }) } |