import React from 'react'
import {View, Dimensions} from 'react-native'
import {msg} from '@lingui/macro'
import {useLingui} from '@lingui/react'
import {AppBskyModerationDefs, LabelGroupDefinition} from '@atproto/api'
import {useSafeAreaInsets} from 'react-native-safe-area-context'
import {atoms as a, useTheme, tokens, native} from '#/alf'
import {Text} from '#/components/Typography'
import * as Dialog from '#/components/Dialog'
import {GlobalDialogProps} from '#/components/dialogs'
import {
Button,
ButtonIcon,
ButtonText,
useButtonContext,
} from '#/components/Button'
import {Divider} from '#/components/Divider'
import {useLabelGroupStrings} from '#/lib/moderation/useLabelGroupStrings'
import {
ChevronRight_Stroke2_Corner0_Rounded as ChevronRight,
ChevronLeft_Stroke2_Corner0_Rounded as ChevronLeft,
} from '#/components/icons/Chevron'
import {Check_Stroke2_Corner0_Rounded as Check} from '#/components/icons/Check'
import {PlusLarge_Stroke2_Corner0_Rounded as Plus} from '#/components/icons/Plus'
import * as Toggle from '#/components/forms/Toggle'
import {GradientFill} from '#/components/GradientFill'
import {CharProgress} from '#/view/com/composer/char-progress/CharProgress'
import {Loader} from '#/components/Loader'
import * as Toast from '#/view/com/util/Toast'
import {usePreferencesQuery} from '#/state/queries/preferences'
import {useModServicesDetailedInfoQuery} from '#/state/queries/modservice'
import {
getLabelGroupsFromLabels,
getModerationServiceTitle,
useConfigurableLabelGroups,
} from '#/lib/moderation'
export type ReportDialogProps =
| {
type: 'post'
uri: string
cid: string
}
| {
type: 'user'
did: string
}
function LabelGroupButton({
labelGroup,
}: {
labelGroup: LabelGroupDefinition['id']
}) {
const t = useTheme()
const {hovered, focused, pressed} = useButtonContext()
const labelGroupStrings = useLabelGroupStrings()
const groupInfoStrings = labelGroupStrings[labelGroup]
const interacted = hovered || focused || pressed
const styles = React.useMemo(() => {
return {
interacted: {
backgroundColor: t.palette.contrast_50,
},
}
}, [t])
return (
{groupInfoStrings.name}
{groupInfoStrings.description}
)
}
function ModServiceToggle({title}: {title: string}) {
const t = useTheme()
const ctx = Toggle.useItemContext()
return (
{ctx.selected && }
{title}
)
}
function SubmitViewLoader({
children,
}: {
children: (props: {
labelers: AppBskyModerationDefs.ModServiceViewDetailed[]
labelGroupToModServiceMap: Record
}) => React.ReactNode
}) {
const {
isLoading: isPreferencesLoading,
error: preferencesError,
data: preferences,
} = usePreferencesQuery()
const {
isLoading: isModServicesLoading,
data: modservices,
error: modservicesError,
} = useModServicesDetailedInfoQuery({
dids: preferences ? preferences.moderationOpts.mods.map(m => m.did) : [],
})
const labelGroupToModServiceMap = React.useMemo(() => {
if (!modservices) return {}
const groups: Partial<
Record<
LabelGroupDefinition['id'],
AppBskyModerationDefs.ModServiceViewDetailed[]
>
> = {}
for (const modservice of modservices) {
const labelGroups = getLabelGroupsFromLabels(
modservice.policies.labelValues,
)
for (const group of labelGroups) {
const g = (groups[group.id] = groups[group.id] || [])
g.push(modservice)
}
}
return groups
}, [modservices])
const isLoading = isPreferencesLoading || isModServicesLoading
const error = preferencesError || modservicesError
return isLoading ? (
) : error || !(preferences && modservices) ? null : ( // TODO
children({
labelers: modservices,
// TODO mismatched types
// @ts-ignore
labelGroupToModServiceMap,
})
)
}
function SubmitView({
selectedLabelGroup,
goBack,
onSubmitComplete,
labelGroupToModServiceMap,
}: {
selectedLabelGroup: LabelGroupDefinition['id']
goBack: () => void
onSubmitComplete: () => void
labelers: AppBskyModerationDefs.ModServiceViewDetailed[]
labelGroupToModServiceMap: Record<
LabelGroupDefinition['id'],
AppBskyModerationDefs.ModServiceViewDetailed[]
>
}) {
const t = useTheme()
const {_} = useLingui()
const labelGroupStrings = useLabelGroupStrings()
const groupInfoStrings = labelGroupStrings[selectedLabelGroup]
const [details, setDetails] = React.useState('')
const [submitting, setSubmitting] = React.useState(false)
const [selectedServices, setSelectedServices] = React.useState([])
const supportedLabelers = labelGroupToModServiceMap[selectedLabelGroup]
const submit = React.useCallback(async () => {
setSubmitting(true)
await new Promise(resolve => setTimeout(resolve, 1000))
setSubmitting(false)
Toast.show(`Thank you. Your report has been sent.`)
onSubmitComplete()
}, [onSubmitComplete])
return (
{groupInfoStrings.name}
{groupInfoStrings.description}
Select the moderation service(s) to report to
{supportedLabelers ? (
{supportedLabelers.map(labeler => {
const title = getModerationServiceTitle({
displayName: labeler.creator.displayName,
handle: labeler.creator.handle,
})
return (
)
})}
) : (
None of your subscribed labelers support this content type.
)}
Optionally provide additional information below:
)
}
/**
* TODO copyright link out to DMCA
* TODO add "other" option
*/
export function ReportDialog({
params,
cleanup,
}: GlobalDialogProps) {
const t = useTheme()
const {_} = useLingui()
const insets = useSafeAreaInsets()
const control = Dialog.useDialogControl()
const [selectedLabelGroup, setSelectedLabelGroup] = React.useState<
LabelGroupDefinition['id'] | undefined
>()
const labelGroupStrings = useLabelGroupStrings()
// REQUIRED CLEANUP
const onClose = React.useCallback(() => cleanup(), [cleanup])
const i18n = React.useMemo(() => {
let title = _(msg`Report this post`)
let description = _(msg`Why should this post be reviewed?`)
if (params.type === 'user') {
title = _(msg`Report this user`)
description = _(msg`Why should this user be reviewed?`)
}
return {
title,
description,
}
}, [_, params.type])
const groups = useConfigurableLabelGroups()
return (
{selectedLabelGroup ? (
{props => (
// TODO same types mismatch
// @ts-ignore
setSelectedLabelGroup(undefined)}
onSubmitComplete={control.close}
/>
)}
) : (
{i18n.title}
{i18n.description}
{groups.map(def => {
const groupStrings = labelGroupStrings[def.id]
return (
)
})}
)}
)
}