Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 52 additions & 6 deletions repositories/d-sports-engage-native.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,11 @@ icon: "smartphone"

## What changed since last docs sync

- Team-aware experiences were expanded to align with backend team/favorites behavior.
- Quest and rewards surfaces were updated to support per-team progression and pass-aware eligibility.
- Pack opening and odds disclosure UX were upgraded with safer interactions and clearer status/error handling.
- Settings and account flows were expanded, including in-app account deletion and richer support/data controls.
- Comprehensive accessibility support added: VoiceOver, Voice Control, larger text, high contrast, reduced motion, and differentiate-without-color across all main screens.
- iOS tab bar now uses `NativeTabs` (`expo-router/unstable-native-tabs`) with system tab bar; Android and web use a custom `PillTabBar` with blur overlay.
- Modular architecture enforced: screen files are thin render shells, all styles extracted to `*.styles.ts` files, one component per file with barrel exports.
- EAS build profiles formalized for development, preview, staging, and production with GitHub Actions OTA workflow.
- Settings and account flows expanded, including in-app account deletion and richer support/data controls.

## Backend integration surfaces

Expand All @@ -62,15 +63,60 @@ icon: "smartphone"
- Native odds disclosure behavior is documented with policy-aligned copy and evidence requirements.
- Disclosure values must come from backend payloads and remain visible/accessible near open actions.

## Environment variables

All runtime variables use the `EXPO_PUBLIC_*` prefix so they are accessible in the Expo app. Create a `.env` file in the repo root:

| Variable | Purpose |
| -------- | ------- |
| `EXPO_PUBLIC_CLERK_PUBLISHABLE_KEY` | Clerk authentication (publishable key) |
| `EXPO_PUBLIC_API_URL` | Backend API base URL (e.g. `https://api.d-sports.org`) |
| `EXPO_PUBLIC_TW_CLIENT_ID` | Thirdweb client ID for web3 features |
| `EXPO_PUBLIC_REVENUECAT_API_KEY` | RevenueCat SDK key for in-app purchases |
| `EXPO_PUBLIC_REVENUECAT_APPSTORE_ID` | RevenueCat App Store app ID |
| `EXPO_PUBLIC_REVENUECAT_ENTITLEMENT` | RevenueCat entitlement identifier (e.g. `premium`) |
| `EXPO_PUBLIC_SUPABASE_URL` | Supabase project URL (client-side features only) |
| `EXPO_PUBLIC_SUPABASE_KEY` | Supabase publishable anon key |

<Note>
Only `EXPO_PUBLIC_*` keys are bundled into the app. Server-only secrets like `SENTRY_AUTH_TOKEN` are set in EAS build secrets or Xcode environment variables.
</Note>

## Getting started

1. Clone the repository and run `bun install`.
2. Configure environment (Clerk, RevenueCat, Thirdweb, API base URL) per repo README.
3. Run `bunx expo start`.
2. Copy `.env` and fill in the required `EXPO_PUBLIC_*` values listed above.
3. Run `bunx expo start` — press **a** for Android, **i** for iOS, or scan the QR code with Expo Go.
4. For development builds: `bun run build:dev` (EAS) or run with Expo dev client.
5. TypeScript check: `bun tsc --noEmit`.

The app targets both native and web (responsive) and uses the same backend (d-sports-api) as the PWA for API and checkout flows.

## EAS build profiles

