From 528c91d8af52383cd28c3289a76e2814080c1dd2 Mon Sep 17 00:00:00 2001 From: Samuel Newman Date: Sat, 18 Apr 2026 17:27:25 +0300 Subject: [PATCH] (wip) restructure convo data dependencies - checkpoint --- src/state/messages/convo/agent.ts | 54 +++------------ src/state/messages/convo/index.tsx | 23 +++++-- src/state/messages/convo/types.ts | 68 ++++++------------- src/state/queries/messages/conversation.ts | 3 +- .../queries/messages/list-convo-members.ts | 43 ++++++++++++ 5 files changed, 90 insertions(+), 101 deletions(-) create mode 100644 src/state/queries/messages/list-convo-members.ts diff --git a/src/state/messages/convo/agent.ts b/src/state/messages/convo/agent.ts index f89155bec4..b32a34f70d 100644 --- a/src/state/messages/convo/agent.ts +++ b/src/state/messages/convo/agent.ts @@ -86,9 +86,10 @@ export class Convo { private emitter = new EventEmitter<{event: [ConvoEvent]}>() convoId: string - convo: ChatBskyConvoDefs.ConvoView | undefined - sender: ChatBskyActorDefs.ProfileViewBasic | undefined - recipients: ChatBskyActorDefs.ProfileViewBasic[] | undefined + data: { + convoView: ChatBskyConvoDefs.ConvoView | undefined + memberList: ChatBskyActorDefs.ProfileViewBasic[] + } snapshot: ConvoState | undefined constructor(params: ConvoParams) { @@ -97,10 +98,7 @@ export class Convo { this.agent = params.agent this.events = params.events this.senderUserDid = params.agent.assertDid - - if (params.placeholderData) { - this.setupPlaceholderData(params.placeholderData) - } + this.data = params.data this.subscribe = this.subscribe.bind(this) this.getSnapshot = this.getSnapshot.bind(this) @@ -572,42 +570,6 @@ export class Convo { } } - private pendingFetchConvo: - | Promise<{ - convo: ChatBskyConvoDefs.ConvoView - sender: ChatBskyActorDefs.ProfileViewBasic | undefined - recipients: ChatBskyActorDefs.ProfileViewBasic[] - }> - | undefined - async fetchConvo() { - if (this.pendingFetchConvo) return this.pendingFetchConvo - - this.pendingFetchConvo = (async () => { - try { - const response = await networkRetry(2, () => { - return this.agent.api.chat.bsky.convo.getConvo( - { - convoId: this.convoId, - }, - {headers: DM_SERVICE_HEADERS}, - ) - }) - - const convo = response.data.convo - - return { - convo, - sender: convo.members.find(m => m.did === this.senderUserDid), - recipients: convo.members.filter(m => m.did !== this.senderUserDid), - } - } finally { - this.pendingFetchConvo = undefined - } - })() - - return this.pendingFetchConvo - } - async refreshConvo() { try { const {convo, sender, recipients} = await this.fetchConvo() @@ -930,7 +892,7 @@ export class Convo { const {id, message} = pendingMessage - const response = await this.agent.api.chat.bsky.convo.sendMessage( + const response = await this.agent.chat.bsky.convo.sendMessage( { convoId: this.convoId, message, @@ -1025,7 +987,7 @@ export class Convo { ) try { - const {data} = await this.agent.api.chat.bsky.convo.sendMessageBatch( + const {data} = await this.agent.chat.bsky.convo.sendMessageBatch( { items: messageArray.map(({message}) => ({ convoId: this.convoId, @@ -1067,7 +1029,7 @@ export class Convo { try { await networkRetry(2, () => { - return this.agent.api.chat.bsky.convo.deleteMessageForSelf( + return this.agent.chat.bsky.convo.deleteMessageForSelf( { convoId: this.convoId, messageId, diff --git a/src/state/messages/convo/index.tsx b/src/state/messages/convo/index.tsx index 5461301fb3..21f3b66f79 100644 --- a/src/state/messages/convo/index.tsx +++ b/src/state/messages/convo/index.tsx @@ -24,6 +24,7 @@ import {isConvoActive} from '#/state/messages/convo/util' import {useMessagesEventBus} from '#/state/messages/events' import { RQKEY as getConvoKey, + useConvoQuery, useMarkAsReadMutation, } from '#/state/queries/messages/conversation' import {RQKEY_ROOT as ListConvosQueryKeyRoot} from '#/state/queries/messages/list-conversations' @@ -72,20 +73,30 @@ export function ConvoProvider({ const queryClient = useQueryClient() const agent = useAgent() const events = useMessagesEventBus() + const {data: convoView} = useConvoQuery({convoId}) + // const {data: convoMembers} = useListConvoMembersQuery({convoId}) + + // eslint-disable-next-line react/hook-use-state const [convo] = useState(() => { - const placeholder = queryClient.getQueryData( - getConvoKey(convoId), - ) return new Convo({ convoId, agent, events, - placeholderData: placeholder ? {convo: placeholder} : undefined, + data: { + convoView, + // convoMembers, + }, }) }) const service = useSyncExternalStore(convo.subscribe, convo.getSnapshot) const {mutate: markAsRead} = useMarkAsReadMutation() + useEffect(() => { + if (convoView) { + service.updateData({convoView}) + } + }, [service, convoView]) + const appState = useAppState() const isActive = appState === 'active' useFocusEffect( @@ -107,11 +118,11 @@ export function ConvoProvider({ switch (event.type) { case 'invalidate-block-state': { for (const did of event.accountDids) { - queryClient.invalidateQueries({ + void queryClient.invalidateQueries({ queryKey: createProfileQueryKey(did), }) } - queryClient.invalidateQueries({ + void queryClient.invalidateQueries({ queryKey: [ListConvosQueryKeyRoot], }) } diff --git a/src/state/messages/convo/types.ts b/src/state/messages/convo/types.ts index f27610053a..f59fba61a3 100644 --- a/src/state/messages/convo/types.ts +++ b/src/state/messages/convo/types.ts @@ -6,13 +6,15 @@ import { } from '@atproto/api' import {type MessagesEventBus} from '#/state/messages/events/agent' +import {type ConvoWithDetails} from '#/components/dms/util' export type ConvoParams = { convoId: string agent: BskyAgent events: MessagesEventBus - placeholderData?: { - convo: ChatBskyConvoDefs.ConvoView + data: { + convoView?: ChatBskyConvoDefs.ConvoView + memberList?: ChatBskyActorDefs.ProfileViewBasic[] } } @@ -136,6 +138,7 @@ export type ConvoItem = retry?: () => void } +type UpdateConvoData = (data: ConvoParams['data']) => void type DeleteMessage = (messageId: string) => Promise type SendMessage = ( message: ChatBskyConvoSendMessage.InputSchema['message'], @@ -144,17 +147,13 @@ type FetchMessageHistory = () => Promise type MarkConvoAccepted = () => void type AddReaction = (messageId: string, reaction: string) => Promise type RemoveReaction = (messageId: string, reaction: string) => Promise -type IsGroup = () => boolean | undefined -type GetGroupInfo = () => ChatBskyConvoDefs.GroupConvo | undefined -type GetPrimaryMember = () => ChatBskyActorDefs.ProfileViewBasic | undefined export type ConvoStateUninitialized = { status: ConvoStatus.Uninitialized items: [] - convo: ChatBskyConvoDefs.ConvoView | undefined + convo: ConvoWithDetails | undefined + updateData: UpdateConvoData error: undefined - sender: ChatBskyActorDefs.ProfileViewBasic | undefined - recipients: ChatBskyActorDefs.ProfileViewBasic[] | undefined isFetchingHistory: false hasAllHistory: boolean deleteMessage: undefined @@ -163,17 +162,13 @@ export type ConvoStateUninitialized = { markConvoAccepted: undefined addReaction: undefined removeReaction: undefined - isGroup: IsGroup - getGroupInfo: GetGroupInfo - getPrimaryMember: GetPrimaryMember } export type ConvoStateInitializing = { status: ConvoStatus.Initializing items: [] - convo: ChatBskyConvoDefs.ConvoView | undefined + convo: ConvoWithDetails | undefined + updateData: UpdateConvoData error: undefined - sender: ChatBskyActorDefs.ProfileViewBasic | undefined - recipients: ChatBskyActorDefs.ProfileViewBasic[] | undefined isFetchingHistory: boolean hasAllHistory: boolean deleteMessage: undefined @@ -182,17 +177,13 @@ export type ConvoStateInitializing = { markConvoAccepted: undefined addReaction: undefined removeReaction: undefined - isGroup: IsGroup - getGroupInfo: GetGroupInfo - getPrimaryMember: GetPrimaryMember } export type ConvoStateReady = { status: ConvoStatus.Ready items: ConvoItem[] - convo: ChatBskyConvoDefs.ConvoView + convo: ConvoWithDetails + updateData: UpdateConvoData error: undefined - sender: ChatBskyActorDefs.ProfileViewBasic - recipients: ChatBskyActorDefs.ProfileViewBasic[] isFetchingHistory: boolean hasAllHistory: boolean deleteMessage: DeleteMessage @@ -201,17 +192,13 @@ export type ConvoStateReady = { markConvoAccepted: MarkConvoAccepted addReaction: AddReaction removeReaction: RemoveReaction - isGroup: IsGroup - getGroupInfo: GetGroupInfo - getPrimaryMember: GetPrimaryMember } export type ConvoStateBackgrounded = { status: ConvoStatus.Backgrounded items: ConvoItem[] - convo: ChatBskyConvoDefs.ConvoView + convo: ConvoWithDetails + updateData: UpdateConvoData error: undefined - sender: ChatBskyActorDefs.ProfileViewBasic - recipients: ChatBskyActorDefs.ProfileViewBasic[] isFetchingHistory: boolean hasAllHistory: boolean deleteMessage: DeleteMessage @@ -220,17 +207,13 @@ export type ConvoStateBackgrounded = { markConvoAccepted: MarkConvoAccepted addReaction: AddReaction removeReaction: RemoveReaction - isGroup: IsGroup - getGroupInfo: GetGroupInfo - getPrimaryMember: GetPrimaryMember } export type ConvoStateSuspended = { status: ConvoStatus.Suspended items: ConvoItem[] - convo: ChatBskyConvoDefs.ConvoView + convo: ConvoWithDetails + updateData: UpdateConvoData error: undefined - sender: ChatBskyActorDefs.ProfileViewBasic - recipients: ChatBskyActorDefs.ProfileViewBasic[] isFetchingHistory: boolean hasAllHistory: boolean deleteMessage: DeleteMessage @@ -239,17 +222,13 @@ export type ConvoStateSuspended = { markConvoAccepted: MarkConvoAccepted addReaction: AddReaction removeReaction: RemoveReaction - isGroup: IsGroup - getGroupInfo: GetGroupInfo - getPrimaryMember: GetPrimaryMember } export type ConvoStateError = { status: ConvoStatus.Error - items: [] - convo: undefined + items: ConvoItem[] + convo: ConvoWithDetails | undefined + updateData: UpdateConvoData error: ConvoError - sender: undefined - recipients: undefined isFetchingHistory: false hasAllHistory: false deleteMessage: undefined @@ -258,17 +237,13 @@ export type ConvoStateError = { markConvoAccepted: undefined addReaction: undefined removeReaction: undefined - isGroup: undefined - getGroupInfo: undefined - getPrimaryMember: undefined } export type ConvoStateDisabled = { status: ConvoStatus.Disabled items: ConvoItem[] - convo: ChatBskyConvoDefs.ConvoView + convo: ConvoWithDetails + updateData: UpdateConvoData error: undefined - sender: ChatBskyActorDefs.ProfileViewBasic - recipients: ChatBskyActorDefs.ProfileViewBasic[] isFetchingHistory: boolean hasAllHistory: boolean deleteMessage: DeleteMessage @@ -277,9 +252,6 @@ export type ConvoStateDisabled = { markConvoAccepted: MarkConvoAccepted addReaction: AddReaction removeReaction: RemoveReaction - isGroup: IsGroup - getGroupInfo: GetGroupInfo - getPrimaryMember: GetPrimaryMember } export type ConvoState = | ConvoStateUninitialized diff --git a/src/state/queries/messages/conversation.ts b/src/state/queries/messages/conversation.ts index b8f26cc88c..f6d39b72d0 100644 --- a/src/state/queries/messages/conversation.ts +++ b/src/state/queries/messages/conversation.ts @@ -31,7 +31,8 @@ export function useConvoQuery({convoId}: {convoId: string}) { ) return data.convo }, - staleTime: STALE.INFINITY, + staleTime: STALE.MINUTES.THIRTY, + retry: 2, }) } diff --git a/src/state/queries/messages/list-convo-members.ts b/src/state/queries/messages/list-convo-members.ts new file mode 100644 index 0000000000..ccfefeb87f --- /dev/null +++ b/src/state/queries/messages/list-convo-members.ts @@ -0,0 +1,43 @@ +// FOR WHEN WE ADD THE ENDPOINT TO LIST MEMBERS + +// import {type ChatBskyActorDefs} from '@atproto/api' +// import {useQuery} from '@tanstack/react-query' + +// import {DM_SERVICE_HEADERS} from '#/lib/constants' +// import {STALE} from '#/state/queries' +// import {useAgent} from '#/state/session' +// import {RQKEY as getConvoKey} from './conversation' + +// const LIMIT = 50 + +// const RQKEY_SEGMENT = 'members' +// // invalidating a convo will also invalidate its member query +// export const listConvoMembersKey = (convoId: string) => [ +// ...getConvoKey(convoId), +// RQKEY_SEGMENT, +// ] + +// export function useListConvoMembersQuery({convoId}: {convoId: string}) { +// const agent = useAgent() + +// return useQuery({ +// queryKey: listConvoMembersKey(convoId), +// queryFn: async () => { +// const members: ChatBskyActorDefs.ProfileViewBasic[] = [] +// let cursor +// do { +// const {data} = await agent.chat.bsky.group.listMembers( +// {convoId, cursor, limit: LIMIT}, +// {headers: DM_SERVICE_HEADERS}, +// ) +// for (const member of data.members) { +// members.push(member) +// } +// cursor = data.cursor +// } while (cursor) +// return members +// }, +// staleTime: STALE.MINUTES.THIRTY, +// retry: 2, +// }) +// }