import AsyncStorage from "@react-native-async-storage/async-storage"; import { Picker } from "@react-native-picker/picker"; import * as LocalAuthentication from "expo-local-authentication"; import * as Location from "expo-location"; import { useRouter } from "expo-router"; import * as SQLite from "expo-sqlite"; import React, { useEffect, useState } from "react"; import { ActivityIndicator, Alert, KeyboardAvoidingView, Platform, SafeAreaView, ScrollView, StyleSheet, Text, TextInput, TouchableOpacity, View, } from "react-native"; // Types interface User { id: number; email: string; firstName: string; lastName: string; residence: string; residenceStreet: string; residenceNumber: string; workplace: string; workplaceStreet: string; workplaceNumber: string; transportMode: string; latitude: string; longitude: string; createdAt: string; } // Simple Auth Component export default function AuthScreen() { const [isLoggedIn, setIsLoggedIn] = useState(false); const [loading, setLoading] = useState(true); const [currentUser, setCurrentUser] = useState(null); const [authMode, setAuthMode] = useState<"login" | "register">("login"); // Form states const [email, setEmail] = useState(""); const [password, setPassword] = useState(""); const [firstName, setFirstName] = useState(""); const [lastName, setLastName] = useState(""); const [residence, setResidence] = useState(""); const [residenceStreet, setResidenceStreet] = useState(""); const [residenceNumber, setResidenceNumber] = useState(""); const [workplace, setWorkplace] = useState(""); const [workplaceStreet, setWorkplaceStreet] = useState(""); const [workplaceNumber, setWorkplaceNumber] = useState(""); const [latitude, setLatitude] = useState(null); const [longitude, setLongitude] = useState(null); const [biometricSupported, setBiometricSupported] = useState(false); const [showCalendar, setShowCalendar] = useState(false); const [transportMode, setTransportMode] = useState("auto"); const [editMode, setEditMode] = useState(false); const [showOnlyName, setShowOnlyName] = useState(false); // Database const [db, setDb] = useState(null); const router = useRouter(); useEffect(() => { initApp(); }, []); const initApp = async () => { try { // Initialize database const database = await SQLite.openDatabaseAsync("AuthApp.db"); setDb(database); await database.execAsync(` CREATE TABLE IF NOT EXISTS users ( id INTEGER PRIMARY KEY AUTOINCREMENT, email TEXT UNIQUE NOT NULL, firstName TEXT NOT NULL, lastName TEXT NOT NULL, password TEXT NOT NULL, residence TEXT, residenceStreet TEXT, residenceNumber TEXT, workplace TEXT, workplaceStreet TEXT, workplaceNumber TEXT, transportMode TEXT, latitude TEXT, longitude TEXT, createdAt TEXT NOT NULL ) `); // Check biometric support const compatible = await LocalAuthentication.hasHardwareAsync(); const enrolled = await LocalAuthentication.isEnrolledAsync(); setBiometricSupported(compatible && enrolled); // Check if user is logged in const session = await AsyncStorage.getItem("@user_session"); if (session) { const userData = JSON.parse(session); setCurrentUser(userData.user); setIsLoggedIn(true); } } catch (error) { console.error("App initialization failed:", error); } finally { setLoading(false); } }; const handleRegister = async () => { if ( !email || !password || !firstName || !lastName || !residence || !residenceStreet || !residenceNumber || !workplace || !workplaceStreet || !workplaceNumber ) { Alert.alert("Fehler", "Bitte füllen Sie alle Felder aus."); return; } if (password.length < 6) { Alert.alert( "Fehler", "Das Passwort muss mindestens 6 Zeichen lang sein." ); return; } if (!db) return; try { setLoading(true); const createdAt = new Date().toISOString(); const result = await db.runAsync( "INSERT INTO users (email, firstName, lastName, password, residence, residenceStreet, residenceNumber, workplace, workplaceStreet, workplaceNumber, transportMode, latitude, longitude, createdAt) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", [ email, firstName, lastName, password, residence, residenceStreet, residenceNumber, workplace, workplaceStreet, workplaceNumber, transportMode, latitude ?? "", longitude ?? "", createdAt, ] ); const newUser: User = { id: result.lastInsertRowId, email, firstName, lastName, residence, residenceStreet, residenceNumber, workplace, workplaceStreet, workplaceNumber, transportMode, latitude: latitude ?? "", longitude: longitude ?? "", createdAt, }; // Save session await AsyncStorage.setItem( "@user_session", JSON.stringify({ user: newUser }) ); setCurrentUser(newUser); setIsLoggedIn(true); Alert.alert("Erfolg", "Registrierung erfolgreich!"); } catch (error: any) { if (error.message?.includes("UNIQUE constraint failed")) { Alert.alert( "Fehler", "Ein Benutzer mit dieser E-Mail existiert bereits." ); } else { Alert.alert("Fehler", "Registrierung fehlgeschlagen."); } } finally { setLoading(false); } }; const handleLogin = async () => { if (!email || !password) { Alert.alert("Fehler", "Bitte füllen Sie alle Felder aus."); return; } if (!db) return; try { setLoading(true); const result = (await db.getFirstAsync( "SELECT * FROM users WHERE email = ? AND password = ?", [email, password] )) as any; if (result) { const user: User = { id: result.id, email: result.email, firstName: result.firstName, lastName: result.lastName, residence: result.residence, workplace: result.workplace, latitude: result.latitude, longitude: result.longitude, createdAt: result.createdAt, residenceStreet: result.residenceStreet, residenceNumber: result.residenceNumber, workplaceStreet: result.workplaceStreet, workplaceNumber: result.workplaceNumber, transportMode: result.transportMode, }; // Save session await AsyncStorage.setItem("@user_session", JSON.stringify({ user })); setCurrentUser(user); setIsLoggedIn(true); Alert.alert("Erfolg", "Anmeldung erfolgreich!"); } else { Alert.alert("Fehler", "Ungültige E-Mail oder Passwort."); } } catch (error) { Alert.alert("Fehler", "Anmeldung fehlgeschlagen."); } finally { setLoading(false); } }; const handleBiometricAuth = async () => { try { const result = await LocalAuthentication.authenticateAsync({ promptMessage: "Biometrische Authentifizierung", cancelLabel: "Abbrechen", fallbackLabel: "Passcode verwenden", }); if (result.success) { // For demo, auto-login first user if (!db) return; const user = (await db.getFirstAsync( "SELECT * FROM users LIMIT 1" )) as any; if (user) { const userData: User = { id: user.id, email: user.email, firstName: user.firstName, lastName: user.lastName, residence: user.residence, workplace: user.workplace, latitude: user.latitude, longitude: user.longitude, createdAt: user.createdAt, residenceStreet: user.residenceStreet, residenceNumber: user.residenceNumber, workplaceStreet: user.workplaceStreet, workplaceNumber: user.workplaceNumber, transportMode: user.transportMode, }; await AsyncStorage.setItem( "@user_session", JSON.stringify({ user: userData }) ); setCurrentUser(userData); setIsLoggedIn(true); } } } catch (error) { Alert.alert("Fehler", "Biometrische Authentifizierung fehlgeschlagen."); } }; const handleLogout = async () => { try { await AsyncStorage.removeItem("@user_session"); setCurrentUser(null); setIsLoggedIn(false); setEmail(""); setPassword(""); setFirstName(""); setLastName(""); setResidence(""); setWorkplace(""); setLatitude(null); setLongitude(null); } catch (error) { Alert.alert("Fehler", "Abmeldung fehlgeschlagen."); } }; const handleUseLocation = async () => { try { const { status } = await Location.requestForegroundPermissionsAsync(); if (status !== "granted") { Alert.alert("Fehler", "Standortberechtigung nicht erteilt."); return; } const loc = await Location.getCurrentPositionAsync({}); setLatitude(loc.coords.latitude.toString()); setLongitude(loc.coords.longitude.toString()); const addr = await Location.reverseGeocodeAsync({ latitude: loc.coords.latitude, longitude: loc.coords.longitude, }); if (addr && addr.length > 0) { setResidence(addr[0].city || addr[0].region || ""); } } catch (e) { Alert.alert("Fehler", "Standort konnte nicht ermittelt werden."); } }; const handleSaveEdit = async () => { if (!currentUser || !db) return; await db.runAsync( `UPDATE users SET firstName=?, lastName=?, residence=?, residenceStreet=?, residenceNumber=?, workplace=?, workplaceStreet=?, workplaceNumber=?, transportMode=?, latitude=?, longitude=? WHERE id=?`, [ firstName, lastName, residence, residenceStreet, residenceNumber, workplace, workplaceStreet, workplaceNumber, transportMode, latitude ?? "", longitude ?? "", currentUser.id, ] ); setEditMode(false); setShowOnlyName(true); setCurrentUser({ ...currentUser, firstName, lastName, residence, residenceStreet, residenceNumber, workplace, workplaceStreet, workplaceNumber, transportMode, latitude: latitude ?? "", longitude: longitude ?? "", }); Alert.alert("Erfolg", "Daten gespeichert."); }; if (loading) { return ( Lade App... ); } if (isLoggedIn && currentUser) { return ( Willkommen zurück! {currentUser.firstName} {currentUser.lastName} {showOnlyName ? ( <> ) : editMode ? ( <> Verkehrsmittel Speichern setEditMode(false)} > Abbrechen ) : ( <> E-Mail: {currentUser.email} Wohnort: {currentUser.residenceStreet} {currentUser.residenceNumber},{" "} {currentUser.residence} Arbeit/Schule/Uni: {currentUser.workplaceStreet} {currentUser.workplaceNumber},{" "} {currentUser.workplace} Verkehrsmittel: {currentUser.transportMode} setEditMode(true)} > Bearbeiten )} Abmelden router.push("/calendar")} > Zum Kalender ); } return ( {authMode === "login" ? "Anmelden" : "Registrieren"} {authMode === "register" && ( <> Verkehrsmittel Aktuellen Standort verwenden )} {loading ? ( ) : ( {authMode === "login" ? "Anmelden" : "Registrieren"} )} {biometricSupported && authMode === "login" && ( Mit Face ID / Touch ID anmelden )} setAuthMode(authMode === "login" ? "register" : "login") } > {authMode === "login" ? "Noch kein Konto? Registrieren" : "Bereits ein Konto? Anmelden"} ); } const styles = StyleSheet.create({ container: { flex: 1, backgroundColor: "#f8f9fa", }, keyboardView: { flex: 1, }, scrollContent: { flexGrow: 1, justifyContent: "center", paddingVertical: 30, }, authContainer: { flex: 1, justifyContent: "center", paddingHorizontal: 30, paddingBottom: 30, }, loadingContainer: { flex: 1, justifyContent: "center", alignItems: "center", }, loadingText: { marginTop: 10, fontSize: 16, color: "#666", }, welcomeContainer: { flex: 1, justifyContent: "center", paddingHorizontal: 30, }, welcomeTitle: { fontSize: 28, fontWeight: "bold", color: "#333", textAlign: "center", marginBottom: 10, }, userName: { fontSize: 20, color: "#666", textAlign: "center", marginBottom: 40, }, userInfo: { backgroundColor: "white", padding: 20, borderRadius: 10, marginBottom: 30, elevation: 2, shadowColor: "#000", shadowOffset: { width: 0, height: 2 }, shadowOpacity: 0.1, shadowRadius: 4, }, infoLabel: { fontSize: 14, color: "#666", marginTop: 10, }, infoValue: { fontSize: 16, color: "#333", fontWeight: "500", marginBottom: 5, }, title: { fontSize: 32, fontWeight: "bold", color: "#333", textAlign: "center", marginBottom: 40, }, input: { backgroundColor: "white", paddingHorizontal: 15, paddingVertical: 15, borderRadius: 10, fontSize: 16, marginBottom: 15, elevation: 2, shadowColor: "#000", shadowOffset: { width: 0, height: 2 }, shadowOpacity: 0.1, shadowRadius: 4, }, submitButton: { backgroundColor: "#007AFF", paddingVertical: 15, borderRadius: 10, alignItems: "center", marginTop: 10, }, submitButtonText: { color: "white", fontSize: 18, fontWeight: "600", }, biometricButton: { backgroundColor: "#34C759", paddingVertical: 15, borderRadius: 10, marginTop: 15, alignItems: "center", }, biometricButtonText: { color: "white", fontSize: 16, fontWeight: "600", }, switchButton: { marginTop: 20, alignItems: "center", }, switchButtonText: { color: "#007AFF", fontSize: 16, }, logoutButton: { backgroundColor: "#FF3B30", paddingVertical: 15, borderRadius: 10, alignItems: "center", }, logoutButtonText: { color: "white", fontSize: 18, fontWeight: "600", }, });