forked from
jollywhoppers.com/witchsky.app
Bluesky app fork with some witchin' additions 馃挮
1import {type AppBskyFeedDefs} from '@atproto/api'
2import {useMutation, useQueryClient} from '@tanstack/react-query'
3
4import {isNetworkError} from '#/lib/strings/errors'
5import {logger} from '#/logger'
6import {updatePostShadow} from '#/state/cache/post-shadow'
7import {
8 optimisticallyDeleteBookmark,
9 optimisticallySaveBookmark,
10} from '#/state/queries/bookmarks/useBookmarksQuery'
11import {useAgent} from '#/state/session'
12
13type MutationArgs =
14 | {action: 'create'; post: AppBskyFeedDefs.PostView}
15 | {
16 action: 'delete'
17 /**
18 * For deletions, we only need to URI. Plus, in some cases we only know the
19 * URI, such as when a post was deleted by the author.
20 */
21 uri: string
22 }
23
24export function useBookmarkMutation() {
25 const qc = useQueryClient()
26 const agent = useAgent()
27
28 return useMutation({
29 async mutationFn(args: MutationArgs) {
30 if (args.action === 'create') {
31 updatePostShadow(qc, args.post.uri, {bookmarked: true})
32 await agent.app.bsky.bookmark.createBookmark({
33 uri: args.post.uri,
34 cid: args.post.cid,
35 })
36 } else if (args.action === 'delete') {
37 updatePostShadow(qc, args.uri, {bookmarked: false})
38 await agent.app.bsky.bookmark.deleteBookmark({
39 uri: args.uri,
40 })
41 }
42 },
43 onSuccess(_, args) {
44 if (args.action === 'create') {
45 optimisticallySaveBookmark(qc, args.post)
46 } else if (args.action === 'delete') {
47 optimisticallyDeleteBookmark(qc, {uri: args.uri})
48 }
49 },
50 onError(e, args) {
51 if (args.action === 'create') {
52 updatePostShadow(qc, args.post.uri, {bookmarked: false})
53 } else if (args.action === 'delete') {
54 updatePostShadow(qc, args.uri, {bookmarked: true})
55 }
56
57 if (!isNetworkError(e)) {
58 logger.error('bookmark mutation failed', {
59 bookmarkAction: args.action,
60 safeMessage: e,
61 })
62 }
63 },
64 })
65}