Update report modal to use new groupings (close [APP-567]) (#533)
parent
9b86cb5c36
commit
fc19ffba38
|
@ -1,4 +1,4 @@
|
||||||
import React, {useState} from 'react'
|
import React, {useState, useMemo} from 'react'
|
||||||
import {
|
import {
|
||||||
ActivityIndicator,
|
ActivityIndicator,
|
||||||
StyleSheet,
|
StyleSheet,
|
||||||
|
@ -15,12 +15,7 @@ import * as Toast from '../util/Toast'
|
||||||
import {ErrorMessage} from '../util/error/ErrorMessage'
|
import {ErrorMessage} from '../util/error/ErrorMessage'
|
||||||
import {cleanError} from 'lib/strings/errors'
|
import {cleanError} from 'lib/strings/errors'
|
||||||
import {usePalette} from 'lib/hooks/usePalette'
|
import {usePalette} from 'lib/hooks/usePalette'
|
||||||
|
import {isDesktopWeb} from 'platform/detection'
|
||||||
const ITEMS: RadioGroupItem[] = [
|
|
||||||
{key: 'spam', label: 'Spam or excessive repeat posts'},
|
|
||||||
{key: 'abuse', label: 'Abusive, rude, or hateful'},
|
|
||||||
{key: 'illegal', label: 'Posts illegal content'},
|
|
||||||
]
|
|
||||||
|
|
||||||
export const snapPoints = ['50%']
|
export const snapPoints = ['50%']
|
||||||
|
|
||||||
|
@ -31,6 +26,39 @@ export function Component({did}: {did: string}) {
|
||||||
const [error, setError] = useState<string>('')
|
const [error, setError] = useState<string>('')
|
||||||
const [issue, setIssue] = useState<string>('')
|
const [issue, setIssue] = useState<string>('')
|
||||||
const onSelectIssue = (v: string) => setIssue(v)
|
const onSelectIssue = (v: string) => setIssue(v)
|
||||||
|
|
||||||
|
const ITEMS: RadioGroupItem[] = useMemo(
|
||||||
|
() => [
|
||||||
|
{
|
||||||
|
key: ComAtprotoModerationDefs.REASONMISLEADING,
|
||||||
|
label: (
|
||||||
|
<View>
|
||||||
|
<Text style={pal.text} type="md-bold">
|
||||||
|
Misleading Account
|
||||||
|
</Text>
|
||||||
|
<Text style={pal.textLight}>
|
||||||
|
Impersonation or false claims about identity or affiliation
|
||||||
|
</Text>
|
||||||
|
</View>
|
||||||
|
),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: ComAtprotoModerationDefs.REASONSPAM,
|
||||||
|
label: (
|
||||||
|
<View>
|
||||||
|
<Text style={pal.text} type="md-bold">
|
||||||
|
Frequently Posts Unwanted Content
|
||||||
|
</Text>
|
||||||
|
<Text style={pal.textLight}>
|
||||||
|
Spam; excessive mentions or replies
|
||||||
|
</Text>
|
||||||
|
</View>
|
||||||
|
),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
[pal],
|
||||||
|
)
|
||||||
|
|
||||||
const onPress = async () => {
|
const onPress = async () => {
|
||||||
setError('')
|
setError('')
|
||||||
if (!issue) {
|
if (!issue) {
|
||||||
|
@ -38,15 +66,8 @@ export function Component({did}: {did: string}) {
|
||||||
}
|
}
|
||||||
setIsProcessing(true)
|
setIsProcessing(true)
|
||||||
try {
|
try {
|
||||||
// NOTE: we should update the lexicon of reasontype to include more options -prf
|
|
||||||
let reasonType = ComAtprotoModerationDefs.REASONOTHER
|
|
||||||
if (issue === 'spam') {
|
|
||||||
reasonType = ComAtprotoModerationDefs.REASONSPAM
|
|
||||||
}
|
|
||||||
const reason = ITEMS.find(item => item.key === issue)?.label || ''
|
|
||||||
await store.agent.com.atproto.moderation.createReport({
|
await store.agent.com.atproto.moderation.createReport({
|
||||||
reasonType,
|
reasonType: issue,
|
||||||
reason,
|
|
||||||
subject: {
|
subject: {
|
||||||
$type: 'com.atproto.admin.defs#repoRef',
|
$type: 'com.atproto.admin.defs#repoRef',
|
||||||
did,
|
did,
|
||||||
|
@ -61,11 +82,11 @@ export function Component({did}: {did: string}) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<View
|
<View testID="reportAccountModal" style={[styles.container, pal.view]}>
|
||||||
testID="reportAccountModal"
|
<Text type="title-xl" style={[pal.text, styles.title]}>
|
||||||
style={[s.flex1, s.pl10, s.pr10, pal.view]}>
|
Report account
|
||||||
<Text style={[pal.text, styles.title]}>Report account</Text>
|
</Text>
|
||||||
<Text style={[pal.textLight, styles.description]}>
|
<Text type="xl" style={[pal.text, styles.description]}>
|
||||||
What is the issue with this account?
|
What is the issue with this account?
|
||||||
</Text>
|
</Text>
|
||||||
<RadioGroup
|
<RadioGroup
|
||||||
|
@ -73,6 +94,9 @@ export function Component({did}: {did: string}) {
|
||||||
items={ITEMS}
|
items={ITEMS}
|
||||||
onSelect={onSelectIssue}
|
onSelect={onSelectIssue}
|
||||||
/>
|
/>
|
||||||
|
<Text type="sm" style={[pal.text, styles.description, s.pt10]}>
|
||||||
|
For other issues, please report specific posts.
|
||||||
|
</Text>
|
||||||
{error ? (
|
{error ? (
|
||||||
<View style={s.mt10}>
|
<View style={s.mt10}>
|
||||||
<ErrorMessage message={error} />
|
<ErrorMessage message={error} />
|
||||||
|
@ -101,15 +125,17 @@ export function Component({did}: {did: string}) {
|
||||||
}
|
}
|
||||||
|
|
||||||
const styles = StyleSheet.create({
|
const styles = StyleSheet.create({
|
||||||
|
container: {
|
||||||
|
flex: 1,
|
||||||
|
paddingHorizontal: isDesktopWeb ? 0 : 10,
|
||||||
|
},
|
||||||
title: {
|
title: {
|
||||||
textAlign: 'center',
|
textAlign: 'center',
|
||||||
fontWeight: 'bold',
|
fontWeight: 'bold',
|
||||||
fontSize: 24,
|
|
||||||
marginBottom: 12,
|
marginBottom: 12,
|
||||||
},
|
},
|
||||||
description: {
|
description: {
|
||||||
textAlign: 'center',
|
textAlign: 'center',
|
||||||
fontSize: 17,
|
|
||||||
paddingHorizontal: 22,
|
paddingHorizontal: 22,
|
||||||
marginBottom: 10,
|
marginBottom: 10,
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import React, {useState} from 'react'
|
import React, {useState, useMemo} from 'react'
|
||||||
import {
|
import {
|
||||||
ActivityIndicator,
|
ActivityIndicator,
|
||||||
|
Linking,
|
||||||
StyleSheet,
|
StyleSheet,
|
||||||
TouchableOpacity,
|
TouchableOpacity,
|
||||||
View,
|
View,
|
||||||
|
@ -16,14 +17,9 @@ import {ErrorMessage} from '../util/error/ErrorMessage'
|
||||||
import {cleanError} from 'lib/strings/errors'
|
import {cleanError} from 'lib/strings/errors'
|
||||||
import {usePalette} from 'lib/hooks/usePalette'
|
import {usePalette} from 'lib/hooks/usePalette'
|
||||||
|
|
||||||
const ITEMS: RadioGroupItem[] = [
|
const DMCA_LINK = 'https://bsky.app/support/copyright'
|
||||||
{key: 'spam', label: 'Spam or excessive repeat posts'},
|
|
||||||
{key: 'abuse', label: 'Abusive, rude, or hateful'},
|
|
||||||
{key: 'copyright', label: 'Contains copyrighted material'},
|
|
||||||
{key: 'illegal', label: 'Contains illegal content'},
|
|
||||||
]
|
|
||||||
|
|
||||||
export const snapPoints = ['50%']
|
export const snapPoints = [500]
|
||||||
|
|
||||||
export function Component({
|
export function Component({
|
||||||
postUri,
|
postUri,
|
||||||
|
@ -38,6 +34,74 @@ export function Component({
|
||||||
const [error, setError] = useState<string>('')
|
const [error, setError] = useState<string>('')
|
||||||
const [issue, setIssue] = useState<string>('')
|
const [issue, setIssue] = useState<string>('')
|
||||||
const onSelectIssue = (v: string) => setIssue(v)
|
const onSelectIssue = (v: string) => setIssue(v)
|
||||||
|
|
||||||
|
const ITEMS: RadioGroupItem[] = useMemo(
|
||||||
|
() => [
|
||||||
|
{
|
||||||
|
key: ComAtprotoModerationDefs.REASONSPAM,
|
||||||
|
label: (
|
||||||
|
<View>
|
||||||
|
<Text style={pal.text} type="md-bold">
|
||||||
|
Spam
|
||||||
|
</Text>
|
||||||
|
<Text style={pal.textLight}>Excessive mentions or replies</Text>
|
||||||
|
</View>
|
||||||
|
),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: ComAtprotoModerationDefs.REASONSEXUAL,
|
||||||
|
label: (
|
||||||
|
<View>
|
||||||
|
<Text style={pal.text} type="md-bold">
|
||||||
|
Unwanted Sexual Content
|
||||||
|
</Text>
|
||||||
|
<Text style={pal.textLight}>
|
||||||
|
Nudity or pornography not labeled as such
|
||||||
|
</Text>
|
||||||
|
</View>
|
||||||
|
),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: '__copyright__',
|
||||||
|
label: (
|
||||||
|
<View>
|
||||||
|
<Text style={pal.text} type="md-bold">
|
||||||
|
Copyright Violation
|
||||||
|
</Text>
|
||||||
|
<Text style={pal.textLight}>Contains copyrighted material</Text>
|
||||||
|
</View>
|
||||||
|
),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: ComAtprotoModerationDefs.REASONVIOLATION,
|
||||||
|
label: (
|
||||||
|
<View>
|
||||||
|
<Text style={pal.text} type="md-bold">
|
||||||
|
Illegal and Urgent
|
||||||
|
</Text>
|
||||||
|
<Text style={pal.textLight}>
|
||||||
|
Glaring violations of law or terms of service
|
||||||
|
</Text>
|
||||||
|
</View>
|
||||||
|
),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: ComAtprotoModerationDefs.REASONOTHER,
|
||||||
|
label: (
|
||||||
|
<View>
|
||||||
|
<Text style={pal.text} type="md-bold">
|
||||||
|
Other
|
||||||
|
</Text>
|
||||||
|
<Text style={pal.textLight}>
|
||||||
|
An issue not included in these options
|
||||||
|
</Text>
|
||||||
|
</View>
|
||||||
|
),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
[pal],
|
||||||
|
)
|
||||||
|
|
||||||
const onPress = async () => {
|
const onPress = async () => {
|
||||||
setError('')
|
setError('')
|
||||||
if (!issue) {
|
if (!issue) {
|
||||||
|
@ -45,15 +109,11 @@ export function Component({
|
||||||
}
|
}
|
||||||
setIsProcessing(true)
|
setIsProcessing(true)
|
||||||
try {
|
try {
|
||||||
// NOTE: we should update the lexicon of reasontype to include more options -prf
|
if (issue === '__copyright__') {
|
||||||
let reasonType = ComAtprotoModerationDefs.REASONOTHER
|
Linking.openURL(DMCA_LINK)
|
||||||
if (issue === 'spam') {
|
} else {
|
||||||
reasonType = ComAtprotoModerationDefs.REASONSPAM
|
|
||||||
}
|
|
||||||
const reason = ITEMS.find(item => item.key === issue)?.label || ''
|
|
||||||
await store.agent.createModerationReport({
|
await store.agent.createModerationReport({
|
||||||
reasonType,
|
reasonType: issue,
|
||||||
reason,
|
|
||||||
subject: {
|
subject: {
|
||||||
$type: 'com.atproto.repo.strongRef',
|
$type: 'com.atproto.repo.strongRef',
|
||||||
uri: postUri,
|
uri: postUri,
|
||||||
|
@ -61,6 +121,7 @@ export function Component({
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
Toast.show("Thank you for your report! We'll look into it promptly.")
|
Toast.show("Thank you for your report! We'll look into it promptly.")
|
||||||
|
}
|
||||||
store.shell.closeModal()
|
store.shell.closeModal()
|
||||||
return
|
return
|
||||||
} catch (e: any) {
|
} catch (e: any) {
|
||||||
|
|
|
@ -15,7 +15,7 @@ export function RadioButton({
|
||||||
}: {
|
}: {
|
||||||
testID?: string
|
testID?: string
|
||||||
type?: ButtonType
|
type?: ButtonType
|
||||||
label: string
|
label: string | JSX.Element
|
||||||
isSelected: boolean
|
isSelected: boolean
|
||||||
style?: StyleProp<ViewStyle>
|
style?: StyleProp<ViewStyle>
|
||||||
onPress: () => void
|
onPress: () => void
|
||||||
|
@ -47,7 +47,7 @@ export function RadioButton({
|
||||||
borderColor: theme.palette.default.border,
|
borderColor: theme.palette.default.border,
|
||||||
},
|
},
|
||||||
'default-light': {
|
'default-light': {
|
||||||
borderColor: theme.palette.default.border,
|
borderColor: theme.palette.default.borderDark,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
const circleFillStyle = choose<TextStyle, Record<ButtonType, TextStyle>>(
|
const circleFillStyle = choose<TextStyle, Record<ButtonType, TextStyle>>(
|
||||||
|
@ -128,9 +128,13 @@ export function RadioButton({
|
||||||
<View style={[circleFillStyle, styles.circleFill]} />
|
<View style={[circleFillStyle, styles.circleFill]} />
|
||||||
) : undefined}
|
) : undefined}
|
||||||
</View>
|
</View>
|
||||||
|
{typeof label === 'string' ? (
|
||||||
<Text type="button" style={[labelStyle, styles.label]}>
|
<Text type="button" style={[labelStyle, styles.label]}>
|
||||||
{label}
|
{label}
|
||||||
</Text>
|
</Text>
|
||||||
|
) : (
|
||||||
|
<View style={styles.label}>{label}</View>
|
||||||
|
)}
|
||||||
</View>
|
</View>
|
||||||
</Button>
|
</Button>
|
||||||
)
|
)
|
||||||
|
|
|
@ -5,7 +5,7 @@ import {ButtonType} from './Button'
|
||||||
import {s} from 'lib/styles'
|
import {s} from 'lib/styles'
|
||||||
|
|
||||||
export interface RadioGroupItem {
|
export interface RadioGroupItem {
|
||||||
label: string
|
label: string | JSX.Element
|
||||||
key: string
|
key: string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue