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
82 changes: 62 additions & 20 deletions repositories/d-sports-engage-native.mdx
Original file line number Diff line number Diff line change
@@ -1,40 +1,56 @@
---
title: "d-sports-engage-native"
description: "Native iOS and Android app for D-Sports Engage. Expo 54, React Native, Clerk, RevenueCat, Thirdweb."
description: "Native iOS and Android app for D-Sports Engage. Expo 55, React Native 0.83, Clerk, RevenueCat, Thirdweb."
icon: "smartphone"
---

## Overview

**d-sports-engage-native** (package name: `engage-native`) is the native mobile app for D-Sports. It mirrors the core PWA experience on iOS and Android: wallet, shop, leaderboard, locker room, and profile.
**d-sports-engage-native** (package name: `engage-native`, version `1.18.1`) is the native mobile app for D-Sports. It mirrors the core PWA experience on iOS and Android: wallet, shop, leaderboard, locker room, and profile.

- **Run:** `bunx expo start` or `bun run start` — then press `a` for Android or `i` for iOS, or scan the QR code with Expo Go.

## Tech stack

| Category | Technology |
| ---------- | ------------------------- |
| Framework | Expo 54, React Native 0.81, React 19 |
| Auth | Clerk (Expo) |
| Payments | RevenueCat (react-native-purchases) |
| Web3 | Thirdweb |
| State | Zustand |
| Storage | MMKV |
| UI | Lucide React Native |
| Navigation | Expo Router |
| Package | Bun |
| Category | Technology |
| -------------- | ------------------------------------------- |
| Framework | Expo 55, React Native 0.83, React 19.2 |
| Auth | Clerk (Expo) |
| Payments | RevenueCat (react-native-purchases) |
| Web3 | Thirdweb |
| State | Zustand 5 |
| Storage | MMKV 4 |
| UI | Lucide React Native |
| Navigation | Expo Router 55 |
| Animations | React Native Reanimated 4 |
| Notifications | OneSignal |
| Error tracking | Sentry |
| Builds/CI | EAS Build, EAS Update, GitHub Actions |
| Package | Bun |

## Features

- **Wallet** — Tokens, holdings, pack opening, crypto checkout (via PWA backend)
- **Shop** — Collectibles, cart, coin bundles, checkout
- **Leaderboard** — Rankings and filters
- **Locker room** — Social feed and engagement
- **Profile** — User profile and settings
- **Wallet** — Tokens, holdings, pack opening, crypto checkout (via PWA backend), send/receive
- **Shop** — Collectibles, cart, coin bundles, fiat and crypto checkout
- **Leaderboard** — Rankings, filters, team-scoped views
- **Locker room** — Social feed, posts, comments, fan exploration, daily games
- **Profile** — User profile, achievements, milestones, follow system, badges
- **Games** — Daily pick-em, spin wheel, guess-the-player
- **Settings** — Account, appearance, accessibility, notifications, privacy, legal, support, changelog
- **Widgets** — iOS and Android home-screen widgets (rank, points, Live Activity)
- **Theme** — Dark/light mode (default dark)

## What changed since last docs sync

- Upgraded to **Expo 55**, **React Native 0.83**, and **React 19.2**.
- Added **iOS and Android widgets** (rank/points widget, Live Activity for scores).
- Added **OneSignal** push notification integration with production app group support.
- Added **Sentry** error tracking and crash reporting.
- Added **EAS Build profiles** (development, preview, production) and **EAS Update** for OTA updates.
- Added **GitHub Actions** workflow for EAS OTA updates on push.
- Expanded locker room with **daily games** (pick-em, spin wheel, guess-the-player) and **quest/reward** surfaces.
- Expanded settings with **accessibility**, **changelog**, **help center**, **contact support**, and **report problem** screens.
- Added **iOS NativeTabs** (Liquid Glass tab bar) and **Android/web PillTabBar** with blur.
- 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.
Expand All @@ -44,7 +60,9 @@ icon: "smartphone"

- Primary API source: `d-sports-api` under `/api/*`.
- Native app consumes team, league, quest, reward, wallet, commerce, and social endpoints.
- Retry/caching logic and auth token injection are centralized in app API client modules.
- Retry/caching logic and auth token injection are centralized in `lib/api/client.ts`.
- Domain-specific API 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`, `games-api.ts`.
- MMKV cache-first fetching via `lib/api/cache.ts`.

## Quest and pass UX integration

Expand All @@ -62,15 +80,39 @@ 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

The native app uses `EXPO_PUBLIC_*` environment variables at runtime:

| Variable | Purpose |
| -------- | ------- |
| `EXPO_PUBLIC_CLERK_PUBLISHABLE_KEY` | Clerk authentication |
| `EXPO_PUBLIC_API_URL` | Backend API base URL |
| `EXPO_PUBLIC_TW_CLIENT_ID` | Thirdweb Web3 client |
| `EXPO_PUBLIC_REVENUECAT_API_KEY` | RevenueCat in-app purchases |
| `EXPO_PUBLIC_SUPABASE_URL` | Supabase client URL |
| `EXPO_PUBLIC_SUPABASE_KEY` | Supabase public key |

## Getting started

1. Clone the repository and run `bun install`.
2. Configure environment (Clerk, RevenueCat, Thirdweb, API base URL) per repo README.
2. Configure environment variables (Clerk, RevenueCat, Thirdweb, API base URL) — see the `.env` file for required keys.
3. Run `bunx expo start`.
4. For development builds: `bun run build:dev` (EAS) or run with Expo dev client.
5. For platform-specific local builds: `bun run local:ios` or `bun run local:android`.

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

| Profile | Command | Purpose |
| ------------- | --------------------------- | -------------------------- |
| Development | `bun run build:dev` | Dev client with debug tools |
| Preview | `bun run build:preview` | Internal testing builds |
| Production | `bun run build:prod` | App Store / Play Store |

OTA updates are delivered via `bun run update` (production) or `bun run update:preview` (preview channel).

## Deep dives

- [Architecture](/repositories/d-sports-engage-native/architecture)
Expand Down
51 changes: 40 additions & 11 deletions repositories/d-sports-engage-native/architecture.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -7,24 +7,53 @@ 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 — `(tabs)` for main navigation, `(auth)` for login/signup, `(onboarding)` for new users, and `settings/` for nested settings pages.
- **Feature logic:** extracted hooks for wallet (`use-wallet-screen.ts`), shop (`use-shop-screen.ts`), feed (`use-feed-section.ts`), and settings (`use-user-settings.ts`).
- **Shared contexts:** user, collectibles, accessibility, navbar visibility, and create-action state.
- **Screen pattern:** screen files (e.g. `wallet.tsx`, `shop.tsx`) contain only imports and JSX. All state, effects, and handlers live in dedicated hooks.

## 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` (system UIKit tab bar with Liquid Glass material). Uses `systemChromeMaterialDark` with gold selection color (`#FFD700`).
- **Android and web:** `app/(tabs)/_layout.tsx` uses a custom `PillTabBar` overlay with `expo-blur` (`BlurView`) and hidden default tab bar.
- **Shared config:** `components/navigation/tab-config.ts` defines tab order, SF Symbol icon pairs for iOS, and active-tab detection rules.

## 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.
- Cross-screen state is managed with context providers (`context/`) and Zustand store (`services/store.ts`) with MMKV persistence.
- User/session-sensitive state is coordinated with backend auth and profile sync endpoints via `context/user-context.tsx`.

## 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.
- All network calls route through `lib/api/*` modules with a centralized client in `lib/api/client.ts`.
- Client wrappers handle auth token propagation (Clerk), error normalization, and retry strategy.
- MMKV cache-first fetching is available via `lib/api/cache.ts` with `fetchWithCache()`.
- 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/Android platform differences are handled in native-specific layout files (e.g. `_layout.ios.tsx` vs `_layout.android.tsx`).
- Web-target support exists with responsive `maxWidth: 480px` container (`components/layout/AppScreen.tsx`) and hover states (`components/ui/WebHoverWrapper.tsx`).
- Haptics via `hooks/use-haptics.ts`, modal controls, and animation handling use platform-safe fallbacks with React Native Reanimated.

## Widget system

The app includes home-screen widgets for both platforms:

- **iOS:** `widgets/ios/RankOrPointsWidget.tsx` (rank/points display) and `widgets/ios/LiveActivityStatus.tsx` (Live Activity for score updates). Configured via the `expo-widgets` plugin.
- **Android:** `widgets/android/registry.tsx` with `react-native-android-widget`. `RankOrPointsWidget` supports `systemSmall` and `systemMedium` sizes.
- **Shared:** `widgets/widget-controls.ts` provides data fetching and widget update logic. `lib/widget-data.ts` prepares data payloads for widget rendering.

## Error tracking and monitoring

- **Sentry** is integrated via `@sentry/react-native/expo` plugin and initialized in `app/_layout.tsx`.
- An `AppErrorBoundary` component (`components/AppErrorBoundary.tsx`) wraps the app to catch and report rendering errors.

## Theme system

- `theme/colors.ts` defines brand colors (Gold `#F5C842`, Royal Blue `#4169E1`) with dark/light palettes.
- `components/theme-provider.tsx` provides `useTheme()` hook with `resolvedTheme`.
- Default theme is dark mode with base background `#0a0e1a`.
55 changes: 55 additions & 0 deletions repositories/d-sports-engage-native/feature-mapping.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,70 @@ description: "Native feature coverage and parity mapping against backend/PWA beh
- Wallet screens consume balances, token data, and secure key/pin flows from backend APIs.
- Pack browsing, purchase, and open flows use backend-driven states and inventory refresh behavior.
- Odds-disclosure surfaces read backend-provided probability payloads.
- Crypto checkout supports Arbitrum (default), Ethereum, and Polygon chains via Thirdweb SDK.
- Opened packs section tracks previously opened pack contents.

## Shop and commerce

- Collectible cards, featured packs, and coin bundles are fetched from backend shop/product endpoints.
- Cart management with add-to-cart toast notifications and full cart modal.
- Fiat checkout via RevenueCat (Apple IAP on iOS, Google Play on Android, Stripe on web).
- Crypto checkout via `CryptoCheckoutModal` with wallet selection, transaction signing, and verification polling.
- 3D collectible preview via `NativeGlbViewer` (native) and `WebGlbViewer` (web).

## Quest, rewards, and pass surfaces

- Quest UI supports team-aware progression and pass-gated eligibility.
- Reward states and claim flows follow backend quest/reward APIs.
- Global pass and event pass effects are reflected in native quest visibility/completion UX.
- Quest detail modals display progress and completion criteria.

## Team and leaderboard integration

- Teams and leagues metadata are consumed from backend `/api/teams` and `/api/leagues`.
- Leaderboard displays and team-scoped ranking views align with backend leaderboard contracts.
- Favorite-team interactions influence quest and leaderboard context where backend eligibility requires it.
- Team detail modals show team information, branding, and member stats.

## Locker room and social

- Social feed with posts, comments, and user interaction.
- Fan exploration and team exploration modals.
- User profile hover cards with follow/block actions.
- Hidden content (UGC) preview with report/hide functionality.

## Daily games

- **Daily pick-em** — `DailyPickEmGame` component with team-based daily predictions.
- **Spin wheel** — `DailySpinWheelGame` component with animated prize wheel and reward claiming.
- **Guess the player** — `GuessThePlayerGame` component with player identification challenges.
- Featured games carousel on the locker room screen.

## Profile and achievements

- User profile with achievements, milestones, badges, and points history.
- Milestone avatar system with progressive visual unlocks.
- Follow/followers system with dedicated list modals.
- Profile badges sourced from backend with cached images.

