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')}
);
}