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.
91 lines
2.7 KiB
TypeScript
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>
|
|
);
|
|
}
|