about summary refs log tree commit diff
path: root/src/state/queries
diff options
context:
space:
mode:
Diffstat (limited to 'src/state/queries')
-rw-r--r--src/state/queries/profile.ts166
-rw-r--r--src/state/queries/resolve-uri.ts15
2 files changed, 171 insertions, 10 deletions
diff --git a/src/state/queries/profile.ts b/src/state/queries/profile.ts
index c2cd19482..1bd28d5b1 100644
--- a/src/state/queries/profile.ts
+++ b/src/state/queries/profile.ts
@@ -1,13 +1,169 @@
-import {useQuery} from '@tanstack/react-query'
+import {AtUri} from '@atproto/api'
+import {useQuery, useMutation} from '@tanstack/react-query'
+import {useSession} from '../session'
+import {updateProfileShadow} from '../cache/profile-shadow'
 
-import {PUBLIC_BSKY_AGENT} from '#/state/queries'
+export const RQKEY = (did: string) => ['profile', did]
 
-export function useProfileQuery({did}: {did: string}) {
+export function useProfileQuery({did}: {did: string | undefined}) {
+  const {agent} = useSession()
   return useQuery({
-    queryKey: ['getProfile', did],
+    queryKey: RQKEY(did),
     queryFn: async () => {
-      const res = await PUBLIC_BSKY_AGENT.getProfile({actor: did})
+      const res = await agent.getProfile({actor: did || ''})
       return res.data
     },
+    enabled: !!did,
+  })
+}
+
+export function useProfileFollowMutation() {
+  const {agent} = useSession()
+  return useMutation<{uri: string; cid: string}, Error, {did: string}>({
+    mutationFn: async ({did}) => {
+      return await agent.follow(did)
+    },
+    onMutate(variables) {
+      // optimstically update
+      updateProfileShadow(variables.did, {
+        followingUri: 'pending',
+      })
+    },
+    onSuccess(data, variables) {
+      // finalize
+      updateProfileShadow(variables.did, {
+        followingUri: data.uri,
+      })
+    },
+    onError(error, variables) {
+      // revert the optimistic update
+      updateProfileShadow(variables.did, {
+        followingUri: undefined,
+      })
+    },
+  })
+}
+
+export function useProfileUnfollowMutation() {
+  const {agent} = useSession()
+  return useMutation<void, Error, {did: string; followUri: string}>({
+    mutationFn: async ({followUri}) => {
+      return await agent.deleteFollow(followUri)
+    },
+    onMutate(variables) {
+      // optimstically update
+      updateProfileShadow(variables.did, {
+        followingUri: undefined,
+      })
+    },
+    onError(error, variables) {
+      // revert the optimistic update
+      updateProfileShadow(variables.did, {
+        followingUri: variables.followUri,
+      })
+    },
+  })
+}
+
+export function useProfileMuteMutation() {
+  const {agent} = useSession()
+  return useMutation<void, Error, {did: string}>({
+    mutationFn: async ({did}) => {
+      await agent.mute(did)
+    },
+    onMutate(variables) {
+      // optimstically update
+      updateProfileShadow(variables.did, {
+        muted: true,
+      })
+    },
+    onError(error, variables) {
+      // revert the optimistic update
+      updateProfileShadow(variables.did, {
+        muted: false,
+      })
+    },
+  })
+}
+
+export function useProfileUnmuteMutation() {
+  const {agent} = useSession()
+  return useMutation<void, Error, {did: string}>({
+    mutationFn: async ({did}) => {
+      await agent.unmute(did)
+    },
+    onMutate(variables) {
+      // optimstically update
+      updateProfileShadow(variables.did, {
+        muted: false,
+      })
+    },
+    onError(error, variables) {
+      // revert the optimistic update
+      updateProfileShadow(variables.did, {
+        muted: true,
+      })
+    },
+  })
+}
+
+export function useProfileBlockMutation() {
+  const {agent, currentAccount} = useSession()
+  return useMutation<{uri: string; cid: string}, Error, {did: string}>({
+    mutationFn: async ({did}) => {
+      if (!currentAccount) {
+        throw new Error('Not signed in')
+      }
+      return await agent.app.bsky.graph.block.create(
+        {repo: currentAccount.did},
+        {subject: did, createdAt: new Date().toISOString()},
+      )
+    },
+    onMutate(variables) {
+      // optimstically update
+      updateProfileShadow(variables.did, {
+        blockingUri: 'pending',
+      })
+    },
+    onSuccess(data, variables) {
+      // finalize
+      updateProfileShadow(variables.did, {
+        blockingUri: data.uri,
+      })
+    },
+    onError(error, variables) {
+      // revert the optimistic update
+      updateProfileShadow(variables.did, {
+        blockingUri: undefined,
+      })
+    },
+  })
+}
+
+export function useProfileUnblockMutation() {
+  const {agent, currentAccount} = useSession()
+  return useMutation<void, Error, {did: string; blockUri: string}>({
+    mutationFn: async ({blockUri}) => {
+      if (!currentAccount) {
+        throw new Error('Not signed in')
+      }
+      const {rkey} = new AtUri(blockUri)
+      await agent.app.bsky.graph.block.delete({
+        repo: currentAccount.did,
+        rkey,
+      })
+    },
+    onMutate(variables) {
+      // optimstically update
+      updateProfileShadow(variables.did, {
+        blockingUri: undefined,
+      })
+    },
+    onError(error, variables) {
+      // revert the optimistic update
+      updateProfileShadow(variables.did, {
+        blockingUri: variables.blockUri,
+      })
+    },
   })
 }
diff --git a/src/state/queries/resolve-uri.ts b/src/state/queries/resolve-uri.ts
index 26e0a475b..83bccdce7 100644
--- a/src/state/queries/resolve-uri.ts
+++ b/src/state/queries/resolve-uri.ts
@@ -4,17 +4,22 @@ import {useSession} from '../session'
 
 export const RQKEY = (uri: string) => ['resolved-uri', uri]
 
-export function useResolveUriQuery(uri: string) {
+export function useResolveUriQuery(uri: string | undefined) {
   const {agent} = useSession()
-  return useQuery<string | undefined, Error>({
-    queryKey: RQKEY(uri),
+  return useQuery<{uri: string; did: string}, Error>({
+    queryKey: RQKEY(uri || ''),
     async queryFn() {
-      const urip = new AtUri(uri)
+      const urip = new AtUri(uri || '')
       if (!urip.host.startsWith('did:')) {
         const res = await agent.resolveHandle({handle: urip.host})
         urip.host = res.data.did
       }
-      return urip.toString()
+      return {did: urip.host, uri: urip.toString()}
     },
+    enabled: !!uri,
   })
 }
+
+export function useResolveDidQuery(didOrHandle: string | undefined) {
+  return useResolveUriQuery(didOrHandle ? `at://${didOrHandle}/` : undefined)
+}