import { StaticScreenProps, useNavigation, StackActions } from '@react-navigation/native' import type { NativeStackNavigationOptions, NativeStackScreenProps, } from '@react-navigation/native-stack' import React, { useCallback, useLayoutEffect, useMemo, useState } from 'react' import { View, StyleSheet, TextInput } from 'react-native' import { useSafeAreaInsets } from 'react-native-safe-area-context' import { Spinner, Text, KeyboardScrollView } from '../components' import { composeOptions, useHeaderRight, withLeftClose, } from '../components/display/platform_modal_header_buttons' import BlankState from '../components/primitive/blank_state_primitive' import { useTheme } from '../hooks' import { useConversationMessages } from '../hooks/use_conversation_messages' import { useReportMessage } from '../hooks/use_report_message' import { MessageResource } from '../types' import { MessageReportReason } from '../types/resources/message_report' import { platformFontWeightBold } from '../utils' import { MessagePreview } from './message_report/components/message_preview' import { ReportReasonList } from './message_report/components/report_reason_list' const MAX_DETAIL_LENGTH = 500 export const MessageReportScreenOptions = ({ navigation, route, }: NativeStackScreenProps): NativeStackNavigationOptions => { const handleClose = () => navigation.dispatch( StackActions.popTo( 'Conversation', { conversation_id: route.params?.conversation_id }, { merge: true } ) ) return composeOptions( { presentation: 'modal', title: 'Report message' }, withLeftClose({ onPress: handleClose }) ) } export type MessageReportScreenProps = StaticScreenProps<{ conversation_id: number message_id: string }> export function MessageReportScreen({ route }: MessageReportScreenProps) { const { conversation_id, message_id } = route.params const { messages } = useConversationMessages({ conversation_id }, { refetchOnMount: false }) const message = messages.find(m => m.id === message_id) if (!message) return null return } function MessageReportScreenContent({ message, conversation_id, }: { message: MessageResource conversation_id: number }) { const styles = useStyles() const navigation = useNavigation() const [selectedReason, setSelectedReason] = useState(null) const [reasonDetail, setReasonDetail] = useState('') const { mutate: submitReport, status } = useReportMessage(conversation_id, message.id) const handleReasonChange = useCallback((reason: MessageReportReason) => { setSelectedReason(reason) if (reason !== 'other') { setReasonDetail('') } }, []) const isFormValid = useMemo(() => { if (selectedReason === null) return false if (selectedReason === 'other' && reasonDetail.trim().length === 0) { return false } if (status === 'pending') return false return true }, [selectedReason, reasonDetail, status]) const handleSubmit = useCallback(() => { if (!isFormValid || !selectedReason) return submitReport({ reason: selectedReason, reasonDetail: selectedReason === 'other' ? reasonDetail : undefined, }) }, [isFormValid, selectedReason, reasonDetail, submitReport]) const handleClose = useCallback(() => { navigation.dispatch(StackActions.popTo('Conversation', { conversation_id }, { merge: true })) }, [navigation, conversation_id]) const formVisible = status !== 'pending' && status !== 'success' useHeaderRight({ icon: 'general.upArrow', accessibilityLabel: 'Submit', prominent: true, onPress: handleSubmit, disabled: !isFormValid, enabled: formVisible, }) useLayoutEffect(() => { if (formVisible) { navigation.setOptions({ headerTitle: 'Report message' }) } }, [formVisible, navigation]) if (status === 'pending') { return ( Submitting report... ) } if (status === 'success') { return ( Message reported The message has been reported and a church leader will be contacted. ) } if (status === 'error') { return ( Unable to submit report We were unable to report this message. Please try again. ) } return ( Reporting this message will notify a church leader. The person you are reporting will not receive a notification from Church Center. If someone is in immediate danger, call local emergency services. Don't wait. What best describes the problem? * {selectedReason === 'other' && ( Please provide more details * {reasonDetail.length >= MAX_DETAIL_LENGTH - 100 && ( {reasonDetail.length}/{MAX_DETAIL_LENGTH} )} )} ) } const useStyles = () => { const { bottom } = useSafeAreaInsets() const { colors } = useTheme() return StyleSheet.create({ container: { padding: 16, paddingBottom: 16 + bottom, gap: 24, }, fullHeight: { flex: 1, justifyContent: 'center', alignItems: 'center', }, fullScreenContainer: { flex: 1, justifyContent: 'center', alignItems: 'center', backgroundColor: colors.surfaceColor100, }, loadingText: { marginTop: 16, fontSize: 16, fontWeight: '600', color: colors.textColorDefaultPrimary, }, warningText: { fontSize: 14, lineHeight: 20, color: colors.textColorDefaultSecondary, }, reasonSection: { gap: 8, }, fieldLabel: { fontSize: 16, fontWeight: platformFontWeightBold, color: colors.textColorDefaultPrimary, }, required: { color: colors.statusErrorText, }, reasonListContainer: { backgroundColor: colors.surfaceColor100, }, detailSection: { gap: 8, }, textInput: { color: colors.textColorDefaultPrimary, fontSize: 16, textAlignVertical: 'top', minHeight: 120, maxHeight: 200, borderWidth: 1, borderColor: colors.borderColorDefaultBase, borderRadius: 8, paddingHorizontal: 16, paddingVertical: 12, backgroundColor: colors.surfaceColor100, }, successIcon: { color: colors.statusSuccessIcon, fontSize: 48, }, successTitle: { fontSize: 24, marginBottom: 4, }, successSubtitle: { fontSize: 16, marginBottom: 4, }, }) }