import React, { useEffect, useState } from 'react'; import { View, Text, TextInput, TouchableOpacity, StyleSheet, KeyboardAvoidingView, Platform, ActivityIndicator, ScrollView, Image, } from 'react-native'; import AsyncStorage from '@react-native-async-storage/async-storage'; import { Ionicons } from '@expo/vector-icons'; import { router } from 'expo-router'; import { useApp } from '../../context/AppContext'; import { useColors } from '../../constants/Colors'; import { ThemeBackdrop } from '../../components/ThemeBackdrop'; import { AuthService } from '../../services/authService'; import * as AppleAuthentication from 'expo-apple-authentication'; import Constants from 'expo-constants'; import { usePostHog } from 'posthog-react-native'; export default function LoginScreen() { const { isDarkMode, colorPalette, hydrateSession, t } = useApp(); const colors = useColors(isDarkMode, colorPalette); const posthog = usePostHog(); const [email, setEmail] = useState(''); const [password, setPassword] = useState(''); const [showPassword, setShowPassword] = useState(false); const [appleAvailable, setAppleAvailable] = useState(false); const [loading, setLoading] = useState(false); const [error, setError] = useState(null); const isExpoGo = Constants.appOwnership === 'expo'; useEffect(() => { if (isExpoGo) { setAppleAvailable(false); return; } let mounted = true; AppleAuthentication.isAvailableAsync() .then((available) => { if (mounted) setAppleAvailable(available); }) .catch(() => { if (mounted) setAppleAvailable(false); }); return () => { mounted = false; }; }, [isExpoGo]); const handleLogin = async () => { if (!email.trim() || !password) { setError(t.errFillAllFields); return; } setLoading(true); setError(null); try { const session = await AuthService.login(email, password); await hydrateSession(session); router.replace('/(tabs)'); } catch (e: any) { if (e.message === 'USER_NOT_FOUND') { setError(t.errUserNotFound); } else if (e.message === 'WRONG_PASSWORD') { setError(t.errWrongPassword); } else if (e.message === 'BACKEND_URL_MISSING') { setError(t.errNetworkError); } else if (e.message === 'NETWORK_ERROR') { setError(t.errNetworkError); } else { setError(t.errLoginFailed); } } finally { setLoading(false); } }; const handleAppleSignIn = async () => { setLoading(true); setError(null); posthog.capture('apple_login_started', { surface: 'login' }); try { const credential = await AppleAuthentication.signInAsync({ requestedScopes: [ AppleAuthentication.AppleAuthenticationScope.FULL_NAME, AppleAuthentication.AppleAuthenticationScope.EMAIL, ], }); if (!credential.identityToken) { throw new Error('APPLE_AUTH_INVALID'); } const fullName = [ credential.fullName?.givenName, credential.fullName?.familyName, ].filter(Boolean).join(' '); const session = await AuthService.signInWithApple({ identityToken: credential.identityToken, appleUser: credential.user, email: credential.email, name: fullName || undefined, }); await hydrateSession(session); if (session.isNewUser) { await AsyncStorage.setItem('greenlens_show_tour', 'true'); } posthog.capture('apple_login_succeeded', { surface: 'login' }); router.replace(session.isNewUser ? '/profile/billing' : '/(tabs)'); } catch (e: any) { if (e?.code === 'ERR_REQUEST_CANCELED') { return; } posthog.capture('apple_login_failed', { surface: 'login', error: e instanceof Error ? e.message : String(e), }); setError(e?.message === 'APPLE_BACKEND_UNAVAILABLE' ? 'Apple Login ist auf dem Backend noch nicht aktiviert. Bitte Backend neu starten oder deployen.' : t.errAuthError); } finally { setLoading(false); } }; return ( {/* Logo / Header */} GreenLens {t.welcomeBack} {/* Card */} {appleAvailable ? ( ) : null} {appleAvailable ? ( {t.orDivider} ) : null} {/* Email */} E-Mail {/* Password */} {t.passwordLabel} setShowPassword((v) => !v)} style={styles.eyeBtn}> {/* Error */} {error && ( {error} )} {/* Login Button */} {loading ? ( ) : ( {t.onboardingLogin} )} {/* Divider */} {t.orDivider} {/* Sign Up Link */} router.replace('/auth/signup')} activeOpacity={0.82} > {t.noAccountYet}{' '} {t.onboardingRegister} ); } const styles = StyleSheet.create({ flex: { flex: 1 }, scroll: { flexGrow: 1, justifyContent: 'center', paddingHorizontal: 24, paddingVertical: 48, }, header: { alignItems: 'center', marginBottom: 32, }, logoIcon: { width: 56, height: 56, borderRadius: 14, marginBottom: 16, }, appName: { fontSize: 30, fontWeight: '700', letterSpacing: -0.5, marginBottom: 6, }, subtitle: { fontSize: 15, fontWeight: '400', }, card: { borderRadius: 20, borderWidth: 1, padding: 24, gap: 16, shadowOffset: { width: 0, height: 4 }, shadowOpacity: 1, shadowRadius: 12, elevation: 4, }, appleButton: { width: '100%', height: 50, marginBottom: 2, }, dividerRowCompact: { flexDirection: 'row', alignItems: 'center', gap: 12, marginVertical: 2, }, fieldGroup: { gap: 6, }, label: { fontSize: 13, fontWeight: '500', marginLeft: 2, }, inputRow: { flexDirection: 'row', alignItems: 'center', borderWidth: 1, borderRadius: 12, paddingHorizontal: 14, height: 50, }, inputIcon: { marginRight: 10, }, input: { flex: 1, fontSize: 15, height: 50, }, eyeBtn: { padding: 4, marginLeft: 6, }, errorBox: { flexDirection: 'row', alignItems: 'center', gap: 6, borderRadius: 10, paddingHorizontal: 12, paddingVertical: 10, }, errorText: { fontSize: 13, flex: 1, }, primaryBtn: { height: 52, borderRadius: 14, justifyContent: 'center', alignItems: 'center', marginTop: 4, }, primaryBtnText: { fontSize: 16, fontWeight: '600', }, dividerRow: { flexDirection: 'row', alignItems: 'center', marginVertical: 20, gap: 12, }, dividerLine: { flex: 1, height: 1, }, dividerText: { fontSize: 13, }, secondaryBtn: { height: 52, borderRadius: 14, borderWidth: 1, justifyContent: 'center', alignItems: 'center', }, secondaryBtnText: { fontSize: 15, }, });