import { useEffect, useState } from 'react'; import { View, Text, TextInput, TouchableOpacity, ActivityIndicator, Platform, } 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 { Ionicons } from '@expo/vector-icons'; import { useAuthStore, type DeviceLockedError } from '../../stores/auth'; import { KeyboardAwareScreen } from '../../components/KeyboardAwareScreen'; function GoogleIcon() { return ( ); } function AppleIcon() { return ( ); } type OAuthProvider = 'google' | 'apple' | null; function formatRemainingTime(isoTarget: string): string { const ms = new Date(isoTarget).getTime() - Date.now(); if (ms <= 0) return '0min'; const totalMin = Math.floor(ms / 60_000); const h = Math.floor(totalMin / 60); const m = totalMin % 60; if (h > 0) return `${h}h ${m}min`; return `${m}min`; } function DeviceLockedPanel({ locked, onBack, }: { locked: DeviceLockedError; onBack: () => void; }) { const { t } = useTranslation(); const [remaining, setRemaining] = useState( locked.lockedUntil ? formatRemainingTime(locked.lockedUntil) : null ); useEffect(() => { if (!locked.lockedUntil) return; const id = setInterval(() => { setRemaining(formatRemainingTime(locked.lockedUntil!)); }, 30_000); return () => clearInterval(id); }, [locked.lockedUntil]); return ( {t('auth.device_locked_headline')} {t('auth.device_locked_body')} {remaining ? ( {t('auth.device_locked_countdown', { remaining })} ) : null} {t('auth.device_locked_email_hint')} {locked.releaseRequestable ? ( {t('auth.device_locked_use_original')} ) : null} {t('auth.device_locked_back')} ); } const INPUT_STYLE = { fontSize: 16, lineHeight: 22, paddingVertical: 14, paddingHorizontal: 16, color: '#0a0a0a', fontFamily: 'Nunito_400Regular', } as const; export default function SignInScreen() { const router = useRouter(); const { t } = useTranslation(); const { signInWithPassword, signInWithOAuth } = useAuthStore(); const [email, setEmail] = useState(''); const [password, setPassword] = useState(''); const [error, setError] = useState(null); const [submitting, setSubmitting] = useState(false); const [oauthLoading, setOauthLoading] = useState(null); const [deviceLocked, setDeviceLocked] = useState(null); const onSubmit = async () => { if (!email.trim() || !password) return; setError(null); setSubmitting(true); const res = await signInWithPassword(email.trim(), password); setSubmitting(false); if (res.deviceLocked) { setDeviceLocked(res.deviceLocked); return; } if (res.error) { setError(res.error); return; } router.replace('/(app)'); }; 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 isLoading = submitting || oauthLoading !== null; if (deviceLocked) { return ( setDeviceLocked(null)} /> ); } return ( {t('auth.welcomeBack')} {t('auth.signinSubtitle')} {/* 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.googleSignin')} {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.appleSignin')} ) : null} {/* Divider */} {t('auth.orWithEmail')} {/* Email + Password */} router.push('/forgot-password')} activeOpacity={0.7} className="self-end py-2 mb-4" > {t('auth.forgotPassword')} {error && ( {error} )} {submitting ? ( ) : ( {t('auth.signin')} )} router.push('/signup')} activeOpacity={0.7} className="py-4 items-center mt-2" > {t('auth.noAccount')}{' '} {t('auth.signup')} ); }