Overview
The EnAccess Maps mobile app is a React Native application built with Expo, providing an accessible-place discovery experience that mirrors the web app. Users can browse a Google Map of accessibility-reviewed places, view detailed place information with ACS (accessibility) attributes, and submit reviews. The app shares types, utilities, and constants with the web app via a shared workspace package (@enaccess/shared), and connects to the same tRPC API backend.
Monorepo Integration
The mobile app lives at apps/mobile/ inside the pnpm monorepo. It consumes the shared package at packages/shared/ for types, utilities, and theme constants.
EMV3.1/
├── src/ # Main Next.js web app
├── docs/ # Docusaurus documentation
├── apps/
│ └── mobile/ # Expo mobile app
├── packages/
│ └── shared/ # Shared types, utils, constants
├── pnpm-workspace.yaml
└── package.json
The pnpm-workspace.yaml includes apps/* and packages/*, allowing the mobile app to reference @enaccess/shared as workspace:*.
Tech Stack
| Layer | Choice | Version |
|---|---|---|
| Framework | Expo (managed workflow) | SDK 55 |
| Language | TypeScript | 5.9 |
| Navigation | Expo Router (file-based) | 55.x |
| Maps | react-native-maps (Google provider) | 1.26.20 |
| API | tRPC client (@trpc/react-query) | 11.0.0-rc.599 |
| Auth | expo-auth-session (Google OAuth) | 55.x |
| State | Zustand | 5.x |
| Forms/Validation | Zod | 3.x |
| Storage | expo-secure-store (tokens) | 55.x |
| Icons | lucide-react-native | 0.577 |
| Styling | NativeWind (Tailwind for RN) | 4.x |
| Animations | react-native-reanimated | 4.2 |
| Bottom Sheet | @gorhom/bottom-sheet | 5.x |
| SVG | react-native-svg | 15.x |
Architecture Diagram
File Structure
apps/mobile/
├── app/
│ ├── _layout.tsx # Root layout: GestureHandlerRootView → TRPCProvider → ThemeProvider → Stack
│ ├── (tabs)/
│ │ ├── _layout.tsx # Tab navigator (Map, Profile)
│ │ ├── index.tsx # Map screen: markers, bottom sheet, search bar
│ │ ├── profile.tsx # User profile, sign-in prompt, logout
│ │ └── search.tsx # Places list view (hidden tab, list browsing)
│ ├── place/
│ │ └── [id].tsx # Fullscreen place detail: ACS attrs, badges, review CTA
│ ├── search-modal.tsx # Search & filter modal (Google Places + category/ACS filters)
│ └── login.tsx # Google OAuth sign-in screen
├── components/
│ ├── MarkerIcon.tsx # SVG map pin (react-native-svg), matches web marker
│ ├── PlaceCard.tsx # Place card: badges, rating, ACS chips
│ ├── PlaceBadges.tsx # Badge row (promoted, verified, self-reported)
│ ├── StarRating.tsx # SVG star rating with partial fills
│ └── useColorScheme.ts # Color scheme hook (light/dark)
├── lib/
│ ├── api.ts # tRPC client setup, platform-aware base URL
│ ├── trpc-provider.tsx # TRPCProvider wrapping QueryClient
│ ├── store.ts # Zustand stores (AuthState, MapState)
│ ├── auth.ts # Google OAuth flow, SecureStore session management
│ └── use-places.ts # usePlaces hook (bounds-based tRPC query)
├── constants/
│ └── Colors.ts # Brand, badge, ACS, marker, light/dark theme colors
├── assets/ # Fonts, images, icons, EM branding
├── app.json # Expo config (scheme, permissions, Google Maps keys)
├── package.json
├── tailwind.config.js
├── global.css
└── tsconfig.json