This commit is contained in:
Hailey
2025-09-24 20:42:25 -07:00
committed by Eric Bailey
parent 9d1219bab0
commit 11d4747b72
3 changed files with 59 additions and 91 deletions
@@ -37,7 +37,7 @@ import {type ReportDialogProps, type ReportSubject} from './types'
import {parseReportSubject} from './utils/parseReportSubject'
import {
type ReportOption,
TopLevelReportOption,
type ReportOptionCategory,
useReportOptions,
} from './utils/useReportOptions'
@@ -99,7 +99,7 @@ function Inner(props: ReportDialogProps) {
} = useMyLabelersQuery({excludeNonConfigurableLabelers: true})
const isLoading = useDelayedLoading(500, isLabelerLoading)
const copy = useCopyForSubject(props.subject)
const {reasons, sortedReasons, getTopLevelReason} = useReportOptions()
const {sortedCategories, getCategory} = useReportOptions()
const [state, dispatch] = React.useReducer(reducer, initialState)
/**
@@ -241,32 +241,32 @@ function Inner(props: ReportDialogProps) {
</Admonition.Outer>
) : (
<>
{state.selectedTopLevelOption ? (
{state.selectedCategory ? (
<View style={[a.flex_row, a.align_center, a.gap_md]}>
<View style={[a.flex_1]}>
<TopLevelOptionCard option={state.selectedTopLevelOption} />
<CategoryCard option={state.selectedCategory} />
</View>
<Button
testID="report:clearTopLevelOption"
testID="report:clearCategory"
label={_(msg`Change report reason`)}
size="tiny"
variant="solid"
color="secondary"
shape="round"
onPress={() => {
dispatch({type: 'clearTopLevelOption'})
dispatch({type: 'clearCategory'})
}}>
<ButtonIcon icon={X} />
</Button>
</View>
) : (
<View style={[a.gap_sm]}>
{sortedReasons.map(o => (
<TopLevelOptionCard
{sortedCategories.map(o => (
<CategoryCard
key={o.key}
option={o}
onSelect={() => {
dispatch({type: 'selectTopLevelOption', option: o})
dispatch({type: 'selectCategory', option: o})
}}
/>
))}
@@ -314,7 +314,7 @@ function Inner(props: ReportDialogProps) {
<StepOuter>
<StepTitle
index={2}
title={_(msg`Select a sub-category`)}
title={_(msg`Select a reason`)}
activeIndex1={state.activeStepIndex1}
/>
{state.selectedOption ? (
@@ -323,77 +323,40 @@ function Inner(props: ReportDialogProps) {
<OptionCard option={state.selectedOption} />
</View>
<Button
testID="report:clearTopLevelOption"
testID="report:clearReportOption"
label={_(msg`Change report reason`)}
size="tiny"
variant="solid"
color="secondary"
shape="round"
onPress={() => {
dispatch({type: 'clearTopLevelOption'})
dispatch({type: 'clearCategory'})
}}>
<ButtonIcon icon={X} />
</Button>
</View>
) : state.selectedTopLevelOption ? (
) : state.selectedCategory ? (
<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>
)}
{getCategory(state.selectedCategory.key).options.map(o => (
<OptionCard
key={o.reason}
option={o}
onSelect={() => {
dispatch({type: 'selectOption', option: o})
}}
/>
))}
</View>
) : null}
</StepOuter>
<StepOuter>
<StepTitle
index={2}
index={3}
title={_(msg`Select moderation service`)}
activeIndex1={state.activeStepIndex1}
/>
{state.activeStepIndex1 >= 2 && (
{state.activeStepIndex1 >= 3 && (
<>
{state.selectedLabeler ? (
<>
@@ -466,11 +429,11 @@ function Inner(props: ReportDialogProps) {
<StepOuter>
<StepTitle
index={3}
index={4}
title={_(msg`Submit report`)}
activeIndex1={state.activeStepIndex1}
/>
{state.activeStepIndex1 === 3 && (
{state.activeStepIndex1 === 4 && (
<>
<View style={[a.pb_xs, a.gap_xs]}>
<Text style={[a.leading_snug, a.pb_xs]}>
@@ -649,12 +612,12 @@ function StepTitle({
)
}
function TopLevelOptionCard({
function CategoryCard({
option,
onSelect,
}: {
option: TopLevelReportOption
onSelect?: (option: TopLevelReportOption) => void
option: ReportOptionCategory
onSelect?: (option: ReportOptionCategory) => void
}) {
const t = useTheme()
const {_} = useLingui()
+13 -10
View File
@@ -1,9 +1,12 @@
import {type AppBskyLabelerDefs, ComAtprotoModerationDefs} from '@atproto/api'
import {TopLevelReportOption, type ReportOption} from './utils/useReportOptions'
import {
type ReportOption,
type ReportOptionCategory,
} from './utils/useReportOptions'
export type ReportState = {
selectedTopLevelOption?: TopLevelReportOption
selectedCategory?: ReportOptionCategory
selectedOption?: ReportOption
selectedLabeler?: AppBskyLabelerDefs.LabelerViewDetailed
details?: string
@@ -14,11 +17,11 @@ export type ReportState = {
export type ReportAction =
| {
type: 'selectTopLevelOption'
option: TopLevelReportOption
type: 'selectCategory'
option: ReportOptionCategory
}
| {
type: 'clearTopLevelOption'
type: 'clearCategory'
}
| {
type: 'selectOption'
@@ -50,7 +53,7 @@ export type ReportAction =
}
export const initialState: ReportState = {
selectedTopLevelOption: undefined,
selectedCategory: undefined,
selectedOption: undefined,
selectedLabeler: undefined,
details: undefined,
@@ -60,17 +63,17 @@ export const initialState: ReportState = {
export function reducer(state: ReportState, action: ReportAction): ReportState {
switch (action.type) {
case 'selectTopLevelOption':
case 'selectCategory':
return {
...state,
selectedTopLevelOption: action.option,
selectedCategory: action.option,
activeStepIndex1: 2,
detailsOpen: !!state.details,
}
case 'clearTopLevelOption':
case 'clearCategory':
return {
...state,
selectedTopLevelOption: undefined,
selectedCategory: undefined,
selectedOption: undefined,
selectedLabeler: undefined,
activeStepIndex1: 1,
@@ -11,7 +11,7 @@ export type TopLevelReason =
| 'civicIntegrity'
| 'other'
export interface TopLevelReportOption {
export interface ReportOptionCategory {
key: TopLevelReason
title: string
description: string
@@ -20,15 +20,15 @@ export interface TopLevelReportOption {
isOther?: boolean
}
export interface TopLevelReportOptions {
childSafety: TopLevelReportOption
violencePhysicalHarm: TopLevelReportOption
sexualAdultContent: TopLevelReportOption
harassmentHate: TopLevelReportOption
misleading: TopLevelReportOption
ruleBreaking: TopLevelReportOption
civicIntegrity: TopLevelReportOption
other: TopLevelReportOption
export interface ReportOptionCategories {
childSafety: ReportOptionCategory
violencePhysicalHarm: ReportOptionCategory
sexualAdultContent: ReportOptionCategory
harassmentHate: ReportOptionCategory
misleading: ReportOptionCategory
ruleBreaking: ReportOptionCategory
civicIntegrity: ReportOptionCategory
other: ReportOptionCategory
}
export interface ReportOption {
@@ -39,7 +39,7 @@ export interface ReportOption {
export function useReportOptions() {
const {_} = useLingui()
const reasons = {
const categories = {
childSafety: {
key: 'childSafety',
title: _(msg`Child Safety`),
@@ -297,11 +297,13 @@ export function useReportOptions() {
},
}
const sortedReasons = Object.values(reasons).sort((a, b) => a.sort - b.sort)
const sortedCategories = (
Object.values(categories) as ReportOptionCategory[]
).sort((a, b) => a.sort - b.sort)
const getTopLevelReason = (reasonName: TopLevelReason) => {
return reasons[reasonName]
const getCategory = (reasonName: TopLevelReason) => {
return categories[reasonName]
}
return {reasons, sortedReasons, getTopLevelReason}
return {categories, sortedCategories, getCategory}
}