Make generic convo report dialog (#4085)

zio/stable
Eric Bailey 2024-05-17 17:56:58 -05:00 committed by GitHub
parent 1cdcb3e6c3
commit 8b3bfb3cf7
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 117 additions and 66 deletions

View File

@ -25,12 +25,10 @@ import {SquareArrowTopRight_Stroke2_Corner0_Rounded as SquareArrowTopRight} from
import {Text} from '#/components/Typography'
import {ReportDialogProps} from './types'
type ParamsWithMessages = ReportDialogProps['params'] | {type: 'message'}
export function SelectReportOptionView({
...props
}: {
params: ParamsWithMessages
params: ReportDialogProps['params']
labelers: AppBskyLabelerDefs.LabelerViewDetailed[]
onSelectReportOption: (reportOption: ReportOption) => void
goBack: () => void
@ -57,9 +55,12 @@ export function SelectReportOptionView({
} else if (props.params.type === 'feedgen') {
title = _(msg`Report this feed`)
description = _(msg`Why should this feed be reviewed?`)
} else if (props.params.type === 'message') {
} else if (props.params.type === 'convoMessage') {
title = _(msg`Report this message`)
description = _(msg`Why should this message be reviewed?`)
} else if (props.params.type === 'convoAccount') {
title = _(msg`Report this account`)
description = _(msg`Why should this account be reviewed?`)
}
return {

View File

@ -12,4 +12,6 @@ export type ReportDialogProps = {
type: 'account'
did: string
}
| {type: 'convoMessage'}
| {type: 'convoAccount'}
}

View File

@ -21,7 +21,7 @@ import * as Toast from '#/view/com/util/Toast'
import {atoms as a, useTheme} from '#/alf'
import {BlockedByListDialog} from '#/components/dms/BlockedByListDialog'
import {LeaveConvoPrompt} from '#/components/dms/LeaveConvoPrompt'
import {ReportConversationPrompt} from '#/components/dms/ReportConversationPrompt'
import {ReportDialog} from '#/components/dms/ReportDialog'
import {ArrowBoxLeft_Stroke2_Corner0_Rounded as ArrowBoxLeft} from '#/components/icons/ArrowBoxLeft'
import {DotGrid_Stroke2_Corner0_Rounded as DotsHorizontal} from '#/components/icons/DotGrid'
import {Flag_Stroke2_Corner0_Rounded as Flag} from '#/components/icons/Flag'
@ -205,7 +205,10 @@ let ConvoMenu = ({
convoId={convo.id}
currentScreen={currentScreen}
/>
<ReportConversationPrompt control={reportControl} />
<ReportDialog
control={reportControl}
params={{type: 'convoAccount', did: profile.did, convoId: convo.id}}
/>
<BlockedByListDialog
control={blockedByListControl}
listBlocks={listBlocks}

View File

@ -11,6 +11,7 @@ import {useConvoActive} from 'state/messages/convo'
import {useSession} from 'state/session'
import * as Toast from '#/view/com/util/Toast'
import {atoms as a, useTheme} from '#/alf'
import {ReportDialog} from '#/components/dms/ReportDialog'
import {DotGrid_Stroke2_Corner0_Rounded as DotsHorizontal} from '#/components/icons/DotGrid'
import {Trash_Stroke2_Corner0_Rounded as Trash} from '#/components/icons/Trash'
import {Warning_Stroke2_Corner0_Rounded as Warning} from '#/components/icons/Warning'
@ -18,7 +19,6 @@ import * as Menu from '#/components/Menu'
import * as Prompt from '#/components/Prompt'
import {usePromptControl} from '#/components/Prompt'
import {Clipboard_Stroke2_Corner2_Rounded as ClipboardIcon} from '../icons/Clipboard'
import {MessageReportDialog} from './MessageReportDialog'
export let MessageMenu = ({
message,
@ -112,7 +112,10 @@ export let MessageMenu = ({
</Menu.Outer>
</Menu.Root>
<MessageReportDialog message={message} control={reportControl} />
<ReportDialog
params={{type: 'convoMessage', convoId: convo.convo.id, message}}
control={reportControl}
/>
<Prompt.Basic
control={deleteControl}

View File

@ -12,7 +12,7 @@ import {useDialogControl} from '#/components/Dialog'
import {Divider} from '#/components/Divider'
import {BlockedByListDialog} from '#/components/dms/BlockedByListDialog'
import {LeaveConvoPrompt} from '#/components/dms/LeaveConvoPrompt'
import {ReportConversationPrompt} from '#/components/dms/ReportConversationPrompt'
import {ReportDialog} from '#/components/dms/ReportDialog'
import {Text} from '#/components/Typography'
export function MessagesListBlockedFooter({
@ -120,7 +120,10 @@ export function MessagesListBlockedFooter({
convoId={convoId}
/>
<ReportConversationPrompt control={reportControl} />
<ReportDialog
control={reportControl}
params={{type: 'convoAccount', did: recipient.did, convoId}}
/>
<BlockedByListDialog
control={blockedByListControl}

View File

@ -1,27 +0,0 @@
import React from 'react'
import {msg} from '@lingui/macro'
import {useLingui} from '@lingui/react'
import {DialogControlProps} from '#/components/Dialog'
import * as Prompt from '#/components/Prompt'
export function ReportConversationPrompt({
control,
}: {
control: DialogControlProps
}) {
const {_} = useLingui()
return (
<Prompt.Basic
control={control}
title={_(msg`Report conversation`)}
description={_(
msg`To report a conversation, please report one of its messages via the conversation screen. This lets our moderators understand the context of your issue.`,
)}
confirmButtonCta={_(msg`I understand`)}
onConfirm={() => {}}
showCancel={false}
/>
)
}

View File

@ -25,12 +25,24 @@ import {RichText} from '../RichText'
import {Text} from '../Typography'
import {MessageItemMetadata} from './MessageItem'
let MessageReportDialog = ({
type ReportDialogParams =
| {
type: 'convoAccount'
did: string
convoId: string
}
| {
type: 'convoMessage'
convoId: string
message: ChatBskyConvoDefs.MessageView
}
let ReportDialog = ({
control,
message,
params,
}: {
control: Dialog.DialogControlProps
message: ChatBskyConvoDefs.MessageView
params: ReportDialogParams
}): React.ReactNode => {
const {_} = useLingui()
return (
@ -39,33 +51,35 @@ let MessageReportDialog = ({
nativeOptions={isAndroid ? {sheet: {snapPoints: ['100%']}} : {}}>
<Dialog.Handle />
<Dialog.ScrollableInner label={_(msg`Report this message`)}>
<DialogInner message={message} />
<DialogInner params={params} />
<Dialog.Close />
</Dialog.ScrollableInner>
</Dialog.Outer>
)
}
MessageReportDialog = memo(MessageReportDialog)
export {MessageReportDialog}
ReportDialog = memo(ReportDialog)
export {ReportDialog}
function DialogInner({message}: {message: ChatBskyConvoDefs.MessageView}) {
function DialogInner({params}: {params: ReportDialogParams}) {
const [reportOption, setReportOption] = useState<ReportOption | null>(null)
return reportOption ? (
<SubmitStep
message={message}
params={params}
reportOption={reportOption}
goBack={() => setReportOption(null)}
/>
) : (
<ReasonStep setReportOption={setReportOption} />
<ReasonStep params={params} setReportOption={setReportOption} />
)
}
function ReasonStep({
setReportOption,
params,
}: {
setReportOption: (reportOption: ReportOption) => void
params: ReportDialogParams
}) {
const control = Dialog.useDialogContext()
@ -73,18 +87,26 @@ function ReasonStep({
<SelectReportOptionView
labelers={[]}
goBack={control.close}
params={{type: 'message'}}
params={
params.type === 'convoMessage'
? {
type: 'convoMessage',
}
: {
type: 'convoAccount',
}
}
onSelectReportOption={setReportOption}
/>
)
}
function SubmitStep({
message,
params,
reportOption,
goBack,
}: {
message: ChatBskyConvoDefs.MessageView
params: ReportDialogParams
reportOption: ReportOption
goBack: () => void
}) {
@ -101,17 +123,33 @@ function SubmitStep({
isPending: submitting,
} = useMutation({
mutationFn: async () => {
const report = {
reasonType: reportOption.reason,
subject: {
$type: 'chat.bsky.convo.defs#messageRef',
messageId: message.id,
did: message.sender!.did,
} satisfies ChatBskyConvoDefs.MessageRef,
reason: details,
} satisfies ComAtprotoModerationCreateReport.InputSchema
if (params.type === 'convoMessage') {
const {convoId, message} = params
await getAgent().createModerationReport(report)
const report = {
reasonType: reportOption.reason,
subject: {
$type: 'chat.bsky.convo.defs#messageRef',
messageId: message.id,
convoId,
did: message.sender.did,
} satisfies ChatBskyConvoDefs.MessageRef,
reason: details,
} satisfies ComAtprotoModerationCreateReport.InputSchema
await getAgent().createModerationReport(report)
} else if (params.type === 'convoAccount') {
const {convoId, did} = params
await getAgent().createModerationReport({
reasonType: reportOption.reason,
subject: {
$type: 'com.atproto.admin.defs#repoRef',
did,
},
reason: details + ` from:dms:${convoId}`,
})
}
},
onSuccess: () => {
control.close(() => {
@ -120,6 +158,17 @@ function SubmitStep({
},
})
const copy = useMemo(() => {
return {
convoMessage: {
title: _(msg`Report this message`),
},
convoAccount: {
title: _(msg`Report this account`),
},
}[params.type]
}, [_, params])
return (
<View style={a.gap_lg}>
<Button
@ -133,9 +182,7 @@ function SubmitStep({
</Button>
<View style={[a.justify_center, gtMobile ? a.gap_sm : a.gap_xs]}>
<Text style={[a.text_2xl, a.font_bold]}>
<Trans>Report this message</Trans>
</Text>
<Text style={[a.text_2xl, a.font_bold]}>{copy.title}</Text>
<Text style={[a.text_md, t.atoms.text_contrast_medium]}>
<Trans>
Your report will be sent to the Bluesky Moderation Service
@ -143,10 +190,15 @@ function SubmitStep({
</Text>
</View>
<PreviewMessage message={message} />
{params.type === 'convoMessage' && (
<PreviewMessage message={params.message} />
)}
<Text style={[a.text_md, t.atoms.text_contrast_medium]}>
<Trans>Reason: {reportOption.title}</Trans>
<Text style={[a.font_bold, a.text_md, t.atoms.text_contrast_medium]}>
<Trans>Reason:</Trans>
</Text>{' '}
<Text style={[a.font_bold, a.text_md]}>{reportOption.title}</Text>
</Text>
<Divider />

View File

@ -15,7 +15,8 @@ interface ReportOptions {
list: ReportOption[]
feedgen: ReportOption[]
other: ReportOption[]
message: ReportOption[]
convoMessage: ReportOption[]
convoAccount: ReportOption[]
}
export function useReportOptions(): ReportOptions {
@ -73,7 +74,20 @@ export function useReportOptions(): ReportOptions {
},
...common,
],
message: [
convoMessage: [
{
reason: ComAtprotoModerationDefs.REASONSPAM,
title: _(msg`Spam`),
description: _(msg`Excessive or unwanted messages`),
},
{
reason: ComAtprotoModerationDefs.REASONSEXUAL,
title: _(msg`Unwanted Sexual Content`),
description: _(msg`Inappropriate messages or explicit links`),
},
...common,
],
convoAccount: [
{
reason: ComAtprotoModerationDefs.REASONSPAM,
title: _(msg`Spam`),