The Tourify frontend is a single Expo application that targets iOS, Android, and Web from one codebase. It is structured around three core pillars: a services layer for HTTP and storage, an AuthContext for session state, and a library of custom hooks that encapsulate every data-fetching concern.Documentation Index
Fetch the complete documentation index at: https://mintlify.com/astrxnomo/tourify/llms.txt
Use this file to discover all available pages before exploring further.
Entry point chain
App.js wraps the entire tree in SafeAreaProvider (from react-native-safe-area-context) and renders a dark StatusBar. It delegates all navigation and auth logic to Router.js.
Auth flow and token validation
On every app start,Router.js validates any persisted token before rendering screens:
Read token from SecureStore
storage.getItem('auth_token') is called inside a useEffect. If nothing is stored, loading is set to false and the unauthenticated stack renders.Validate with GET /api/auth/me
If a token exists,
get('/auth/me') is called. A successful response means the token is still valid and setToken(stored) switches the app to the authenticated stack.Handle expired or invalid token
If the request throws (401 or network error), the stored token is deleted via
storage.deleteItem('auth_token') and the user is sent to the Login screen.Navigation structure
Router.js uses React Navigation 7 with a NativeStackNavigator as the root. The authenticated branch nests a BottomTabNavigator (MainTabs) as the first screen.
Unauthenticated stack
Rendered whentoken is null:
| Screen | Component | Notes |
|---|---|---|
Login | LoginScreen | No header shown |
Register | RegisterScreen | Back title: “Atrás” |
ForgotPassword | ForgotPasswordScreen | Back title: “Atrás” |
Authenticated stack
Rendered when a valid token exists.Main hosts the bottom tabs; the remaining screens are full-stack screens pushed over the tabs:
| Screen | Component | Tab icon |
|---|---|---|
Main → Home (tab) | HomeScreen | home (MaterialIcons) |
Main → Explore (tab) | ExploreScreen | explore |
Main → Favorites (tab) | FavoritesScreen | favorite |
Main → Profile (tab) | ProfileScreen | person |
CityDetail | CityDetailScreen | — |
PlaceDetail | PlaceDetailScreen | — |
EventDetail | EventDetailScreen | — |
CategoryDetail | CategoryDetailScreen | — |
Notifications | NotificationsScreen | — |
MyRegistrations | MyRegistrationsScreen | — |
colors.primary (#0d9d8e) for the active tint and colors.textTertiary (#55777b) for inactive icons. It has a fixed height of 90 with 8 px padding top and bottom.
AuthContext
context/AuthContext.js creates a single React context that exposes login and logout functions defined in Router.js:
Router.js:
useAuth():
Services layer
services/post.js — HTTP client
Wraps the native fetch API with a base URL of http://localhost:8000/api. Every request reads the current Bearer token from storage before executing.
| Export | Method | Usage |
|---|---|---|
get(endpoint) | GET | Fetching lists and detail pages |
post(endpoint, data) | POST | Auth, creating favorites, registering for events |
patch(endpoint, data) | PATCH | Marking notifications as read |
del(endpoint, data) | DELETE | Removing favorites, cancelling registrations |
Error with the first human-readable message it can find: json.message → first validation error string → fallback "Error en la solicitud".
services/storage.js — Secure storage adapter
Abstracts platform differences: on native (iOS/Android) it delegates to expo-secure-store; on web it falls back to localStorage. The API is intentionally identical to SecureStore so callers never branch on platform.
Custom hooks
Every data-fetching and form-submission concern lives in a dedicated hook underhooks/. Hooks call the services layer and manage their own loading and error state, keeping screen components purely presentational.
Screen components
All screen components live inviews/public/ and map 1-to-1 with the navigation routes defined in Router.js:
Reusable component library
Components are grouped by concern underviews/components/:
auth/
AuthCheckbox, AuthDivider, AuthInput — form primitives for login, register, and password-recovery screens.common/
Button, Card, Chip, Divider, MediaListItem, Pill — generic layout and interaction elements used across all screens.detail/
DetailCard, DetailHero, DetailItem, ReviewCard, ReviewForm, StatCard — building blocks for city, place, and event detail pages.explore/ & home/
explore/:
home/:
CategoryCard, CityCard, EventCardhome/:
CategoryList, FilterChips, HomeHeader, PlaceCard, PromoCard, SearchBar, SectionHeaderTheming and design tokens
All colors, shadows, spacing, and border radii are exported fromviews/constants/colors.js and imported by every component — no hard-coded hex values appear in screen files.
shadows export provides cross-platform shadow styles (CSS box-shadow for web, elevation integers for Android):
When building for Android, import
shadowStyles (elevation) instead of shadows (box-shadow). For iOS and Web, use shadows. The separation keeps styles correct on all three platforms without runtime branching inside components.