diff --git a/apps/rebreak-native/app/onboarding/index.tsx b/apps/rebreak-native/app/onboarding/index.tsx
index 840e6f3..eed7e23 100644
--- a/apps/rebreak-native/app/onboarding/index.tsx
+++ b/apps/rebreak-native/app/onboarding/index.tsx
@@ -11,6 +11,7 @@ import { PlanSlide } from '../../components/onboarding/slides/PlanSlide';
import { PaymentSlide } from '../../components/onboarding/slides/PaymentSlide';
import { ProtectionSlide } from '../../components/onboarding/slides/ProtectionSlide';
import { DoneSlide } from '../../components/onboarding/slides/DoneSlide';
+import { OnboardingNavProvider } from '../../components/onboarding/OnboardingNavContext';
/**
* Duo-Style Onboarding — single route, state-machine intern.
@@ -97,6 +98,18 @@ export default function OnboardingScreen() {
setSlide(LINEAR_ORDER[idx + 1]);
}
+ function goToLinearPrevious() {
+ const idx = LINEAR_ORDER.indexOf(slide);
+ if (idx <= 0) return;
+ setSlide(LINEAR_ORDER[idx - 1]);
+ }
+
+ // Back erlaubt nur auf reinen Info-/Auswahl-Slides. NICHT auf:
+ // welcome (erste), done (final), diga_code (hat eigenen onBack),
+ // protection (interne Phasen + persistierter Backend-Step + Permission-Flow).
+ const BACK_ALLOWED: Slide[] = ['privacy', 'nickname', 'diga_choice', 'plan', 'payment'];
+ const canGoBack = BACK_ALLOWED.includes(slide);
+
function exitToApp() {
router.replace('/(app)');
}
@@ -135,42 +148,50 @@ export default function OnboardingScreen() {
// Slide-Dispatch ────────────────────────────────────────────────────────────
- switch (slide) {
- case 'welcome':
- return ;
- case 'privacy':
- return ;
- case 'nickname':
- return ;
- case 'diga_choice':
- return (
-
- );
- case 'diga_code':
- return (
- setSlide('diga_choice')}
- current={current}
- total={total}
- />
- );
- case 'plan':
- return ;
- case 'payment':
- return (
-
- );
- case 'protection':
- return (
-
- );
- case 'done':
- return ;
+ function renderSlide() {
+ switch (slide) {
+ case 'welcome':
+ return ;
+ case 'privacy':
+ return ;
+ case 'nickname':
+ return ;
+ case 'diga_choice':
+ return (
+
+ );
+ case 'diga_code':
+ return (
+ setSlide('diga_choice')}
+ current={current}
+ total={total}
+ />
+ );
+ case 'plan':
+ return ;
+ case 'payment':
+ return (
+
+ );
+ case 'protection':
+ return (
+
+ );
+ case 'done':
+ return ;
+ }
}
+
+ return (
+
+ {renderSlide()}
+
+ );
}
diff --git a/apps/rebreak-native/components/onboarding/OnboardingNavContext.tsx b/apps/rebreak-native/components/onboarding/OnboardingNavContext.tsx
new file mode 100644
index 0000000..d846879
--- /dev/null
+++ b/apps/rebreak-native/components/onboarding/OnboardingNavContext.tsx
@@ -0,0 +1,30 @@
+import { createContext, useContext, type ReactNode } from 'react';
+
+/**
+ * Stellt der OnboardingShell einen optionalen Back-Handler bereit, ohne
+ * `onBack` durch alle 8 Slide-Komponenten prop-drillen zu müssen.
+ *
+ * Controller (app/onboarding/index.tsx) entscheidet pro Slide ob ein Back
+ * möglich ist (welcome = erste Slide, done = final → kein Back) und liefert
+ * entsprechend `goBack` oder `null`.
+ */
+const OnboardingBackContext = createContext<(() => void) | null>(null);
+
+export function OnboardingNavProvider({
+ goBack,
+ children,
+}: {
+ goBack: (() => void) | null;
+ children: ReactNode;
+}) {
+ return (
+
+ {children}
+
+ );
+}
+
+/** Gibt den Back-Handler zurück, oder null wenn die aktuelle Slide kein Back erlaubt. */
+export function useOnboardingBack(): (() => void) | null {
+ return useContext(OnboardingBackContext);
+}
diff --git a/apps/rebreak-native/components/onboarding/OnboardingShell.tsx b/apps/rebreak-native/components/onboarding/OnboardingShell.tsx
index f52fca4..30ecbdf 100644
--- a/apps/rebreak-native/components/onboarding/OnboardingShell.tsx
+++ b/apps/rebreak-native/components/onboarding/OnboardingShell.tsx
@@ -1,8 +1,10 @@
import { ReactNode } from 'react';
-import { ScrollView, View } from 'react-native';
+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.
@@ -32,6 +34,7 @@ export function OnboardingShell({
}) {
const colors = useColors();
const insets = useSafeAreaInsets();
+ const goBack = useOnboardingBack();
return (
@@ -40,9 +43,31 @@ export function OnboardingShell({
paddingTop: insets.top + 12,
paddingHorizontal: 20,
paddingBottom: 8,
+ flexDirection: 'row',
+ alignItems: 'center',
+ gap: 12,
}}
>
-
+ {goBack ? (
+
+
+
+ ) : null}
+
+
+
s.language);
+ const setLanguage = useLanguageStore((s) => s.setLanguage);
+ return (
+
+ {LANGS.map((l) => {
+ const active = language === l.code;
+ return (
+ setLanguage(l.code)}
+ activeOpacity={0.7}
+ style={{
+ paddingHorizontal: 12,
+ paddingVertical: 6,
+ borderRadius: 8,
+ backgroundColor: active ? colors.brandOrange : colors.surfaceElevated,
+ }}
+ >
+
+ {l.label}
+
+
+ );
+ })}
+
+ );
+}
+
/**
* Slide 1: Lyra stellt sich vor + erklärt die Mission in einem Satz.
* Hat den langen Empathie-Touch, weil's der erste Eindruck nach Signup ist.
@@ -28,6 +76,10 @@ export function WelcomeSlide({
total={total}
cta={}
>
+
+
+
+