Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/viet2811/uk-travel-recommendation/llms.txt

Use this file to discover all available pages before exploring further.

The UK Travel Recommendation frontend is a cross-platform mobile application built with Expo SDK 54 and React Native 0.81.5. It delivers a swipe-based attraction discovery experience backed by vector-embedding recommendations from the Django REST API. The app is structured around three distinct navigation stacks — authentication, onboarding, and the main tabbed interface — with TanStack Query v5 managing all server state, an AuthContext handling JWT lifecycle, and NativeWind providing a Tailwind-compatible utility styling layer throughout.

Tech Stack

The following core libraries underpin the application:
LibraryVersionPurpose
expo^54.0.0Build tooling, OTA updates, native module access
react-native0.81.5Cross-platform UI primitives
react19.1.0Component model and concurrent rendering
nativewindlatestUtility-class styling for React Native
tailwindcss^3.4.0Tailwind CSS compiler used by NativeWind
@tanstack/react-query^5.90.21Server-state fetching, caching, and invalidation
@react-navigation/native^7.1.28Stack and bottom-tab navigation
axios^1.13.5HTTP client with request/response interceptors
expo-secure-store~15.0.8Encrypted JWT storage on device
@react-native-async-storage/async-storage2.2.0Persistent geo filter preference
react-native-maps1.20.1Interactive map view for liked attractions
@gorhom/bottom-sheet^5Attraction detail sheet on discovery cards
lucide-react-native^0.563.0Icon set
react-native-reanimated4.1.1Animation libraries, used for custom swiping animation
react-native-gesture-handler2.28.0Handling mobile gesture: swipe, scroll, ..etc
The app uses a single root NativeStackNavigator whose screens branch into three logical groups. Unauthenticated users land in the Auth stack, complete the Preference onboarding stack on first sign-up, and then enter the Main bottom-tab stack for everyday use.
Root Stack
├── Landing          (WelcomeScreen)
├── Register         (RegisterScreen)
├── Login            (LoginScreen)
├── PreferenceStack
│   ├── PreferenceCat    (category picker)
│   ├── PreferenceArea   (geo area picker)
│   └── PreferenceImport (bulk import visited)
└── Main (Bottom Tabs)
    ├── Discovery    (swipe deck)
    ├── LikedStack   (liked attractions tab)
	│   ├── LikedMain (maps, group by geo area, list all)
	│   ├── LikedAreaScreen (attractions grid by a specific area)
    └── Profile / Settings (settings tab)
	│   ├── UpdateGeoFilter (same as PreferenceArea)
	│   ├── AttractionImport (same as PreferenceImport)
The full TypeScript parameter list for every route is defined in types/navigation.tsx:
export type RootStackParamList = {
  Landing: undefined;
  Register: undefined;
  Login: undefined;
  PreferenceStack: undefined;
  PreferenceCat: undefined;
  PreferenceArea: undefined;
  PreferenceImport: undefined;
  Main: undefined;
  Discovery: undefined;
  Liked: undefined;
  LikedMain: undefined;
  LikedAreaScreen: { items: Attraction[]; areaName: string };
  Profile: undefined;
  Settings: undefined;
  UpdateGeoFilter: undefined;
  AttractionImport: undefined;
};
LikedAreaScreen is the only parameterised route. It receives an array of Attraction objects and the name of the selected area so the map view can be pre-filtered without an additional network request.

State Management

State in the app is deliberately split by concern:

TanStack Query

Manages all server-originated state: the paginated recommendations feed, the liked-attractions history, and search results. Stale-while-revalidate semantics keep the UI snappy while background refreshes run automatically.

AuthContext

Wraps the entire app and exposes isAuthenticated, isLoading, login(), and logout(). Tokens are persisted in expo-secure-store and rehydrated on every cold start.

AsyncStorage

Stores the user’s geo filter string (e.g. ?area=London). This lightweight preference does not need the encryption that SecureStore provides but does need to survive app restarts.

Local Component State

Ephemeral UI state — sheet open/close, form field values, swipe deck index — lives in plain React useState and never escapes the component tree.

Theming

Styling is handled by NativeWind, which compiles Tailwind CSS utility classes down to React Native StyleSheet objects at build time. Custom design tokens are declared in theme/colors.ts and made available as Tailwind colour names throughout the app:
// theme/colors.ts
export const colors = {
  background:             '#fdf6e3',  // warm parchment
  foreground:             '#073642',  // dark slate
  card:                   '#eee8d5',  // light sand
  'card-foreground':      '#073642',  // dark slate
  primary:                '#d33682',  // vibrant pink
  'primary-foreground':   '#ffffff',
  secondary:              '#2aa198',  // teal
  'secondary-foreground': '#ffffff',
  muted:                  '#93a1a1',  // muted grey
  'muted-foreground':     '#073642',  // dark slate
  accent:                 '#cb4b16',  // burnt orange
  'accent-foreground':    '#ffffff',
  destructive:            '#dc322f',  // red
  'destructive-foreground':'#ffffff',
  border:                 '#839496',  // muted grey-blue
  input:                  '#839496',  // muted grey-blue
  ring:                   '#d33682',  // vibrant pink
};
The palette is derived from the Solarized colour scheme, giving the app a warm, readable aesthetic that works well in both bright outdoor and indoor lighting conditions.

Key Dependencies

Expo

Provides the managed build workflow, OTA update infrastructure, and access to native APIs (SecureStore, Camera, Location) without requiring a custom native build for development.

TanStack Query v5

Infinite query support powers the paginated recommendations feed. The useRecommendations hook triggers the next page fetch automatically when five or fewer cards remain in the deck.

NativeWind

Brings the full Tailwind CSS v3 utility vocabulary to React Native. Combined with the custom colour tokens, it eliminates bespoke StyleSheet boilerplate across the entire codebase.

React Navigation

Handles both the root native stack (for full-screen transitions) and the bottom-tab bar inside the Main screen. Deep linking and type-safe route params are configured via RootStackParamList.

react-native-maps

Renders the LikedAreaScreen map, plotting liked attractions as map markers. On iOS it uses Apple Maps; on Android it defaults to Google Maps.

react-native-animated & react-native-gesture-handler

Powers the DiscoveryScreen card deck. Left swipes trigger dislikeAttraction, right swipes trigger likeAttraction, and the deck automatically re-fills from the TanStack Query infinite cache.

Running the Frontend

Follow these steps to start the development server locally:
1

Configure the backend URL

Create a .env file (or .env.local) in the frontend project root and set the Expo public environment variable that points to your running Django backend:
EXPO_PUBLIC_BACKEND_URL=http://192.168.1.100:8000/api
Use your machine’s LAN IP address (not localhost) so that a physical device or emulator can reach the backend.
2

Install dependencies

npm install
3

Start the Expo development server

npx expo start
The Metro bundler launches and displays a QR code in the terminal.
4

Open on a device or emulator

  • Physical device — scan the QR code with the Expo Go app (iOS or Android).
  • iOS Simulator — press i in the Metro terminal (requires Xcode).
  • Android Emulator — press a in the Metro terminal (requires Android Studio).
If you are running the Django backend inside Docker, make sure the container’s port is bound to 0.0.0.0 rather than 127.0.0.1 so that devices on your local network can reach it.

Build docs developers (and LLMs) love