import { useState } from 'react';
import {
View,
Text,
TextInput,
Pressable,
KeyboardAvoidingView,
Platform,
ScrollView,
Image,
ActivityIndicator,
} from 'react-native';
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 { useAuthStore } from '../../stores/auth';
import { HERO_AVATARS, getAvatarUrl } from '../../lib/avatars';
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 [firstName, setFirstName] = useState('');
const [lastName, setLastName] = 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(),
firstName: firstName.trim() || undefined,
lastName: lastName.trim() || undefined,
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}
className="flex-row items-center justify-center gap-3 bg-white border border-neutral-200 rounded-xl mb-3 active:opacity-80 disabled:opacity-40"
style={{ paddingVertical: 14 }}
>
{oauthLoading === 'google' ? (
) : (
)}
{t('auth.googleSignup')}
onOAuth('apple')}
disabled={isLoading}
className="flex-row items-center justify-center gap-3 bg-neutral-900 rounded-xl mb-6 active:opacity-80 disabled:opacity-40"
style={{ paddingVertical: 14 }}
>
{oauthLoading === 'apple' ? (
) : (
)}
{t('auth.appleSignup')}
{/* 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}
className={`rounded-full ${selected ? 'opacity-100' : 'opacity-40'}`}
>
);
})}
{/* Privacy notice */}
🛡
{t('auth.privacyNotice')}
{/* Terms Checkbox */}
setTermsAccepted(!termsAccepted)}
disabled={isLoading}
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')}
className="py-4 items-center mt-2"
>
{t('auth.alreadyRegistered')}{' '}
{t('auth.signin')}
);
}