mirror of https://git.lenooby09.tech/LeNooby09/social-app.git
at schema-errors 267 lines 7.3 kB view raw
1import React from 'react' 2import {View} from 'react-native' 3import {AppBskyLabelerDefs} from '@atproto/api' 4import {msg, Trans} from '@lingui/macro' 5import {useLingui} from '@lingui/react' 6 7import {getLabelingServiceTitle} from '#/lib/moderation' 8import {ReportOption} from '#/lib/moderation/useReportOptions' 9import {useAgent} from '#/state/session' 10import {CharProgress} from '#/view/com/composer/char-progress/CharProgress' 11import * as Toast from '#/view/com/util/Toast' 12import {atoms as a, native, useTheme} from '#/alf' 13import {Button, ButtonIcon, ButtonText} from '#/components/Button' 14import * as Dialog from '#/components/Dialog' 15import * as Toggle from '#/components/forms/Toggle' 16import {Check_Stroke2_Corner0_Rounded as Check} from '#/components/icons/Check' 17import {ChevronLeft_Stroke2_Corner0_Rounded as ChevronLeft} from '#/components/icons/Chevron' 18import {KeyboardPadding} from '#/components/KeyboardPadding' 19import {Loader} from '#/components/Loader' 20import {Text} from '#/components/Typography' 21import {ReportDialogProps} from './types' 22 23export function SubmitView({ 24 params, 25 labelers, 26 selectedLabeler, 27 selectedReportOption, 28 goBack, 29 onSubmitComplete, 30}: ReportDialogProps & { 31 labelers: AppBskyLabelerDefs.LabelerViewDetailed[] 32 selectedLabeler: string 33 selectedReportOption: ReportOption 34 goBack: () => void 35 onSubmitComplete: () => void 36}) { 37 const t = useTheme() 38 const {_} = useLingui() 39 const agent = useAgent() 40 const [details, setDetails] = React.useState<string>('') 41 const [submitting, setSubmitting] = React.useState<boolean>(false) 42 const [selectedServices, setSelectedServices] = React.useState<string[]>([ 43 selectedLabeler, 44 ]) 45 const [error, setError] = React.useState('') 46 47 const submit = React.useCallback(async () => { 48 setSubmitting(true) 49 setError('') 50 51 const $type = 52 params.type === 'account' 53 ? 'com.atproto.admin.defs#repoRef' 54 : 'com.atproto.repo.strongRef' 55 const report = { 56 reasonType: selectedReportOption.reason, 57 subject: { 58 $type, 59 ...params, 60 }, 61 reason: details, 62 } 63 const results = await Promise.all( 64 selectedServices.map(did => 65 agent 66 .withProxy('atproto_labeler', did) 67 .createModerationReport(report) 68 .then( 69 _ => true, 70 _ => false, 71 ), 72 ), 73 ) 74 75 setSubmitting(false) 76 77 if (results.includes(true)) { 78 Toast.show(_(msg`Thank you. Your report has been sent.`)) 79 onSubmitComplete() 80 } else { 81 setError( 82 _( 83 msg`There was an issue sending your report. Please check your internet connection.`, 84 ), 85 ) 86 } 87 }, [ 88 _, 89 params, 90 details, 91 selectedReportOption, 92 selectedServices, 93 onSubmitComplete, 94 setError, 95 agent, 96 ]) 97 98 return ( 99 <View style={[a.gap_2xl]}> 100 <Button 101 size="small" 102 variant="solid" 103 color="secondary" 104 shape="round" 105 label={_(msg`Go back to previous step`)} 106 onPress={goBack}> 107 <ButtonIcon icon={ChevronLeft} /> 108 </Button> 109 110 <View 111 style={[ 112 a.w_full, 113 a.flex_row, 114 a.align_center, 115 a.justify_between, 116 a.gap_lg, 117 a.p_md, 118 a.rounded_md, 119 a.border, 120 t.atoms.border_contrast_low, 121 ]}> 122 <View style={[a.flex_1, a.gap_xs]}> 123 <Text style={[a.text_md, a.font_bold]}> 124 {selectedReportOption.title} 125 </Text> 126 <Text style={[a.leading_tight, {maxWidth: 400}]}> 127 {selectedReportOption.description} 128 </Text> 129 </View> 130 131 <Check size="md" style={[a.pr_sm, t.atoms.text_contrast_low]} /> 132 </View> 133 134 <View style={[a.gap_md]}> 135 <Text style={[t.atoms.text_contrast_medium]}> 136 <Trans>Select the moderation service(s) to report to</Trans> 137 </Text> 138 139 <Toggle.Group 140 label="Select mod services" 141 values={selectedServices} 142 onChange={setSelectedServices}> 143 <View style={[a.flex_row, a.gap_md, a.flex_wrap]}> 144 {labelers.map(labeler => { 145 const title = getLabelingServiceTitle({ 146 displayName: labeler.creator.displayName, 147 handle: labeler.creator.handle, 148 }) 149 return ( 150 <Toggle.Item 151 key={labeler.creator.did} 152 name={labeler.creator.did} 153 label={title}> 154 <LabelerToggle title={title} /> 155 </Toggle.Item> 156 ) 157 })} 158 </View> 159 </Toggle.Group> 160 </View> 161 <View style={[a.gap_md]}> 162 <Text style={[t.atoms.text_contrast_medium]}> 163 <Trans>Optionally provide additional information below:</Trans> 164 </Text> 165 166 <View style={[a.relative, a.w_full]}> 167 <Dialog.Input 168 multiline 169 value={details} 170 onChangeText={setDetails} 171 label="Text field" 172 style={{paddingRight: 60}} 173 numberOfLines={6} 174 /> 175 176 <View 177 style={[ 178 a.absolute, 179 a.flex_row, 180 a.align_center, 181 a.pr_md, 182 a.pb_sm, 183 { 184 bottom: 0, 185 right: 0, 186 }, 187 ]}> 188 <CharProgress count={details?.length || 0} /> 189 </View> 190 </View> 191 </View> 192 193 <View style={[a.flex_row, a.align_center, a.justify_end, a.gap_lg]}> 194 {!selectedServices.length || 195 (error && ( 196 <Text 197 style={[ 198 a.flex_1, 199 a.italic, 200 a.leading_snug, 201 t.atoms.text_contrast_medium, 202 ]}> 203 {error ? ( 204 error 205 ) : ( 206 <Trans>You must select at least one labeler for a report</Trans> 207 )} 208 </Text> 209 ))} 210 211 <Button 212 testID="sendReportBtn" 213 size="large" 214 variant="solid" 215 color="negative" 216 label={_(msg`Send report`)} 217 onPress={submit} 218 disabled={!selectedServices.length}> 219 <ButtonText> 220 <Trans>Send report</Trans> 221 </ButtonText> 222 {submitting && <ButtonIcon icon={Loader} />} 223 </Button> 224 </View> 225 <KeyboardPadding /> 226 </View> 227 ) 228} 229 230function LabelerToggle({title}: {title: string}) { 231 const t = useTheme() 232 const ctx = Toggle.useItemContext() 233 234 return ( 235 <View 236 style={[ 237 a.flex_row, 238 a.align_center, 239 a.gap_md, 240 a.p_md, 241 a.pr_lg, 242 a.rounded_sm, 243 a.overflow_hidden, 244 t.atoms.bg_contrast_25, 245 ctx.selected && [t.atoms.bg_contrast_50], 246 ]}> 247 <Toggle.Checkbox /> 248 <View 249 style={[ 250 a.flex_row, 251 a.align_center, 252 a.justify_between, 253 a.gap_lg, 254 a.z_10, 255 ]}> 256 <Text 257 style={[ 258 native({marginTop: 2}), 259 t.atoms.text_contrast_medium, 260 ctx.selected && t.atoms.text, 261 ]}> 262 {title} 263 </Text> 264 </View> 265 </View> 266 ) 267}