chahinebrini 312c668ae9 feat(onboarding): back-button between steps + language switcher on welcome
Back-Button:
- OnboardingNavContext liefert der Shell einen optionalen goBack-Handler
  (kein prop-drilling durch 8 Slides).
- OnboardingShell: chevron-back links neben der Progress-Bar wenn goBack
  gesetzt ist.
- Controller: goToLinearPrevious() + BACK_ALLOWED-Liste. Back nur auf
  privacy/nickname/diga_choice/plan/payment — NICHT welcome (erste),
  done (final), diga_code (eigener onBack), protection (Backend-Step +
  Permission-Flow).

Language-Switcher:
- WelcomeSlide: 4 Sprach-Pills (DE/EN/FR/AR) oben rechts. User kommt
  während Onboarding nicht zu Settings — sonst kein Weg die Sprache
  zu wechseln. setLanguage persistiert + flippt RTL für AR.
2026-05-20 04:20:22 +02:00

91 lines
2.7 KiB
TypeScript

import { ReactNode } from 'react';
import { ScrollView, TouchableOpacity, View } from 'react-native';
import { useSafeAreaInsets } from 'react-native-safe-area-context';
import { Ionicons } from '@expo/vector-icons';
import { useColors } from '../../lib/theme';
import { SlideProgress } from './SlideProgress';
import { useOnboardingBack } from './OnboardingNavContext';
/**
* Layout-Wrapper für alle Onboarding-Slides.
*
* ┌──────────────────────────────┐
* │ [Top-Padding + SafeArea] │
* │ ────── Progress-Bar ───── │
* │ │
* │ <children — ScrollView> │
* │ │
* │ ───── CTABar (sticky) ───── │
* └──────────────────────────────┘
*
* `cta` wird IM Shell gerendert (sticky-bottom + SafeArea). Slides müssen
* ihre Inhalte als `children` reinpacken (= scrollbarer Content-Bereich).
*/
export function OnboardingShell({
current,
total,
children,
cta,
}: {
current: number;
total: number;
children: ReactNode;
cta: ReactNode;
}) {
const colors = useColors();
const insets = useSafeAreaInsets();
const goBack = useOnboardingBack();
return (
<View style={{ flex: 1, backgroundColor: colors.bg }}>
<View
style={{
paddingTop: insets.top + 12,
paddingHorizontal: 20,
paddingBottom: 8,
flexDirection: 'row',
alignItems: 'center',
gap: 12,
}}
>
{goBack ? (
<TouchableOpacity
onPress={goBack}
activeOpacity={0.6}
hitSlop={{ top: 12, bottom: 12, left: 12, right: 12 }}
style={{
width: 32,
height: 32,
borderRadius: 10,
backgroundColor: colors.surfaceElevated,
alignItems: 'center',
justifyContent: 'center',
}}
>
<Ionicons name="chevron-back" size={20} color={colors.text} />
</TouchableOpacity>
) : null}
<View style={{ flex: 1 }}>
<SlideProgress current={current} total={total} />
</View>
</View>
<ScrollView
style={{ flex: 1 }}
contentContainerStyle={{
paddingHorizontal: 20,
paddingTop: 12,
paddingBottom: 16,
flexGrow: 1,
}}
keyboardShouldPersistTaps="handled"
showsVerticalScrollIndicator={false}
>
{children}
</ScrollView>
{cta}
</View>
);
}