(wip) restructure convo data dependencies - checkpoint

This commit is contained in:
Samuel Newman
2026-04-18 17:27:25 +03:00
parent bc3672ceeb
commit 528c91d8af
5 changed files with 90 additions and 101 deletions
+8 -46
View File
@@ -86,9 +86,10 @@ export class Convo {
private emitter = new EventEmitter<{event: [ConvoEvent]}>() private emitter = new EventEmitter<{event: [ConvoEvent]}>()
convoId: string convoId: string
convo: ChatBskyConvoDefs.ConvoView | undefined data: {
sender: ChatBskyActorDefs.ProfileViewBasic | undefined convoView: ChatBskyConvoDefs.ConvoView | undefined
recipients: ChatBskyActorDefs.ProfileViewBasic[] | undefined memberList: ChatBskyActorDefs.ProfileViewBasic[]
}
snapshot: ConvoState | undefined snapshot: ConvoState | undefined
constructor(params: ConvoParams) { constructor(params: ConvoParams) {
@@ -97,10 +98,7 @@ export class Convo {
this.agent = params.agent this.agent = params.agent
this.events = params.events this.events = params.events
this.senderUserDid = params.agent.assertDid this.senderUserDid = params.agent.assertDid
this.data = params.data
if (params.placeholderData) {
this.setupPlaceholderData(params.placeholderData)
}
this.subscribe = this.subscribe.bind(this) this.subscribe = this.subscribe.bind(this)
this.getSnapshot = this.getSnapshot.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() { async refreshConvo() {
try { try {
const {convo, sender, recipients} = await this.fetchConvo() const {convo, sender, recipients} = await this.fetchConvo()
@@ -930,7 +892,7 @@ export class Convo {
const {id, message} = pendingMessage 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, convoId: this.convoId,
message, message,
@@ -1025,7 +987,7 @@ export class Convo {
) )
try { try {
const {data} = await this.agent.api.chat.bsky.convo.sendMessageBatch( const {data} = await this.agent.chat.bsky.convo.sendMessageBatch(
{ {
items: messageArray.map(({message}) => ({ items: messageArray.map(({message}) => ({
convoId: this.convoId, convoId: this.convoId,
@@ -1067,7 +1029,7 @@ export class Convo {
try { try {
await networkRetry(2, () => { await networkRetry(2, () => {
return this.agent.api.chat.bsky.convo.deleteMessageForSelf( return this.agent.chat.bsky.convo.deleteMessageForSelf(
{ {
convoId: this.convoId, convoId: this.convoId,
messageId, messageId,
+17 -6
View File
@@ -24,6 +24,7 @@ import {isConvoActive} from '#/state/messages/convo/util'
import {useMessagesEventBus} from '#/state/messages/events' import {useMessagesEventBus} from '#/state/messages/events'
import { import {
RQKEY as getConvoKey, RQKEY as getConvoKey,
useConvoQuery,
useMarkAsReadMutation, useMarkAsReadMutation,
} from '#/state/queries/messages/conversation' } from '#/state/queries/messages/conversation'
import {RQKEY_ROOT as ListConvosQueryKeyRoot} from '#/state/queries/messages/list-conversations' import {RQKEY_ROOT as ListConvosQueryKeyRoot} from '#/state/queries/messages/list-conversations'
@@ -72,20 +73,30 @@ export function ConvoProvider({
const queryClient = useQueryClient() const queryClient = useQueryClient()
const agent = useAgent() const agent = useAgent()
const events = useMessagesEventBus() 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 [convo] = useState(() => {
const placeholder = queryClient.getQueryData<ChatBskyConvoDefs.ConvoView>(
getConvoKey(convoId),
)
return new Convo({ return new Convo({
convoId, convoId,
agent, agent,
events, events,
placeholderData: placeholder ? {convo: placeholder} : undefined, data: {
convoView,
// convoMembers,
},
}) })
}) })
const service = useSyncExternalStore(convo.subscribe, convo.getSnapshot) const service = useSyncExternalStore(convo.subscribe, convo.getSnapshot)
const {mutate: markAsRead} = useMarkAsReadMutation() const {mutate: markAsRead} = useMarkAsReadMutation()
useEffect(() => {
if (convoView) {
service.updateData({convoView})
}
}, [service, convoView])
const appState = useAppState() const appState = useAppState()
const isActive = appState === 'active' const isActive = appState === 'active'
useFocusEffect( useFocusEffect(
@@ -107,11 +118,11 @@ export function ConvoProvider({
switch (event.type) { switch (event.type) {
case 'invalidate-block-state': { case 'invalidate-block-state': {
for (const did of event.accountDids) { for (const did of event.accountDids) {
queryClient.invalidateQueries({ void queryClient.invalidateQueries({
queryKey: createProfileQueryKey(did), queryKey: createProfileQueryKey(did),
}) })
} }
queryClient.invalidateQueries({ void queryClient.invalidateQueries({
queryKey: [ListConvosQueryKeyRoot], queryKey: [ListConvosQueryKeyRoot],
}) })
} }
+20 -48
View File
@@ -6,13 +6,15 @@ import {
} from '@atproto/api' } from '@atproto/api'
import {type MessagesEventBus} from '#/state/messages/events/agent' import {type MessagesEventBus} from '#/state/messages/events/agent'
import {type ConvoWithDetails} from '#/components/dms/util'
export type ConvoParams = { export type ConvoParams = {
convoId: string convoId: string
agent: BskyAgent agent: BskyAgent
events: MessagesEventBus events: MessagesEventBus
placeholderData?: { data: {
convo: ChatBskyConvoDefs.ConvoView convoView?: ChatBskyConvoDefs.ConvoView
memberList?: ChatBskyActorDefs.ProfileViewBasic[]
} }
} }
@@ -136,6 +138,7 @@ export type ConvoItem =
retry?: () => void retry?: () => void
} }
type UpdateConvoData = (data: ConvoParams['data']) => void
type DeleteMessage = (messageId: string) => Promise<void> type DeleteMessage = (messageId: string) => Promise<void>
type SendMessage = ( type SendMessage = (
message: ChatBskyConvoSendMessage.InputSchema['message'], message: ChatBskyConvoSendMessage.InputSchema['message'],
@@ -144,17 +147,13 @@ type FetchMessageHistory = () => Promise<void>
type MarkConvoAccepted = () => void type MarkConvoAccepted = () => void
type AddReaction = (messageId: string, reaction: string) => Promise<void> type AddReaction = (messageId: string, reaction: string) => Promise<void>
type RemoveReaction = (messageId: string, reaction: string) => Promise<void> type RemoveReaction = (messageId: string, reaction: string) => Promise<void>
type IsGroup = () => boolean | undefined
type GetGroupInfo = () => ChatBskyConvoDefs.GroupConvo | undefined
type GetPrimaryMember = () => ChatBskyActorDefs.ProfileViewBasic | undefined
export type ConvoStateUninitialized = { export type ConvoStateUninitialized = {
status: ConvoStatus.Uninitialized status: ConvoStatus.Uninitialized
items: [] items: []
convo: ChatBskyConvoDefs.ConvoView | undefined convo: ConvoWithDetails | undefined
updateData: UpdateConvoData
error: undefined error: undefined
sender: ChatBskyActorDefs.ProfileViewBasic | undefined
recipients: ChatBskyActorDefs.ProfileViewBasic[] | undefined
isFetchingHistory: false isFetchingHistory: false
hasAllHistory: boolean hasAllHistory: boolean
deleteMessage: undefined deleteMessage: undefined
@@ -163,17 +162,13 @@ export type ConvoStateUninitialized = {
markConvoAccepted: undefined markConvoAccepted: undefined
addReaction: undefined addReaction: undefined
removeReaction: undefined removeReaction: undefined
isGroup: IsGroup
getGroupInfo: GetGroupInfo
getPrimaryMember: GetPrimaryMember
} }
export type ConvoStateInitializing = { export type ConvoStateInitializing = {
status: ConvoStatus.Initializing status: ConvoStatus.Initializing
items: [] items: []
convo: ChatBskyConvoDefs.ConvoView | undefined convo: ConvoWithDetails | undefined
updateData: UpdateConvoData
error: undefined error: undefined
sender: ChatBskyActorDefs.ProfileViewBasic | undefined
recipients: ChatBskyActorDefs.ProfileViewBasic[] | undefined
isFetchingHistory: boolean isFetchingHistory: boolean
hasAllHistory: boolean hasAllHistory: boolean
deleteMessage: undefined deleteMessage: undefined
@@ -182,17 +177,13 @@ export type ConvoStateInitializing = {
markConvoAccepted: undefined markConvoAccepted: undefined
addReaction: undefined addReaction: undefined
removeReaction: undefined removeReaction: undefined
isGroup: IsGroup
getGroupInfo: GetGroupInfo
getPrimaryMember: GetPrimaryMember
} }
export type ConvoStateReady = { export type ConvoStateReady = {
status: ConvoStatus.Ready status: ConvoStatus.Ready
items: ConvoItem[] items: ConvoItem[]
convo: ChatBskyConvoDefs.ConvoView convo: ConvoWithDetails
updateData: UpdateConvoData
error: undefined error: undefined
sender: ChatBskyActorDefs.ProfileViewBasic
recipients: ChatBskyActorDefs.ProfileViewBasic[]
isFetchingHistory: boolean isFetchingHistory: boolean
hasAllHistory: boolean hasAllHistory: boolean
deleteMessage: DeleteMessage deleteMessage: DeleteMessage
@@ -201,17 +192,13 @@ export type ConvoStateReady = {
markConvoAccepted: MarkConvoAccepted markConvoAccepted: MarkConvoAccepted
addReaction: AddReaction addReaction: AddReaction
removeReaction: RemoveReaction removeReaction: RemoveReaction
isGroup: IsGroup
getGroupInfo: GetGroupInfo
getPrimaryMember: GetPrimaryMember
} }
export type ConvoStateBackgrounded = { export type ConvoStateBackgrounded = {
status: ConvoStatus.Backgrounded status: ConvoStatus.Backgrounded
items: ConvoItem[] items: ConvoItem[]
convo: ChatBskyConvoDefs.ConvoView convo: ConvoWithDetails
updateData: UpdateConvoData
error: undefined error: undefined
sender: ChatBskyActorDefs.ProfileViewBasic
recipients: ChatBskyActorDefs.ProfileViewBasic[]
isFetchingHistory: boolean isFetchingHistory: boolean
hasAllHistory: boolean hasAllHistory: boolean
deleteMessage: DeleteMessage deleteMessage: DeleteMessage
@@ -220,17 +207,13 @@ export type ConvoStateBackgrounded = {
markConvoAccepted: MarkConvoAccepted markConvoAccepted: MarkConvoAccepted
addReaction: AddReaction addReaction: AddReaction
removeReaction: RemoveReaction removeReaction: RemoveReaction
isGroup: IsGroup
getGroupInfo: GetGroupInfo
getPrimaryMember: GetPrimaryMember
} }
export type ConvoStateSuspended = { export type ConvoStateSuspended = {
status: ConvoStatus.Suspended status: ConvoStatus.Suspended
items: ConvoItem[] items: ConvoItem[]
convo: ChatBskyConvoDefs.ConvoView convo: ConvoWithDetails
updateData: UpdateConvoData
error: undefined error: undefined
sender: ChatBskyActorDefs.ProfileViewBasic
recipients: ChatBskyActorDefs.ProfileViewBasic[]
isFetchingHistory: boolean isFetchingHistory: boolean
hasAllHistory: boolean hasAllHistory: boolean
deleteMessage: DeleteMessage deleteMessage: DeleteMessage
@@ -239,17 +222,13 @@ export type ConvoStateSuspended = {
markConvoAccepted: MarkConvoAccepted markConvoAccepted: MarkConvoAccepted
addReaction: AddReaction addReaction: AddReaction
removeReaction: RemoveReaction removeReaction: RemoveReaction
isGroup: IsGroup
getGroupInfo: GetGroupInfo
getPrimaryMember: GetPrimaryMember
} }
export type ConvoStateError = { export type ConvoStateError = {
status: ConvoStatus.Error status: ConvoStatus.Error
items: [] items: ConvoItem[]
convo: undefined convo: ConvoWithDetails | undefined
updateData: UpdateConvoData
error: ConvoError error: ConvoError
sender: undefined
recipients: undefined
isFetchingHistory: false isFetchingHistory: false
hasAllHistory: false hasAllHistory: false
deleteMessage: undefined deleteMessage: undefined
@@ -258,17 +237,13 @@ export type ConvoStateError = {
markConvoAccepted: undefined markConvoAccepted: undefined
addReaction: undefined addReaction: undefined
removeReaction: undefined removeReaction: undefined
isGroup: undefined
getGroupInfo: undefined
getPrimaryMember: undefined
} }
export type ConvoStateDisabled = { export type ConvoStateDisabled = {
status: ConvoStatus.Disabled status: ConvoStatus.Disabled
items: ConvoItem[] items: ConvoItem[]
convo: ChatBskyConvoDefs.ConvoView convo: ConvoWithDetails
updateData: UpdateConvoData
error: undefined error: undefined
sender: ChatBskyActorDefs.ProfileViewBasic
recipients: ChatBskyActorDefs.ProfileViewBasic[]
isFetchingHistory: boolean isFetchingHistory: boolean
hasAllHistory: boolean hasAllHistory: boolean
deleteMessage: DeleteMessage deleteMessage: DeleteMessage
@@ -277,9 +252,6 @@ export type ConvoStateDisabled = {
markConvoAccepted: MarkConvoAccepted markConvoAccepted: MarkConvoAccepted
addReaction: AddReaction addReaction: AddReaction
removeReaction: RemoveReaction removeReaction: RemoveReaction
isGroup: IsGroup
getGroupInfo: GetGroupInfo
getPrimaryMember: GetPrimaryMember
} }
export type ConvoState = export type ConvoState =
| ConvoStateUninitialized | ConvoStateUninitialized
+2 -1
View File
@@ -31,7 +31,8 @@ export function useConvoQuery({convoId}: {convoId: string}) {
) )
return data.convo return data.convo
}, },
staleTime: STALE.INFINITY, staleTime: STALE.MINUTES.THIRTY,
retry: 2,
}) })
} }
@@ -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,
// })
// }