Builds use [Expo Application Services (EAS)](https://expo.dev/eas) configured in `eas.json`:

| Profile | Channel | Use case |
| ------- | ------- | -------- |
| `development` | `development` | Dev client with simulator support |
| `development-device` | `development` | Dev client on physical device |
| `preview` | `preview` | Internal distribution (APK on Android) |
| `staging` | `staging` | Pre-production with auto-increment |
| `production` | `production` | App Store / Play Store release |

Common build commands:

```bash
bun run build:dev:ios # development build for iOS simulator
bun run build:preview:android # preview APK for Android
bun run build:prod:ios # production build for iOS
bun run build:submit:ios # production build + auto-submit to App Store
```

## CI/CD

A GitHub Actions workflow (`.github/workflows/eas-update.yml`) publishes OTA updates via `eas update` on pushes to `develop` and `main` branches. The workflow uses Bun for dependency installation and the Expo GitHub Action for EAS CLI setup.

## Deep dives

- [Architecture](/repositories/d-sports-engage-native/architecture)
Expand Down
65 changes: 56 additions & 9 deletions repositories/d-sports-engage-native/architecture.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -7,24 +7,71 @@ description: "Architecture overview for d-sports-engage-native application layer

The native app is structured around Expo Router screens, feature-oriented components, shared hooks, and API modules.

- Routing: `app/*` with grouped routes for tabs/auth/onboarding/settings.
- Feature logic: extracted hooks for wallet, shop, locker room, and settings.
- Shared contexts: user, collectibles, accessibility, and UI visibility/state controls.
- **Routing:** `app/*` with grouped routes for `(tabs)`, `(auth)`, `(onboarding)`, and `settings/`.
- **Feature logic:** extracted hooks (`hooks/use-wallet-screen.ts`, `hooks/use-shop-screen.ts`, etc.) keep screen files as thin render shells.
- **Shared contexts:** user, collectibles, accessibility, navbar visibility, and create-action state.

## Modular architecture

The codebase enforces strict modular patterns:

- **Screen files are thin render shells** — files in `app/(tabs)/` contain only imports and JSX. All state, effects, and handlers live in custom hooks under `hooks/`.
- **External stylesheets** — `StyleSheet.create()` is never placed inside component files. All styles go in `styles/` subdirectories as `ComponentName.styles.ts`.
- **One component per file** — each component gets its own `.tsx` file with a named export. Related components are grouped in `components/<domain>/` with a barrel `index.ts`.
- **Centralized types and constants** — shared types live in `types/<domain>.types.ts`, constants in `constants/<domain>.constants.ts`.
- **File size limit** — no file should exceed ~300 lines; large files are split into sub-components, hooks, styles, and types.
- **Path aliases** — all imports use `@/*` (maps to project root).

## Tab bar architecture

The app uses platform-specific tab bar implementations:

### iOS

`app/(tabs)/_layout.ios.tsx` uses `NativeTabs` from `expo-router/unstable-native-tabs` for the system tab bar. Key details:
- Uses `systemChromeMaterialDark` background with gold selection tint (`#FFD700`).
- Wallet tab shows a numeric `Badge` for unopened packs.
- SF Symbol pairs are defined in `app/(tabs)/tab-config.ts`.
- `disableTransparentOnScrollEdge` prevents the bar from losing its dark material on scroll.

### Android and web

`app/(tabs)/_layout.tsx` uses the JS `Tabs` component with a hidden default bar and a custom `PillTabBar` overlay. Android uses `expo-blur` (`BlurView`) for the pill background.

### Shared config

`app/(tabs)/tab-config.ts` defines tab order, SF Symbol pairs for iOS, and helper functions like `getActiveTabIndex` and `isPublicProfileStackRoute`.

## State and context boundaries

- Local/ephemeral UI state lives near feature hooks and components.
- Cross-screen state is managed with context providers and persisted storage where required.
- User/session-sensitive state is coordinated with backend auth and profile sync endpoints.
- **Zustand** store in `services/store.ts` with MMKV persistence for theme, cart, and points.
- **React Context** providers in `context/`: `UserContext`, `CollectiblesContext`, `NavBarVisibilityContext`, `CreateActionContext`, and `AccessibilityContext`.

## Accessibility architecture

The app supports all 9 Apple Accessibility Nutrition Label categories. The central `AccessibilityContext` (`context/accessibility-context.tsx`) manages:

- **VoiceOver and Voice Control** — all interactive elements have `accessibilityRole`, `accessibilityLabel`, `accessibilityHint`, and `accessibilityState`.
- **Larger text** — respects iOS Dynamic Type via `AccessibilityInfo` with in-app 1.25× toggle, capped at 2× via `maxFontSizeMultiplier`.
- **Reduced motion** — `ReducedMotionConfig` from `react-native-reanimated` at the root layout, plus in-app toggle.
- **High contrast** — `theme/colors.ts` exports `darkHighContrast` and `lightHighContrast` variants; activated by in-app toggle or iOS Bold Text setting.
- **Differentiate without color** — directional arrows (▲/▼) alongside price change colors, text labels on rarity badges.

See [Accessibility compliance](/repositories/d-sports-engage-native/compliance/accessibility) for the full implementation matrix.

## API client and retry behavior

- All network calls route through `lib/api/*` modules.
- Client wrappers handle auth token propagation, error normalization, and retry strategy.
- Quest/reward/team flows should consume backend eligibility as source of truth.
- `lib/api/client.ts` is the base HTTP client with auth token injection.
- `lib/api/cache.ts` provides `fetchWithCache()` using MMKV for cache-first fetching.
- Domain modules: `wallet-api.ts`, `shop-api.ts`, `user-api.ts`, `quests-api.ts`, `leaderboard-api.ts`, `locker-room-api.ts`, `teams-api.ts`, `collectibles-api.ts`, `checkout-api.ts`.
- Quest/reward/team flows consume backend eligibility as source of truth.

## Platform-specific behavior

- iOS/Android platform differences are handled in native-specific components and runtime checks.
- Web-target support exists but mobile behavior is primary for interaction and performance design.
- Haptics, modal controls, and animation handling are implemented with platform-safe fallbacks.
- **iOS:** system tab bar via `NativeTabs`, native haptics, Apple authentication.
- **Android:** custom pill tab bar with `BlurView`, platform keyboard handling (`softwareKeyboardLayoutMode: resize`).
- **Web:** responsive `maxWidth: 480px` container via `AppScreen`, hover states via `WebHoverWrapper`, PWA manifest with `display: "standalone"`.
- Haptics, modal controls, and animation handling use platform-safe fallbacks.