mirror of https://git.lenooby09.tech/LeNooby09/social-app.git
1import {memo} from 'react'
2import {type Insets} from 'react-native'
3import {type AppBskyFeedDefs} from '@atproto/api'
4import {msg, Trans} from '@lingui/macro'
5import {useLingui} from '@lingui/react'
6import type React from 'react'
7
8import {useCleanError} from '#/lib/hooks/useCleanError'
9import {logger} from '#/logger'
10import {type Shadow} from '#/state/cache/post-shadow'
11import {useBookmarkMutation} from '#/state/queries/bookmarks/useBookmarkMutation'
12import {useRequireAuth} from '#/state/session'
13import {useTheme} from '#/alf'
14import {Bookmark, BookmarkFilled} from '#/components/icons/Bookmark'
15import {Trash_Stroke2_Corner0_Rounded as TrashIcon} from '#/components/icons/Trash'
16import * as toast from '#/components/Toast'
17import {PostControlButton, PostControlButtonIcon} from './PostControlButton'
18
19export const BookmarkButton = memo(function BookmarkButton({
20 post,
21 big,
22 logContext,
23 hitSlop,
24}: {
25 post: Shadow<AppBskyFeedDefs.PostView>
26 big?: boolean
27 logContext: 'FeedItem' | 'PostThreadItem' | 'Post' | 'ImmersiveVideo'
28 hitSlop?: Insets
29}): React.ReactNode {
30 const t = useTheme()
31 const {_} = useLingui()
32 const {mutateAsync: bookmark} = useBookmarkMutation()
33 const cleanError = useCleanError()
34 const requireAuth = useRequireAuth()
35
36 const {viewer} = post
37 const isBookmarked = !!viewer?.bookmarked
38
39 const undoLabel = _(
40 msg({
41 message: `Undo`,
42 context: `Button label to undo saving/removing a post from saved posts.`,
43 }),
44 )
45
46 const save = async ({disableUndo}: {disableUndo?: boolean} = {}) => {
47 try {
48 await bookmark({
49 action: 'create',
50 post,
51 })
52
53 logger.metric('post:bookmark', {logContext})
54
55 toast.show(
56 <toast.Outer>
57 <toast.Icon />
58 <toast.Text>
59 <Trans>Post saved</Trans>
60 </toast.Text>
61 {!disableUndo && (
62 <toast.Action
63 label={undoLabel}
64 onPress={() => remove({disableUndo: true})}>
65 {undoLabel}
66 </toast.Action>
67 )}
68 </toast.Outer>,
69 {
70 type: 'success',
71 },
72 )
73 } catch (e: any) {
74 const {raw, clean} = cleanError(e)
75 toast.show(clean || raw || e, {
76 type: 'error',
77 })
78 }
79 }
80
81 const remove = async ({disableUndo}: {disableUndo?: boolean} = {}) => {
82 try {
83 await bookmark({
84 action: 'delete',
85 uri: post.uri,
86 })
87
88 logger.metric('post:unbookmark', {logContext})
89
90 toast.show(
91 <toast.Outer>
92 <toast.Icon icon={TrashIcon} />
93 <toast.Text>
94 <Trans>Removed from saved posts</Trans>
95 </toast.Text>
96 {!disableUndo && (
97 <toast.Action
98 label={undoLabel}
99 onPress={() => save({disableUndo: true})}>
100 {undoLabel}
101 </toast.Action>
102 )}
103 </toast.Outer>,
104 )
105 } catch (e: any) {
106 const {raw, clean} = cleanError(e)
107 toast.show(clean || raw || e, {
108 type: 'error',
109 })
110 }
111 }
112
113 const onHandlePress = () =>
114 requireAuth(async () => {
115 if (isBookmarked) {
116 await remove()
117 } else {
118 await save()
119 }
120 })
121
122 return (
123 <PostControlButton
124 testID="postBookmarkBtn"
125 big={big}
126 label={
127 isBookmarked
128 ? _(msg`Remove from saved posts`)
129 : _(msg`Add to saved posts`)
130 }
131 onPress={onHandlePress}
132 hitSlop={hitSlop}>
133 <PostControlButtonIcon
134 fill={isBookmarked ? t.palette.primary_500 : undefined}
135 icon={isBookmarked ? BookmarkFilled : Bookmark}
136 />
137 </PostControlButton>
138 )
139})