Fix convo header loading state (#7603)
* get initial convo state from cache * undo useConvoQuery changes * fix shadowing situation with new hook
This commit is contained in:
Vendored
+38
@@ -63,6 +63,44 @@ export function useProfileShadow<
|
||||
}, [profile, shadow])
|
||||
}
|
||||
|
||||
/**
|
||||
* Same as useProfileShadow, but allows for the profile to be undefined.
|
||||
* This is useful for when the profile is not guaranteed to be loaded yet.
|
||||
*/
|
||||
export function useMaybeProfileShadow<
|
||||
TProfileView extends AppBskyActorDefs.ProfileView,
|
||||
>(profile?: TProfileView): Shadow<TProfileView> | undefined {
|
||||
const [shadow, setShadow] = useState(() =>
|
||||
profile ? shadows.get(profile) : undefined,
|
||||
)
|
||||
const [prevPost, setPrevPost] = useState(profile)
|
||||
if (profile !== prevPost) {
|
||||
setPrevPost(profile)
|
||||
setShadow(profile ? shadows.get(profile) : undefined)
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
if (!profile) return
|
||||
function onUpdate() {
|
||||
if (!profile) return
|
||||
setShadow(shadows.get(profile))
|
||||
}
|
||||
emitter.addListener(profile.did, onUpdate)
|
||||
return () => {
|
||||
emitter.removeListener(profile.did, onUpdate)
|
||||
}
|
||||
}, [profile])
|
||||
|
||||
return useMemo(() => {
|
||||
if (!profile) return undefined
|
||||
if (shadow) {
|
||||
return mergeShadow(profile, shadow)
|
||||
} else {
|
||||
return castAsShadow(profile)
|
||||
}
|
||||
}, [profile, shadow])
|
||||
}
|
||||
|
||||
export function updateProfileShadow(
|
||||
queryClient: QueryClient,
|
||||
did: string,
|
||||
|
||||
@@ -81,7 +81,7 @@ export class Convo {
|
||||
convoId: string
|
||||
convo: ChatBskyConvoDefs.ConvoView | undefined
|
||||
sender: AppBskyActorDefs.ProfileViewBasic | undefined
|
||||
recipients: AppBskyActorDefs.ProfileViewBasic[] | undefined = undefined
|
||||
recipients: AppBskyActorDefs.ProfileViewBasic[] | undefined
|
||||
snapshot: ConvoState | undefined
|
||||
|
||||
constructor(params: ConvoParams) {
|
||||
@@ -91,6 +91,10 @@ export class Convo {
|
||||
this.events = params.events
|
||||
this.senderUserDid = params.agent.session?.did!
|
||||
|
||||
if (params.placeholderData) {
|
||||
this.setupPlaceholderData(params.placeholderData)
|
||||
}
|
||||
|
||||
this.subscribe = this.subscribe.bind(this)
|
||||
this.getSnapshot = this.getSnapshot.bind(this)
|
||||
this.sendMessage = this.sendMessage.bind(this)
|
||||
@@ -131,10 +135,10 @@ export class Convo {
|
||||
return {
|
||||
status: ConvoStatus.Initializing,
|
||||
items: [],
|
||||
convo: undefined,
|
||||
convo: this.convo,
|
||||
error: undefined,
|
||||
sender: undefined,
|
||||
recipients: undefined,
|
||||
sender: this.sender,
|
||||
recipients: this.recipients,
|
||||
isFetchingHistory: this.isFetchingHistory,
|
||||
deleteMessage: undefined,
|
||||
sendMessage: undefined,
|
||||
@@ -176,10 +180,10 @@ export class Convo {
|
||||
return {
|
||||
status: ConvoStatus.Uninitialized,
|
||||
items: [],
|
||||
convo: undefined,
|
||||
convo: this.convo,
|
||||
error: undefined,
|
||||
sender: undefined,
|
||||
recipients: undefined,
|
||||
sender: this.sender,
|
||||
recipients: this.recipients,
|
||||
isFetchingHistory: false,
|
||||
deleteMessage: undefined,
|
||||
sendMessage: undefined,
|
||||
@@ -424,6 +428,20 @@ export class Convo {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialises the convo with placeholder data, if provided. We still refetch it before rendering the convo,
|
||||
* but this allows us to render the convo header immediately.
|
||||
*/
|
||||
private setupPlaceholderData(
|
||||
data: NonNullable<ConvoParams['placeholderData']>,
|
||||
) {
|
||||
this.convo = data.convo
|
||||
this.sender = data.convo.members.find(m => m.did === this.senderUserDid)
|
||||
this.recipients = data.convo.members.filter(
|
||||
m => m.did !== this.senderUserDid,
|
||||
)
|
||||
}
|
||||
|
||||
private async setup() {
|
||||
try {
|
||||
const {convo, sender, recipients} = await this.fetchConvo()
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import React, {useContext, useState, useSyncExternalStore} from 'react'
|
||||
import {ChatBskyConvoDefs} from '@atproto/api'
|
||||
import {useFocusEffect} from '@react-navigation/native'
|
||||
import {useQueryClient} from '@tanstack/react-query'
|
||||
|
||||
@@ -14,7 +15,10 @@ import {
|
||||
} from '#/state/messages/convo/types'
|
||||
import {isConvoActive} from '#/state/messages/convo/util'
|
||||
import {useMessagesEventBus} from '#/state/messages/events'
|
||||
import {useMarkAsReadMutation} from '#/state/queries/messages/conversation'
|
||||
import {
|
||||
RQKEY as getConvoKey,
|
||||
useMarkAsReadMutation,
|
||||
} from '#/state/queries/messages/conversation'
|
||||
import {RQKEY as ListConvosQueryKey} from '#/state/queries/messages/list-conversations'
|
||||
import {RQKEY as createProfileQueryKey} from '#/state/queries/profile'
|
||||
import {useAgent} from '#/state/session'
|
||||
@@ -60,14 +64,17 @@ export function ConvoProvider({
|
||||
const queryClient = useQueryClient()
|
||||
const agent = useAgent()
|
||||
const events = useMessagesEventBus()
|
||||
const [convo] = useState(
|
||||
() =>
|
||||
new Convo({
|
||||
convoId,
|
||||
agent,
|
||||
events,
|
||||
}),
|
||||
)
|
||||
const [convo] = useState(() => {
|
||||
const placeholder = queryClient.getQueryData<ChatBskyConvoDefs.ConvoView>(
|
||||
getConvoKey(convoId),
|
||||
)
|
||||
return new Convo({
|
||||
convoId,
|
||||
agent,
|
||||
events,
|
||||
placeholderData: placeholder ? {convo: placeholder} : undefined,
|
||||
})
|
||||
})
|
||||
const service = useSyncExternalStore(convo.subscribe, convo.getSnapshot)
|
||||
const {mutate: markAsRead} = useMarkAsReadMutation()
|
||||
|
||||
|
||||
@@ -11,6 +11,9 @@ export type ConvoParams = {
|
||||
convoId: string
|
||||
agent: BskyAgent
|
||||
events: MessagesEventBus
|
||||
placeholderData?: {
|
||||
convo: ChatBskyConvoDefs.ConvoView
|
||||
}
|
||||
}
|
||||
|
||||
export enum ConvoStatus {
|
||||
@@ -142,10 +145,10 @@ type FetchMessageHistory = () => Promise<void>
|
||||
export type ConvoStateUninitialized = {
|
||||
status: ConvoStatus.Uninitialized
|
||||
items: []
|
||||
convo: undefined
|
||||
convo: ChatBskyConvoDefs.ConvoView | undefined
|
||||
error: undefined
|
||||
sender: undefined
|
||||
recipients: undefined
|
||||
sender: AppBskyActorDefs.ProfileViewBasic | undefined
|
||||
recipients: AppBskyActorDefs.ProfileViewBasic[] | undefined
|
||||
isFetchingHistory: false
|
||||
deleteMessage: undefined
|
||||
sendMessage: undefined
|
||||
@@ -154,10 +157,10 @@ export type ConvoStateUninitialized = {
|
||||
export type ConvoStateInitializing = {
|
||||
status: ConvoStatus.Initializing
|
||||
items: []
|
||||
convo: undefined
|
||||
convo: ChatBskyConvoDefs.ConvoView | undefined
|
||||
error: undefined
|
||||
sender: undefined
|
||||
recipients: undefined
|
||||
sender: AppBskyActorDefs.ProfileViewBasic | undefined
|
||||
recipients: AppBskyActorDefs.ProfileViewBasic[] | undefined
|
||||
isFetchingHistory: boolean
|
||||
deleteMessage: undefined
|
||||
sendMessage: undefined
|
||||
|
||||
@@ -1,5 +1,10 @@
|
||||
import {ChatBskyConvoDefs} from '@atproto/api'
|
||||
import {useMutation, useQuery, useQueryClient} from '@tanstack/react-query'
|
||||
import {
|
||||
QueryClient,
|
||||
useMutation,
|
||||
useQuery,
|
||||
useQueryClient,
|
||||
} from '@tanstack/react-query'
|
||||
|
||||
import {STALE} from '#/state/queries'
|
||||
import {DM_SERVICE_HEADERS} from '#/state/queries/messages/const'
|
||||
@@ -20,7 +25,7 @@ export function useConvoQuery(convo: ChatBskyConvoDefs.ConvoView) {
|
||||
return useQuery({
|
||||
queryKey: RQKEY(convo.id),
|
||||
queryFn: async () => {
|
||||
const {data} = await agent.api.chat.bsky.convo.getConvo(
|
||||
const {data} = await agent.chat.bsky.convo.getConvo(
|
||||
{convoId: convo.id},
|
||||
{headers: DM_SERVICE_HEADERS},
|
||||
)
|
||||
@@ -31,6 +36,13 @@ export function useConvoQuery(convo: ChatBskyConvoDefs.ConvoView) {
|
||||
})
|
||||
}
|
||||
|
||||
export function precacheConvoQuery(
|
||||
queryClient: QueryClient,
|
||||
convo: ChatBskyConvoDefs.ConvoView,
|
||||
) {
|
||||
queryClient.setQueryData(RQKEY(convo.id), convo)
|
||||
}
|
||||
|
||||
export function useMarkAsReadMutation() {
|
||||
const optimisticUpdate = useOnMarkAsRead()
|
||||
const queryClient = useQueryClient()
|
||||
|
||||
Reference in New Issue
Block a user