/** * 登录/注册弹窗组件 * 支持登录和注册两种模式 */ import React, { useState, useCallback } from 'react'; import { View, Text, StyleSheet, TouchableOpacity, TextInput, Modal, ScrollView, KeyboardAvoidingView, Platform, Alert, } from 'react-native'; import { useColorScheme, useThemeColors } from '@/theme'; import { createThemeStyles } from '@/theme'; import { useUserStore } from '@/stores'; import Ionicons from '@expo/vector-icons/Ionicons'; /** * 创建主题样式 */ const styles = createThemeStyles((colors) => ({ overlay: { flex: 1, backgroundColor: 'rgba(0, 0, 0, 0.5)', justifyContent: 'flex-end', }, container: { backgroundColor: colors.background, borderTopLeftRadius: 20, borderTopRightRadius: 20, paddingHorizontal: 20, paddingTop: 20, paddingBottom: 40, maxHeight: '80%', }, header: { flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center', marginBottom: 20, }, title: { fontSize: 18, fontWeight: '700', color: colors.text, }, closeButton: { padding: 8, }, tabContainer: { flexDirection: 'row', marginBottom: 20, borderBottomWidth: 1, borderBottomColor: colors.borderSecondary, }, tab: { flex: 1, paddingVertical: 12, alignItems: 'center', borderBottomWidth: 2, borderBottomColor: 'transparent', }, activeTab: { borderBottomColor: colors.primary, }, tabText: { fontSize: 14, fontWeight: '600', color: colors.text + '80', }, activeTabText: { color: colors.primary, }, form: { gap: 12, }, inputContainer: { marginBottom: 12, }, label: { fontSize: 12, color: colors.text + '80', marginBottom: 6, }, input: { borderWidth: 1, borderColor: colors.borderSecondary, borderRadius: 8, paddingHorizontal: 12, paddingVertical: 10, fontSize: 14, color: colors.text, backgroundColor: colors.card, }, inputFocused: { borderColor: colors.primary, }, errorText: { fontSize: 12, color: '#ff4444', marginTop: 4, }, submitButton: { backgroundColor: colors.primary, borderRadius: 8, paddingVertical: 12, alignItems: 'center', marginTop: 20, }, submitButtonText: { color: '#fff', fontSize: 16, fontWeight: '700', }, divider: { flexDirection: 'row', alignItems: 'center', marginVertical: 16, }, dividerLine: { flex: 1, height: 1, backgroundColor: colors.borderSecondary, }, dividerText: { marginHorizontal: 12, fontSize: 12, color: colors.text + '80', }, socialButtons: { flexDirection: 'row', gap: 12, }, socialButton: { flex: 1, borderWidth: 1, borderColor: colors.borderSecondary, borderRadius: 8, paddingVertical: 10, alignItems: 'center', }, agreementText: { fontSize: 12, color: colors.text + '80', marginTop: 12, lineHeight: 18, }, agreementLink: { color: colors.primary, textDecorationLine: 'underline', }, })); interface LoginRegisterModalProps { visible: boolean; onClose: () => void; } /** * 登录/注册弹窗组件 */ export default function LoginRegisterModal({ visible, onClose }: LoginRegisterModalProps) { const colorScheme = useColorScheme(); const s = styles[colorScheme]; const themeColors = useThemeColors(); const { login } = useUserStore(); const [mode, setMode] = useState<'login' | 'register'>('login'); const [email, setEmail] = useState(''); const [password, setPassword] = useState(''); const [confirmPassword, setConfirmPassword] = useState(''); const [errors, setErrors] = useState>({}); const [loading, setLoading] = useState(false); const validateEmail = useCallback((email: string) => { const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; return emailRegex.test(email); }, []); const validateForm = useCallback(() => { const newErrors: Record = {}; if (!email.trim()) { newErrors.email = '请输入邮箱'; } else if (!validateEmail(email)) { newErrors.email = '邮箱格式不正确'; } if (!password.trim()) { newErrors.password = '请输入密码'; } else if (password.length < 6) { newErrors.password = '密码至少6个字符'; } if (mode === 'register') { if (!confirmPassword.trim()) { newErrors.confirmPassword = '请确认密码'; } else if (password !== confirmPassword) { newErrors.confirmPassword = '两次输入的密码不一致'; } } setErrors(newErrors); return Object.keys(newErrors).length === 0; }, [email, password, confirmPassword, mode, validateEmail]); const handleSubmit = useCallback(async () => { if (!validateForm()) { return; } try { setLoading(true); // 模拟 API 调用 await new Promise((resolve) => setTimeout(resolve, 1000)); // 模拟登录/注册成功 const mockUser = { id: '1', username: email.split('@')[0], email, avatar: 'https://i.pravatar.cc/150?img=1', nickname: '用户', createdAt: new Date().toISOString(), }; login(mockUser, 'mock-token-' + Date.now()); Alert.alert('成功', mode === 'login' ? '登录成功!' : '注册成功!'); onClose(); } catch (error: any) { Alert.alert('失败', error.message || '操作失败,请重试'); } finally { setLoading(false); } }, [validateForm, email, mode, login, onClose]); const handleSwitchMode = useCallback(() => { setMode(mode === 'login' ? 'register' : 'login'); setErrors({}); }, [mode]); return ( {/* 头部 */} {mode === 'login' ? '登录' : '注册'} {/* 标签页 */} setMode('login')} activeOpacity={0.7} > 登录 setMode('register')} activeOpacity={0.7} > 注册 {/* 表单 */} {/* 邮箱 */} 邮箱 {errors.email && {errors.email}} {/* 密码 */} 密码 {errors.password && {errors.password}} {/* 确认密码(注册模式) */} {mode === 'register' && ( 确认密码 {errors.confirmPassword && ( {errors.confirmPassword} )} )} {/* 提交按钮 */} {loading ? '处理中...' : mode === 'login' ? '登录' : '注册'} {/* 用户协议 */} {mode === 'register' && ( 注册即表示同意 用户协议隐私政策 )} ); }