[Clipclops] Clop menu, leave clop, mute/unmute clop (#3804)
* convo menu * memoize convomenu * add convoId to useChat + memoize value * leave convo * Create mute-conversation.ts * add mutes, remove changes to useChat and use chat.convo instead * add todo comments * leave convo confirm prompt * remove dependency on useChat and pass in props instead * show menu on long press * optimistic update * optimistic update leave + add error capture * don't `popToTop` when unnecessary --------- Co-authored-by: Hailey <me@haileyok.com>
This commit is contained in:
parent
d3fafdc066
commit
e19f882450
11 changed files with 420 additions and 57 deletions
|
@ -1,4 +1,4 @@
|
|||
import React from 'react'
|
||||
import React, {useContext, useEffect, useMemo, useState} from 'react'
|
||||
import {BskyAgent} from '@atproto-labs/api'
|
||||
|
||||
import {Convo, ConvoParams} from '#/state/messages/convo'
|
||||
|
@ -8,15 +8,14 @@ import {useDmServiceUrlStorage} from '#/screens/Messages/Temp/useDmServiceUrlSto
|
|||
const ChatContext = React.createContext<{
|
||||
service: Convo
|
||||
state: Convo['state']
|
||||
}>({
|
||||
// @ts-ignore
|
||||
service: null,
|
||||
// @ts-ignore
|
||||
state: null,
|
||||
})
|
||||
} | null>(null)
|
||||
|
||||
export function useChat() {
|
||||
return React.useContext(ChatContext)
|
||||
const ctx = useContext(ChatContext)
|
||||
if (!ctx) {
|
||||
throw new Error('useChat must be used within a ChatProvider')
|
||||
}
|
||||
return ctx
|
||||
}
|
||||
|
||||
export function ChatProvider({
|
||||
|
@ -25,7 +24,7 @@ export function ChatProvider({
|
|||
}: Pick<ConvoParams, 'convoId'> & {children: React.ReactNode}) {
|
||||
const {serviceUrl} = useDmServiceUrlStorage()
|
||||
const {getAgent} = useAgent()
|
||||
const [service] = React.useState(
|
||||
const [service] = useState(
|
||||
() =>
|
||||
new Convo({
|
||||
convoId,
|
||||
|
@ -35,13 +34,13 @@ export function ChatProvider({
|
|||
__tempFromUserDid: getAgent().session?.did!,
|
||||
}),
|
||||
)
|
||||
const [state, setState] = React.useState(service.state)
|
||||
const [state, setState] = useState(service.state)
|
||||
|
||||
React.useEffect(() => {
|
||||
useEffect(() => {
|
||||
service.initialize()
|
||||
}, [service])
|
||||
|
||||
React.useEffect(() => {
|
||||
useEffect(() => {
|
||||
const update = () => setState(service.state)
|
||||
service.on('update', update)
|
||||
return () => {
|
||||
|
@ -49,9 +48,7 @@ export function ChatProvider({
|
|||
}
|
||||
}, [service])
|
||||
|
||||
return (
|
||||
<ChatContext.Provider value={{state, service}}>
|
||||
{children}
|
||||
</ChatContext.Provider>
|
||||
)
|
||||
const value = useMemo(() => ({service, state}), [service, state])
|
||||
|
||||
return <ChatContext.Provider value={value}>{children}</ChatContext.Provider>
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import {BskyAgent, ChatBskyConvoGetConvoForMembers} from '@atproto-labs/api'
|
||||
import {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 {useHeaders} from './temp-headers'
|
||||
|
@ -30,6 +31,9 @@ export function useGetConvoForMembers({
|
|||
queryClient.setQueryData(CONVO_KEY(data.convo.id), data.convo)
|
||||
onSuccess?.(data)
|
||||
},
|
||||
onError,
|
||||
onError: error => {
|
||||
logger.error(error)
|
||||
onError?.(error)
|
||||
},
|
||||
})
|
||||
}
|
||||
|
|
68
src/state/queries/messages/leave-conversation.ts
Normal file
68
src/state/queries/messages/leave-conversation.ts
Normal file
|
@ -0,0 +1,68 @@
|
|||
import {
|
||||
BskyAgent,
|
||||
ChatBskyConvoLeaveConvo,
|
||||
ChatBskyConvoListConvos,
|
||||
} from '@atproto-labs/api'
|
||||
import {useMutation, useQueryClient} from '@tanstack/react-query'
|
||||
|
||||
import {logger} from '#/logger'
|
||||
import {useDmServiceUrlStorage} from '#/screens/Messages/Temp/useDmServiceUrlStorage'
|
||||
import {RQKEY as CONVO_LIST_KEY} from './list-converations'
|
||||
import {useHeaders} from './temp-headers'
|
||||
|
||||
export function useLeaveConvo(
|
||||
convoId: string,
|
||||
{
|
||||
onSuccess,
|
||||
onError,
|
||||
}: {
|
||||
onSuccess?: (data: ChatBskyConvoLeaveConvo.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.leaveConvo(
|
||||
{convoId},
|
||||
{headers, encoding: 'application/json'},
|
||||
)
|
||||
|
||||
return data
|
||||
},
|
||||
onMutate: () => {
|
||||
queryClient.setQueryData(
|
||||
CONVO_LIST_KEY,
|
||||
(old?: {
|
||||
pageParams: Array<string | undefined>
|
||||
pages: Array<ChatBskyConvoListConvos.OutputSchema>
|
||||
}) => {
|
||||
console.log('old', old)
|
||||
if (!old) return old
|
||||
return {
|
||||
...old,
|
||||
pages: old.pages.map(page => {
|
||||
return {
|
||||
...page,
|
||||
convos: page.convos.filter(convo => convo.id !== convoId),
|
||||
}
|
||||
}),
|
||||
}
|
||||
},
|
||||
)
|
||||
},
|
||||
onSuccess: data => {
|
||||
queryClient.invalidateQueries({queryKey: CONVO_LIST_KEY})
|
||||
onSuccess?.(data)
|
||||
},
|
||||
onError: error => {
|
||||
logger.error(error)
|
||||
queryClient.invalidateQueries({queryKey: CONVO_LIST_KEY})
|
||||
onError?.(error)
|
||||
},
|
||||
})
|
||||
}
|
84
src/state/queries/messages/mute-conversation.ts
Normal file
84
src/state/queries/messages/mute-conversation.ts
Normal file
|
@ -0,0 +1,84 @@
|
|||
import {
|
||||
BskyAgent,
|
||||
ChatBskyConvoMuteConvo,
|
||||
ChatBskyConvoUnmuteConvo,
|
||||
} from '@atproto-labs/api'
|
||||
import {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,
|
||||
{
|
||||
onSuccess,
|
||||
onError,
|
||||
}: {
|
||||
onSuccess?: (data: ChatBskyConvoMuteConvo.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.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)
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
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'},
|
||||
)
|
||||
|
||||
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)
|
||||
},
|
||||
})
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue