Optimistically update chat invite button status (#10870)

This commit is contained in:
DS Boyce
2026-06-11 09:48:23 -07:00
committed by GitHub
parent b0eaecb01b
commit 91053e3f70
2 changed files with 63 additions and 1 deletions
+14 -1
View File
@@ -20,6 +20,7 @@ import {logger} from '#/logger'
import {useModerationOpts} from '#/state/preferences/moderation-opts'
import {
invalidateJoinLinkPreviewsForCode,
setJoinLinkPreviewRequestedForCode,
useJoinLinkPreviewsQuery,
} from '#/state/queries/join-links'
import {useRequestJoinGroupChat} from '#/state/queries/messages/request-join-group-chat'
@@ -104,9 +105,14 @@ function GroupChatJoinDialogContent({code}: {code?: string}) {
const {mutate: joinGroupChat, isPending: isJoinPending} =
useRequestJoinGroupChat({
onSuccess: data => {
if (code) void invalidateJoinLinkPreviewsForCode(queryClient, code)
switch (data.status) {
case 'pending':
// Optimistically mark the link as requested so any invite cards
// backed by the preview cache (e.g. the DM embed) flip to
// "Requested" right away, rather than waiting on a server refetch
// that can lag behind the write.
if (code)
setJoinLinkPreviewRequestedForCode(queryClient, code, true)
ax.metric('groupchat:inviteLink:redeem', {})
control.close(() => {
Toast.show(
@@ -116,6 +122,10 @@ function GroupChatJoinDialogContent({code}: {code?: string}) {
break
case 'joined': {
if (data.convo && data.convo.id) {
// Refetch so invite cards pick up the resolved convo and switch
// their action to "Open chat".
if (code)
void invalidateJoinLinkPreviewsForCode(queryClient, code)
ax.metric('groupchat:inviteLink:redeem', {})
control.close(() => {
Toast.show(l`Successfully joined the group chat!`)
@@ -172,6 +182,9 @@ function GroupChatJoinDialogContent({code}: {code?: string}) {
const {mutate: withdrawRequest, isPending: isWithdrawPending} =
useWithdrawJoinGroupChatRequest({
onSuccess: () => {
// Optimistically clear the requested state so invite cards backed by
// the preview cache flip back to "Request to join" right away.
if (code) setJoinLinkPreviewRequestedForCode(queryClient, code, false)
control.close(() => {
Toast.show(l`Join request rescinded.`)
})
+49
View File
@@ -76,6 +76,55 @@ export function invalidateJoinLinkPreviewsForCode(
})
}
/**
* Optimistically set whether the viewer has requested to join the link with the
* given code, across any cached join link preview queries. Used right after a
* successful join request (requested = true) or withdrawal (requested = false)
* so the UI ("Requested" vs "Request to join") updates immediately, without
* waiting on a server refetch that can lag behind the write.
*/
export function setJoinLinkPreviewRequestedForCode(
queryClient: QueryClient,
code: string,
requested: boolean,
) {
queryClient.setQueriesData<ChatBskyGroupGetJoinLinkPreviews.OutputSchema>(
{
predicate: query => {
const [root, args] = query.queryKey as Partial<
StructuredQueryKey<{codes?: string[]}>
>
return (
root === joinLinkPreviewQueryKeyRoot &&
Array.isArray(args?.codes) &&
args.codes.includes(code)
)
},
},
old => {
if (!old) return old
return {
...old,
joinLinkPreviews: old.joinLinkPreviews.map(preview => {
if (
ChatBskyGroupDefs.isJoinLinkPreviewView(preview) &&
preview.code === code
) {
return {
...preview,
viewer: {
...preview.viewer,
requestedAt: requested ? new Date().toISOString() : undefined,
},
}
}
return preview
}),
}
},
)
}
/**
* Invalidate any join link preview queries that resolved to the given convo.
* The code isn't always known to the viewer (e.g. when they're a regular