/** * 注册页面(分步向导版) * 威友 - 用户注册流程 * * 步骤: * 1. 输入邮箱 * 2. 填写验证码 * 3. 设置用户信息 * * 使用 registerStore 纯内存状态管理 */ import React, { useEffect, useMemo, useRef } from 'react'; import { View, Text, StyleSheet, KeyboardAvoidingView, Platform, ScrollView, Animated, StatusBar, TouchableOpacity, } from 'react-native'; import { SafeAreaView } from 'react-native-safe-area-context'; import { useRouter } from 'expo-router'; import { MaterialCommunityIcons } from '@expo/vector-icons'; import { useAppColors, useResolvedColorScheme, type AppColors } from '../../theme'; import { authService, resolveAuthApiError } from '@/services/auth'; import { useAuthStore } from '../../stores'; import { useRegisterStore, useRegisterStep, useRegisterFormData, useRegisterCountdown, } from '../../stores/auth'; import * as hrefs from '../../navigation/hrefs'; import { showPrompt } from '@/services/ui'; import { RegisterStepIndicator } from '../../components/common'; import { RegisterStepProps, RegisterStep } from './types'; import { RegisterStep1Email } from './RegisterStep1Email'; import { RegisterStep2Verification } from './RegisterStep2Verification'; import { RegisterStep3Profile } from './RegisterStep3Profile'; // 威友橙主题色 const THEME_COLORS = { primary: '#FF6B35', primaryLight: '#FF8C5A', primaryDark: '#E55A2B', }; // 步骤组件映射 const STEP_COMPONENTS = [ RegisterStep1Email, RegisterStep2Verification, RegisterStep3Profile, ]; export const RegisterScreen: React.FC = () => { const colors = useAppColors(); const resolved = useResolvedColorScheme(); const styles = useMemo(() => createRegisterStyles(colors), [colors]); const router = useRouter(); const register = useAuthStore((state) => state.register); const isAuthenticated = useAuthStore((state) => state.isAuthenticated); // 注册步骤状态 const currentStep = useRegisterStep(); const formData = useRegisterFormData(); const countdown = useRegisterCountdown(); const { setCurrentStep, updateFormData, setCountdown, decrementCountdown, markStepCompleted, resetRegisterData, goToNextStep, goToPrevStep, } = useRegisterStore.getState(); // 本地状态 const [loading, setLoading] = React.useState(false); const [sendingCode, setSendingCode] = React.useState(false); // 动画值 const fadeAnim = useRef(new Animated.Value(0)).current; const slideAnim = useRef(new Animated.Value(20)).current; // 页面挂载时重置倒计时,避免上次残留的倒计时导致无法重新获取验证码 useEffect(() => { setCountdown(0); }, []); // 检查是否已登录 useEffect(() => { if (isAuthenticated) { router.replace(hrefs.hrefHome()); } }, [isAuthenticated, router]); // 启动入场动画 useEffect(() => { Animated.parallel([ Animated.timing(fadeAnim, { toValue: 1, duration: 400, useNativeDriver: true, }), Animated.timing(slideAnim, { toValue: 0, duration: 400, useNativeDriver: true, }), ]).start(); }, [currentStep]); // 步骤切换时重新触发动画 // 倒计时处理 useEffect(() => { if (countdown <= 0) { return; } const timer = setInterval(() => { decrementCountdown(); }, 1000); return () => clearInterval(timer); }, [countdown, decrementCountdown]); // 发送验证码 const handleSendCode = async (email: string): Promise => { setSendingCode(true); try { const ok = await authService.sendRegisterCode(email.trim()); if (ok) { setCountdown(180); // 3分钟倒计时 showPrompt({ title: '发送成功', message: '验证码已发送,请查收邮箱(有效期3分钟)', type: 'success', }); return true; } return false; } catch (error: any) { showPrompt({ title: '发送失败', message: resolveAuthApiError(error, '验证码发送失败,请稍后重试'), type: 'error', }); return false; } finally { setSendingCode(false); } }; // 处理步骤完成 const handleStepComplete = () => { markStepCompleted(currentStep as 0 | 1 | 2); goToNextStep(); }; // 处理返回上一步 const handleGoBack = () => { if (currentStep > 0) { goToPrevStep(); } }; // 处理注册 const handleRegister = async () => { setLoading(true); try { const success = await register({ username: formData.username, password: formData.password, nickname: formData.nickname, email: formData.email.trim(), verification_code: formData.verificationCode.trim(), phone: formData.phone || undefined, }); if (success) { // 注册成功,清空注册数据 resetRegisterData(); // 导航会自动切换到主页(通过 isAuthenticated 变化) } else { const msg = useAuthStore.getState().error || '注册失败,请稍后重试'; showPrompt({ title: '注册失败', message: msg, type: 'error' }); } } catch (error: any) { showPrompt({ title: '注册失败', message: resolveAuthApiError(error, '请稍后重试'), type: 'error', }); } finally { setLoading(false); } }; // 渲染当前步骤的组件 const StepComponent = STEP_COMPONENTS[currentStep]; // 准备步骤组件的 props const stepProps: RegisterStepProps = { formData, updateFormData, onNext: currentStep === 2 ? handleRegister : handleStepComplete, onPrev: handleGoBack, colors, loading, sendingCode, countdown, onSendCode: handleSendCode, }; // 获取已完成的步骤 const completedSteps = [0, 1, 2].filter( (step) => useRegisterStore.getState().completedSteps[step as 0 | 1 | 2] ); // 跳转到登录页 const handleGoToLogin = () => { router.push(hrefs.hrefAuthLogin()); }; return ( {/* 顶部导航 */} 0 ? handleGoBack : handleGoToLogin} style={styles.backIconButton} activeOpacity={0.8} > 0 ? 'arrow-left' : 'close'} size={24} color={colors.text?.primary || '#333'} /> 注册 {/* 步骤指示器 */} {/* 步骤内容 */} {/* 底部登录提示 */} 已有账号? 立即登录 ); }; function createRegisterStyles(colors: AppColors) { return StyleSheet.create({ container: { flex: 1, backgroundColor: colors.background.paper, }, keyboardView: { flex: 1, }, scrollContent: { flexGrow: 1, paddingHorizontal: 24, paddingTop: 20, paddingBottom: 40, }, header: { flexDirection: 'row', alignItems: 'center', justifyContent: 'space-between', marginBottom: 24, }, backIconButton: { width: 40, height: 40, alignItems: 'center', justifyContent: 'center', marginLeft: -12, padding: 0, }, headerTitle: { fontSize: 18, fontWeight: '600', color: colors.text?.primary || '#333', }, headerRight: { width: 40, }, stepIndicator: { marginBottom: 32, }, content: { flex: 1, }, footer: { flexDirection: 'row', justifyContent: 'center', alignItems: 'center', marginTop: 32, }, footerText: { fontSize: 15, color: colors.text?.secondary || '#666', }, loginLink: { fontSize: 15, color: colors.primary.main, fontWeight: '600', marginLeft: 6, }, }); } export default RegisterScreen;