Bluesky app fork with some witchin' additions 💫
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

Update the reporting flow to first select a recipient if the user has multiple labelers (#3258)

authored by

Paul Frazee and committed by
GitHub
959121f3 1b10c7bc

+175 -20
+115
src/components/ReportDialog/SelectLabelerView.tsx
··· 1 + import React from 'react' 2 + import {View} from 'react-native' 3 + import {msg, Trans} from '@lingui/macro' 4 + import {useLingui} from '@lingui/react' 5 + import {AppBskyLabelerDefs} from '@atproto/api' 6 + 7 + export {useDialogControl as useReportDialogControl} from '#/components/Dialog' 8 + 9 + import {atoms as a, useTheme} from '#/alf' 10 + import {Text} from '#/components/Typography' 11 + import {Button, useButtonContext} from '#/components/Button' 12 + import {Divider} from '#/components/Divider' 13 + import {ChevronRight_Stroke2_Corner0_Rounded as ChevronRight} from '#/components/icons/Chevron' 14 + 15 + import {ReportDialogProps} from './types' 16 + 17 + export function SelectLabelerView({ 18 + ...props 19 + }: ReportDialogProps & { 20 + labelers: AppBskyLabelerDefs.LabelerViewDetailed[] 21 + onSelectLabeler: (v: string) => void 22 + }) { 23 + const t = useTheme() 24 + const {_} = useLingui() 25 + 26 + return ( 27 + <View style={[a.gap_lg]}> 28 + <View style={[a.justify_center, a.gap_sm]}> 29 + <Text style={[a.text_2xl, a.font_bold]}> 30 + <Trans>Select moderation service</Trans> 31 + </Text> 32 + <Text style={[a.text_md, t.atoms.text_contrast_medium]}> 33 + <Trans>Who do you want to send this report to?</Trans> 34 + </Text> 35 + </View> 36 + 37 + <Divider /> 38 + 39 + <View style={[a.gap_sm, {marginHorizontal: a.p_md.padding * -1}]}> 40 + {props.labelers.map(labeler => { 41 + return ( 42 + <Button 43 + key={labeler.creator.did} 44 + label={_(msg`Send report to ${labeler.creator.displayName}`)} 45 + onPress={() => props.onSelectLabeler(labeler.creator.did)}> 46 + <LabelerButton 47 + title={labeler.creator.displayName || labeler.creator.handle} 48 + description={labeler.creator.description || ''} 49 + /> 50 + </Button> 51 + ) 52 + })} 53 + </View> 54 + </View> 55 + ) 56 + } 57 + 58 + function LabelerButton({ 59 + title, 60 + description, 61 + }: { 62 + title: string 63 + description: string 64 + }) { 65 + const t = useTheme() 66 + const {hovered, pressed} = useButtonContext() 67 + const interacted = hovered || pressed 68 + 69 + const styles = React.useMemo(() => { 70 + return { 71 + interacted: { 72 + backgroundColor: t.palette.contrast_50, 73 + }, 74 + } 75 + }, [t]) 76 + 77 + return ( 78 + <View 79 + style={[ 80 + a.w_full, 81 + a.flex_row, 82 + a.align_center, 83 + a.justify_between, 84 + a.p_md, 85 + a.rounded_md, 86 + {paddingRight: 70}, 87 + interacted && styles.interacted, 88 + ]}> 89 + <View style={[a.flex_1, a.gap_xs]}> 90 + <Text style={[a.text_md, a.font_bold, t.atoms.text_contrast_medium]}> 91 + {title} 92 + </Text> 93 + <Text style={[a.leading_tight, {maxWidth: 400}]} numberOfLines={3}> 94 + {description} 95 + </Text> 96 + </View> 97 + 98 + <View 99 + style={[ 100 + a.absolute, 101 + a.inset_0, 102 + a.justify_center, 103 + a.pr_md, 104 + {left: 'auto'}, 105 + ]}> 106 + <ChevronRight 107 + size="md" 108 + fill={ 109 + hovered ? t.palette.primary_500 : t.atoms.text_contrast_low.color 110 + } 111 + /> 112 + </View> 113 + </View> 114 + ) 115 + }
+17 -1
src/components/ReportDialog/SelectReportOptionView.tsx
··· 18 18 useButtonContext, 19 19 } from '#/components/Button' 20 20 import {Divider} from '#/components/Divider' 21 - import {ChevronRight_Stroke2_Corner0_Rounded as ChevronRight} from '#/components/icons/Chevron' 21 + import { 22 + ChevronRight_Stroke2_Corner0_Rounded as ChevronRight, 23 + ChevronLeft_Stroke2_Corner0_Rounded as ChevronLeft, 24 + } from '#/components/icons/Chevron' 22 25 import {SquareArrowTopRight_Stroke2_Corner0_Rounded as SquareArrowTopRight} from '#/components/icons/SquareArrowTopRight' 23 26 24 27 import {ReportDialogProps} from './types' ··· 28 31 }: ReportDialogProps & { 29 32 labelers: AppBskyLabelerDefs.LabelerViewDetailed[] 30 33 onSelectReportOption: (reportOption: ReportOption) => void 34 + goBack: () => void 31 35 }) { 32 36 const t = useTheme() 33 37 const {_} = useLingui() ··· 60 64 61 65 return ( 62 66 <View style={[a.gap_lg]}> 67 + {props.labelers?.length > 1 ? ( 68 + <Button 69 + size="small" 70 + variant="solid" 71 + color="secondary" 72 + shape="round" 73 + label={_(msg`Go back to previous step`)} 74 + onPress={props.goBack}> 75 + <ButtonIcon icon={ChevronLeft} /> 76 + </Button> 77 + ) : null} 78 + 63 79 <View style={[a.justify_center, a.gap_sm]}> 64 80 <Text style={[a.text_2xl, a.font_bold]}>{i18n.title}</Text> 65 81 <Text style={[a.text_md, t.atoms.text_contrast_medium]}>
+5 -3
src/components/ReportDialog/SubmitView.tsx
··· 24 24 export function SubmitView({ 25 25 params, 26 26 labelers, 27 + selectedLabeler, 27 28 selectedReportOption, 28 29 goBack, 29 30 onSubmitComplete, 30 31 }: ReportDialogProps & { 31 32 labelers: AppBskyLabelerDefs.LabelerViewDetailed[] 33 + selectedLabeler: string 32 34 selectedReportOption: ReportOption 33 35 goBack: () => void 34 36 onSubmitComplete: () => void ··· 37 39 const {_} = useLingui() 38 40 const [details, setDetails] = React.useState<string>('') 39 41 const [submitting, setSubmitting] = React.useState<boolean>(false) 40 - const [selectedServices, setSelectedServices] = React.useState<string[]>( 41 - labelers?.map(labeler => labeler.creator.did) || [], 42 - ) 42 + const [selectedServices, setSelectedServices] = React.useState<string[]>([ 43 + selectedLabeler, 44 + ]) 43 45 const [error, setError] = React.useState('') 44 46 45 47 const submit = React.useCallback(async () => {
+38 -16
src/components/ReportDialog/index.tsx
··· 12 12 import {Text} from '#/components/Typography' 13 13 14 14 import {ReportDialogProps} from './types' 15 + import {SelectLabelerView} from './SelectLabelerView' 15 16 import {SelectReportOptionView} from './SelectReportOptionView' 16 17 import {SubmitView} from './SubmitView' 17 18 import {useDelayedLoading} from '#/components/hooks/useDelayedLoading' 19 + import {AppBskyLabelerDefs} from '@atproto/api' 18 20 19 21 export function ReportDialog(props: ReportDialogProps) { 20 22 return ( ··· 33 35 error, 34 36 } = useMyLabelersQuery() 35 37 const isLoading = useDelayedLoading(500, isLabelerLoading) 36 - const [selectedReportOption, setSelectedReportOption] = React.useState< 37 - ReportOption | undefined 38 - >() 39 38 40 39 return ( 41 40 <Dialog.ScrollableInner label="Report Dialog"> ··· 51 50 <Trans>Something went wrong, please try again.</Trans> 52 51 </Text> 53 52 </View> 54 - ) : selectedReportOption ? ( 55 - <SubmitView 56 - {...props} 57 - labelers={labelers} 58 - selectedReportOption={selectedReportOption} 59 - goBack={() => setSelectedReportOption(undefined)} 60 - onSubmitComplete={() => props.control.close()} 61 - /> 62 53 ) : ( 63 - <SelectReportOptionView 64 - {...props} 65 - labelers={labelers} 66 - onSelectReportOption={setSelectedReportOption} 67 - /> 54 + <ReportDialogLoaded labelers={labelers} {...props} /> 68 55 )} 69 56 70 57 <Dialog.Close /> 71 58 </Dialog.ScrollableInner> 72 59 ) 73 60 } 61 + 62 + function ReportDialogLoaded( 63 + props: ReportDialogProps & { 64 + labelers: AppBskyLabelerDefs.LabelerViewDetailed[] 65 + }, 66 + ) { 67 + const [selectedLabeler, setSelectedLabeler] = React.useState< 68 + string | undefined 69 + >(props.labelers.length === 1 ? props.labelers[0].creator.did : undefined) 70 + const [selectedReportOption, setSelectedReportOption] = React.useState< 71 + ReportOption | undefined 72 + >() 73 + 74 + if (selectedReportOption && selectedLabeler) { 75 + return ( 76 + <SubmitView 77 + {...props} 78 + selectedLabeler={selectedLabeler} 79 + selectedReportOption={selectedReportOption} 80 + goBack={() => setSelectedReportOption(undefined)} 81 + onSubmitComplete={() => props.control.close()} 82 + /> 83 + ) 84 + } 85 + if (selectedLabeler) { 86 + return ( 87 + <SelectReportOptionView 88 + {...props} 89 + goBack={() => setSelectedLabeler(undefined)} 90 + onSelectReportOption={setSelectedReportOption} 91 + /> 92 + ) 93 + } 94 + return <SelectLabelerView {...props} onSelectLabeler={setSelectedLabeler} /> 95 + }