## Settings

- **Account** — profile editing, connected accounts, blocked users, security, account deletion.
- **Appearance** — theme selection (dark/light).
- **Accessibility** — accessibility features with persistent sync across sessions.
- **Notifications** — push notification preferences.
- **Privacy, legal, data** — privacy controls, terms of service, EULA, data management.
- **Support** — help center, contact support, report problem screens.
- **Changelog** — in-app changelog with timeline view.

## Widgets

- **iOS** — `RankOrPointsWidget` (system small/medium) and `LiveActivityStatus` (accessory rectangular/inline).
- **Android** — `RankOrPointsWidget` with 30-minute auto-refresh.
- Widget data is prepared by `lib/widget-data.ts` and pushed via `widgets/widget-controls.ts`.

## Notifications

- Push notifications via **OneSignal** with production app group support.
- In-app notifications screen (`app/notifications.tsx`) for viewing notification history.
- Subscription management via `lib/onesignal-subscription.ts`.
29 changes: 28 additions & 1 deletion repositories/d-sports-engage-native/integration-contracts.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -5,23 +5,50 @@ description: "Backend-facing contracts and behavior expectations for native clie

## Auth/session contracts

- Native auth uses backend-compatible token/session validation flows.
- Native auth uses Clerk (Expo) with backend-compatible token/session validation flows.
- The API client in `lib/api/client.ts` injects `Authorization` headers via `getToken()` from Clerk.
- Protected feature calls require authenticated user context and must handle session expiry gracefully.
- If `getToken()` returns null during cold start, requests proceed unauthenticated — endpoints requiring Clerk `auth()` on the server may return 401.

## Quest and reward API contracts

- Quest progression is backend-authoritative for eligibility and completion.
- Reward claim/redeem behavior must use server responses as truth for user-facing state.
- Pass-related gating (global/event) is evaluated server-side and reflected in client rendering.
- Games API (`lib/api/games-api.ts`) provides daily game data (pick-em, spin wheel, guess-the-player).

## Team and league API contracts

- Team lists and team metadata come from `/api/teams`.
- League metadata and branding come from `/api/leagues`.
- Synced canonical data changes can propagate asynchronously; client should tolerate short-lived staleness.

## Commerce and payment contracts

- **RevenueCat** (`lib/revenuecat/provider.tsx`) handles fiat payments: Apple IAP (iOS), Google Play (Android), Stripe (web). The `premium` entitlement is checked for gated features.
- **Crypto checkout** (`lib/api/checkout-api.ts`) calls backend `POST /api/checkout/crypto` to initiate and `POST /api/checkout/crypto/verify` to confirm on-chain payments.
- **Thirdweb SDK** is used for on-chain transaction signing via `prepareTransaction` + `sendTransaction`. Supported chains: Arbitrum (default), Ethereum, Polygon.

## Push notification contracts

- **OneSignal** integration via `onesignal-expo-plugin` with production mode and app group `group.com.dsports.wallet.beta.dengage`.
- Subscription management is handled in `lib/onesignal-subscription.ts`.
- Notification preferences are managed in-app via settings and synced with the backend.

## Error tracking contracts

- **Sentry** (`@sentry/react-native/expo`) captures crashes and errors with project `engage-native`.
- `AppErrorBoundary` wraps the app to catch rendering errors and report them.

## OTA update contracts

- **EAS Update** is configured with `runtimeVersion: "1.18.1"` matching the app version.
- Updates are delivered to production, preview, and development branches via `bunx eas update`.
- The `runtimeVersion` must be an explicit string (not a policy object) for bare/prebuilt workflow builds.

## Error handling and fallback UX

- Show user-actionable errors for purchase/open/claim failures.
- Avoid silent failures for mutation endpoints.
- Use retry/backoff for transient network failures; avoid retry storms on authorization or validation errors.
- Logger utility (`lib/logger.ts`) provides structured logging with level filtering.