forked from
jollywhoppers.com/witchsky.app
Bluesky app fork with some witchin' additions 馃挮
1import {type ChatBskyConvoDefs} from '@atproto/api'
2import {
3 type QueryClient,
4 useMutation,
5 useQuery,
6 useQueryClient,
7} from '@tanstack/react-query'
8
9import {DM_SERVICE_HEADERS} from '#/lib/constants'
10import {STALE} from '#/state/queries'
11import {useOnMarkAsRead} from '#/state/queries/messages/list-conversations'
12import {useAgent} from '#/state/session'
13import {
14 type ConvoListQueryData,
15 getConvoFromQueryData,
16 RQKEY_ROOT as LIST_CONVOS_KEY,
17} from './list-conversations'
18
19const RQKEY_ROOT = 'convo'
20export const RQKEY = (convoId: string) => [RQKEY_ROOT, convoId]
21
22export function useConvoQuery(convo: ChatBskyConvoDefs.ConvoView) {
23 const agent = useAgent()
24
25 return useQuery({
26 queryKey: RQKEY(convo.id),
27 queryFn: async () => {
28 const {data} = await agent.chat.bsky.convo.getConvo(
29 {convoId: convo.id},
30 {headers: DM_SERVICE_HEADERS},
31 )
32 return data.convo
33 },
34 initialData: convo,
35 staleTime: STALE.INFINITY,
36 })
37}
38
39export function precacheConvoQuery(
40 queryClient: QueryClient,
41 convo: ChatBskyConvoDefs.ConvoView,
42) {
43 queryClient.setQueryData(RQKEY(convo.id), convo)
44}
45
46export function useMarkAsReadMutation() {
47 const optimisticUpdate = useOnMarkAsRead()
48 const queryClient = useQueryClient()
49 const agent = useAgent()
50
51 return useMutation({
52 mutationFn: async ({
53 convoId,
54 messageId,
55 }: {
56 convoId?: string
57 messageId?: string
58 }) => {
59 if (!convoId) throw new Error('No convoId provided')
60
61 await agent.api.chat.bsky.convo.updateRead(
62 {
63 convoId,
64 messageId,
65 },
66 {
67 encoding: 'application/json',
68 headers: DM_SERVICE_HEADERS,
69 },
70 )
71 },
72 onMutate({convoId}) {
73 if (!convoId) throw new Error('No convoId provided')
74 optimisticUpdate(convoId)
75 },
76 onSuccess(_, {convoId}) {
77 if (!convoId) return
78
79 queryClient.setQueriesData(
80 {queryKey: [LIST_CONVOS_KEY]},
81 (old?: ConvoListQueryData) => {
82 if (!old) return old
83
84 const existingConvo = getConvoFromQueryData(convoId, old)
85
86 if (existingConvo) {
87 return {
88 ...old,
89 pages: old.pages.map(page => {
90 return {
91 ...page,
92 convos: page.convos.map(convo => {
93 if (convo.id === convoId) {
94 return {
95 ...convo,
96 unreadCount: 0,
97 }
98 }
99 return convo
100 }),
101 }
102 }),
103 }
104 } else {
105 // If we somehow marked a convo as read that doesn't exist in the
106 // list, then we don't need to do anything.
107 }
108 },
109 )
110 },
111 })
112}