about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/components/dms/ConvoMenu.tsx43
-rw-r--r--src/screens/Messages/Conversation/index.tsx27
-rw-r--r--src/state/queries/messages/conversation.ts13
-rw-r--r--src/state/queries/messages/leave-conversation.ts5
-rw-r--r--src/state/queries/messages/mute-conversation.ts101
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)
     },
   })
 }