Use new listConvoRequests endpoint (#10755)
Co-authored-by: Samuel Newman <mozzius@protonmail.com>
This commit is contained in:
@@ -1773,16 +1773,6 @@
|
||||
"count": 7
|
||||
}
|
||||
},
|
||||
"src/state/queries/messages/accept-conversation.ts": {
|
||||
"@typescript-eslint/no-floating-promises": {
|
||||
"count": 2
|
||||
}
|
||||
},
|
||||
"src/state/queries/messages/update-all-read.ts": {
|
||||
"@typescript-eslint/no-floating-promises": {
|
||||
"count": 3
|
||||
}
|
||||
},
|
||||
"src/state/queries/my-lists.ts": {
|
||||
"@typescript-eslint/no-floating-promises": {
|
||||
"count": 2
|
||||
|
||||
@@ -36,7 +36,7 @@ export function AvatarBubbles({
|
||||
moderationOpts,
|
||||
}: {
|
||||
animate?: boolean
|
||||
profiles: bsky.profile.AnyProfileView[]
|
||||
profiles: (bsky.profile.AnyProfileView | undefined)[]
|
||||
/**
|
||||
* By default, when there are more than 2 profiles, the current user is
|
||||
* filtered out (so you don't see yourself among your own group's members).
|
||||
@@ -50,12 +50,12 @@ export function AvatarBubbles({
|
||||
const {currentAccount} = useSession()
|
||||
const profiles =
|
||||
!self && allProfiles.length > 2
|
||||
? allProfiles.filter(p => p?.did != null && p.did !== currentAccount?.did)
|
||||
? allProfiles.filter(p => !p || p.did !== currentAccount?.did)
|
||||
: allProfiles
|
||||
const moderations = useMemo(() => {
|
||||
if (!moderationOpts) return []
|
||||
return profiles.map(p => {
|
||||
return moderateProfile(p, moderationOpts)
|
||||
return p && moderateProfile(p, moderationOpts)
|
||||
})
|
||||
}, [profiles, moderationOpts])
|
||||
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
import {useCallback, useMemo, useState} from 'react'
|
||||
import {View} from 'react-native'
|
||||
import {
|
||||
type ChatBskyConvoDefs,
|
||||
type ChatBskyConvoListConvos,
|
||||
ChatBskyConvoDefs,
|
||||
type ChatBskyConvoListConvoRequests,
|
||||
ChatBskyGroupDefs,
|
||||
} from '@atproto/api'
|
||||
import {Trans, useLingui} from '@lingui/react/macro'
|
||||
import {useFocusEffect, useNavigation} from '@react-navigation/native'
|
||||
@@ -23,7 +24,7 @@ import {logger} from '#/logger'
|
||||
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 {useListConvoRequests} from '#/state/queries/messages/list-conversation-requests'
|
||||
import {useUpdateAllRead} from '#/state/queries/messages/update-all-read'
|
||||
import {EmptyState} from '#/view/com/util/EmptyState'
|
||||
import {List} from '#/view/com/util/List'
|
||||
@@ -43,11 +44,16 @@ import {ListFooter} from '#/components/Lists'
|
||||
import * as Toast from '#/components/Toast'
|
||||
import {Text} from '#/components/Typography'
|
||||
import {IS_NATIVE} from '#/env'
|
||||
import {RequestListItem} from './components/RequestListItem'
|
||||
import {IncomingRequestListItem} from './components/IncomingRequestListItem'
|
||||
import {OutgoingRequestListItem} from './components/OutgoingRequestListItem'
|
||||
import {useIsWithinSplitView} from './components/splitView/context'
|
||||
|
||||
type Props = NativeStackScreenProps<CommonNavigatorParams, 'MessagesInbox'>
|
||||
|
||||
type RequestItem =
|
||||
| {type: 'incoming'; view: ChatBskyConvoDefs.ConvoView}
|
||||
| {type: 'outgoing'; view: ChatBskyGroupDefs.JoinRequestConvoView}
|
||||
|
||||
export function MessagesInboxScreen(props: Props) {
|
||||
const {t: l} = useLingui()
|
||||
const aaCopy = useAgeAssuranceCopy()
|
||||
@@ -61,29 +67,36 @@ export function MessagesInboxScreen(props: Props) {
|
||||
}
|
||||
|
||||
export function MessagesInboxScreenInner({}: Props) {
|
||||
const listConvosQuery = useListConvosQuery({status: 'request'})
|
||||
const listConvosQuery = useListConvoRequests()
|
||||
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))
|
||||
|
||||
return convos
|
||||
const conversations = useMemo<RequestItem[]>(() => {
|
||||
if (!data?.pages) return []
|
||||
const items: RequestItem[] = []
|
||||
for (const page of data.pages) {
|
||||
for (const item of page.requests) {
|
||||
if (ChatBskyConvoDefs.isConvoView(item)) {
|
||||
// filter out convos that are actively being left
|
||||
if (leftConvos.includes(item.id)) continue
|
||||
items.push({type: 'incoming', view: item})
|
||||
} else if (ChatBskyGroupDefs.isJoinRequestConvoView(item)) {
|
||||
items.push({type: 'outgoing', view: item})
|
||||
}
|
||||
}
|
||||
}
|
||||
return []
|
||||
return items
|
||||
}, [data, leftConvos])
|
||||
|
||||
const hasUnreadConvos = useMemo(() => {
|
||||
return conversations.some(
|
||||
conversation =>
|
||||
conversation.members.every(
|
||||
item =>
|
||||
item.type === 'incoming' &&
|
||||
item.view.members.every(
|
||||
member => member.handle !== 'missing.invalid',
|
||||
) && conversation.unreadCount > 0,
|
||||
) &&
|
||||
item.view.unreadCount > 0,
|
||||
)
|
||||
}, [conversations])
|
||||
|
||||
@@ -111,10 +124,10 @@ function RequestList({
|
||||
conversations,
|
||||
}: {
|
||||
listConvosQuery: UseInfiniteQueryResult<
|
||||
InfiniteData<ChatBskyConvoListConvos.OutputSchema>,
|
||||
InfiniteData<ChatBskyConvoListConvoRequests.OutputSchema>,
|
||||
Error
|
||||
>
|
||||
conversations: ChatBskyConvoDefs.ConvoView[]
|
||||
conversations: RequestItem[]
|
||||
}) {
|
||||
const {t: l} = useLingui()
|
||||
const t = useTheme()
|
||||
@@ -274,17 +287,21 @@ function RequestList({
|
||||
windowSize={11}
|
||||
desktopFixedHeight
|
||||
sideBorders={false}
|
||||
contentContainerStyle={[web(a.py_sm)]}
|
||||
/>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
function keyExtractor(item: ChatBskyConvoDefs.ConvoView) {
|
||||
return item.id
|
||||
function keyExtractor(item: RequestItem) {
|
||||
return item.type === 'incoming' ? item.view.id : item.view.convoId
|
||||
}
|
||||
|
||||
function renderItem({item}: {item: ChatBskyConvoDefs.ConvoView}) {
|
||||
return <RequestListItem convo={item} />
|
||||
function renderItem({item}: {item: RequestItem}) {
|
||||
if (item.type === 'incoming') {
|
||||
return <IncomingRequestListItem convo={item.view} />
|
||||
}
|
||||
return <OutgoingRequestListItem convo={item.view} />
|
||||
}
|
||||
|
||||
function MarkAsReadHeaderButton() {
|
||||
|
||||
+1
-1
@@ -11,7 +11,7 @@ import {Text} from '#/components/Typography'
|
||||
import {ChatListItem, ChatListItemPortal} from './ChatListItem'
|
||||
import {AcceptChatButton, DeleteChatButton, RejectMenu} from './RequestButtons'
|
||||
|
||||
export function RequestListItem({
|
||||
export function IncomingRequestListItem({
|
||||
convo: convoView,
|
||||
}: {
|
||||
convo: ChatBskyConvoDefs.ConvoView
|
||||
@@ -0,0 +1,128 @@
|
||||
import {View} from 'react-native'
|
||||
import {
|
||||
type ChatBskyGroupDefs,
|
||||
ChatBskyGroupWithdrawJoinRequest,
|
||||
} from '@atproto/api'
|
||||
import {Trans, useLingui} from '@lingui/react/macro'
|
||||
|
||||
import {isNetworkError} from '#/lib/strings/errors'
|
||||
import {useModerationOpts} from '#/state/preferences/moderation-opts'
|
||||
import {useWithdrawJoinGroupChatRequest} from '#/state/queries/messages/withdraw-join-group-chat'
|
||||
import {TimeElapsed} from '#/view/com/util/TimeElapsed'
|
||||
import {atoms as a, useTheme, web} from '#/alf'
|
||||
import {AvatarBubbles} from '#/components/AvatarBubbles'
|
||||
import {createStaticClick, Link} from '#/components/Link'
|
||||
import * as Prompt from '#/components/Prompt'
|
||||
import * as Toast from '#/components/Toast'
|
||||
import {Text} from '#/components/Typography'
|
||||
|
||||
export function OutgoingRequestListItem({
|
||||
convo: convoView,
|
||||
}: {
|
||||
convo: ChatBskyGroupDefs.JoinRequestConvoView
|
||||
}) {
|
||||
const t = useTheme()
|
||||
const {t: l} = useLingui()
|
||||
|
||||
const prompt = Prompt.usePromptControl()
|
||||
|
||||
const moderationOpts = useModerationOpts()
|
||||
|
||||
const {mutate: withdrawRequest, isPending: isWithdrawPending} =
|
||||
useWithdrawJoinGroupChatRequest({
|
||||
onSuccess: () => {
|
||||
Toast.show(l`Join request rescinded.`)
|
||||
},
|
||||
onError: error => {
|
||||
let errorMessage = l`Failed to rescind your request. Please try again.`
|
||||
if (isNetworkError(error)) {
|
||||
errorMessage = l`There was a problem with your internet connection, please try again`
|
||||
} else if (
|
||||
error instanceof
|
||||
ChatBskyGroupWithdrawJoinRequest.InvalidJoinRequestError
|
||||
) {
|
||||
errorMessage = l`Invalid rescind request.`
|
||||
}
|
||||
Toast.show(errorMessage)
|
||||
},
|
||||
})
|
||||
|
||||
return (
|
||||
<>
|
||||
<Link
|
||||
label={l`Rescind request to join group chat`}
|
||||
{...createStaticClick(() => {
|
||||
prompt.open()
|
||||
})}>
|
||||
{({hovered, pressed, focused}) => (
|
||||
<View
|
||||
style={[
|
||||
a.flex_row,
|
||||
a.align_center,
|
||||
a.flex_1,
|
||||
a.px_lg,
|
||||
a.py_md,
|
||||
a.gap_md,
|
||||
(hovered || pressed || focused) && t.atoms.bg_contrast_25,
|
||||
]}>
|
||||
<AvatarBubbles
|
||||
profiles={[
|
||||
convoView?.owner ?? undefined,
|
||||
...Array(
|
||||
Math.min(3, Math.max(0, convoView.memberCount - 1)),
|
||||
).fill(undefined),
|
||||
]}
|
||||
size={48}
|
||||
moderationOpts={moderationOpts}
|
||||
/>
|
||||
<View style={[a.flex_1]}>
|
||||
<View style={[a.w_full, a.flex_row, a.align_center, a.pb_2xs]}>
|
||||
<View style={[a.flex_shrink]}>
|
||||
<Text
|
||||
emoji
|
||||
numberOfLines={1}
|
||||
style={[a.text_md, a.font_semi_bold]}>
|
||||
{convoView.name}
|
||||
</Text>
|
||||
</View>
|
||||
<View style={[a.pl_xs]}>
|
||||
<TimeElapsed timestamp={convoView.requestedAt}>
|
||||
{({timeElapsed}) => (
|
||||
<Text
|
||||
style={[
|
||||
a.text_sm,
|
||||
t.atoms.text_contrast_medium,
|
||||
web({whiteSpace: 'preserve nowrap'}),
|
||||
]}>
|
||||
{timeElapsed}
|
||||
</Text>
|
||||
)}
|
||||
</TimeElapsed>
|
||||
</View>
|
||||
</View>
|
||||
<Text
|
||||
numberOfLines={1}
|
||||
style={[a.text_sm, t.atoms.text_contrast_high]}>
|
||||
<Trans comment="Displayed when the user has requested to join a group chat.">
|
||||
You requested to join
|
||||
</Trans>
|
||||
</Text>
|
||||
</View>
|
||||
</View>
|
||||
)}
|
||||
</Link>
|
||||
<Prompt.Basic
|
||||
control={prompt}
|
||||
title={l`Rescind request`}
|
||||
description={l`Are you sure you want to rescind your request to join ${convoView.name}?`}
|
||||
confirmButtonCta={l`Rescind request`}
|
||||
onConfirm={() => {
|
||||
prompt.close(() => {
|
||||
if (isWithdrawPending) return
|
||||
withdrawRequest({convoId: convoView.convoId})
|
||||
})
|
||||
}}
|
||||
/>
|
||||
</>
|
||||
)
|
||||
}
|
||||
Vendored
+2
@@ -11,6 +11,7 @@ import {findAllProfilesInQueryData as findAllProfilesInContactMatchesQueryData}
|
||||
import {findAllProfilesInQueryData as findAllProfilesInKnownFollowersQueryData} from '#/state/queries/known-followers'
|
||||
import {findAllProfilesInQueryData as findAllProfilesInListMembersQueryData} from '#/state/queries/list-members'
|
||||
import {findAllProfilesInQueryData as findAllProfilesInGetConvoQueryData} from '#/state/queries/messages/conversation'
|
||||
import {findAllProfilesInQueryData as findAllProfilesInListConvoRequestsQueryData} from '#/state/queries/messages/list-conversation-requests'
|
||||
import {findAllProfilesInQueryData as findAllProfilesInListConvosQueryData} from '#/state/queries/messages/list-conversations'
|
||||
import {findAllProfilesInQueryData as findAllProfilesInMessagesQueryData} from '#/state/queries/messages/list-convo-members'
|
||||
import {findAllProfilesInQueryData as findAllProfilesInMyBlockedAccountsQueryData} from '#/state/queries/my-blocked-accounts'
|
||||
@@ -259,6 +260,7 @@ function* findProfilesInCache(
|
||||
yield* findAllProfilesInSuggestedFollowsQueryData(queryClient, did)
|
||||
yield* findAllProfilesInActorSearchQueryData(queryClient, did)
|
||||
yield* findAllProfilesInListConvosQueryData(queryClient, did)
|
||||
yield* findAllProfilesInListConvoRequestsQueryData(queryClient, did)
|
||||
yield* findAllProfilesInFeedsQueryData(queryClient, did)
|
||||
yield* findAllProfilesInPostThreadV2QueryData(queryClient, did)
|
||||
yield* findAllProfilesInKnownFollowersQueryData(queryClient, did)
|
||||
|
||||
@@ -7,6 +7,11 @@ import {useMutation, useQueryClient} from '@tanstack/react-query'
|
||||
import {DM_SERVICE_HEADERS} from '#/lib/constants'
|
||||
import {logger} from '#/logger'
|
||||
import {useAgent} from '#/state/session'
|
||||
import {
|
||||
type ConvoRequestListQueryData,
|
||||
optimisticDelete as optimisticDeleteRequest,
|
||||
RQKEY_ROOT as REQUESTS_RQKEY_ROOT,
|
||||
} from './list-conversation-requests'
|
||||
import {
|
||||
RQKEY as CONVO_LIST_KEY,
|
||||
RQKEY_ROOT as CONVO_LIST_ROOT_KEY,
|
||||
@@ -96,11 +101,20 @@ export function useAcceptConversation(
|
||||
}
|
||||
},
|
||||
)
|
||||
const prevRequestsQueries =
|
||||
queryClient.getQueriesData<ConvoRequestListQueryData>({
|
||||
queryKey: [REQUESTS_RQKEY_ROOT],
|
||||
})
|
||||
queryClient.setQueriesData<ConvoRequestListQueryData>(
|
||||
{queryKey: [REQUESTS_RQKEY_ROOT]},
|
||||
old => optimisticDeleteRequest(convoId, old),
|
||||
)
|
||||
onMutate?.()
|
||||
return {prevAcceptedPages, prevInboxPages}
|
||||
return {prevAcceptedPages, prevInboxPages, prevRequestsQueries}
|
||||
},
|
||||
onSuccess: data => {
|
||||
queryClient.invalidateQueries({queryKey: [CONVO_LIST_KEY]})
|
||||
void queryClient.invalidateQueries({queryKey: [CONVO_LIST_KEY]})
|
||||
void queryClient.invalidateQueries({queryKey: [REQUESTS_RQKEY_ROOT]})
|
||||
onSuccess?.(data)
|
||||
},
|
||||
onError: (error, _, context) => {
|
||||
@@ -131,7 +145,13 @@ export function useAcceptConversation(
|
||||
}
|
||||
},
|
||||
)
|
||||
queryClient.invalidateQueries({queryKey: [CONVO_LIST_ROOT_KEY]})
|
||||
if (context?.prevRequestsQueries) {
|
||||
for (const [queryKey, prevData] of context.prevRequestsQueries) {
|
||||
queryClient.setQueryData(queryKey, prevData)
|
||||
}
|
||||
}
|
||||
void queryClient.invalidateQueries({queryKey: [CONVO_LIST_ROOT_KEY]})
|
||||
void queryClient.invalidateQueries({queryKey: [REQUESTS_RQKEY_ROOT]})
|
||||
onError?.(error)
|
||||
},
|
||||
})
|
||||
|
||||
@@ -0,0 +1,165 @@
|
||||
import {
|
||||
ChatBskyConvoDefs,
|
||||
type ChatBskyConvoListConvoRequests,
|
||||
ChatBskyGroupDefs,
|
||||
} from '@atproto/api'
|
||||
import {
|
||||
type InfiniteData,
|
||||
type QueryClient,
|
||||
useInfiniteQuery,
|
||||
} from '@tanstack/react-query'
|
||||
|
||||
import {DM_SERVICE_HEADERS} from '#/lib/constants'
|
||||
import {useAgent} from '#/state/session'
|
||||
|
||||
const DEFAULT_LIMIT = 10
|
||||
|
||||
export const RQKEY_ROOT = 'convo-request-list'
|
||||
export const RQKEY = (limit: number = DEFAULT_LIMIT) => [RQKEY_ROOT, limit]
|
||||
|
||||
type RQPageParam = string | undefined
|
||||
|
||||
export function useListConvoRequests({
|
||||
enabled = true,
|
||||
limit = DEFAULT_LIMIT,
|
||||
}: {
|
||||
enabled?: boolean
|
||||
limit?: number
|
||||
} = {}) {
|
||||
const agent = useAgent()
|
||||
|
||||
return useInfiniteQuery({
|
||||
enabled,
|
||||
queryKey: RQKEY(limit),
|
||||
queryFn: async ({pageParam}) => {
|
||||
const {data} = await agent.chat.bsky.convo.listConvoRequests(
|
||||
{limit, cursor: pageParam},
|
||||
{headers: DM_SERVICE_HEADERS},
|
||||
)
|
||||
return data
|
||||
},
|
||||
initialPageParam: undefined as RQPageParam,
|
||||
getNextPageParam: lastPage => lastPage.cursor,
|
||||
})
|
||||
}
|
||||
|
||||
export type ConvoRequestListQueryData = {
|
||||
pageParams: Array<string | undefined>
|
||||
pages: Array<ChatBskyConvoListConvoRequests.OutputSchema>
|
||||
}
|
||||
|
||||
export type ConvoRequestItem =
|
||||
ChatBskyConvoListConvoRequests.OutputSchema['requests'][number]
|
||||
|
||||
export function optimisticUpdate(
|
||||
chatId: string,
|
||||
old: ConvoRequestListQueryData | undefined,
|
||||
updateFn: (convo: ChatBskyConvoDefs.ConvoView) => ChatBskyConvoDefs.ConvoView,
|
||||
): ConvoRequestListQueryData | undefined {
|
||||
if (!old) return old
|
||||
|
||||
return {
|
||||
...old,
|
||||
pages: old.pages.map(page => ({
|
||||
...page,
|
||||
requests: page.requests.map((item): ConvoRequestItem => {
|
||||
if (ChatBskyConvoDefs.isConvoView(item) && item.id === chatId) {
|
||||
return {
|
||||
...updateFn(item),
|
||||
$type: 'chat.bsky.convo.defs#convoView',
|
||||
}
|
||||
}
|
||||
return item
|
||||
}),
|
||||
})),
|
||||
}
|
||||
}
|
||||
|
||||
export function optimisticDelete(
|
||||
chatId: string,
|
||||
old: ConvoRequestListQueryData | undefined,
|
||||
) {
|
||||
if (!old) return old
|
||||
|
||||
return {
|
||||
...old,
|
||||
pages: old.pages.map(page => ({
|
||||
...page,
|
||||
requests: page.requests.filter(
|
||||
item => !ChatBskyConvoDefs.isConvoView(item) || item.id !== chatId,
|
||||
),
|
||||
})),
|
||||
}
|
||||
}
|
||||
|
||||
export function markAllRead(
|
||||
old: ConvoRequestListQueryData | undefined,
|
||||
): ConvoRequestListQueryData | undefined {
|
||||
if (!old) return old
|
||||
|
||||
return {
|
||||
...old,
|
||||
pages: old.pages.map(page => ({
|
||||
...page,
|
||||
requests: page.requests.map((item): ConvoRequestItem => {
|
||||
if (ChatBskyConvoDefs.isConvoView(item)) {
|
||||
return {
|
||||
...item,
|
||||
$type: 'chat.bsky.convo.defs#convoView',
|
||||
unreadCount: 0,
|
||||
}
|
||||
}
|
||||
return item
|
||||
}),
|
||||
})),
|
||||
}
|
||||
}
|
||||
|
||||
export function optimisticDeleteJoinRequest(
|
||||
convoId: string,
|
||||
old: ConvoRequestListQueryData | undefined,
|
||||
) {
|
||||
if (!old) return old
|
||||
|
||||
return {
|
||||
...old,
|
||||
pages: old.pages.map(page => ({
|
||||
...page,
|
||||
requests: page.requests.filter(
|
||||
item =>
|
||||
!ChatBskyGroupDefs.isJoinRequestConvoView(item) ||
|
||||
item.convoId !== convoId,
|
||||
),
|
||||
})),
|
||||
}
|
||||
}
|
||||
|
||||
export function* findAllProfilesInQueryData(
|
||||
queryClient: QueryClient,
|
||||
did: string,
|
||||
) {
|
||||
const queryDatas = queryClient.getQueriesData<
|
||||
InfiniteData<ChatBskyConvoListConvoRequests.OutputSchema>
|
||||
>({
|
||||
queryKey: [RQKEY_ROOT],
|
||||
})
|
||||
for (const [_queryKey, queryData] of queryDatas) {
|
||||
if (!queryData?.pages) continue
|
||||
|
||||
for (const page of queryData.pages) {
|
||||
for (const item of page.requests) {
|
||||
if (ChatBskyConvoDefs.isConvoView(item)) {
|
||||
for (const member of item.members) {
|
||||
if (member.did === did) {
|
||||
yield member
|
||||
}
|
||||
}
|
||||
} else if (ChatBskyGroupDefs.isJoinRequestConvoView(item)) {
|
||||
if (item.owner.did === did) {
|
||||
yield item.owner
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -23,6 +23,13 @@ import {parseConvoView} from '#/components/dms/util'
|
||||
import * as bsky from '#/types/bsky'
|
||||
import {RQKEY as CONVO_KEY} from './conversation'
|
||||
import {useLeftConvos} from './leave-conversation'
|
||||
import {
|
||||
type ConvoRequestListQueryData,
|
||||
optimisticDelete as optimisticDeleteRequest,
|
||||
optimisticDeleteJoinRequest,
|
||||
optimisticUpdate as optimisticUpdateRequest,
|
||||
RQKEY_ROOT as REQUESTS_RQKEY_ROOT,
|
||||
} from './list-conversation-requests'
|
||||
import {listConvoMembersQueryKey} from './list-convo-members'
|
||||
|
||||
const DEFAULT_LIMIT = 10
|
||||
@@ -130,6 +137,7 @@ export function ListConvosProviderInner({
|
||||
const refetchAndInvalidate = () => {
|
||||
void refetch()
|
||||
void queryClient.invalidateQueries({queryKey: [RQKEY_ROOT]})
|
||||
void queryClient.invalidateQueries({queryKey: [REQUESTS_RQKEY_ROOT]})
|
||||
}
|
||||
return throttle(refetchAndInvalidate, 500, {
|
||||
leading: true,
|
||||
@@ -157,6 +165,22 @@ export function ListConvosProviderInner({
|
||||
)
|
||||
}
|
||||
|
||||
function updateConvoInAllLists(
|
||||
convoId: string,
|
||||
fn: (
|
||||
convo: ChatBskyConvoDefs.ConvoView,
|
||||
) => ChatBskyConvoDefs.ConvoView,
|
||||
) {
|
||||
queryClient.setQueriesData<ConvoListQueryData>(
|
||||
{queryKey: [RQKEY_ROOT]},
|
||||
old => optimisticUpdate(convoId, old, fn),
|
||||
)
|
||||
queryClient.setQueriesData<ConvoRequestListQueryData>(
|
||||
{queryKey: [REQUESTS_RQKEY_ROOT]},
|
||||
old => optimisticUpdateRequest(convoId, old, fn),
|
||||
)
|
||||
}
|
||||
|
||||
function mutateConvoView(
|
||||
convoId: string,
|
||||
fn: (
|
||||
@@ -167,9 +191,17 @@ export function ListConvosProviderInner({
|
||||
CONVO_KEY(convoId),
|
||||
old => (old ? fn(old) : old),
|
||||
)
|
||||
updateConvoInAllLists(convoId, fn)
|
||||
}
|
||||
|
||||
function deleteConvoFromAllLists(convoId: string) {
|
||||
queryClient.setQueriesData<ConvoListQueryData>(
|
||||
{queryKey: [RQKEY_ROOT]},
|
||||
old => optimisticUpdate(convoId, old, fn),
|
||||
old => optimisticDelete(convoId, old),
|
||||
)
|
||||
queryClient.setQueriesData<ConvoRequestListQueryData>(
|
||||
{queryKey: [REQUESTS_RQKEY_ROOT]},
|
||||
old => optimisticDeleteRequest(convoId, old),
|
||||
)
|
||||
}
|
||||
|
||||
@@ -220,35 +252,26 @@ export function ListConvosProviderInner({
|
||||
if (ChatBskyConvoDefs.isLogBeginConvo(log)) {
|
||||
debouncedRefetch()
|
||||
} else if (ChatBskyConvoDefs.isLogLeaveConvo(log)) {
|
||||
queryClient.setQueriesData(
|
||||
{queryKey: [RQKEY_ROOT]},
|
||||
(old?: ConvoListQueryData) => optimisticDelete(log.convoId, old),
|
||||
)
|
||||
deleteConvoFromAllLists(log.convoId)
|
||||
} else if (ChatBskyConvoDefs.isLogDeleteMessage(log)) {
|
||||
queryClient.setQueriesData(
|
||||
{queryKey: [RQKEY_ROOT]},
|
||||
(old?: ConvoListQueryData) =>
|
||||
optimisticUpdate(log.convoId, old, convo => {
|
||||
if (
|
||||
(ChatBskyConvoDefs.isDeletedMessageView(log.message) ||
|
||||
ChatBskyConvoDefs.isMessageView(log.message)) &&
|
||||
(ChatBskyConvoDefs.isDeletedMessageView(
|
||||
convo.lastMessage,
|
||||
) ||
|
||||
ChatBskyConvoDefs.isMessageView(convo.lastMessage))
|
||||
) {
|
||||
return log.message.id === convo.lastMessage.id
|
||||
? {
|
||||
...convo,
|
||||
rev: log.rev,
|
||||
lastMessage: log.message,
|
||||
}
|
||||
: convo
|
||||
} else {
|
||||
return convo
|
||||
}
|
||||
}),
|
||||
)
|
||||
updateConvoInAllLists(log.convoId, convo => {
|
||||
if (
|
||||
(ChatBskyConvoDefs.isDeletedMessageView(log.message) ||
|
||||
ChatBskyConvoDefs.isMessageView(log.message)) &&
|
||||
(ChatBskyConvoDefs.isDeletedMessageView(convo.lastMessage) ||
|
||||
ChatBskyConvoDefs.isMessageView(convo.lastMessage))
|
||||
) {
|
||||
return log.message.id === convo.lastMessage.id
|
||||
? {
|
||||
...convo,
|
||||
rev: log.rev,
|
||||
lastMessage: log.message,
|
||||
}
|
||||
: convo
|
||||
} else {
|
||||
return convo
|
||||
}
|
||||
})
|
||||
} else if (ChatBskyConvoDefs.isLogCreateMessage(log)) {
|
||||
// Store in a new var to avoid TS errors due to closures.
|
||||
const logRef: ChatBskyConvoDefs.LogCreateMessage = log
|
||||
@@ -335,27 +358,24 @@ export function ListConvosProviderInner({
|
||||
)
|
||||
} else if (updatedConvo.status === 'request') {
|
||||
queryClient.setQueriesData({queryKey: RQKEY('request')}, updateFn)
|
||||
// also move-to-top in the new requests cache
|
||||
queryClient.setQueriesData<ConvoRequestListQueryData>(
|
||||
{queryKey: [REQUESTS_RQKEY_ROOT]},
|
||||
old => moveConvoToTopInRequests(updatedConvo, old),
|
||||
)
|
||||
}
|
||||
} else if (ChatBskyConvoDefs.isLogReadMessage(log)) {
|
||||
queryClient.setQueriesData(
|
||||
{queryKey: [RQKEY_ROOT]},
|
||||
(old?: ConvoListQueryData) =>
|
||||
optimisticUpdate(log.convoId, old, convo => ({
|
||||
...convo,
|
||||
unreadCount: 0,
|
||||
rev: log.rev,
|
||||
})),
|
||||
)
|
||||
updateConvoInAllLists(log.convoId, convo => ({
|
||||
...convo,
|
||||
unreadCount: 0,
|
||||
rev: log.rev,
|
||||
}))
|
||||
} else if (ChatBskyConvoDefs.isLogReadConvo(log)) {
|
||||
queryClient.setQueriesData(
|
||||
{queryKey: [RQKEY_ROOT]},
|
||||
(old?: ConvoListQueryData) =>
|
||||
optimisticUpdate(log.convoId, old, convo => ({
|
||||
...convo,
|
||||
unreadCount: 0,
|
||||
rev: log.rev,
|
||||
})),
|
||||
)
|
||||
updateConvoInAllLists(log.convoId, convo => ({
|
||||
...convo,
|
||||
unreadCount: 0,
|
||||
rev: log.rev,
|
||||
}))
|
||||
} else if (ChatBskyConvoDefs.isLogAcceptConvo(log)) {
|
||||
const requests = queryClient.getQueryData<ConvoListQueryData>(
|
||||
RQKEY('request'),
|
||||
@@ -373,6 +393,11 @@ export function ListConvosProviderInner({
|
||||
RQKEY('request'),
|
||||
(old?: ConvoListQueryData) => optimisticDelete(log.convoId, old),
|
||||
)
|
||||
// also remove from the new requests cache
|
||||
queryClient.setQueriesData<ConvoRequestListQueryData>(
|
||||
{queryKey: [REQUESTS_RQKEY_ROOT]},
|
||||
old => optimisticDeleteRequest(log.convoId, old),
|
||||
)
|
||||
queryClient.setQueriesData(
|
||||
{queryKey: RQKEY('accepted')},
|
||||
(old?: ConvoListQueryData) => {
|
||||
@@ -398,55 +423,50 @@ export function ListConvosProviderInner({
|
||||
},
|
||||
)
|
||||
} else if (ChatBskyConvoDefs.isLogMuteConvo(log)) {
|
||||
queryClient.setQueriesData(
|
||||
{queryKey: [RQKEY_ROOT]},
|
||||
(old?: ConvoListQueryData) =>
|
||||
optimisticUpdate(log.convoId, old, convo => ({
|
||||
...convo,
|
||||
muted: true,
|
||||
rev: log.rev,
|
||||
})),
|
||||
)
|
||||
updateConvoInAllLists(log.convoId, convo => ({
|
||||
...convo,
|
||||
muted: true,
|
||||
rev: log.rev,
|
||||
}))
|
||||
} else if (ChatBskyConvoDefs.isLogUnmuteConvo(log)) {
|
||||
queryClient.setQueriesData(
|
||||
{queryKey: [RQKEY_ROOT]},
|
||||
(old?: ConvoListQueryData) =>
|
||||
optimisticUpdate(log.convoId, old, convo => ({
|
||||
...convo,
|
||||
muted: false,
|
||||
rev: log.rev,
|
||||
})),
|
||||
)
|
||||
updateConvoInAllLists(log.convoId, convo => ({
|
||||
...convo,
|
||||
muted: false,
|
||||
rev: log.rev,
|
||||
}))
|
||||
} else if (ChatBskyConvoDefs.isLogLockConvo(log)) {
|
||||
mutateConvoView(log.convoId, convo =>
|
||||
ChatBskyConvoDefs.isGroupConvo(convo.kind)
|
||||
? {
|
||||
...convo,
|
||||
kind: {...convo.kind, lockStatus: 'locked'},
|
||||
rev: log.rev,
|
||||
}
|
||||
: {...convo, rev: log.rev},
|
||||
)
|
||||
mutateConvoView(log.convoId, convo => {
|
||||
if (ChatBskyConvoDefs.isGroupConvo(convo.kind)) {
|
||||
return {
|
||||
...convo,
|
||||
kind: {...convo.kind, lockStatus: 'locked'},
|
||||
rev: log.rev,
|
||||
}
|
||||
}
|
||||
return {...convo, rev: log.rev}
|
||||
})
|
||||
} else if (ChatBskyConvoDefs.isLogUnlockConvo(log)) {
|
||||
mutateConvoView(log.convoId, convo =>
|
||||
ChatBskyConvoDefs.isGroupConvo(convo.kind)
|
||||
? {
|
||||
...convo,
|
||||
kind: {...convo.kind, lockStatus: 'unlocked'},
|
||||
rev: log.rev,
|
||||
}
|
||||
: {...convo, rev: log.rev},
|
||||
)
|
||||
mutateConvoView(log.convoId, convo => {
|
||||
if (ChatBskyConvoDefs.isGroupConvo(convo.kind)) {
|
||||
return {
|
||||
...convo,
|
||||
kind: {...convo.kind, lockStatus: 'unlocked'},
|
||||
rev: log.rev,
|
||||
}
|
||||
}
|
||||
return {...convo, rev: log.rev}
|
||||
})
|
||||
} else if (ChatBskyConvoDefs.isLogLockConvoPermanently(log)) {
|
||||
mutateConvoView(log.convoId, convo =>
|
||||
ChatBskyConvoDefs.isGroupConvo(convo.kind)
|
||||
? {
|
||||
...convo,
|
||||
kind: {...convo.kind, lockStatus: 'locked-permanently'},
|
||||
rev: log.rev,
|
||||
}
|
||||
: {...convo, rev: log.rev},
|
||||
)
|
||||
mutateConvoView(log.convoId, convo => {
|
||||
if (ChatBskyConvoDefs.isGroupConvo(convo.kind)) {
|
||||
return {
|
||||
...convo,
|
||||
kind: {...convo.kind, lockStatus: 'locked-permanently'},
|
||||
rev: log.rev,
|
||||
}
|
||||
}
|
||||
return {...convo, rev: log.rev}
|
||||
})
|
||||
} else if (
|
||||
ChatBskyConvoDefs.isLogCreateJoinLink(log) ||
|
||||
ChatBskyConvoDefs.isLogEditJoinLink(log) ||
|
||||
@@ -455,37 +475,68 @@ export function ListConvosProviderInner({
|
||||
) {
|
||||
// Join link data not included in the log event, trigger refetch to get it
|
||||
debouncedRefetch()
|
||||
} else if (ChatBskyConvoDefs.isLogEditGroup(log)) {
|
||||
// Updated group details (name etc.) aren't included in the log
|
||||
// event, so refetch to pick them up.
|
||||
debouncedRefetch()
|
||||
} else if (
|
||||
ChatBskyConvoDefs.isLogApproveJoinRequest(log) ||
|
||||
ChatBskyConvoDefs.isLogRejectJoinRequest(log)
|
||||
) {
|
||||
queryClient.setQueriesData(
|
||||
{queryKey: [RQKEY_ROOT]},
|
||||
(old?: ConvoListQueryData) =>
|
||||
updateGroupConvoJoinRequestCount(log, old, -1),
|
||||
// Route through mutateConvoView (not updateConvoInAllLists) so the
|
||||
// single-convo cache updates too, keeping the in-convo requests
|
||||
// banner in sync.
|
||||
mutateConvoView(log.convoId, convo =>
|
||||
applyJoinRequestCountDelta(convo, log.rev, -1),
|
||||
)
|
||||
} else if (ChatBskyConvoDefs.isLogIncomingJoinRequest(log)) {
|
||||
queryClient.setQueriesData(
|
||||
{queryKey: [RQKEY_ROOT]},
|
||||
(old?: ConvoListQueryData) =>
|
||||
updateGroupConvoJoinRequestCount(log, old, 1),
|
||||
// Route through mutateConvoView (not updateConvoInAllLists) so the
|
||||
// single-convo cache updates too, letting the in-convo requests
|
||||
// banner appear live.
|
||||
mutateConvoView(log.convoId, convo =>
|
||||
applyJoinRequestCountDelta(convo, log.rev, 1),
|
||||
)
|
||||
} else if (ChatBskyConvoDefs.isLogReadJoinRequests(log)) {
|
||||
// The owner marked join requests as read (possibly on another
|
||||
// device). Zero the unread count but keep the total, mirroring the
|
||||
// useMarkJoinRequestsRead mutation.
|
||||
mutateConvoView(log.convoId, convo => {
|
||||
if (!ChatBskyConvoDefs.isGroupConvo(convo.kind)) {
|
||||
return {...convo, rev: log.rev}
|
||||
}
|
||||
return {
|
||||
...convo,
|
||||
kind: {...convo.kind, unreadJoinRequestCount: 0},
|
||||
rev: log.rev,
|
||||
}
|
||||
})
|
||||
} else if (ChatBskyConvoDefs.isLogOutgoingJoinRequest(log)) {
|
||||
// Viewer isn't in the chat yet, no need to do anything
|
||||
} else if (ChatBskyConvoDefs.isLogAddReaction(log)) {
|
||||
queryClient.setQueriesData(
|
||||
{queryKey: [RQKEY_ROOT]},
|
||||
(old?: ConvoListQueryData) =>
|
||||
optimisticUpdate(log.convoId, old, convo => ({
|
||||
...convo,
|
||||
lastReaction: {
|
||||
$type: 'chat.bsky.convo.defs#messageAndReactionView',
|
||||
reaction: log.reaction,
|
||||
message: log.message,
|
||||
},
|
||||
rev: log.rev,
|
||||
})),
|
||||
// Viewer isn't in the chat yet, but the inbox surfaces outgoing
|
||||
// requests, so refetch to pick up the new entry.
|
||||
debouncedRefetch()
|
||||
} else if (ChatBskyConvoDefs.isLogWithdrawIncomingJoinRequest(log)) {
|
||||
// A requester rescinded their request to a group the viewer owns.
|
||||
// Mirror of isLogIncomingJoinRequest: decrement the counts.
|
||||
mutateConvoView(log.convoId, convo =>
|
||||
applyJoinRequestCountDelta(convo, log.rev, -1),
|
||||
)
|
||||
} else if (ChatBskyConvoDefs.isLogWithdrawOutgoingJoinRequest(log)) {
|
||||
// The viewer rescinded their own outgoing join request (possibly on
|
||||
// another device). Remove it from the requests inbox cache.
|
||||
queryClient.setQueriesData<ConvoRequestListQueryData>(
|
||||
{queryKey: [REQUESTS_RQKEY_ROOT]},
|
||||
old => optimisticDeleteJoinRequest(log.convoId, old),
|
||||
)
|
||||
} else if (ChatBskyConvoDefs.isLogAddReaction(log)) {
|
||||
updateConvoInAllLists(log.convoId, convo => ({
|
||||
...convo,
|
||||
lastReaction: {
|
||||
$type: 'chat.bsky.convo.defs#messageAndReactionView',
|
||||
reaction: log.reaction,
|
||||
message: log.message,
|
||||
},
|
||||
rev: log.rev,
|
||||
}))
|
||||
} else if (ChatBskyConvoDefs.isLogAddMember(log)) {
|
||||
const data = log.message.data
|
||||
if (
|
||||
@@ -739,27 +790,58 @@ function optimisticUpdate(
|
||||
}
|
||||
}
|
||||
|
||||
function updateGroupConvoJoinRequestCount(
|
||||
log: {convoId: string; rev: string},
|
||||
old: ConvoListQueryData | undefined,
|
||||
function applyJoinRequestCountDelta(
|
||||
convo: ChatBskyConvoDefs.ConvoView,
|
||||
rev: string,
|
||||
delta: 1 | -1,
|
||||
) {
|
||||
return optimisticUpdate(log.convoId, old, convo => {
|
||||
// Join requests are only meaningful for group convos.
|
||||
if (!ChatBskyConvoDefs.isGroupConvo(convo.kind)) {
|
||||
return {...convo, rev: log.rev}
|
||||
): ChatBskyConvoDefs.ConvoView {
|
||||
// Join requests are only meaningful for group convos.
|
||||
if (!ChatBskyConvoDefs.isGroupConvo(convo.kind)) {
|
||||
return {...convo, rev}
|
||||
}
|
||||
// Bump the total and unread counts together. Both are clamped at 0 and
|
||||
// collapse to undefined when empty, matching the server's shape.
|
||||
const bump = (current: number | undefined) => {
|
||||
const next = Math.max(0, (current ?? 0) + delta)
|
||||
return next === 0 ? undefined : next
|
||||
}
|
||||
return {
|
||||
...convo,
|
||||
kind: {
|
||||
...convo.kind,
|
||||
joinRequestCount: bump(convo.kind.joinRequestCount),
|
||||
unreadJoinRequestCount: bump(convo.kind.unreadJoinRequestCount),
|
||||
},
|
||||
rev,
|
||||
}
|
||||
}
|
||||
|
||||
function moveConvoToTopInRequests(
|
||||
updatedConvo: ChatBskyConvoDefs.ConvoView,
|
||||
old: ConvoRequestListQueryData | undefined,
|
||||
): ConvoRequestListQueryData | undefined {
|
||||
if (!old) return old
|
||||
const typedConvo: ConvoRequestListQueryData['pages'][number]['requests'][number] =
|
||||
{
|
||||
$type: 'chat.bsky.convo.defs#convoView',
|
||||
...updatedConvo,
|
||||
}
|
||||
const current = convo.kind.joinRequestCount ?? 0
|
||||
const next = Math.max(0, current + delta)
|
||||
return {
|
||||
...convo,
|
||||
kind: {
|
||||
...convo.kind,
|
||||
joinRequestCount: next === 0 ? undefined : next,
|
||||
},
|
||||
rev: log.rev,
|
||||
}
|
||||
})
|
||||
return {
|
||||
...old,
|
||||
pages: old.pages.map((page, i) => {
|
||||
const filtered = page.requests.filter(
|
||||
item =>
|
||||
!ChatBskyConvoDefs.isConvoView(item) || item.id !== updatedConvo.id,
|
||||
)
|
||||
if (i === 0) {
|
||||
return {
|
||||
...page,
|
||||
requests: [typedConvo, ...filtered],
|
||||
}
|
||||
}
|
||||
return {...page, requests: filtered}
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
function removeMemberFromConvoView(
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
import {type ChatBskyGroupRequestJoin} from '@atproto/api'
|
||||
import {useMutation} from '@tanstack/react-query'
|
||||
import {useMutation, useQueryClient} from '@tanstack/react-query'
|
||||
|
||||
import {DM_SERVICE_HEADERS} from '#/lib/constants'
|
||||
import {logger} from '#/logger'
|
||||
import {useAgent, useSession} from '#/state/session'
|
||||
import {RQKEY_ROOT as REQUESTS_RQKEY_ROOT} from './list-conversation-requests'
|
||||
|
||||
export function useRequestJoinGroupChat({
|
||||
onSuccess,
|
||||
@@ -13,6 +14,7 @@ export function useRequestJoinGroupChat({
|
||||
onError?: (error: Error) => void
|
||||
} = {}) {
|
||||
const agent = useAgent()
|
||||
const queryClient = useQueryClient()
|
||||
const {hasSession} = useSession()
|
||||
|
||||
return useMutation({
|
||||
@@ -27,6 +29,7 @@ export function useRequestJoinGroupChat({
|
||||
return res.data
|
||||
},
|
||||
onSuccess: data => {
|
||||
void queryClient.invalidateQueries({queryKey: [REQUESTS_RQKEY_ROOT]})
|
||||
onSuccess?.(data)
|
||||
},
|
||||
onError: error => {
|
||||
|
||||
@@ -4,6 +4,11 @@ import {useMutation, useQueryClient} from '@tanstack/react-query'
|
||||
import {DM_SERVICE_HEADERS} from '#/lib/constants'
|
||||
import {logger} from '#/logger'
|
||||
import {useAgent} from '#/state/session'
|
||||
import {
|
||||
type ConvoRequestListQueryData,
|
||||
markAllRead as markAllRequestsRead,
|
||||
RQKEY_ROOT as REQUESTS_RQKEY_ROOT,
|
||||
} from './list-conversation-requests'
|
||||
import {RQKEY as CONVO_LIST_KEY} from './list-conversations'
|
||||
|
||||
export function useUpdateAllRead(
|
||||
@@ -32,6 +37,9 @@ export function useUpdateAllRead(
|
||||
},
|
||||
onMutate: () => {
|
||||
let prevPages: ChatBskyConvoListConvos.OutputSchema[] = []
|
||||
let prevRequestsQueries: Array<
|
||||
[readonly unknown[], ConvoRequestListQueryData | undefined]
|
||||
> = []
|
||||
queryClient.setQueryData(
|
||||
CONVO_LIST_KEY(status),
|
||||
(old?: {
|
||||
@@ -75,11 +83,24 @@ export function useUpdateAllRead(
|
||||
}
|
||||
},
|
||||
)
|
||||
if (status === 'request') {
|
||||
prevRequestsQueries =
|
||||
queryClient.getQueriesData<ConvoRequestListQueryData>({
|
||||
queryKey: [REQUESTS_RQKEY_ROOT],
|
||||
})
|
||||
queryClient.setQueriesData<ConvoRequestListQueryData>(
|
||||
{queryKey: [REQUESTS_RQKEY_ROOT]},
|
||||
markAllRequestsRead,
|
||||
)
|
||||
}
|
||||
onMutate?.()
|
||||
return {prevPages}
|
||||
return {prevPages, prevRequestsQueries}
|
||||
},
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({queryKey: CONVO_LIST_KEY(status)})
|
||||
void queryClient.invalidateQueries({queryKey: CONVO_LIST_KEY(status)})
|
||||
if (status === 'request') {
|
||||
void queryClient.invalidateQueries({queryKey: [REQUESTS_RQKEY_ROOT]})
|
||||
}
|
||||
onSuccess?.()
|
||||
},
|
||||
onError: (error, _, context) => {
|
||||
@@ -97,8 +118,18 @@ export function useUpdateAllRead(
|
||||
}
|
||||
},
|
||||
)
|
||||
queryClient.invalidateQueries({queryKey: CONVO_LIST_KEY(status)})
|
||||
queryClient.invalidateQueries({queryKey: CONVO_LIST_KEY('all', 'unread')})
|
||||
if (status === 'request' && context?.prevRequestsQueries) {
|
||||
for (const [queryKey, prevData] of context.prevRequestsQueries) {
|
||||
queryClient.setQueryData(queryKey, prevData)
|
||||
}
|
||||
}
|
||||
void queryClient.invalidateQueries({queryKey: CONVO_LIST_KEY(status)})
|
||||
void queryClient.invalidateQueries({
|
||||
queryKey: CONVO_LIST_KEY('all', 'unread'),
|
||||
})
|
||||
if (status === 'request') {
|
||||
void queryClient.invalidateQueries({queryKey: [REQUESTS_RQKEY_ROOT]})
|
||||
}
|
||||
onError?.(error)
|
||||
},
|
||||
})
|
||||
|
||||
@@ -1,9 +1,14 @@
|
||||
import {type ChatBskyGroupWithdrawJoinRequest} from '@atproto/api'
|
||||
import {useMutation} from '@tanstack/react-query'
|
||||
import {useMutation, useQueryClient} from '@tanstack/react-query'
|
||||
|
||||
import {DM_SERVICE_HEADERS} from '#/lib/constants'
|
||||
import {logger} from '#/logger'
|
||||
import {useAgent, useSession} from '#/state/session'
|
||||
import {
|
||||
type ConvoRequestListQueryData,
|
||||
optimisticDeleteJoinRequest,
|
||||
RQKEY_ROOT as REQUESTS_RQKEY_ROOT,
|
||||
} from './list-conversation-requests'
|
||||
|
||||
export function useWithdrawJoinGroupChatRequest({
|
||||
onSuccess,
|
||||
@@ -13,6 +18,7 @@ export function useWithdrawJoinGroupChatRequest({
|
||||
onError?: (error: Error) => void
|
||||
} = {}) {
|
||||
const agent = useAgent()
|
||||
const queryClient = useQueryClient()
|
||||
const {hasSession} = useSession()
|
||||
|
||||
return useMutation({
|
||||
@@ -27,7 +33,11 @@ export function useWithdrawJoinGroupChatRequest({
|
||||
)
|
||||
return res.data
|
||||
},
|
||||
onSuccess: data => {
|
||||
onSuccess: (data, {convoId}) => {
|
||||
queryClient.setQueriesData<ConvoRequestListQueryData>(
|
||||
{queryKey: [REQUESTS_RQKEY_ROOT]},
|
||||
old => optimisticDeleteJoinRequest(convoId, old),
|
||||
)
|
||||
onSuccess?.(data)
|
||||
},
|
||||
onError: error => {
|
||||
|
||||
Reference in New Issue
Block a user