/** * 举报对话框组件 * 支持举报帖子、评论、消息 */ import React, { useState, useCallback } from 'react'; import { Modal, View, Text, TouchableOpacity, StyleSheet, ScrollView, TextInput, ActivityIndicator, Alert, } from 'react-native'; import { MaterialCommunityIcons } from '@expo/vector-icons'; import { useAppColors } from '../../../theme'; import { spacing, borderRadius, fontSizes } from '../../../theme'; import reportService, { ReportReason, ReportTargetType, REPORT_REASONS } from '../../../services/reportService'; export interface ReportDialogProps { visible: boolean; targetType: ReportTargetType; targetId: string; onClose: () => void; onSuccess?: () => void; } // 目标类型中文名称映射 const TARGET_TYPE_LABELS: Record = { post: '帖子', comment: '评论', message: '消息', }; export const ReportDialog: React.FC = ({ visible, targetType, targetId, onClose, onSuccess, }) => { const colors = useAppColors(); const styles = useStyles(colors); const [selectedReason, setSelectedReason] = useState(null); const [description, setDescription] = useState(''); const [submitting, setSubmitting] = useState(false); // 提交举报 const handleSubmit = useCallback(async () => { if (!selectedReason) { Alert.alert('提示', '请选择举报原因'); return; } setSubmitting(true); try { const result = await reportService.createReport( targetType, targetId, selectedReason, description.trim() || undefined ); if (result) { Alert.alert('举报成功', '感谢您的反馈,我们会尽快处理', [ { text: '确定', onPress: () => { onClose(); onSuccess?.(); }, }, ]); } else { Alert.alert('举报失败', '请稍后重试'); } } catch (error) { console.error('Submit report error:', error); Alert.alert('举报失败', '网络错误,请稍后重试'); } finally { setSubmitting(false); } }, [selectedReason, description, targetType, targetId, onClose, onSuccess]); // 重置状态 const handleClose = useCallback(() => { setSelectedReason(null); setDescription(''); onClose(); }, [onClose]); return ( {/* 头部 */} 举报{TARGET_TYPE_LABELS[targetType]} {/* 内容 */} {/* 举报原因选择 */} 请选择举报原因 {REPORT_REASONS.map((item) => ( setSelectedReason(item.value)} disabled={submitting} > {selectedReason === item.value && ( )} {item.label} ))} {/* 补充说明 */} 补充说明(选填) {description.length}/500 {/* 底部按钮 */} 取消 {submitting ? ( ) : ( 提交举报 )} ); }; // 创建样式 const useStyles = (colors: ReturnType) => StyleSheet.create({ overlay: { flex: 1, backgroundColor: 'rgba(0, 0, 0, 0.5)', justifyContent: 'center', alignItems: 'center', padding: spacing.lg, }, container: { backgroundColor: colors.backgroundPrimary, borderRadius: borderRadius.lg, width: '100%', maxWidth: 400, maxHeight: '80%', }, header: { flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center', padding: spacing.lg, borderBottomWidth: 1, borderBottomColor: colors.borderLight, }, title: { fontSize: fontSizes.lg, fontWeight: '600', color: colors.textPrimary, }, closeButton: { padding: spacing.xs, }, content: { padding: spacing.lg, maxHeight: 400, }, sectionTitle: { fontSize: fontSizes.md, fontWeight: '500', color: colors.textPrimary, marginBottom: spacing.sm, }, reasonList: { marginBottom: spacing.lg, }, reasonItem: { paddingVertical: spacing.sm, borderBottomWidth: 1, borderBottomColor: colors.borderLight, }, reasonItemSelected: { backgroundColor: colors.backgroundSecondary, marginHorizontal: -spacing.sm, paddingHorizontal: spacing.sm, borderRadius: borderRadius.sm, }, radioContainer: { flexDirection: 'row', alignItems: 'center', }, radio: { width: 20, height: 20, borderRadius: 10, borderWidth: 2, borderColor: colors.border, justifyContent: 'center', alignItems: 'center', marginRight: spacing.sm, }, radioSelected: { borderColor: colors.primary, }, radioDot: { width: 10, height: 10, borderRadius: 5, backgroundColor: colors.primary, }, reasonLabel: { fontSize: fontSizes.md, color: colors.textPrimary, }, textInput: { borderWidth: 1, borderColor: colors.border, borderRadius: borderRadius.md, padding: spacing.sm, fontSize: fontSizes.md, color: colors.textPrimary, minHeight: 100, textAlignVertical: 'top', }, charCount: { fontSize: fontSizes.sm, color: colors.textTertiary, textAlign: 'right', marginTop: spacing.xs, }, footer: { flexDirection: 'row', padding: spacing.lg, borderTopWidth: 1, borderTopColor: colors.borderLight, gap: spacing.sm, }, cancelButton: { flex: 1, paddingVertical: spacing.sm, borderRadius: borderRadius.md, borderWidth: 1, borderColor: colors.border, alignItems: 'center', }, cancelButtonText: { fontSize: fontSizes.md, color: colors.textSecondary, }, submitButton: { flex: 1, paddingVertical: spacing.sm, borderRadius: borderRadius.md, backgroundColor: colors.primary, alignItems: 'center', }, submitButtonDisabled: { backgroundColor: colors.primary + '60', }, submitButtonText: { fontSize: fontSizes.md, color: '#FFFFFF', fontWeight: '500', }, }); export default ReportDialog;