mirror of https://git.lenooby09.tech/LeNooby09/social-app.git
at verify-code 285 lines 7.6 kB view raw
1import React, {memo, useMemo, useState} from 'react' 2import {View} from 'react-native' 3import { 4 ChatBskyConvoDefs, 5 ComAtprotoModerationCreateReport, 6 RichText as RichTextAPI, 7} from '@atproto/api' 8import {msg, Trans} from '@lingui/macro' 9import {useLingui} from '@lingui/react' 10import {useMutation} from '@tanstack/react-query' 11 12import {ReportOption} from '#/lib/moderation/useReportOptions' 13import {isAndroid} from '#/platform/detection' 14import {useAgent} from '#/state/session' 15import {CharProgress} from '#/view/com/composer/char-progress/CharProgress' 16import * as Toast from '#/view/com/util/Toast' 17import {atoms as a, useBreakpoints, useTheme} from '#/alf' 18import * as Dialog from '#/components/Dialog' 19import {KeyboardControllerPadding} from '#/components/KeyboardControllerPadding' 20import {Button, ButtonIcon, ButtonText} from '../Button' 21import {Divider} from '../Divider' 22import {ChevronLeft_Stroke2_Corner0_Rounded as Chevron} from '../icons/Chevron' 23import {Loader} from '../Loader' 24import {SelectReportOptionView} from '../ReportDialog/SelectReportOptionView' 25import {RichText} from '../RichText' 26import {Text} from '../Typography' 27import {MessageItemMetadata} from './MessageItem' 28 29type ReportDialogParams = { 30 type: 'convoMessage' 31 convoId: string 32 message: ChatBskyConvoDefs.MessageView 33} 34 35let ReportDialog = ({ 36 control, 37 params, 38}: { 39 control: Dialog.DialogControlProps 40 params: ReportDialogParams 41}): React.ReactNode => { 42 const {_} = useLingui() 43 return ( 44 <Dialog.Outer 45 control={control} 46 nativeOptions={isAndroid ? {sheet: {snapPoints: ['100%']}} : {}}> 47 <Dialog.Handle /> 48 <Dialog.ScrollableInner label={_(msg`Report this message`)}> 49 <DialogInner params={params} /> 50 <Dialog.Close /> 51 <KeyboardControllerPadding /> 52 </Dialog.ScrollableInner> 53 </Dialog.Outer> 54 ) 55} 56ReportDialog = memo(ReportDialog) 57export {ReportDialog} 58 59function DialogInner({params}: {params: ReportDialogParams}) { 60 const [reportOption, setReportOption] = useState<ReportOption | null>(null) 61 62 return reportOption ? ( 63 <SubmitStep 64 params={params} 65 reportOption={reportOption} 66 goBack={() => setReportOption(null)} 67 /> 68 ) : ( 69 <ReasonStep params={params} setReportOption={setReportOption} /> 70 ) 71} 72 73function ReasonStep({ 74 setReportOption, 75}: { 76 setReportOption: (reportOption: ReportOption) => void 77 params: ReportDialogParams 78}) { 79 const control = Dialog.useDialogContext() 80 81 return ( 82 <SelectReportOptionView 83 labelers={[]} 84 goBack={control.close} 85 params={{ 86 type: 'convoMessage', 87 }} 88 onSelectReportOption={setReportOption} 89 /> 90 ) 91} 92 93function SubmitStep({ 94 params, 95 reportOption, 96 goBack, 97}: { 98 params: ReportDialogParams 99 reportOption: ReportOption 100 goBack: () => void 101}) { 102 const {_} = useLingui() 103 const {gtMobile} = useBreakpoints() 104 const t = useTheme() 105 const [details, setDetails] = useState('') 106 const control = Dialog.useDialogContext() 107 const agent = useAgent() 108 109 const { 110 mutate: submit, 111 error, 112 isPending: submitting, 113 } = useMutation({ 114 mutationFn: async () => { 115 if (params.type === 'convoMessage') { 116 const {convoId, message} = params 117 118 const report = { 119 reasonType: reportOption.reason, 120 subject: { 121 $type: 'chat.bsky.convo.defs#messageRef', 122 messageId: message.id, 123 convoId, 124 did: message.sender.did, 125 } satisfies ChatBskyConvoDefs.MessageRef, 126 reason: details, 127 } satisfies ComAtprotoModerationCreateReport.InputSchema 128 129 await agent.createModerationReport(report) 130 } 131 }, 132 onSuccess: () => { 133 control.close(() => { 134 Toast.show(_(msg`Thank you. Your report has been sent.`)) 135 }) 136 }, 137 }) 138 139 const copy = useMemo(() => { 140 return { 141 convoMessage: { 142 title: _(msg`Report this message`), 143 }, 144 }[params.type] 145 }, [_, params]) 146 147 return ( 148 <View style={a.gap_lg}> 149 <Button 150 size="small" 151 variant="solid" 152 color="secondary" 153 shape="round" 154 label={_(msg`Go back to previous step`)} 155 onPress={goBack}> 156 <ButtonIcon icon={Chevron} /> 157 </Button> 158 159 <View style={[a.justify_center, gtMobile ? a.gap_sm : a.gap_xs]}> 160 <Text style={[a.text_2xl, a.font_bold]}>{copy.title}</Text> 161 <Text style={[a.text_md, t.atoms.text_contrast_medium]}> 162 <Trans> 163 Your report will be sent to the Bluesky Moderation Service 164 </Trans> 165 </Text> 166 </View> 167 168 {params.type === 'convoMessage' && ( 169 <PreviewMessage message={params.message} /> 170 )} 171 172 <Text style={[a.text_md, t.atoms.text_contrast_medium]}> 173 <Text style={[a.font_bold, a.text_md, t.atoms.text_contrast_medium]}> 174 <Trans>Reason:</Trans> 175 </Text>{' '} 176 <Text style={[a.font_bold, a.text_md]}>{reportOption.title}</Text> 177 </Text> 178 179 <Divider /> 180 181 <View style={[a.gap_md]}> 182 <Text style={[t.atoms.text_contrast_medium]}> 183 <Trans>Optionally provide additional information below:</Trans> 184 </Text> 185 186 <View style={[a.relative, a.w_full]}> 187 <Dialog.Input 188 multiline 189 value={details} 190 onChangeText={setDetails} 191 label="Text field" 192 style={{paddingRight: 60}} 193 numberOfLines={6} 194 /> 195 196 <View 197 style={[ 198 a.absolute, 199 a.flex_row, 200 a.align_center, 201 a.pr_md, 202 a.pb_sm, 203 { 204 bottom: 0, 205 right: 0, 206 }, 207 ]}> 208 <CharProgress count={details?.length || 0} /> 209 </View> 210 </View> 211 </View> 212 213 <View style={[a.flex_row, a.align_center, a.justify_end, a.gap_lg]}> 214 {error && ( 215 <Text 216 style={[ 217 a.flex_1, 218 a.italic, 219 a.leading_snug, 220 t.atoms.text_contrast_medium, 221 ]}> 222 <Trans> 223 There was an issue sending your report. Please check your internet 224 connection. 225 </Trans> 226 </Text> 227 )} 228 229 <Button 230 testID="sendReportBtn" 231 size="large" 232 variant="solid" 233 color="negative" 234 label={_(msg`Send report`)} 235 onPress={() => submit()}> 236 <ButtonText> 237 <Trans>Send report</Trans> 238 </ButtonText> 239 {submitting && <ButtonIcon icon={Loader} />} 240 </Button> 241 </View> 242 </View> 243 ) 244} 245 246function PreviewMessage({message}: {message: ChatBskyConvoDefs.MessageView}) { 247 const t = useTheme() 248 const rt = useMemo(() => { 249 return new RichTextAPI({text: message.text, facets: message.facets}) 250 }, [message.text, message.facets]) 251 252 return ( 253 <View style={a.align_start}> 254 <View 255 style={[ 256 a.py_sm, 257 a.my_2xs, 258 a.rounded_md, 259 { 260 paddingLeft: 14, 261 paddingRight: 14, 262 backgroundColor: t.palette.contrast_50, 263 borderRadius: 17, 264 }, 265 {borderBottomLeftRadius: 2}, 266 ]}> 267 <RichText 268 value={rt} 269 style={[a.text_md, a.leading_snug]} 270 interactiveStyle={a.underline} 271 enableTags 272 /> 273 </View> 274 <MessageItemMetadata 275 item={{ 276 type: 'message', 277 message, 278 key: '', 279 nextMessage: null, 280 }} 281 style={[a.text_left, a.mb_0]} 282 /> 283 </View> 284 ) 285}