[claude] Mobile first-launch onboarding walkthrough (#35) (#79)

Co-authored-by: Claude (Opus 4.6) <claude@hermes.local>
Co-committed-by: Claude (Opus 4.6) <claude@hermes.local>
This commit was merged in pull request #79.
This commit is contained in:
2026-03-23 14:31:47 +00:00
committed by rockachopa
parent 04398e88e0
commit fb847b6e53
3 changed files with 293 additions and 2 deletions

View File

@@ -5,24 +5,50 @@ import {
Inter_700Bold,
useFonts,
} from "@expo-google-fonts/inter";
import AsyncStorage from "@react-native-async-storage/async-storage";
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import { Stack } from "expo-router";
import { Stack, router, useSegments } from "expo-router";
import * as SplashScreen from "expo-splash-screen";
import React, { useEffect } from "react";
import React, { useEffect, useState } from "react";
import { GestureHandlerRootView } from "react-native-gesture-handler";
import { KeyboardProvider } from "react-native-keyboard-controller";
import { SafeAreaProvider } from "react-native-safe-area-context";
import { ErrorBoundary } from "@/components/ErrorBoundary";
import { TimmyProvider } from "@/context/TimmyContext";
import { ONBOARDING_COMPLETED_KEY } from "@/constants/storage-keys";
SplashScreen.preventAutoHideAsync();
const queryClient = new QueryClient();
function RootLayoutNav() {
const segments = useSegments();
const [onboardingChecked, setOnboardingChecked] = useState(false);
const [needsOnboarding, setNeedsOnboarding] = useState(false);
useEffect(() => {
AsyncStorage.getItem(ONBOARDING_COMPLETED_KEY).then((value) => {
setNeedsOnboarding(value !== "true");
setOnboardingChecked(true);
});
}, []);
useEffect(() => {
if (!onboardingChecked) return;
const inOnboarding = segments[0] === "onboarding";
if (needsOnboarding && !inOnboarding) {
router.replace("/onboarding");
} else if (!needsOnboarding && inOnboarding) {
router.replace("/(tabs)");
}
}, [onboardingChecked, needsOnboarding, segments]);
return (
<Stack screenOptions={{ headerBackTitle: "Back" }}>
<Stack.Screen name="onboarding" options={{ headerShown: false, animation: "none" }} />
<Stack.Screen name="(tabs)" options={{ headerShown: false }} />
</Stack>
);