import React, {memo, useMemo, useState} from 'react' import {View} from 'react-native' import { $Typed, AppBskyActorDefs, ChatBskyConvoDefs, ComAtprotoModerationCreateReport, RichText as RichTextAPI, } from '@atproto/api' import {msg, Trans} from '@lingui/macro' import {useLingui} from '@lingui/react' import {StackActions, useNavigation} from '@react-navigation/native' import {useMutation} from '@tanstack/react-query' import {ReportOption} from '#/lib/moderation/useReportOptions' import {NavigationProp} from '#/lib/routes/types' import {isNative} from '#/platform/detection' import {useProfileShadow} from '#/state/cache/profile-shadow' import {useLeaveConvo} from '#/state/queries/messages/leave-conversation' import { useProfileBlockMutationQueue, useProfileQuery, } from '#/state/queries/profile' import {useAgent} from '#/state/session' import {CharProgress} from '#/view/com/composer/char-progress/CharProgress' import * as Toast from '#/view/com/util/Toast' import {atoms as a, platform, useBreakpoints, useTheme, web} from '#/alf' import {Button, ButtonIcon, ButtonText} from '#/components/Button' import * as Dialog from '#/components/Dialog' import {Divider} from '#/components/Divider' import * as Toggle from '#/components/forms/Toggle' import {ChevronLeft_Stroke2_Corner0_Rounded as Chevron} from '#/components/icons/Chevron' import {PaperPlane_Stroke2_Corner0_Rounded as SendIcon} from '#/components/icons/PaperPlane' import {Loader} from '#/components/Loader' import {SelectReportOptionView} from '#/components/ReportDialog/SelectReportOptionView' import {RichText} from '#/components/RichText' import {Text} from '#/components/Typography' import {MessageItemMetadata} from './MessageItem' type ReportDialogParams = { type: 'convoMessage' convoId: string message: ChatBskyConvoDefs.MessageView } let ReportDialog = ({ control, params, currentScreen, }: { control: Dialog.DialogControlProps params: ReportDialogParams currentScreen: 'list' | 'conversation' }): React.ReactNode => { const {_} = useLingui() return ( ) } ReportDialog = memo(ReportDialog) export {ReportDialog} function DialogInner({ params, currentScreen, }: { params: ReportDialogParams currentScreen: 'list' | 'conversation' }) { const {data: profile, isError} = useProfileQuery({ did: params.message.sender.did, }) const [reportOption, setReportOption] = useState(null) const [done, setDone] = useState(false) const control = Dialog.useDialogContext() return done ? ( profile ? ( ) : ( ) ) : reportOption ? ( setReportOption(null)} onComplete={() => { if (isError) { control.close() } else { setDone(true) } }} /> ) : ( ) } function ReasonStep({ setReportOption, }: { setReportOption: (reportOption: ReportOption) => void params: ReportDialogParams }) { const control = Dialog.useDialogContext() return ( ) } function SubmitStep({ params, reportOption, goBack, onComplete, }: { params: ReportDialogParams reportOption: ReportOption goBack: () => void onComplete: () => void }) { const {_} = useLingui() const {gtMobile} = useBreakpoints() const t = useTheme() const [details, setDetails] = useState('') const agent = useAgent() const { mutate: submit, error, isPending: submitting, } = useMutation({ mutationFn: async () => { if (params.type === 'convoMessage') { const {convoId, message} = params const subject: $Typed = { $type: 'chat.bsky.convo.defs#messageRef', messageId: message.id, convoId, did: message.sender.did, } const report = { reasonType: reportOption.reason, subject, reason: details, } satisfies ComAtprotoModerationCreateReport.InputSchema await agent.createModerationReport(report) } }, onSuccess: onComplete, }) const copy = useMemo(() => { return { convoMessage: { title: _(msg`Report this message`), }, }[params.type] }, [_, params]) return ( {copy.title} Your report will be sent to the Bluesky Moderation Service {params.type === 'convoMessage' && ( )} Reason: {' '} {reportOption.title} Optionally provide additional information below: {error && ( There was an issue sending your report. Please check your internet connection. )} ) } function DoneStep({ convoId, currentScreen, profile, }: { convoId: string currentScreen: 'list' | 'conversation' profile: AppBskyActorDefs.ProfileViewDetailed }) { const {_} = useLingui() const navigation = useNavigation() const control = Dialog.useDialogContext() const {gtMobile} = useBreakpoints() const t = useTheme() const [actions, setActions] = useState(['block', 'leave']) const shadow = useProfileShadow(profile) const [queueBlock] = useProfileBlockMutationQueue(shadow) const {mutate: leaveConvo} = useLeaveConvo(convoId, { onMutate: () => { if (currentScreen === 'conversation') { navigation.dispatch( StackActions.replace('Messages', isNative ? {animation: 'pop'} : {}), ) } }, onError: () => { Toast.show(_(msg`Could not leave chat`), 'xmark') }, }) let btnText = _(msg`Done`) let toastMsg: string | undefined if (actions.includes('leave') && actions.includes('block')) { btnText = _(msg`Block and Delete`) toastMsg = _(msg`Conversation deleted`) } else if (actions.includes('leave')) { btnText = _(msg`Delete Conversation`) toastMsg = _(msg`Conversation deleted`) } else if (actions.includes('block')) { btnText = _(msg`Block User`) toastMsg = _(msg`User blocked`) } const onPressPrimaryAction = () => { control.close(() => { if (actions.includes('block')) { queueBlock() } if (actions.includes('leave')) { leaveConvo() } if (toastMsg) { Toast.show(toastMsg, 'check') } }) } return ( Report submitted Our moderation team has received your report. Block user Delete conversation ) } function PreviewMessage({message}: {message: ChatBskyConvoDefs.MessageView}) { const t = useTheme() const rt = useMemo(() => { return new RichTextAPI({text: message.text, facets: message.facets}) }, [message.text, message.facets]) return ( ) }