Skip to content

[FEAT] - Update Navigation #37

@BeWelsh

Description

@BeWelsh

Summary

Refactor the app's navigation from a single general stack into three conditional stacks — Auth, Onboarding, and Main — gated by the Zustand useAuthStore state. This ensures users are always routed to the correct flow based on their authentication and onboarding status.

Motivation

With the current navigation stack, there is no sort of nuance with authentication/onboarding status. By splitting into three declarative stacks that swap based on global state, navigation becomes self-enforcing: the correct screens are simply the only screens that exist in the tree at any given time. This is the standard React Navigation pattern for auth flows and eliminates an entire class of routing bugs.

Requirements

Acceptance Criteria

  • Navigation is split into three stack navigators: AuthStack, OnboardingStack, and MainStack
  • A root-level navigator conditionally renders the correct stack based on useAuthStore state (isAuthenticated, hasCompletedOnboarding)
  • Unauthenticated users can only access screens in AuthStack — there is no way to navigate to onboarding or main app screens
  • Authenticated users who haven't completed onboarding can only access screens in OnboardingStack
  • Authenticated users who have completed onboarding land in MainStack
  • A splash/loading screen is shown while the Zustand store rehydrates from AsyncStorage — no flash of the wrong stack (This feature may or may not be blocked, will come back)
  • Transitions between stacks (e.g., login → onboarding, onboarding → main) are driven by store state changes, not imperative navigation.navigate() calls
  • Logging out from any screen in MainStack returns the user to AuthStack with no back gesture available

Out of Scope

  • Individual screen UI within any stack (login form, onboarding steps, home screen, etc.)
  • Any sort of navigation bar (follow-up ticket)
  • The Zustand store itself — that's handled by the auth store ticket; this ticket consumes it

File structure:

src/navigation/
  RootNavigator.tsx       # Conditional stack switching
  stacks/
    AuthStack.tsx         # Login, Signup, Forgot Password
    OnboardingStack.tsx   # Onboarding step screens
    MainStack.tsx         # Home, Tracking, Profile, etc.

Placeholder screens — each stack should have at least one placeholder screen so the navigation is testable end to end before real screen UI is built:

  • AuthStack: a placeholder login screen with a "Sign In" button that calls useAuthStore.getState().login()
  • OnboardingStack: a placeholder screen with a "Complete Onboarding" button that calls completeOnboarding()
  • MainStack: a placeholder home screen with a "Log Out" button that calls logout()

This lets us verify the full routing flow independently of screen UI work.

Affected Areas

  • src/navigation/RootNavigator.tsx (new or heavily refactored)
  • src/navigation/stacks/AuthStack.tsx (new)
  • src/navigation/stacks/OnboardingStack.tsx (new)
  • src/navigation/stacks/MainStack.tsx (new)
  • App entry point (App.tsx) — should render RootNavigator as the top-level component
  • Any existing screen registrations in the current single stack need to be migrated into the appropriate new stack

Dependencies

  • Zustand auth store ticket — this ticket directly consumes useAuthStore and its isAuthenticated, hasCompletedOnboarding

Flow diagram:

App Launch
  → Not Authenticated? → AuthStack (Login / Signup)
  → Authenticated + Not Onboarded? → OnboardingStack
  → Authenticated + Onboarded? → MainStack

Testing Notes

  • Fresh install — no persisted state → should show Auth stack
  • Login flow — calling login() from Auth stack → should transition to Onboarding stack (if not completed) or Main stack (if completed)
  • Onboarding completion — calling completeOnboarding() from Onboarding stack → should transition to Main stack
  • Logout — calling logout() from Main stack → should transition to Auth stack with no ability to swipe back
  • App kill + reopen (authenticated, onboarded) → should show Main stack directly, no flash of Auth
  • App kill + reopen (authenticated, not onboarded) → should show Onboarding stack
  • Back gesture/button — confirm users cannot navigate backwards across stack boundaries (e.g., pressing back on the first onboarding screen should not return to the login screen)
  • Rapid state changes

Metadata

Metadata

Labels

No labels
No labels

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions