import { useRouter } from 'expo-router'; import { useState } from 'react'; import { ActivityIndicator, Alert, Pressable, ScrollView, StyleSheet, Text, View, } from 'react-native'; import { PinInput } from '../../components/PinInput'; import { useAuth } from '../../lib/authContext'; import { setupNewUserIdentity } from '../../lib/userIdentity'; import { colors } from '../../theme/colors'; type Step = 'pin' | 'confirm' | 'recovery' | 'done'; export default function SetupScreen() { const router = useRouter(); const { userId, refreshUserKeyState } = useAuth(); const [step, setStep] = useState('pin'); const [pin, setPin] = useState(''); const [confirm, setConfirm] = useState(''); const [recoveryCode, setRecoveryCode] = useState(null); const [withRecovery, setWithRecovery] = useState(true); const [submitting, setSubmitting] = useState(false); const [error, setError] = useState(null); async function runSetup(saveRecovery: boolean) { if (!userId) return; setSubmitting(true); setError(null); try { const out = await setupNewUserIdentity({ userId, pin, withRecovery: saveRecovery }); setRecoveryCode(out.recoveryCode); if (out.recoveryCode) { setStep('recovery'); } else { setStep('done'); await refreshUserKeyState(); router.replace('/(app)/chats'); } } catch (err) { setError(err instanceof Error ? err.message : 'Setup fehlgeschlagen'); } finally { setSubmitting(false); } } if (step === 'pin') { return ( PIN festlegen Mit dieser 6-stelligen PIN entsperrst du Netralax auf jedem Gerät. {error && {error}} setStep('confirm')} > Weiter ); } if (step === 'confirm') { return ( PIN bestätigen Bitte gib dieselbe PIN erneut ein. {error && {error}} { if (pin !== confirm) { setError('PIN stimmt nicht überein.'); setConfirm(''); return; } void runSetup(withRecovery); }} > {submitting ? ( ) : ( PIN speichern )} setWithRecovery((v) => !v)} style={styles.secondary}> {withRecovery ? 'Recovery-Code überspringen (riskant)' : 'Recovery-Code erzeugen (empfohlen)'} ); } if (step === 'recovery' && recoveryCode) { return ( Recovery-Code Notiere dir diesen Code an einem sicheren Ort. Du brauchst ihn, wenn du deine PIN vergisst. Wir zeigen ihn dir nur EINMAL. {recoveryCode} { await refreshUserKeyState(); router.replace('/(app)/chats'); }} > Habe ich gespeichert { Alert.alert( 'Sicher?', 'Ohne Recovery-Code verlierst du den Zugriff, wenn du die PIN vergisst.', [ { text: 'Abbrechen', style: 'cancel' }, { text: 'Weiter ohne', style: 'destructive', onPress: async () => { await refreshUserKeyState(); router.replace('/(app)/chats'); }, }, ], ); }} > Überspringen ); } return null; } const styles = StyleSheet.create({ container: { flex: 1, padding: 24, paddingTop: 64, backgroundColor: colors.bg, gap: 16, }, title: { color: colors.text, fontSize: 24, fontWeight: '700' }, subtitle: { color: colors.textMuted, fontSize: 14, lineHeight: 20 }, error: { color: colors.danger, fontSize: 13 }, primary: { backgroundColor: colors.accent, paddingVertical: 14, borderRadius: 12, alignItems: 'center', marginTop: 12, }, primaryText: { color: colors.text, fontWeight: '700' }, disabled: { opacity: 0.5 }, secondary: { paddingVertical: 12, alignItems: 'center' }, secondaryText: { color: colors.accent, fontWeight: '600' }, codeBox: { backgroundColor: colors.surface, borderColor: colors.border, borderWidth: 1, padding: 16, borderRadius: 12, }, codeText: { color: colors.text, fontSize: 20, fontFamily: 'Courier', letterSpacing: 1.5, textAlign: 'center', }, });