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})