Make generic convo report dialog (#4085)
parent
1cdcb3e6c3
commit
8b3bfb3cf7
|
@ -25,12 +25,10 @@ import {SquareArrowTopRight_Stroke2_Corner0_Rounded as SquareArrowTopRight} from
|
||||||
import {Text} from '#/components/Typography'
|
import {Text} from '#/components/Typography'
|
||||||
import {ReportDialogProps} from './types'
|
import {ReportDialogProps} from './types'
|
||||||
|
|
||||||
type ParamsWithMessages = ReportDialogProps['params'] | {type: 'message'}
|
|
||||||
|
|
||||||
export function SelectReportOptionView({
|
export function SelectReportOptionView({
|
||||||
...props
|
...props
|
||||||
}: {
|
}: {
|
||||||
params: ParamsWithMessages
|
params: ReportDialogProps['params']
|
||||||
labelers: AppBskyLabelerDefs.LabelerViewDetailed[]
|
labelers: AppBskyLabelerDefs.LabelerViewDetailed[]
|
||||||
onSelectReportOption: (reportOption: ReportOption) => void
|
onSelectReportOption: (reportOption: ReportOption) => void
|
||||||
goBack: () => void
|
goBack: () => void
|
||||||
|
@ -57,9 +55,12 @@ export function SelectReportOptionView({
|
||||||
} else if (props.params.type === 'feedgen') {
|
} else if (props.params.type === 'feedgen') {
|
||||||
title = _(msg`Report this feed`)
|
title = _(msg`Report this feed`)
|
||||||
description = _(msg`Why should this feed be reviewed?`)
|
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`)
|
title = _(msg`Report this message`)
|
||||||
description = _(msg`Why should this message be reviewed?`)
|
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 {
|
return {
|
||||||
|
|
|
@ -12,4 +12,6 @@ export type ReportDialogProps = {
|
||||||
type: 'account'
|
type: 'account'
|
||||||
did: string
|
did: string
|
||||||
}
|
}
|
||||||
|
| {type: 'convoMessage'}
|
||||||
|
| {type: 'convoAccount'}
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,7 +21,7 @@ import * as Toast from '#/view/com/util/Toast'
|
||||||
import {atoms as a, useTheme} from '#/alf'
|
import {atoms as a, useTheme} from '#/alf'
|
||||||
import {BlockedByListDialog} from '#/components/dms/BlockedByListDialog'
|
import {BlockedByListDialog} from '#/components/dms/BlockedByListDialog'
|
||||||
import {LeaveConvoPrompt} from '#/components/dms/LeaveConvoPrompt'
|
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 {ArrowBoxLeft_Stroke2_Corner0_Rounded as ArrowBoxLeft} from '#/components/icons/ArrowBoxLeft'
|
||||||
import {DotGrid_Stroke2_Corner0_Rounded as DotsHorizontal} from '#/components/icons/DotGrid'
|
import {DotGrid_Stroke2_Corner0_Rounded as DotsHorizontal} from '#/components/icons/DotGrid'
|
||||||
import {Flag_Stroke2_Corner0_Rounded as Flag} from '#/components/icons/Flag'
|
import {Flag_Stroke2_Corner0_Rounded as Flag} from '#/components/icons/Flag'
|
||||||
|
@ -205,7 +205,10 @@ let ConvoMenu = ({
|
||||||
convoId={convo.id}
|
convoId={convo.id}
|
||||||
currentScreen={currentScreen}
|
currentScreen={currentScreen}
|
||||||
/>
|
/>
|
||||||
<ReportConversationPrompt control={reportControl} />
|
<ReportDialog
|
||||||
|
control={reportControl}
|
||||||
|
params={{type: 'convoAccount', did: profile.did, convoId: convo.id}}
|
||||||
|
/>
|
||||||
<BlockedByListDialog
|
<BlockedByListDialog
|
||||||
control={blockedByListControl}
|
control={blockedByListControl}
|
||||||
listBlocks={listBlocks}
|
listBlocks={listBlocks}
|
||||||
|
|
|
@ -11,6 +11,7 @@ import {useConvoActive} from 'state/messages/convo'
|
||||||
import {useSession} from 'state/session'
|
import {useSession} from 'state/session'
|
||||||
import * as Toast from '#/view/com/util/Toast'
|
import * as Toast from '#/view/com/util/Toast'
|
||||||
import {atoms as a, useTheme} from '#/alf'
|
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 {DotGrid_Stroke2_Corner0_Rounded as DotsHorizontal} from '#/components/icons/DotGrid'
|
||||||
import {Trash_Stroke2_Corner0_Rounded as Trash} from '#/components/icons/Trash'
|
import {Trash_Stroke2_Corner0_Rounded as Trash} from '#/components/icons/Trash'
|
||||||
import {Warning_Stroke2_Corner0_Rounded as Warning} from '#/components/icons/Warning'
|
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 * as Prompt from '#/components/Prompt'
|
||||||
import {usePromptControl} from '#/components/Prompt'
|
import {usePromptControl} from '#/components/Prompt'
|
||||||
import {Clipboard_Stroke2_Corner2_Rounded as ClipboardIcon} from '../icons/Clipboard'
|
import {Clipboard_Stroke2_Corner2_Rounded as ClipboardIcon} from '../icons/Clipboard'
|
||||||
import {MessageReportDialog} from './MessageReportDialog'
|
|
||||||
|
|
||||||
export let MessageMenu = ({
|
export let MessageMenu = ({
|
||||||
message,
|
message,
|
||||||
|
@ -112,7 +112,10 @@ export let MessageMenu = ({
|
||||||
</Menu.Outer>
|
</Menu.Outer>
|
||||||
</Menu.Root>
|
</Menu.Root>
|
||||||
|
|
||||||
<MessageReportDialog message={message} control={reportControl} />
|
<ReportDialog
|
||||||
|
params={{type: 'convoMessage', convoId: convo.convo.id, message}}
|
||||||
|
control={reportControl}
|
||||||
|
/>
|
||||||
|
|
||||||
<Prompt.Basic
|
<Prompt.Basic
|
||||||
control={deleteControl}
|
control={deleteControl}
|
||||||
|
|
|
@ -12,7 +12,7 @@ import {useDialogControl} from '#/components/Dialog'
|
||||||
import {Divider} from '#/components/Divider'
|
import {Divider} from '#/components/Divider'
|
||||||
import {BlockedByListDialog} from '#/components/dms/BlockedByListDialog'
|
import {BlockedByListDialog} from '#/components/dms/BlockedByListDialog'
|
||||||
import {LeaveConvoPrompt} from '#/components/dms/LeaveConvoPrompt'
|
import {LeaveConvoPrompt} from '#/components/dms/LeaveConvoPrompt'
|
||||||
import {ReportConversationPrompt} from '#/components/dms/ReportConversationPrompt'
|
import {ReportDialog} from '#/components/dms/ReportDialog'
|
||||||
import {Text} from '#/components/Typography'
|
import {Text} from '#/components/Typography'
|
||||||
|
|
||||||
export function MessagesListBlockedFooter({
|
export function MessagesListBlockedFooter({
|
||||||
|
@ -120,7 +120,10 @@ export function MessagesListBlockedFooter({
|
||||||
convoId={convoId}
|
convoId={convoId}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<ReportConversationPrompt control={reportControl} />
|
<ReportDialog
|
||||||
|
control={reportControl}
|
||||||
|
params={{type: 'convoAccount', did: recipient.did, convoId}}
|
||||||
|
/>
|
||||||
|
|
||||||
<BlockedByListDialog
|
<BlockedByListDialog
|
||||||
control={blockedByListControl}
|
control={blockedByListControl}
|
||||||
|
|
|
@ -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}
|
|
||||||
/>
|
|
||||||
)
|
|
||||||
}
|
|
|
@ -25,12 +25,24 @@ import {RichText} from '../RichText'
|
||||||
import {Text} from '../Typography'
|
import {Text} from '../Typography'
|
||||||
import {MessageItemMetadata} from './MessageItem'
|
import {MessageItemMetadata} from './MessageItem'
|
||||||
|
|
||||||
let MessageReportDialog = ({
|
type ReportDialogParams =
|
||||||
|
| {
|
||||||
|
type: 'convoAccount'
|
||||||
|
did: string
|
||||||
|
convoId: string
|
||||||
|
}
|
||||||
|
| {
|
||||||
|
type: 'convoMessage'
|
||||||
|
convoId: string
|
||||||
|
message: ChatBskyConvoDefs.MessageView
|
||||||
|
}
|
||||||
|
|
||||||
|
let ReportDialog = ({
|
||||||
control,
|
control,
|
||||||
message,
|
params,
|
||||||
}: {
|
}: {
|
||||||
control: Dialog.DialogControlProps
|
control: Dialog.DialogControlProps
|
||||||
message: ChatBskyConvoDefs.MessageView
|
params: ReportDialogParams
|
||||||
}): React.ReactNode => {
|
}): React.ReactNode => {
|
||||||
const {_} = useLingui()
|
const {_} = useLingui()
|
||||||
return (
|
return (
|
||||||
|
@ -39,33 +51,35 @@ let MessageReportDialog = ({
|
||||||
nativeOptions={isAndroid ? {sheet: {snapPoints: ['100%']}} : {}}>
|
nativeOptions={isAndroid ? {sheet: {snapPoints: ['100%']}} : {}}>
|
||||||
<Dialog.Handle />
|
<Dialog.Handle />
|
||||||
<Dialog.ScrollableInner label={_(msg`Report this message`)}>
|
<Dialog.ScrollableInner label={_(msg`Report this message`)}>
|
||||||
<DialogInner message={message} />
|
<DialogInner params={params} />
|
||||||
<Dialog.Close />
|
<Dialog.Close />
|
||||||
</Dialog.ScrollableInner>
|
</Dialog.ScrollableInner>
|
||||||
</Dialog.Outer>
|
</Dialog.Outer>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
MessageReportDialog = memo(MessageReportDialog)
|
ReportDialog = memo(ReportDialog)
|
||||||
export {MessageReportDialog}
|
export {ReportDialog}
|
||||||
|
|
||||||
function DialogInner({message}: {message: ChatBskyConvoDefs.MessageView}) {
|
function DialogInner({params}: {params: ReportDialogParams}) {
|
||||||
const [reportOption, setReportOption] = useState<ReportOption | null>(null)
|
const [reportOption, setReportOption] = useState<ReportOption | null>(null)
|
||||||
|
|
||||||
return reportOption ? (
|
return reportOption ? (
|
||||||
<SubmitStep
|
<SubmitStep
|
||||||
message={message}
|
params={params}
|
||||||
reportOption={reportOption}
|
reportOption={reportOption}
|
||||||
goBack={() => setReportOption(null)}
|
goBack={() => setReportOption(null)}
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<ReasonStep setReportOption={setReportOption} />
|
<ReasonStep params={params} setReportOption={setReportOption} />
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
function ReasonStep({
|
function ReasonStep({
|
||||||
setReportOption,
|
setReportOption,
|
||||||
|
params,
|
||||||
}: {
|
}: {
|
||||||
setReportOption: (reportOption: ReportOption) => void
|
setReportOption: (reportOption: ReportOption) => void
|
||||||
|
params: ReportDialogParams
|
||||||
}) {
|
}) {
|
||||||
const control = Dialog.useDialogContext()
|
const control = Dialog.useDialogContext()
|
||||||
|
|
||||||
|
@ -73,18 +87,26 @@ function ReasonStep({
|
||||||
<SelectReportOptionView
|
<SelectReportOptionView
|
||||||
labelers={[]}
|
labelers={[]}
|
||||||
goBack={control.close}
|
goBack={control.close}
|
||||||
params={{type: 'message'}}
|
params={
|
||||||
|
params.type === 'convoMessage'
|
||||||
|
? {
|
||||||
|
type: 'convoMessage',
|
||||||
|
}
|
||||||
|
: {
|
||||||
|
type: 'convoAccount',
|
||||||
|
}
|
||||||
|
}
|
||||||
onSelectReportOption={setReportOption}
|
onSelectReportOption={setReportOption}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
function SubmitStep({
|
function SubmitStep({
|
||||||
message,
|
params,
|
||||||
reportOption,
|
reportOption,
|
||||||
goBack,
|
goBack,
|
||||||
}: {
|
}: {
|
||||||
message: ChatBskyConvoDefs.MessageView
|
params: ReportDialogParams
|
||||||
reportOption: ReportOption
|
reportOption: ReportOption
|
||||||
goBack: () => void
|
goBack: () => void
|
||||||
}) {
|
}) {
|
||||||
|
@ -101,17 +123,33 @@ function SubmitStep({
|
||||||
isPending: submitting,
|
isPending: submitting,
|
||||||
} = useMutation({
|
} = useMutation({
|
||||||
mutationFn: async () => {
|
mutationFn: async () => {
|
||||||
const report = {
|
if (params.type === 'convoMessage') {
|
||||||
reasonType: reportOption.reason,
|
const {convoId, message} = params
|
||||||
subject: {
|
|
||||||
$type: 'chat.bsky.convo.defs#messageRef',
|
|
||||||
messageId: message.id,
|
|
||||||
did: message.sender!.did,
|
|
||||||
} satisfies ChatBskyConvoDefs.MessageRef,
|
|
||||||
reason: details,
|
|
||||||
} satisfies ComAtprotoModerationCreateReport.InputSchema
|
|
||||||
|
|
||||||
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: () => {
|
onSuccess: () => {
|
||||||
control.close(() => {
|
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 (
|
return (
|
||||||
<View style={a.gap_lg}>
|
<View style={a.gap_lg}>
|
||||||
<Button
|
<Button
|
||||||
|
@ -133,9 +182,7 @@ function SubmitStep({
|
||||||
</Button>
|
</Button>
|
||||||
|
|
||||||
<View style={[a.justify_center, gtMobile ? a.gap_sm : a.gap_xs]}>
|
<View style={[a.justify_center, gtMobile ? a.gap_sm : a.gap_xs]}>
|
||||||
<Text style={[a.text_2xl, a.font_bold]}>
|
<Text style={[a.text_2xl, a.font_bold]}>{copy.title}</Text>
|
||||||
<Trans>Report this message</Trans>
|
|
||||||
</Text>
|
|
||||||
<Text style={[a.text_md, t.atoms.text_contrast_medium]}>
|
<Text style={[a.text_md, t.atoms.text_contrast_medium]}>
|
||||||
<Trans>
|
<Trans>
|
||||||
Your report will be sent to the Bluesky Moderation Service
|
Your report will be sent to the Bluesky Moderation Service
|
||||||
|
@ -143,10 +190,15 @@ function SubmitStep({
|
||||||
</Text>
|
</Text>
|
||||||
</View>
|
</View>
|
||||||
|
|
||||||
<PreviewMessage message={message} />
|
{params.type === 'convoMessage' && (
|
||||||
|
<PreviewMessage message={params.message} />
|
||||||
|
)}
|
||||||
|
|
||||||
<Text style={[a.text_md, t.atoms.text_contrast_medium]}>
|
<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>
|
</Text>
|
||||||
|
|
||||||
<Divider />
|
<Divider />
|
|
@ -15,7 +15,8 @@ interface ReportOptions {
|
||||||
list: ReportOption[]
|
list: ReportOption[]
|
||||||
feedgen: ReportOption[]
|
feedgen: ReportOption[]
|
||||||
other: ReportOption[]
|
other: ReportOption[]
|
||||||
message: ReportOption[]
|
convoMessage: ReportOption[]
|
||||||
|
convoAccount: ReportOption[]
|
||||||
}
|
}
|
||||||
|
|
||||||
export function useReportOptions(): ReportOptions {
|
export function useReportOptions(): ReportOptions {
|
||||||
|
@ -73,7 +74,20 @@ export function useReportOptions(): ReportOptions {
|
||||||
},
|
},
|
||||||
...common,
|
...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,
|
reason: ComAtprotoModerationDefs.REASONSPAM,
|
||||||
title: _(msg`Spam`),
|
title: _(msg`Spam`),
|
||||||
|
|
Loading…
Reference in New Issue