import { useState } from 'react'; import { View, Text, TextInput, TouchableOpacity, ActivityIndicator, Platform, } from 'react-native'; import { Image } from 'expo-image'; import { useRouter } from 'expo-router'; import { SafeAreaView } from 'react-native-safe-area-context'; import Svg, { Path } from 'react-native-svg'; import { useTranslation } from 'react-i18next'; import { Ionicons } from '@expo/vector-icons'; import { useAuthStore } from '../../stores/auth'; import { HERO_AVATARS, getAvatarUrl } from '../../lib/avatars'; import { KeyboardAwareScreen } from '../../components/KeyboardAwareScreen'; function GoogleIcon() { return ( ); } function AppleIcon() { return ( ); } type OAuthProvider = 'google' | 'apple' | null; const INPUT_STYLE = { fontSize: 16, lineHeight: 22, paddingVertical: 14, paddingHorizontal: 16, color: '#0a0a0a', fontFamily: 'Nunito_400Regular', } as const; export default function SignUpScreen() { const router = useRouter(); const { t } = useTranslation(); const { signUp, signInWithOAuth } = useAuthStore(); const [email, setEmail] = useState(''); const [password, setPassword] = useState(''); const [nickname, setNickname] = useState(''); const [avatarId, setAvatarId] = useState('spider'); const [termsAccepted, setTermsAccepted] = useState(false); const [error, setError] = useState(null); const [submitting, setSubmitting] = useState(false); const [oauthLoading, setOauthLoading] = useState(null); const isLoading = submitting || oauthLoading !== null; const onOAuth = async (provider: 'google' | 'apple') => { setError(null); setOauthLoading(provider); const res = await signInWithOAuth(provider); setOauthLoading(null); if (res.error) { setError(res.error); return; } router.replace('/(app)'); }; const onSubmit = async () => { if (!email.trim() || !password || !nickname.trim()) { setError(t('auth.fillRequired')); return; } if (password.length < 8) { setError(t('auth.passwordMin8')); return; } if (!termsAccepted) { setError(t('auth.pleaseAcceptTerms')); return; } setError(null); setSubmitting(true); const res = await signUp(email.trim(), password, { username: nickname.trim(), avatarId, avatarUrl: getAvatarUrl(avatarId), }); setSubmitting(false); if (res.error) { setError(res.error); return; } router.push({ pathname: '/confirm-otp', params: { email: email.trim() } }); }; return ( {t('auth.signupTitle')} {t('auth.signupSubtitle')} {/* OAuth Buttons */} onOAuth('google')} disabled={isLoading} activeOpacity={0.8} className="flex-row items-center justify-center gap-3 bg-white border border-neutral-200 rounded-xl mb-3 disabled:opacity-40" style={{ paddingVertical: 14 }} > {oauthLoading === 'google' ? ( ) : ( )} {t('auth.googleSignup')} {Platform.OS === 'ios' ? ( onOAuth('apple')} disabled={isLoading} activeOpacity={0.8} className="flex-row items-center justify-center gap-3 bg-neutral-900 rounded-xl mb-6 disabled:opacity-40" style={{ paddingVertical: 14 }} > {oauthLoading === 'apple' ? ( ) : ( )} {t('auth.appleSignup')} ) : null} {/* Divider */} {t('auth.orWithEmail')} {error && ( {error} )} {/* Avatar Picker */} {t('auth.chooseAvatar')} {HERO_AVATARS.map((avatar) => { const selected = avatar.id === avatarId; return ( setAvatarId(avatar.id)} disabled={isLoading} activeOpacity={0.7} className={`rounded-full ${selected ? 'opacity-100' : 'opacity-40'}`} > ); })} {/* Privacy notice */} {t('auth.privacyNotice')} {/* Terms Checkbox */} setTermsAccepted(!termsAccepted)} disabled={isLoading} activeOpacity={0.7} className="flex-row items-start gap-3 mb-6" > {termsAccepted && ( )} {t('auth.acceptTerms')}{' '} {t('auth.termsLink')} {t('auth.acceptTermsSuffix')} {submitting ? ( ) : ( {t('auth.signupTitle')} )} router.push('/signin')} activeOpacity={0.7} className="py-4 items-center mt-2" > {t('auth.alreadyRegistered')}{' '} {t('auth.signin')} ); }