* Only enable keyboard controller when necessary * make it screen only * rm keyboard padding * rm keyboardpadding file * revert using keyboard controller in composer * remove styles.outer (unnecessary for revert) * continue to use keyboard padding in the report dialog for dms --------- Co-authored-by: Hailey <me@haileyok.com>
265 lines
7 KiB
TypeScript
265 lines
7 KiB
TypeScript
import React from 'react'
|
|
import {View} from 'react-native'
|
|
import {AppBskyLabelerDefs} from '@atproto/api'
|
|
import {msg, Trans} from '@lingui/macro'
|
|
import {useLingui} from '@lingui/react'
|
|
|
|
import {getLabelingServiceTitle} from '#/lib/moderation'
|
|
import {ReportOption} from '#/lib/moderation/useReportOptions'
|
|
import {useAgent} from '#/state/session'
|
|
import {CharProgress} from '#/view/com/composer/char-progress/CharProgress'
|
|
import * as Toast from '#/view/com/util/Toast'
|
|
import {atoms as a, native, useTheme} from '#/alf'
|
|
import {Button, ButtonIcon, ButtonText} from '#/components/Button'
|
|
import * as Dialog from '#/components/Dialog'
|
|
import * as Toggle from '#/components/forms/Toggle'
|
|
import {Check_Stroke2_Corner0_Rounded as Check} from '#/components/icons/Check'
|
|
import {ChevronLeft_Stroke2_Corner0_Rounded as ChevronLeft} from '#/components/icons/Chevron'
|
|
import {Loader} from '#/components/Loader'
|
|
import {Text} from '#/components/Typography'
|
|
import {ReportDialogProps} from './types'
|
|
|
|
export function SubmitView({
|
|
params,
|
|
labelers,
|
|
selectedLabeler,
|
|
selectedReportOption,
|
|
goBack,
|
|
onSubmitComplete,
|
|
}: ReportDialogProps & {
|
|
labelers: AppBskyLabelerDefs.LabelerViewDetailed[]
|
|
selectedLabeler: string
|
|
selectedReportOption: ReportOption
|
|
goBack: () => void
|
|
onSubmitComplete: () => void
|
|
}) {
|
|
const t = useTheme()
|
|
const {_} = useLingui()
|
|
const agent = useAgent()
|
|
const [details, setDetails] = React.useState<string>('')
|
|
const [submitting, setSubmitting] = React.useState<boolean>(false)
|
|
const [selectedServices, setSelectedServices] = React.useState<string[]>([
|
|
selectedLabeler,
|
|
])
|
|
const [error, setError] = React.useState('')
|
|
|
|
const submit = React.useCallback(async () => {
|
|
setSubmitting(true)
|
|
setError('')
|
|
|
|
const $type =
|
|
params.type === 'account'
|
|
? 'com.atproto.admin.defs#repoRef'
|
|
: 'com.atproto.repo.strongRef'
|
|
const report = {
|
|
reasonType: selectedReportOption.reason,
|
|
subject: {
|
|
$type,
|
|
...params,
|
|
},
|
|
reason: details,
|
|
}
|
|
const results = await Promise.all(
|
|
selectedServices.map(did =>
|
|
agent
|
|
.withProxy('atproto_labeler', did)
|
|
.createModerationReport(report)
|
|
.then(
|
|
_ => true,
|
|
_ => false,
|
|
),
|
|
),
|
|
)
|
|
|
|
setSubmitting(false)
|
|
|
|
if (results.includes(true)) {
|
|
Toast.show(_(msg`Thank you. Your report has been sent.`))
|
|
onSubmitComplete()
|
|
} else {
|
|
setError(
|
|
_(
|
|
msg`There was an issue sending your report. Please check your internet connection.`,
|
|
),
|
|
)
|
|
}
|
|
}, [
|
|
_,
|
|
params,
|
|
details,
|
|
selectedReportOption,
|
|
selectedServices,
|
|
onSubmitComplete,
|
|
setError,
|
|
agent,
|
|
])
|
|
|
|
return (
|
|
<View style={[a.gap_2xl]}>
|
|
<Button
|
|
size="small"
|
|
variant="solid"
|
|
color="secondary"
|
|
shape="round"
|
|
label={_(msg`Go back to previous step`)}
|
|
onPress={goBack}>
|
|
<ButtonIcon icon={ChevronLeft} />
|
|
</Button>
|
|
|
|
<View
|
|
style={[
|
|
a.w_full,
|
|
a.flex_row,
|
|
a.align_center,
|
|
a.justify_between,
|
|
a.gap_lg,
|
|
a.p_md,
|
|
a.rounded_md,
|
|
a.border,
|
|
t.atoms.border_contrast_low,
|
|
]}>
|
|
<View style={[a.flex_1, a.gap_xs]}>
|
|
<Text style={[a.text_md, a.font_bold]}>
|
|
{selectedReportOption.title}
|
|
</Text>
|
|
<Text style={[a.leading_tight, {maxWidth: 400}]}>
|
|
{selectedReportOption.description}
|
|
</Text>
|
|
</View>
|
|
|
|
<Check size="md" style={[a.pr_sm, t.atoms.text_contrast_low]} />
|
|
</View>
|
|
|
|
<View style={[a.gap_md]}>
|
|
<Text style={[t.atoms.text_contrast_medium]}>
|
|
<Trans>Select the moderation service(s) to report to</Trans>
|
|
</Text>
|
|
|
|
<Toggle.Group
|
|
label="Select mod services"
|
|
values={selectedServices}
|
|
onChange={setSelectedServices}>
|
|
<View style={[a.flex_row, a.gap_md, a.flex_wrap]}>
|
|
{labelers.map(labeler => {
|
|
const title = getLabelingServiceTitle({
|
|
displayName: labeler.creator.displayName,
|
|
handle: labeler.creator.handle,
|
|
})
|
|
return (
|
|
<Toggle.Item
|
|
key={labeler.creator.did}
|
|
name={labeler.creator.did}
|
|
label={title}>
|
|
<LabelerToggle title={title} />
|
|
</Toggle.Item>
|
|
)
|
|
})}
|
|
</View>
|
|
</Toggle.Group>
|
|
</View>
|
|
<View style={[a.gap_md]}>
|
|
<Text style={[t.atoms.text_contrast_medium]}>
|
|
<Trans>Optionally provide additional information below:</Trans>
|
|
</Text>
|
|
|
|
<View style={[a.relative, a.w_full]}>
|
|
<Dialog.Input
|
|
multiline
|
|
value={details}
|
|
onChangeText={setDetails}
|
|
label="Text field"
|
|
style={{paddingRight: 60}}
|
|
numberOfLines={6}
|
|
/>
|
|
|
|
<View
|
|
style={[
|
|
a.absolute,
|
|
a.flex_row,
|
|
a.align_center,
|
|
a.pr_md,
|
|
a.pb_sm,
|
|
{
|
|
bottom: 0,
|
|
right: 0,
|
|
},
|
|
]}>
|
|
<CharProgress count={details?.length || 0} />
|
|
</View>
|
|
</View>
|
|
</View>
|
|
|
|
<View style={[a.flex_row, a.align_center, a.justify_end, a.gap_lg]}>
|
|
{!selectedServices.length ||
|
|
(error && (
|
|
<Text
|
|
style={[
|
|
a.flex_1,
|
|
a.italic,
|
|
a.leading_snug,
|
|
t.atoms.text_contrast_medium,
|
|
]}>
|
|
{error ? (
|
|
error
|
|
) : (
|
|
<Trans>You must select at least one labeler for a report</Trans>
|
|
)}
|
|
</Text>
|
|
))}
|
|
|
|
<Button
|
|
testID="sendReportBtn"
|
|
size="large"
|
|
variant="solid"
|
|
color="negative"
|
|
label={_(msg`Send report`)}
|
|
onPress={submit}
|
|
disabled={!selectedServices.length}>
|
|
<ButtonText>
|
|
<Trans>Send report</Trans>
|
|
</ButtonText>
|
|
{submitting && <ButtonIcon icon={Loader} />}
|
|
</Button>
|
|
</View>
|
|
</View>
|
|
)
|
|
}
|
|
|
|
function LabelerToggle({title}: {title: string}) {
|
|
const t = useTheme()
|
|
const ctx = Toggle.useItemContext()
|
|
|
|
return (
|
|
<View
|
|
style={[
|
|
a.flex_row,
|
|
a.align_center,
|
|
a.gap_md,
|
|
a.p_md,
|
|
a.pr_lg,
|
|
a.rounded_sm,
|
|
a.overflow_hidden,
|
|
t.atoms.bg_contrast_25,
|
|
ctx.selected && [t.atoms.bg_contrast_50],
|
|
]}>
|
|
<Toggle.Checkbox />
|
|
<View
|
|
style={[
|
|
a.flex_row,
|
|
a.align_center,
|
|
a.justify_between,
|
|
a.gap_lg,
|
|
a.z_10,
|
|
]}>
|
|
<Text
|
|
style={[
|
|
native({marginTop: 2}),
|
|
t.atoms.text_contrast_medium,
|
|
ctx.selected && t.atoms.text,
|
|
]}>
|
|
{title}
|
|
</Text>
|
|
</View>
|
|
</View>
|
|
)
|
|
}
|