mirror of https://git.lenooby09.tech/LeNooby09/social-app.git
1import React from 'react'
2import {LayoutAnimation, Pressable, View} from 'react-native'
3import * as Clipboard from 'expo-clipboard'
4import {ChatBskyConvoDefs, RichText} from '@atproto/api'
5import {msg} from '@lingui/macro'
6import {useLingui} from '@lingui/react'
7
8import {richTextToString} from '#/lib/strings/rich-text-helpers'
9import {getTranslatorLink} from '#/locale/helpers'
10import {useLanguagePrefs} from '#/state/preferences'
11import {useOpenLink} from '#/state/preferences/in-app-browser'
12import {isWeb} from 'platform/detection'
13import {useConvoActive} from 'state/messages/convo'
14import {useSession} from 'state/session'
15import * as Toast from '#/view/com/util/Toast'
16import {atoms as a, useTheme} from '#/alf'
17import {ReportDialog} from '#/components/dms/ReportDialog'
18import {BubbleQuestion_Stroke2_Corner0_Rounded as Translate} from '#/components/icons/Bubble'
19import {DotGrid_Stroke2_Corner0_Rounded as DotsHorizontal} from '#/components/icons/DotGrid'
20import {Trash_Stroke2_Corner0_Rounded as Trash} from '#/components/icons/Trash'
21import {Warning_Stroke2_Corner0_Rounded as Warning} from '#/components/icons/Warning'
22import * as Menu from '#/components/Menu'
23import * as Prompt from '#/components/Prompt'
24import {usePromptControl} from '#/components/Prompt'
25import {Clipboard_Stroke2_Corner2_Rounded as ClipboardIcon} from '../icons/Clipboard'
26
27export let MessageMenu = ({
28 message,
29 control,
30 triggerOpacity,
31}: {
32 triggerOpacity?: number
33 message: ChatBskyConvoDefs.MessageView
34 control: Menu.MenuControlProps
35}): React.ReactNode => {
36 const {_} = useLingui()
37 const t = useTheme()
38 const {currentAccount} = useSession()
39 const convo = useConvoActive()
40 const deleteControl = usePromptControl()
41 const reportControl = usePromptControl()
42 const langPrefs = useLanguagePrefs()
43 const openLink = useOpenLink()
44
45 const isFromSelf = message.sender?.did === currentAccount?.did
46
47 const onCopyMessage = React.useCallback(() => {
48 const str = richTextToString(
49 new RichText({
50 text: message.text,
51 facets: message.facets,
52 }),
53 true,
54 )
55
56 Clipboard.setStringAsync(str)
57 Toast.show(_(msg`Copied to clipboard`), 'clipboard-check')
58 }, [_, message.text, message.facets])
59
60 const onPressTranslateMessage = React.useCallback(() => {
61 const translatorUrl = getTranslatorLink(
62 message.text,
63 langPrefs.primaryLanguage,
64 )
65 openLink(translatorUrl)
66 }, [langPrefs.primaryLanguage, message.text, openLink])
67
68 const onDelete = React.useCallback(() => {
69 LayoutAnimation.configureNext(LayoutAnimation.Presets.easeInEaseOut)
70 convo
71 .deleteMessage(message.id)
72 .then(() => Toast.show(_(msg`Message deleted`)))
73 .catch(() => Toast.show(_(msg`Failed to delete message`)))
74 }, [_, convo, message.id])
75
76 return (
77 <>
78 <Menu.Root control={control}>
79 {isWeb && (
80 <View style={{opacity: triggerOpacity}}>
81 <Menu.Trigger label={_(msg`Chat settings`)}>
82 {({props, state}) => (
83 <Pressable
84 {...props}
85 style={[
86 a.p_sm,
87 a.rounded_full,
88 (state.hovered || state.pressed) && t.atoms.bg_contrast_25,
89 ]}>
90 <DotsHorizontal size="md" style={t.atoms.text} />
91 </Pressable>
92 )}
93 </Menu.Trigger>
94 </View>
95 )}
96
97 <Menu.Outer>
98 {message.text.length > 0 && (
99 <>
100 <Menu.Group>
101 <Menu.Item
102 testID="messageDropdownTranslateBtn"
103 label={_(msg`Translate`)}
104 onPress={onPressTranslateMessage}>
105 <Menu.ItemText>{_(msg`Translate`)}</Menu.ItemText>
106 <Menu.ItemIcon icon={Translate} position="right" />
107 </Menu.Item>
108 <Menu.Item
109 testID="messageDropdownCopyBtn"
110 label={_(msg`Copy message text`)}
111 onPress={onCopyMessage}>
112 <Menu.ItemText>{_(msg`Copy message text`)}</Menu.ItemText>
113 <Menu.ItemIcon icon={ClipboardIcon} position="right" />
114 </Menu.Item>
115 </Menu.Group>
116 <Menu.Divider />
117 </>
118 )}
119 <Menu.Group>
120 <Menu.Item
121 testID="messageDropdownDeleteBtn"
122 label={_(msg`Delete message for me`)}
123 onPress={deleteControl.open}>
124 <Menu.ItemText>{_(msg`Delete for me`)}</Menu.ItemText>
125 <Menu.ItemIcon icon={Trash} position="right" />
126 </Menu.Item>
127 {!isFromSelf && (
128 <Menu.Item
129 testID="messageDropdownReportBtn"
130 label={_(msg`Report message`)}
131 onPress={reportControl.open}>
132 <Menu.ItemText>{_(msg`Report`)}</Menu.ItemText>
133 <Menu.ItemIcon icon={Warning} position="right" />
134 </Menu.Item>
135 )}
136 </Menu.Group>
137 </Menu.Outer>
138 </Menu.Root>
139
140 <ReportDialog
141 params={{type: 'convoMessage', convoId: convo.convo.id, message}}
142 control={reportControl}
143 />
144
145 <Prompt.Basic
146 control={deleteControl}
147 title={_(msg`Delete message`)}
148 description={_(
149 msg`Are you sure you want to delete this message? The message will be deleted for you, but not for the other participant.`,
150 )}
151 confirmButtonCta={_(msg`Delete`)}
152 confirmButtonColor="negative"
153 onConfirm={onDelete}
154 />
155 </>
156 )
157}
158MessageMenu = React.memo(MessageMenu)