start adding new report reasons
This commit is contained in:
@@ -35,7 +35,11 @@ import {useCopyForSubject} from './copy'
|
|||||||
import {initialState, reducer} from './state'
|
import {initialState, reducer} from './state'
|
||||||
import {type ReportDialogProps, type ReportSubject} from './types'
|
import {type ReportDialogProps, type ReportSubject} from './types'
|
||||||
import {parseReportSubject} from './utils/parseReportSubject'
|
import {parseReportSubject} from './utils/parseReportSubject'
|
||||||
import {type ReportOption, useReportOptions} from './utils/useReportOptions'
|
import {
|
||||||
|
type ReportOption,
|
||||||
|
TopLevelReportOption,
|
||||||
|
useReportOptions,
|
||||||
|
} from './utils/useReportOptions'
|
||||||
|
|
||||||
export {useDialogControl as useReportDialogControl} from '#/components/Dialog'
|
export {useDialogControl as useReportDialogControl} from '#/components/Dialog'
|
||||||
|
|
||||||
@@ -95,7 +99,7 @@ function Inner(props: ReportDialogProps) {
|
|||||||
} = useMyLabelersQuery({excludeNonConfigurableLabelers: true})
|
} = useMyLabelersQuery({excludeNonConfigurableLabelers: true})
|
||||||
const isLoading = useDelayedLoading(500, isLabelerLoading)
|
const isLoading = useDelayedLoading(500, isLabelerLoading)
|
||||||
const copy = useCopyForSubject(props.subject)
|
const copy = useCopyForSubject(props.subject)
|
||||||
const reportOptions = useReportOptions()
|
const {reasons, sortedReasons, getTopLevelReason} = useReportOptions()
|
||||||
const [state, dispatch] = React.useReducer(reducer, initialState)
|
const [state, dispatch] = React.useReducer(reducer, initialState)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -237,32 +241,32 @@ function Inner(props: ReportDialogProps) {
|
|||||||
</Admonition.Outer>
|
</Admonition.Outer>
|
||||||
) : (
|
) : (
|
||||||
<>
|
<>
|
||||||
{state.selectedOption ? (
|
{state.selectedTopLevelOption ? (
|
||||||
<View style={[a.flex_row, a.align_center, a.gap_md]}>
|
<View style={[a.flex_row, a.align_center, a.gap_md]}>
|
||||||
<View style={[a.flex_1]}>
|
<View style={[a.flex_1]}>
|
||||||
<OptionCard option={state.selectedOption} />
|
<TopLevelOptionCard option={state.selectedTopLevelOption} />
|
||||||
</View>
|
</View>
|
||||||
<Button
|
<Button
|
||||||
testID="report:clearOption"
|
testID="report:clearTopLevelOption"
|
||||||
label={_(msg`Change report reason`)}
|
label={_(msg`Change report reason`)}
|
||||||
size="tiny"
|
size="tiny"
|
||||||
variant="solid"
|
variant="solid"
|
||||||
color="secondary"
|
color="secondary"
|
||||||
shape="round"
|
shape="round"
|
||||||
onPress={() => {
|
onPress={() => {
|
||||||
dispatch({type: 'clearOption'})
|
dispatch({type: 'clearTopLevelOption'})
|
||||||
}}>
|
}}>
|
||||||
<ButtonIcon icon={X} />
|
<ButtonIcon icon={X} />
|
||||||
</Button>
|
</Button>
|
||||||
</View>
|
</View>
|
||||||
) : (
|
) : (
|
||||||
<View style={[a.gap_sm]}>
|
<View style={[a.gap_sm]}>
|
||||||
{reportOptions[props.subject.type].map(o => (
|
{sortedReasons.map(o => (
|
||||||
<OptionCard
|
<TopLevelOptionCard
|
||||||
key={o.reason}
|
key={o.key}
|
||||||
option={o}
|
option={o}
|
||||||
onSelect={() => {
|
onSelect={() => {
|
||||||
dispatch({type: 'selectOption', option: o})
|
dispatch({type: 'selectTopLevelOption', option: o})
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
@@ -307,6 +311,82 @@ function Inner(props: ReportDialogProps) {
|
|||||||
)}
|
)}
|
||||||
</StepOuter>
|
</StepOuter>
|
||||||
|
|
||||||
|
<StepOuter>
|
||||||
|
<StepTitle
|
||||||
|
index={2}
|
||||||
|
title={_(msg`Select a sub-category`)}
|
||||||
|
activeIndex1={state.activeStepIndex1}
|
||||||
|
/>
|
||||||
|
{state.selectedOption ? (
|
||||||
|
<View style={[a.flex_row, a.align_center, a.gap_md]}>
|
||||||
|
<View style={[a.flex_1]}>
|
||||||
|
<OptionCard option={state.selectedOption} />
|
||||||
|
</View>
|
||||||
|
<Button
|
||||||
|
testID="report:clearTopLevelOption"
|
||||||
|
label={_(msg`Change report reason`)}
|
||||||
|
size="tiny"
|
||||||
|
variant="solid"
|
||||||
|
color="secondary"
|
||||||
|
shape="round"
|
||||||
|
onPress={() => {
|
||||||
|
dispatch({type: 'clearTopLevelOption'})
|
||||||
|
}}>
|
||||||
|
<ButtonIcon icon={X} />
|
||||||
|
</Button>
|
||||||
|
</View>
|
||||||
|
) : state.selectedTopLevelOption ? (
|
||||||
|
<View style={[a.gap_sm]}>
|
||||||
|
{getTopLevelReason(state.selectedTopLevelOption.key).options.map(
|
||||||
|
o => (
|
||||||
|
<OptionCard
|
||||||
|
key={o.reason}
|
||||||
|
option={o}
|
||||||
|
onSelect={() => {
|
||||||
|
dispatch({type: 'selectOption', option: o})
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
),
|
||||||
|
)}
|
||||||
|
|
||||||
|
{['post', 'account'].includes(props.subject.type) && (
|
||||||
|
<Link
|
||||||
|
to={SUPPORT_PAGE}
|
||||||
|
label={_(
|
||||||
|
msg`Need to report a copyright violation, legal request, or regulatory compliance issue?`,
|
||||||
|
)}>
|
||||||
|
{({hovered, pressed}) => (
|
||||||
|
<View
|
||||||
|
style={[
|
||||||
|
a.flex_row,
|
||||||
|
a.align_center,
|
||||||
|
a.w_full,
|
||||||
|
a.px_md,
|
||||||
|
a.py_sm,
|
||||||
|
a.rounded_sm,
|
||||||
|
a.border,
|
||||||
|
hovered || pressed
|
||||||
|
? [t.atoms.border_contrast_high]
|
||||||
|
: [t.atoms.border_contrast_low],
|
||||||
|
]}>
|
||||||
|
<Text style={[a.flex_1, a.italic, a.leading_snug]}>
|
||||||
|
<Trans>
|
||||||
|
Need to report a copyright violation, legal request,
|
||||||
|
or regulatory compliance issue?
|
||||||
|
</Trans>
|
||||||
|
</Text>
|
||||||
|
<SquareArrowTopRight
|
||||||
|
size="sm"
|
||||||
|
fill={t.atoms.text.color}
|
||||||
|
/>
|
||||||
|
</View>
|
||||||
|
)}
|
||||||
|
</Link>
|
||||||
|
)}
|
||||||
|
</View>
|
||||||
|
) : null}
|
||||||
|
</StepOuter>
|
||||||
|
|
||||||
<StepOuter>
|
<StepOuter>
|
||||||
<StepTitle
|
<StepTitle
|
||||||
index={2}
|
index={2}
|
||||||
@@ -569,12 +649,12 @@ function StepTitle({
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
function OptionCard({
|
function TopLevelOptionCard({
|
||||||
option,
|
option,
|
||||||
onSelect,
|
onSelect,
|
||||||
}: {
|
}: {
|
||||||
option: ReportOption
|
option: TopLevelReportOption
|
||||||
onSelect?: (option: ReportOption) => void
|
onSelect?: (option: TopLevelReportOption) => void
|
||||||
}) {
|
}) {
|
||||||
const t = useTheme()
|
const t = useTheme()
|
||||||
const {_} = useLingui()
|
const {_} = useLingui()
|
||||||
@@ -584,7 +664,7 @@ function OptionCard({
|
|||||||
}, [onSelect, option])
|
}, [onSelect, option])
|
||||||
return (
|
return (
|
||||||
<Button
|
<Button
|
||||||
testID={`report:option:${option.reason}`}
|
testID={`report:option:${option.title}`}
|
||||||
label={_(msg`Create report for ${option.title}`)}
|
label={_(msg`Create report for ${option.title}`)}
|
||||||
onPress={onPress}
|
onPress={onPress}
|
||||||
disabled={!onSelect}>
|
disabled={!onSelect}>
|
||||||
@@ -614,6 +694,47 @@ function OptionCard({
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function OptionCard({
|
||||||
|
option,
|
||||||
|
onSelect,
|
||||||
|
}: {
|
||||||
|
option: ReportOption
|
||||||
|
onSelect?: (option: ReportOption) => void
|
||||||
|
}) {
|
||||||
|
const t = useTheme()
|
||||||
|
const {_} = useLingui()
|
||||||
|
const gutters = useGutters(['compact'])
|
||||||
|
const onPress = React.useCallback(() => {
|
||||||
|
onSelect?.(option)
|
||||||
|
}, [onSelect, option])
|
||||||
|
return (
|
||||||
|
<Button
|
||||||
|
testID={`report:option:${option.title}`}
|
||||||
|
label={_(msg`Create report for ${option.title}`)}
|
||||||
|
onPress={onPress}
|
||||||
|
disabled={!onSelect}>
|
||||||
|
{({hovered, pressed}) => (
|
||||||
|
<View
|
||||||
|
style={[
|
||||||
|
a.w_full,
|
||||||
|
gutters,
|
||||||
|
a.py_sm,
|
||||||
|
a.rounded_sm,
|
||||||
|
a.border,
|
||||||
|
t.atoms.bg_contrast_25,
|
||||||
|
hovered || pressed
|
||||||
|
? [t.atoms.border_contrast_high]
|
||||||
|
: [t.atoms.border_contrast_low],
|
||||||
|
]}>
|
||||||
|
<Text style={[a.text_md, a.font_semi_bold, a.leading_snug]}>
|
||||||
|
{option.title}
|
||||||
|
</Text>
|
||||||
|
</View>
|
||||||
|
)}
|
||||||
|
</Button>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
function OptionCardSkeleton() {
|
function OptionCardSkeleton() {
|
||||||
const t = useTheme()
|
const t = useTheme()
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
import {type AppBskyLabelerDefs, ComAtprotoModerationDefs} from '@atproto/api'
|
import {type AppBskyLabelerDefs, ComAtprotoModerationDefs} from '@atproto/api'
|
||||||
|
|
||||||
import {type ReportOption} from './utils/useReportOptions'
|
import {TopLevelReportOption, type ReportOption} from './utils/useReportOptions'
|
||||||
|
|
||||||
export type ReportState = {
|
export type ReportState = {
|
||||||
|
selectedTopLevelOption?: TopLevelReportOption
|
||||||
selectedOption?: ReportOption
|
selectedOption?: ReportOption
|
||||||
selectedLabeler?: AppBskyLabelerDefs.LabelerViewDetailed
|
selectedLabeler?: AppBskyLabelerDefs.LabelerViewDetailed
|
||||||
details?: string
|
details?: string
|
||||||
@@ -12,6 +13,13 @@ export type ReportState = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export type ReportAction =
|
export type ReportAction =
|
||||||
|
| {
|
||||||
|
type: 'selectTopLevelOption'
|
||||||
|
option: TopLevelReportOption
|
||||||
|
}
|
||||||
|
| {
|
||||||
|
type: 'clearTopLevelOption'
|
||||||
|
}
|
||||||
| {
|
| {
|
||||||
type: 'selectOption'
|
type: 'selectOption'
|
||||||
option: ReportOption
|
option: ReportOption
|
||||||
@@ -42,6 +50,7 @@ export type ReportAction =
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const initialState: ReportState = {
|
export const initialState: ReportState = {
|
||||||
|
selectedTopLevelOption: undefined,
|
||||||
selectedOption: undefined,
|
selectedOption: undefined,
|
||||||
selectedLabeler: undefined,
|
selectedLabeler: undefined,
|
||||||
details: undefined,
|
details: undefined,
|
||||||
@@ -51,11 +60,29 @@ export const initialState: ReportState = {
|
|||||||
|
|
||||||
export function reducer(state: ReportState, action: ReportAction): ReportState {
|
export function reducer(state: ReportState, action: ReportAction): ReportState {
|
||||||
switch (action.type) {
|
switch (action.type) {
|
||||||
|
case 'selectTopLevelOption':
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
selectedTopLevelOption: action.option,
|
||||||
|
activeStepIndex1: 2,
|
||||||
|
detailsOpen: !!state.details,
|
||||||
|
}
|
||||||
|
case 'clearTopLevelOption':
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
selectedTopLevelOption: undefined,
|
||||||
|
selectedOption: undefined,
|
||||||
|
selectedLabeler: undefined,
|
||||||
|
activeStepIndex1: 1,
|
||||||
|
detailsOpen:
|
||||||
|
!!state.details ||
|
||||||
|
state.selectedOption?.reason === ComAtprotoModerationDefs.REASONOTHER,
|
||||||
|
}
|
||||||
case 'selectOption':
|
case 'selectOption':
|
||||||
return {
|
return {
|
||||||
...state,
|
...state,
|
||||||
selectedOption: action.option,
|
selectedOption: action.option,
|
||||||
activeStepIndex1: 2,
|
activeStepIndex1: 3,
|
||||||
detailsOpen:
|
detailsOpen:
|
||||||
!!state.details ||
|
!!state.details ||
|
||||||
action.option.reason === ComAtprotoModerationDefs.REASONOTHER,
|
action.option.reason === ComAtprotoModerationDefs.REASONOTHER,
|
||||||
@@ -65,7 +92,7 @@ export function reducer(state: ReportState, action: ReportAction): ReportState {
|
|||||||
...state,
|
...state,
|
||||||
selectedOption: undefined,
|
selectedOption: undefined,
|
||||||
selectedLabeler: undefined,
|
selectedLabeler: undefined,
|
||||||
activeStepIndex1: 1,
|
activeStepIndex1: 2,
|
||||||
detailsOpen:
|
detailsOpen:
|
||||||
!!state.details ||
|
!!state.details ||
|
||||||
state.selectedOption?.reason === ComAtprotoModerationDefs.REASONOTHER,
|
state.selectedOption?.reason === ComAtprotoModerationDefs.REASONOTHER,
|
||||||
@@ -74,13 +101,13 @@ export function reducer(state: ReportState, action: ReportAction): ReportState {
|
|||||||
return {
|
return {
|
||||||
...state,
|
...state,
|
||||||
selectedLabeler: action.labeler,
|
selectedLabeler: action.labeler,
|
||||||
activeStepIndex1: 3,
|
activeStepIndex1: 4,
|
||||||
}
|
}
|
||||||
case 'clearLabeler':
|
case 'clearLabeler':
|
||||||
return {
|
return {
|
||||||
...state,
|
...state,
|
||||||
selectedLabeler: undefined,
|
selectedLabeler: undefined,
|
||||||
activeStepIndex1: 2,
|
activeStepIndex1: 3,
|
||||||
detailsOpen:
|
detailsOpen:
|
||||||
!!state.details ||
|
!!state.details ||
|
||||||
state.selectedOption?.reason === ComAtprotoModerationDefs.REASONOTHER,
|
state.selectedOption?.reason === ComAtprotoModerationDefs.REASONOTHER,
|
||||||
|
|||||||
@@ -1,121 +1,307 @@
|
|||||||
import {useMemo} from 'react'
|
|
||||||
import {ComAtprotoModerationDefs} from '@atproto/api'
|
|
||||||
import {msg} from '@lingui/macro'
|
import {msg} from '@lingui/macro'
|
||||||
import {useLingui} from '@lingui/react'
|
import {useLingui} from '@lingui/react'
|
||||||
|
|
||||||
export interface ReportOption {
|
export type TopLevelReason =
|
||||||
reason: string
|
| 'childSafety'
|
||||||
|
| 'violencePhysicalHarm'
|
||||||
|
| 'sexualAdultContent'
|
||||||
|
| 'harassmentHate'
|
||||||
|
| 'misleading'
|
||||||
|
| 'ruleBreaking'
|
||||||
|
| 'civicIntegrity'
|
||||||
|
| 'other'
|
||||||
|
|
||||||
|
export interface TopLevelReportOption {
|
||||||
|
key: TopLevelReason
|
||||||
title: string
|
title: string
|
||||||
description: string
|
description: string
|
||||||
|
options: ReportOption[]
|
||||||
|
sort: number
|
||||||
|
isOther?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
interface ReportOptions {
|
export interface TopLevelReportOptions {
|
||||||
account: ReportOption[]
|
childSafety: TopLevelReportOption
|
||||||
post: ReportOption[]
|
violencePhysicalHarm: TopLevelReportOption
|
||||||
list: ReportOption[]
|
sexualAdultContent: TopLevelReportOption
|
||||||
starterPack: ReportOption[]
|
harassmentHate: TopLevelReportOption
|
||||||
feed: ReportOption[]
|
misleading: TopLevelReportOption
|
||||||
chatMessage: ReportOption[]
|
ruleBreaking: TopLevelReportOption
|
||||||
|
civicIntegrity: TopLevelReportOption
|
||||||
|
other: TopLevelReportOption
|
||||||
}
|
}
|
||||||
|
|
||||||
export function useReportOptions(): ReportOptions {
|
export interface ReportOption {
|
||||||
|
title: string
|
||||||
|
reason: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export function useReportOptions() {
|
||||||
const {_} = useLingui()
|
const {_} = useLingui()
|
||||||
|
|
||||||
return useMemo(() => {
|
const reasons = {
|
||||||
const other = {
|
childSafety: {
|
||||||
reason: ComAtprotoModerationDefs.REASONOTHER,
|
key: 'childSafety',
|
||||||
|
title: _(msg`Child Safety`),
|
||||||
|
description: _(
|
||||||
|
msg`Content harming or endangering minors' safety and wellbeing`,
|
||||||
|
),
|
||||||
|
sort: 1,
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
title: _(msg`Child Sexual Abuse Material (CSAM)`),
|
||||||
|
reason: '#reasonChildSafetyCSAM',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: _(msg`Grooming or Predatory Behavior`),
|
||||||
|
reason: '#reasonChildSafetyGroom',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: _(msg`Minor Privacy Violation`),
|
||||||
|
reason: '#reasonChildSafetyMinorPrivacy',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: _(msg`Child Endangerment`),
|
||||||
|
reason: '#reasonChildSafetyEndangerment',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: _(msg`Minor Harassment or Bullying`),
|
||||||
|
reason: '#reasonChildSafetyHarassment',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: _(msg`Promotion of Child Exploitation`),
|
||||||
|
reason: '#reasonChildSafetyPromotion',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: _(msg`Other Child Safety`),
|
||||||
|
reason: '#reasonChildSafetyOther',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
violencePhysicalHarm: {
|
||||||
|
key: 'violencePhysicalHarm',
|
||||||
|
title: _(msg`Violence of Physical Harm`),
|
||||||
|
sort: 2,
|
||||||
|
description: _(msg`Threats, calls for violence, or graphic content`),
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
title: _(msg`Animal Welfare`),
|
||||||
|
reason: '#reasonViolenceAnimalWelfare',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: _(msg`Threats or Inticement`),
|
||||||
|
reason: '#reasonViolenceThreats',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: _(msg`Graphic Violent Content`),
|
||||||
|
reason: '#reasonViolenceGraphicContent',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: _(msg`Self Harm`),
|
||||||
|
reason: '#reasonViolenceSelfHarm',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: _(msg`Glorification of Violence`),
|
||||||
|
reason: '#reasonViolenceGlorification',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: _(msg`Extermist Content`),
|
||||||
|
reason: '#reasonViolenceExtermistContent',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: _(msg`Human Trafficking`),
|
||||||
|
reason: '#reasonViolenceTrafficking',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: _(msg`Other Violent Content`),
|
||||||
|
reason: '#reasonViolenceOther',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
sexualAdultContent: {
|
||||||
|
key: 'sexualAdultContent',
|
||||||
|
title: _(msg`Sexaul and Adult Content`),
|
||||||
|
description: _(msg`Adult, child or animal sexual abuse`),
|
||||||
|
sort: 3,
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
title: _(msg`Adult Sexual Abuse Content`),
|
||||||
|
reason: '#reasonSexualAbuseContent',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: _(msg`Non-Consensual Intimate Imagery`),
|
||||||
|
reason: '#reasonSexualNCII',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: _(msg`SexualSextortion`),
|
||||||
|
reason: '#reasonSexualSextortion',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: _(msg`Deepfake Adult Content`),
|
||||||
|
reason: '#reasonSexualDeepfake',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: _(msg`Animal Sexual Abuse`),
|
||||||
|
reason: '#reasonSexualAnimal',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: _(msg`Unlabelled Adult Content`),
|
||||||
|
reason: '#reasonSexualUnlabelled',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: _(msg`Other Sexual Violence Content`),
|
||||||
|
reason: '#reasonSexualOther',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
harassmentHate: {
|
||||||
|
key: 'harassmentHate',
|
||||||
|
title: _(msg`Harassment or Hate`),
|
||||||
|
description: _(
|
||||||
|
msg`Targeted attacks, hate speech, or organized harassment`,
|
||||||
|
),
|
||||||
|
sort: 4,
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
title: _(msg`Trolling`),
|
||||||
|
reason: '#reasonHarassmentTroll',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: _(msg`Targeted Harassment`),
|
||||||
|
reason: '#reasonHarassmentTargeted',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: _(msg`Hate Speech`),
|
||||||
|
reason: '#reasonHarassmentHateSpeech',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: _(msg`Doxxing`),
|
||||||
|
reason: '#reasonHarassmentDoxxing',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: _(msg`Other Harassing or Hateful Content`),
|
||||||
|
reason: '#reasonHarassmentOther',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
misleading: {
|
||||||
|
key: 'misleading',
|
||||||
|
title: _(msg`Misleading`),
|
||||||
|
description: _(msg`Spam, scams, false info or impersonation`),
|
||||||
|
sort: 5,
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
title: _(msg`Fake Account or Bot`),
|
||||||
|
reason: '#reasonMisleadingBot',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: _(msg`Impersonation`),
|
||||||
|
reason: '#reasonMisleadingImpersonation',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: _(msg`Spam`),
|
||||||
|
reason: '#reasonMisleadingSpam',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: _(msg`Scam`),
|
||||||
|
reason: '#reasonMisleadingScam',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: _(msg`Unlabelled GenAI or Synthetic Content`),
|
||||||
|
reason: '#reasonMisleadingSyntheticContent',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: _(msg`Harmful False Claims`),
|
||||||
|
reason: '#reasonMisleadingMisinformation',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: _(msg`Other Misleading Content`),
|
||||||
|
reason: '#reasonMisleadingOther',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
ruleBreaking: {
|
||||||
|
key: 'ruleBreaking',
|
||||||
|
title: _(msg`Breaking Network Rules`),
|
||||||
|
description: _(msg`Hacking, stolen content or prohibited sales`),
|
||||||
|
sort: 6,
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
title: _(msg`Hacking or System Attacks`),
|
||||||
|
reason: '#reasonRuleSiteSecurity',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: _(msg`Stolen Content`),
|
||||||
|
reason: '#reasonRuleStolenContent',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: _(msg`Promoting or Selling Prohibited Items of Services`),
|
||||||
|
reason: '#reasonRuleProhibitedSales',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: _(msg`Banned User Returning`),
|
||||||
|
reason: '#reasonRuleBanEvasion',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: _(msg`Other`),
|
||||||
|
reason: '#reasonRuleOther',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
civicIntegrity: {
|
||||||
|
key: 'civicIntegrity',
|
||||||
|
title: _(msg`Civic Integrity`),
|
||||||
|
description: _(
|
||||||
|
msg`Electoral interference or political process violations`,
|
||||||
|
),
|
||||||
|
sort: 7,
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
title: _(msg`Electoral Process Violations`),
|
||||||
|
reason: '#reasonCivicElectoralProcess',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: _(msg`Disclosure and Transparency Violations`),
|
||||||
|
reason: '#reasonCivicDisclosure',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: _(msg`Voter Intimidation or Interference`),
|
||||||
|
reason: '#reasonCivicInterference',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: _(msg`Election Misinformation`),
|
||||||
|
reason: '#reasonCivicMisinformation',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: _(msg`Impersation of Electoral Officials/Entities`),
|
||||||
|
reason: '#reasonCivicImpersonation',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: _(msg`Other`),
|
||||||
|
reason: '#reasonCivicOther',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
other: {
|
||||||
|
key: 'other',
|
||||||
title: _(msg`Other`),
|
title: _(msg`Other`),
|
||||||
description: _(msg`An issue not included in these options`),
|
description: _(msg`An issue not included in these options`),
|
||||||
}
|
sort: 8,
|
||||||
const common = [
|
options: [
|
||||||
{
|
|
||||||
reason: ComAtprotoModerationDefs.REASONRUDE,
|
|
||||||
title: _(msg`Anti-Social Behavior`),
|
|
||||||
description: _(msg`Harassment, trolling, or intolerance`),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
reason: ComAtprotoModerationDefs.REASONVIOLATION,
|
|
||||||
title: _(msg`Illegal and Urgent`),
|
|
||||||
description: _(msg`Glaring violations of law or terms of service`),
|
|
||||||
},
|
|
||||||
other,
|
|
||||||
]
|
|
||||||
return {
|
|
||||||
account: [
|
|
||||||
{
|
{
|
||||||
reason: ComAtprotoModerationDefs.REASONMISLEADING,
|
title: _(msg`Other`),
|
||||||
title: _(msg`Misleading Account`),
|
reason: '#reasonOther',
|
||||||
description: _(
|
|
||||||
msg`Impersonation or false claims about identity or affiliation`,
|
|
||||||
),
|
|
||||||
},
|
},
|
||||||
{
|
|
||||||
reason: ComAtprotoModerationDefs.REASONSPAM,
|
|
||||||
title: _(msg`Frequently Posts Unwanted Content`),
|
|
||||||
description: _(msg`Spam; excessive mentions or replies`),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
reason: ComAtprotoModerationDefs.REASONVIOLATION,
|
|
||||||
title: _(msg`Name or Description Violates Community Standards`),
|
|
||||||
description: _(msg`Terms used violate community standards`),
|
|
||||||
},
|
|
||||||
other,
|
|
||||||
],
|
],
|
||||||
post: [
|
isOther: true,
|
||||||
{
|
},
|
||||||
reason: ComAtprotoModerationDefs.REASONMISLEADING,
|
}
|
||||||
title: _(msg`Misleading Post`),
|
|
||||||
description: _(msg`Impersonation, misinformation, or false claims`),
|
const sortedReasons = Object.values(reasons).sort((a, b) => a.sort - b.sort)
|
||||||
},
|
|
||||||
{
|
const getTopLevelReason = (reasonName: TopLevelReason) => {
|
||||||
reason: ComAtprotoModerationDefs.REASONSPAM,
|
return reasons[reasonName]
|
||||||
title: _(msg`Spam`),
|
}
|
||||||
description: _(msg`Excessive mentions or replies`),
|
|
||||||
},
|
return {reasons, sortedReasons, getTopLevelReason}
|
||||||
{
|
|
||||||
reason: ComAtprotoModerationDefs.REASONSEXUAL,
|
|
||||||
title: _(msg`Unwanted Sexual Content`),
|
|
||||||
description: _(msg`Nudity or adult content not labeled as such`),
|
|
||||||
},
|
|
||||||
...common,
|
|
||||||
],
|
|
||||||
chatMessage: [
|
|
||||||
{
|
|
||||||
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,
|
|
||||||
],
|
|
||||||
list: [
|
|
||||||
{
|
|
||||||
reason: ComAtprotoModerationDefs.REASONVIOLATION,
|
|
||||||
title: _(msg`Name or Description Violates Community Standards`),
|
|
||||||
description: _(msg`Terms used violate community standards`),
|
|
||||||
},
|
|
||||||
...common,
|
|
||||||
],
|
|
||||||
starterPack: [
|
|
||||||
{
|
|
||||||
reason: ComAtprotoModerationDefs.REASONVIOLATION,
|
|
||||||
title: _(msg`Name or Description Violates Community Standards`),
|
|
||||||
description: _(msg`Terms used violate community standards`),
|
|
||||||
},
|
|
||||||
...common,
|
|
||||||
],
|
|
||||||
feed: [
|
|
||||||
{
|
|
||||||
reason: ComAtprotoModerationDefs.REASONVIOLATION,
|
|
||||||
title: _(msg`Name or Description Violates Community Standards`),
|
|
||||||
description: _(msg`Terms used violate community standards`),
|
|
||||||
},
|
|
||||||
...common,
|
|
||||||
],
|
|
||||||
}
|
|
||||||
}, [_])
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user