Add additional questions before routing to TIDA intake form
This commit is contained in:
@@ -7,7 +7,7 @@ import {type ParsedReportSubject} from '#/components/moderation/ReportDialog/typ
|
|||||||
|
|
||||||
export const DMCA_LINK = 'https://bsky.social/about/support/copyright'
|
export const DMCA_LINK = 'https://bsky.social/about/support/copyright'
|
||||||
export const SUPPORT_PAGE = 'https://bsky.social/about/support'
|
export const SUPPORT_PAGE = 'https://bsky.social/about/support'
|
||||||
export const TAKE_IT_DOWN_ACT_FORM = 'https://forms.bsky.app/f/ncii'
|
export const NCII_FORM = 'https://forms.bsky.app/f/ncii'
|
||||||
|
|
||||||
export const NEW_TO_OLD_REASON_MAPPING: Record<string, string> = {}
|
export const NEW_TO_OLD_REASON_MAPPING: Record<string, string> = {}
|
||||||
|
|
||||||
|
|||||||
@@ -40,12 +40,18 @@ import {useSubmitReportMutation} from './action'
|
|||||||
import {
|
import {
|
||||||
BSKY_LABELER_ONLY_REPORT_REASONS,
|
BSKY_LABELER_ONLY_REPORT_REASONS,
|
||||||
BSKY_LABELER_ONLY_SUBJECT_TYPES,
|
BSKY_LABELER_ONLY_SUBJECT_TYPES,
|
||||||
|
NCII_FORM,
|
||||||
NEW_TO_OLD_REASONS_MAP,
|
NEW_TO_OLD_REASONS_MAP,
|
||||||
SUPPORT_PAGE,
|
SUPPORT_PAGE,
|
||||||
TAKE_IT_DOWN_ACT_FORM,
|
|
||||||
} from './const'
|
} from './const'
|
||||||
import {useCopyForSubject} from './copy'
|
import {useCopyForSubject} from './copy'
|
||||||
import {initialState, reducer} from './state'
|
import {
|
||||||
|
getNciiQualificationOutcome,
|
||||||
|
initialState,
|
||||||
|
type NciiQualification as NciiQualificationState,
|
||||||
|
reducer,
|
||||||
|
type ReportAction,
|
||||||
|
} 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 {
|
import {
|
||||||
@@ -382,23 +388,28 @@ function Inner(props: ReportDialogProps) {
|
|||||||
activeIndex1={state.activeStepIndex1}
|
activeIndex1={state.activeStepIndex1}
|
||||||
/>
|
/>
|
||||||
{state.selectedOption ? (
|
{state.selectedOption ? (
|
||||||
<View style={[a.flex_row, a.align_center, a.gap_md]}>
|
<>
|
||||||
<View style={[a.flex_1]}>
|
<View style={[a.flex_row, a.align_center, a.gap_md]}>
|
||||||
<OptionCard option={state.selectedOption} />
|
<View style={[a.flex_1]}>
|
||||||
|
<OptionCard option={state.selectedOption} />
|
||||||
|
</View>
|
||||||
|
<Button
|
||||||
|
testID="report:clearReportOption"
|
||||||
|
label={l`Change report reason`}
|
||||||
|
size="tiny"
|
||||||
|
variant="solid"
|
||||||
|
color="secondary"
|
||||||
|
shape="round"
|
||||||
|
onPress={() => {
|
||||||
|
dispatch({type: 'clearOption'})
|
||||||
|
}}>
|
||||||
|
<ButtonIcon icon={X} />
|
||||||
|
</Button>
|
||||||
</View>
|
</View>
|
||||||
<Button
|
{state.ncii && (
|
||||||
testID="report:clearReportOption"
|
<NciiQualification ncii={state.ncii} dispatch={dispatch} />
|
||||||
label={l`Change report reason`}
|
)}
|
||||||
size="tiny"
|
</>
|
||||||
variant="solid"
|
|
||||||
color="secondary"
|
|
||||||
shape="round"
|
|
||||||
onPress={() => {
|
|
||||||
dispatch({type: 'clearOption'})
|
|
||||||
}}>
|
|
||||||
<ButtonIcon icon={X} />
|
|
||||||
</Button>
|
|
||||||
</View>
|
|
||||||
) : state.selectedCategory ? (
|
) : state.selectedCategory ? (
|
||||||
<View style={[a.gap_sm]}>
|
<View style={[a.gap_sm]}>
|
||||||
{getCategory(state.selectedCategory.key).options.map(o => (
|
{getCategory(state.selectedCategory.key).options.map(o => (
|
||||||
@@ -410,39 +421,6 @@ function Inner(props: ReportDialogProps) {
|
|||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
|
|
||||||
{state.selectedCategory.key === 'sexualAdultContent' && (
|
|
||||||
<Link
|
|
||||||
to={TAKE_IT_DOWN_ACT_FORM}
|
|
||||||
label={l`Need this report to be reviewed under the "Take it down act"?`}>
|
|
||||||
{({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 this report to be reviewed under the “Take it
|
|
||||||
down act”?
|
|
||||||
</Trans>
|
|
||||||
</Text>
|
|
||||||
<SquareArrowTopRight
|
|
||||||
size="sm"
|
|
||||||
fill={t.atoms.text.color}
|
|
||||||
/>
|
|
||||||
</View>
|
|
||||||
)}
|
|
||||||
</Link>
|
|
||||||
)}
|
|
||||||
</View>
|
</View>
|
||||||
) : null}
|
) : null}
|
||||||
</StepOuter>
|
</StepOuter>
|
||||||
@@ -814,6 +792,138 @@ function OptionCard({
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Qualifying questions shown when the NCII reason is selected. US residents
|
||||||
|
* reporting imagery of themselves (or on behalf of the person depicted) are
|
||||||
|
* directed to the external NCII report form; everyone else continues
|
||||||
|
* with the normal in-app submission.
|
||||||
|
*/
|
||||||
|
function NciiQualification({
|
||||||
|
ncii,
|
||||||
|
dispatch,
|
||||||
|
}: {
|
||||||
|
ncii: NciiQualificationState
|
||||||
|
dispatch: React.Dispatch<ReportAction>
|
||||||
|
}) {
|
||||||
|
const t = useTheme()
|
||||||
|
const {t: l} = useLingui()
|
||||||
|
const outcome = getNciiQualificationOutcome(ncii)
|
||||||
|
return (
|
||||||
|
<View style={[a.gap_md]}>
|
||||||
|
<YesNoQuestion
|
||||||
|
testID="report:ncii:residesInUS"
|
||||||
|
question={l`Do you reside in the United States?`}
|
||||||
|
value={ncii.residesInUS}
|
||||||
|
onAnswer={answer => {
|
||||||
|
dispatch({
|
||||||
|
type: 'answerNciiQuestion',
|
||||||
|
question: 'residesInUS',
|
||||||
|
answer,
|
||||||
|
})
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
{ncii.residesInUS === true && (
|
||||||
|
<YesNoQuestion
|
||||||
|
testID="report:ncii:isDepicted"
|
||||||
|
question={l`Are you the person depicted, or an authorized representative acting on behalf of the person depicted?`}
|
||||||
|
value={ncii.isDepicted}
|
||||||
|
onAnswer={answer => {
|
||||||
|
dispatch({
|
||||||
|
type: 'answerNciiQuestion',
|
||||||
|
question: 'isDepicted',
|
||||||
|
answer,
|
||||||
|
})
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
{outcome === 'externalForm' && (
|
||||||
|
<Link
|
||||||
|
to={NCII_FORM}
|
||||||
|
label={l`Submit your report through the Report non-consensual intimate imagery (NCII) form`}>
|
||||||
|
{({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>
|
||||||
|
Please submit your report through the Report non-consensual
|
||||||
|
intimate imagery (NCII) form.
|
||||||
|
</Trans>
|
||||||
|
</Text>
|
||||||
|
<SquareArrowTopRight size="sm" fill={t.atoms.text.color} />
|
||||||
|
</View>
|
||||||
|
)}
|
||||||
|
</Link>
|
||||||
|
)}
|
||||||
|
</View>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
function YesNoQuestion({
|
||||||
|
question,
|
||||||
|
value,
|
||||||
|
onAnswer,
|
||||||
|
testID,
|
||||||
|
}: {
|
||||||
|
question: string
|
||||||
|
value?: boolean
|
||||||
|
onAnswer: (answer: boolean) => void
|
||||||
|
testID?: string
|
||||||
|
}) {
|
||||||
|
const {t: l} = useLingui()
|
||||||
|
return (
|
||||||
|
<View style={[a.gap_sm]}>
|
||||||
|
<Text style={[a.text_md, a.leading_snug]}>{question}</Text>
|
||||||
|
<View style={[a.flex_row, a.gap_sm]}>
|
||||||
|
<View style={[a.flex_1]}>
|
||||||
|
<Button
|
||||||
|
testID={testID ? `${testID}:yes` : undefined}
|
||||||
|
label={l({
|
||||||
|
message: 'Yes',
|
||||||
|
context: 'Answer to a yes/no question',
|
||||||
|
})}
|
||||||
|
accessibilityHint={question}
|
||||||
|
size="small"
|
||||||
|
variant="solid"
|
||||||
|
color={value === true ? 'primary' : 'secondary'}
|
||||||
|
onPress={() => onAnswer(true)}>
|
||||||
|
<ButtonText>
|
||||||
|
<Trans context="Answer to a yes/no question">Yes</Trans>
|
||||||
|
</ButtonText>
|
||||||
|
</Button>
|
||||||
|
</View>
|
||||||
|
<View style={[a.flex_1]}>
|
||||||
|
<Button
|
||||||
|
testID={testID ? `${testID}:no` : undefined}
|
||||||
|
label={l({
|
||||||
|
message: 'No',
|
||||||
|
context: 'Answer to a yes/no question',
|
||||||
|
})}
|
||||||
|
accessibilityHint={question}
|
||||||
|
size="small"
|
||||||
|
variant="solid"
|
||||||
|
color={value === false ? 'primary' : 'secondary'}
|
||||||
|
onPress={() => onAnswer(false)}>
|
||||||
|
<ButtonText>
|
||||||
|
<Trans context="Answer to a yes/no question">No</Trans>
|
||||||
|
</ButtonText>
|
||||||
|
</Button>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
function OptionCardSkeleton() {
|
function OptionCardSkeleton() {
|
||||||
const t = useTheme()
|
const t = useTheme()
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -0,0 +1,167 @@
|
|||||||
|
import {
|
||||||
|
type AppBskyLabelerDefs,
|
||||||
|
ToolsOzoneReportDefs as OzoneReportDefs,
|
||||||
|
} from '@atproto/api'
|
||||||
|
|
||||||
|
import {
|
||||||
|
getNciiQualificationOutcome,
|
||||||
|
initialState,
|
||||||
|
reducer,
|
||||||
|
type ReportState,
|
||||||
|
} from './state'
|
||||||
|
|
||||||
|
const nciiOption = {
|
||||||
|
title: 'Non-consensual intimate imagery',
|
||||||
|
reason: OzoneReportDefs.REASONSEXUALNCII,
|
||||||
|
}
|
||||||
|
|
||||||
|
const otherOption = {
|
||||||
|
title: 'Unlabeled adult content',
|
||||||
|
reason: OzoneReportDefs.REASONSEXUALUNLABELED,
|
||||||
|
}
|
||||||
|
|
||||||
|
function selectNciiOption(state: ReportState = initialState) {
|
||||||
|
return reducer(state, {type: 'selectOption', option: nciiOption})
|
||||||
|
}
|
||||||
|
|
||||||
|
describe('getNciiQualificationOutcome', () => {
|
||||||
|
it('returns undefined when not an NCII report', () => {
|
||||||
|
expect(getNciiQualificationOutcome(undefined)).toBeUndefined()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('is pending until questions are answered', () => {
|
||||||
|
expect(getNciiQualificationOutcome({})).toBe('pending')
|
||||||
|
expect(getNciiQualificationOutcome({residesInUS: true})).toBe('pending')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('directs US residents depicted in the imagery to the external form', () => {
|
||||||
|
expect(
|
||||||
|
getNciiQualificationOutcome({residesInUS: true, isDepicted: true}),
|
||||||
|
).toBe('externalForm')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('directs everyone else to in-app submission', () => {
|
||||||
|
expect(getNciiQualificationOutcome({residesInUS: false})).toBe('inApp')
|
||||||
|
expect(
|
||||||
|
getNciiQualificationOutcome({residesInUS: true, isDepicted: false}),
|
||||||
|
).toBe('inApp')
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('reducer NCII qualification', () => {
|
||||||
|
it('holds at step 2 when the NCII reason is selected', () => {
|
||||||
|
const state = selectNciiOption()
|
||||||
|
expect(state.activeStepIndex1).toBe(2)
|
||||||
|
expect(state.ncii).toEqual({})
|
||||||
|
})
|
||||||
|
|
||||||
|
it('does not gate non-NCII reasons', () => {
|
||||||
|
const state = reducer(initialState, {
|
||||||
|
type: 'selectOption',
|
||||||
|
option: otherOption,
|
||||||
|
})
|
||||||
|
expect(state.activeStepIndex1).toBe(3)
|
||||||
|
expect(state.ncii).toBeUndefined()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('advances to step 3 for non-US residents', () => {
|
||||||
|
let state = selectNciiOption()
|
||||||
|
state = reducer(state, {
|
||||||
|
type: 'answerNciiQuestion',
|
||||||
|
question: 'residesInUS',
|
||||||
|
answer: false,
|
||||||
|
})
|
||||||
|
expect(state.activeStepIndex1).toBe(3)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('holds at step 2 for US residents until the second answer', () => {
|
||||||
|
let state = selectNciiOption()
|
||||||
|
state = reducer(state, {
|
||||||
|
type: 'answerNciiQuestion',
|
||||||
|
question: 'residesInUS',
|
||||||
|
answer: true,
|
||||||
|
})
|
||||||
|
expect(state.activeStepIndex1).toBe(2)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('holds at step 2 for depicted US residents (external form)', () => {
|
||||||
|
let state = selectNciiOption()
|
||||||
|
state = reducer(state, {
|
||||||
|
type: 'answerNciiQuestion',
|
||||||
|
question: 'residesInUS',
|
||||||
|
answer: true,
|
||||||
|
})
|
||||||
|
state = reducer(state, {
|
||||||
|
type: 'answerNciiQuestion',
|
||||||
|
question: 'isDepicted',
|
||||||
|
answer: true,
|
||||||
|
})
|
||||||
|
expect(getNciiQualificationOutcome(state.ncii)).toBe('externalForm')
|
||||||
|
expect(state.activeStepIndex1).toBe(2)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('advances to step 3 for non-depicted US residents', () => {
|
||||||
|
let state = selectNciiOption()
|
||||||
|
state = reducer(state, {
|
||||||
|
type: 'answerNciiQuestion',
|
||||||
|
question: 'residesInUS',
|
||||||
|
answer: true,
|
||||||
|
})
|
||||||
|
state = reducer(state, {
|
||||||
|
type: 'answerNciiQuestion',
|
||||||
|
question: 'isDepicted',
|
||||||
|
answer: false,
|
||||||
|
})
|
||||||
|
expect(state.activeStepIndex1).toBe(3)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('resets the second answer when the first changes', () => {
|
||||||
|
let state = selectNciiOption()
|
||||||
|
state = reducer(state, {
|
||||||
|
type: 'answerNciiQuestion',
|
||||||
|
question: 'residesInUS',
|
||||||
|
answer: true,
|
||||||
|
})
|
||||||
|
state = reducer(state, {
|
||||||
|
type: 'answerNciiQuestion',
|
||||||
|
question: 'isDepicted',
|
||||||
|
answer: true,
|
||||||
|
})
|
||||||
|
state = reducer(state, {
|
||||||
|
type: 'answerNciiQuestion',
|
||||||
|
question: 'residesInUS',
|
||||||
|
answer: true,
|
||||||
|
})
|
||||||
|
expect(state.ncii?.isDepicted).toBeUndefined()
|
||||||
|
expect(state.activeStepIndex1).toBe(2)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('does not advance past pending questions when a labeler is auto-selected', () => {
|
||||||
|
let state = selectNciiOption()
|
||||||
|
state = reducer(state, {
|
||||||
|
type: 'selectLabeler',
|
||||||
|
labeler: {} as AppBskyLabelerDefs.LabelerViewDetailed,
|
||||||
|
})
|
||||||
|
expect(state.activeStepIndex1).toBe(2)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('skips to step 4 when answers resolve after labeler auto-selection', () => {
|
||||||
|
let state = selectNciiOption()
|
||||||
|
state = reducer(state, {
|
||||||
|
type: 'selectLabeler',
|
||||||
|
labeler: {} as AppBskyLabelerDefs.LabelerViewDetailed,
|
||||||
|
})
|
||||||
|
state = reducer(state, {
|
||||||
|
type: 'answerNciiQuestion',
|
||||||
|
question: 'residesInUS',
|
||||||
|
answer: false,
|
||||||
|
})
|
||||||
|
expect(state.activeStepIndex1).toBe(4)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('clears NCII state when the reason or category is cleared', () => {
|
||||||
|
let state = selectNciiOption()
|
||||||
|
expect(reducer(state, {type: 'clearOption'}).ncii).toBeUndefined()
|
||||||
|
expect(reducer(state, {type: 'clearCategory'}).ncii).toBeUndefined()
|
||||||
|
})
|
||||||
|
})
|
||||||
@@ -1,4 +1,7 @@
|
|||||||
import {type AppBskyLabelerDefs} from '@atproto/api'
|
import {
|
||||||
|
type AppBskyLabelerDefs,
|
||||||
|
ToolsOzoneReportDefs as OzoneReportDefs,
|
||||||
|
} from '@atproto/api'
|
||||||
|
|
||||||
import {OTHER_REPORT_REASONS} from '#/components/moderation/ReportDialog/const'
|
import {OTHER_REPORT_REASONS} from '#/components/moderation/ReportDialog/const'
|
||||||
import {
|
import {
|
||||||
@@ -6,6 +9,11 @@ import {
|
|||||||
type ReportOption,
|
type ReportOption,
|
||||||
} from '#/components/moderation/ReportDialog/utils/useReportOptions'
|
} from '#/components/moderation/ReportDialog/utils/useReportOptions'
|
||||||
|
|
||||||
|
export type NciiQualification = {
|
||||||
|
residesInUS?: boolean
|
||||||
|
isDepicted?: boolean
|
||||||
|
}
|
||||||
|
|
||||||
export type ReportState = {
|
export type ReportState = {
|
||||||
selectedCategory?: ReportCategoryConfig
|
selectedCategory?: ReportCategoryConfig
|
||||||
selectedOption?: ReportOption
|
selectedOption?: ReportOption
|
||||||
@@ -14,6 +22,30 @@ export type ReportState = {
|
|||||||
detailsOpen: boolean
|
detailsOpen: boolean
|
||||||
activeStepIndex1: number
|
activeStepIndex1: number
|
||||||
error?: string
|
error?: string
|
||||||
|
/**
|
||||||
|
* Present while the selected reason is NCII. Tracks answers to the
|
||||||
|
* qualifying questions that determine whether the report should go through
|
||||||
|
* the external NCII report form instead of in-app submission.
|
||||||
|
*/
|
||||||
|
ncii?: NciiQualification
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resolves the NCII qualifying questions into an outcome. US residents who
|
||||||
|
* are the depicted person (or their authorized representative) are directed
|
||||||
|
* to the external NCII report form; everyone else proceeds with the
|
||||||
|
* normal in-app submission.
|
||||||
|
*/
|
||||||
|
export function getNciiQualificationOutcome(
|
||||||
|
ncii?: NciiQualification,
|
||||||
|
): 'pending' | 'externalForm' | 'inApp' | undefined {
|
||||||
|
if (!ncii) return undefined
|
||||||
|
if (ncii.residesInUS === false) return 'inApp'
|
||||||
|
if (ncii.residesInUS === true) {
|
||||||
|
if (ncii.isDepicted === true) return 'externalForm'
|
||||||
|
if (ncii.isDepicted === false) return 'inApp'
|
||||||
|
}
|
||||||
|
return 'pending'
|
||||||
}
|
}
|
||||||
|
|
||||||
export type ReportAction =
|
export type ReportAction =
|
||||||
@@ -32,6 +64,11 @@ export type ReportAction =
|
|||||||
| {
|
| {
|
||||||
type: 'clearOption'
|
type: 'clearOption'
|
||||||
}
|
}
|
||||||
|
| {
|
||||||
|
type: 'answerNciiQuestion'
|
||||||
|
question: keyof NciiQualification
|
||||||
|
answer: boolean
|
||||||
|
}
|
||||||
| {
|
| {
|
||||||
type: 'selectLabeler'
|
type: 'selectLabeler'
|
||||||
labeler: AppBskyLabelerDefs.LabelerViewDetailed
|
labeler: AppBskyLabelerDefs.LabelerViewDetailed
|
||||||
@@ -81,14 +118,19 @@ export function reducer(state: ReportState, action: ReportAction): ReportState {
|
|||||||
selectedLabeler: undefined,
|
selectedLabeler: undefined,
|
||||||
activeStepIndex1: 1,
|
activeStepIndex1: 1,
|
||||||
detailsOpen: false,
|
detailsOpen: false,
|
||||||
|
ncii: undefined,
|
||||||
}
|
}
|
||||||
case 'selectOption':
|
case 'selectOption': {
|
||||||
|
const isNcii = action.option.reason === OzoneReportDefs.REASONSEXUALNCII
|
||||||
return {
|
return {
|
||||||
...state,
|
...state,
|
||||||
selectedOption: action.option,
|
selectedOption: action.option,
|
||||||
activeStepIndex1: 3,
|
// NCII reports require answering qualifying questions before moving on
|
||||||
|
activeStepIndex1: isNcii ? 2 : 3,
|
||||||
detailsOpen: OTHER_REPORT_REASONS.has(action.option.reason),
|
detailsOpen: OTHER_REPORT_REASONS.has(action.option.reason),
|
||||||
|
ncii: isNcii ? {} : undefined,
|
||||||
}
|
}
|
||||||
|
}
|
||||||
case 'clearOption':
|
case 'clearOption':
|
||||||
return {
|
return {
|
||||||
...state,
|
...state,
|
||||||
@@ -96,12 +138,37 @@ export function reducer(state: ReportState, action: ReportAction): ReportState {
|
|||||||
selectedLabeler: undefined,
|
selectedLabeler: undefined,
|
||||||
activeStepIndex1: 2,
|
activeStepIndex1: 2,
|
||||||
detailsOpen: false,
|
detailsOpen: false,
|
||||||
|
ncii: undefined,
|
||||||
}
|
}
|
||||||
|
case 'answerNciiQuestion': {
|
||||||
|
const ncii = {...state.ncii, [action.question]: action.answer}
|
||||||
|
// the second question only applies to US residents
|
||||||
|
if (action.question === 'residesInUS') {
|
||||||
|
ncii.isDepicted = undefined
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
ncii,
|
||||||
|
activeStepIndex1:
|
||||||
|
getNciiQualificationOutcome(ncii) === 'inApp'
|
||||||
|
? state.selectedLabeler
|
||||||
|
? 4
|
||||||
|
: 3
|
||||||
|
: 2,
|
||||||
|
}
|
||||||
|
}
|
||||||
case 'selectLabeler':
|
case 'selectLabeler':
|
||||||
return {
|
return {
|
||||||
...state,
|
...state,
|
||||||
selectedLabeler: action.labeler,
|
selectedLabeler: action.labeler,
|
||||||
activeStepIndex1: 4,
|
/*
|
||||||
|
* Labelers may be auto-selected (e.g. chat reports only go to
|
||||||
|
* Bluesky), so don't advance past pending NCII qualifying questions.
|
||||||
|
*/
|
||||||
|
activeStepIndex1:
|
||||||
|
getNciiQualificationOutcome(state.ncii) === 'inApp' || !state.ncii
|
||||||
|
? 4
|
||||||
|
: 2,
|
||||||
detailsOpen: state.selectedOption
|
detailsOpen: state.selectedOption
|
||||||
? OTHER_REPORT_REASONS.has(state.selectedOption?.reason)
|
? OTHER_REPORT_REASONS.has(state.selectedOption?.reason)
|
||||||
: false,
|
: false,
|
||||||
|
|||||||
Reference in New Issue
Block a user