An ATproto social media client -- with an independent Appview.
1import {
2 type AppBskyActorDefs,
3 type AppBskyNotificationDeclaration,
4 type AppBskyNotificationListActivitySubscriptions,
5} from '@atproto/api'
6import {t} from '@lingui/macro'
7import {
8 type InfiniteData,
9 type QueryClient,
10 useInfiniteQuery,
11 useMutation,
12 useQuery,
13 useQueryClient,
14} from '@tanstack/react-query'
15
16import {useAgent, useSession} from '#/state/session'
17import * as Toast from '#/view/com/util/Toast'
18
19export const RQKEY_getActivitySubscriptions = ['activity-subscriptions']
20export const RQKEY_getNotificationDeclaration = ['notification-declaration']
21
22export function useActivitySubscriptionsQuery() {
23 const agent = useAgent()
24
25 return useInfiniteQuery({
26 queryKey: RQKEY_getActivitySubscriptions,
27 queryFn: async ({pageParam}) => {
28 const response =
29 await agent.app.bsky.notification.listActivitySubscriptions({
30 cursor: pageParam,
31 })
32 return response.data
33 },
34 initialPageParam: undefined as string | undefined,
35 getNextPageParam: prev => prev.cursor,
36 })
37}
38
39export function useNotificationDeclarationQuery() {
40 const agent = useAgent()
41 const {currentAccount} = useSession()
42 return useQuery({
43 queryKey: RQKEY_getNotificationDeclaration,
44 queryFn: async () => {
45 try {
46 const response = await agent.app.bsky.notification.declaration.get({
47 repo: currentAccount!.did,
48 rkey: 'self',
49 })
50 return response
51 } catch (err) {
52 if (
53 err instanceof Error &&
54 err.message.startsWith('Could not locate record')
55 ) {
56 return {
57 value: {
58 $type: 'app.bsky.notification.declaration',
59 allowSubscriptions: 'followers',
60 } satisfies AppBskyNotificationDeclaration.Record,
61 }
62 } else {
63 throw err
64 }
65 }
66 },
67 })
68}
69
70export function useNotificationDeclarationMutation() {
71 const agent = useAgent()
72 const {currentAccount} = useSession()
73 const queryClient = useQueryClient()
74 return useMutation({
75 mutationFn: async (record: AppBskyNotificationDeclaration.Record) => {
76 const response = await agent.app.bsky.notification.declaration.put(
77 {
78 repo: currentAccount!.did,
79 rkey: 'self',
80 },
81 record,
82 )
83 return response
84 },
85 onMutate: value => {
86 queryClient.setQueryData(
87 RQKEY_getNotificationDeclaration,
88 (old?: {
89 uri: string
90 cid: string
91 value: AppBskyNotificationDeclaration.Record
92 }) => {
93 if (!old) return old
94 return {
95 value,
96 }
97 },
98 )
99 },
100 onError: () => {
101 Toast.show(t`Failed to update notification declaration`)
102 queryClient.invalidateQueries({
103 queryKey: RQKEY_getNotificationDeclaration,
104 })
105 },
106 })
107}
108
109export function* findAllProfilesInQueryData(
110 queryClient: QueryClient,
111 did: string,
112): Generator<AppBskyActorDefs.ProfileView, void> {
113 const queryDatas = queryClient.getQueriesData<
114 InfiniteData<AppBskyNotificationListActivitySubscriptions.OutputSchema>
115 >({
116 queryKey: RQKEY_getActivitySubscriptions,
117 })
118 for (const [_queryKey, queryData] of queryDatas) {
119 if (!queryData?.pages) {
120 continue
121 }
122 for (const page of queryData.pages) {
123 for (const subscription of page.subscriptions) {
124 if (subscription.did === did) {
125 yield subscription
126 }
127 }
128 }
129 }
130}