Skip to main content

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. The app also supports web via responsive layout and PWA manifest.

Tech stack

CategoryTechnology
FrameworkExpo 54, React Native 0.81, React 19
LanguageTypeScript 5.9
AuthClerk (Expo)
PaymentsRevenueCat (react-native-purchases)
Web3Thirdweb
StateZustand 5
StorageMMKV
AnimationReanimated 4.1
UI iconsLucide React Native
NavigationExpo Router 6 (file-based routing)
PackageBun

Features

  • Wallet — tokens, holdings, pack opening, crypto checkout (via PWA backend and Thirdweb SDK)
  • Shop — collectibles, cart, coin bundles, crypto checkout
  • Leaderboard — rankings, filters, and season-based views
  • Locker room — social feed, posts, quests, daily games (Pick’Em, Spin Wheel, Guess the Player), team exploration, and fan profiles
  • Profile — user profile, stats, and full settings suite
  • Onboarding — new-user onboarding flow with team selection
  • Theme — dark/light mode (default dark)

Project structure

The codebase follows a modular architecture pattern — screen files are thin render shells containing only JSX, with all business logic extracted into dedicated hooks.
app/
├── (auth)/           # Login, signup, SSO callback, password reset
├── (onboarding)/     # New-user onboarding flow
├── (tabs)/           # Main tab navigation (wallet, shop, leaderboard, locker room, profile)
├── settings/         # Settings pages with nested modals/tabs
└── _layout.tsx       # Root layout with providers and auth protection

components/
├── wallet/           # Wallet sub-components (TokenRow, ActionModal, PackOpeningModal, etc.)
├── shop/             # Shop sub-components (CartModal, CryptoCheckoutModal, etc.)
├── locker-room/      # Locker room components (FeedSection, DailyPickEmGame, QuestSection, etc.)
├── leaderboard/      # BaseLeaderboard, LeaderboardModal
├── settings/         # SettingItem, SettingSection, and modals/tabs
├── ui/               # Reusable primitives (Button, TextField, TutorialOverlay, etc.)
├── Icon/             # Icon wrapper using lucide-react-native
└── theme-provider.tsx

hooks/
├── use-wallet-screen.ts     # All wallet state, effects, and handlers
├── use-shop-screen.ts       # All shop state, effects, and handlers
├── use-feed-section.ts      # Feed posts state and handlers
├── use-carousel-scroll.ts   # Carousel scroll logic
└── use-draggable-scroll.ts  # Drag-to-scroll logic

lib/api/              # API client modules (wallet, shop, user, quests, checkout, etc.)
context/              # React Context (user, collectibles, navbar visibility)
types/                # Shared TypeScript types (wallet, shop, checkout, API)
constants/            # Static data and configuration
theme/                # Brand colors, spacing, typography tokens
services/             # Zustand store, MMKV storage adapter

Key architecture patterns

  • File-based routing via Expo Router with route groups (tabs), (auth), (onboarding)
  • Thin screens — screen files import a hook and render JSX; all state and logic live in hooks/
  • External stylesheetsStyleSheet.create() is never inline; styles live in styles/ directories
  • Barrel exports — each component domain has an index.ts re-exporting all public components
  • API client layer in lib/api/ with MMKV cache fallback (lib/api/cache.ts)
  • Path alias @/* maps to the project root

Getting started

1

Clone and install

git clone <repo-url>
cd d-sports-engage-native
bun install
2

Configure environment

Create a .env file with the required variables:
VariablePurpose
EXPO_PUBLIC_CLERK_PUBLISHABLE_KEYClerk authentication
EXPO_PUBLIC_API_URLBackend API base URL
EXPO_PUBLIC_TW_CLIENT_IDThirdweb Web3 client ID
EXPO_PUBLIC_REVENUECAT_API_KEYRevenueCat in-app purchases
EXPO_PUBLIC_REVENUECAT_APPSTORE_IDRevenueCat App Store ID
EXPO_PUBLIC_REVENUECAT_ENTITLEMENTRevenueCat entitlement identifier
EXPO_PUBLIC_SUPABASE_URLSupabase client URL
EXPO_PUBLIC_SUPABASE_KEYSupabase publishable key
Only EXPO_PUBLIC_* variables are accessible at runtime in the Expo app.
3

Start the dev server

bunx expo start
Press a for Android, i for iOS, or scan the QR code with Expo Go.
4

Development builds (optional)

For a full dev-client build with native module support:
bun run build:dev:ios       # iOS simulator
bun run build:dev:android   # Android APK
After installing the dev build, start the server with:
bunx expo start --dev-client

EAS builds and deployments

The app uses Expo Application Services (EAS) for native builds, OTA updates, and store submissions.
Build profileCommandPurpose
Developmentbun run build:devDev builds with dev-client and fast refresh
Previewbun run build:previewRelease-mode builds for internal QA
Productionbun run build:prodStore-ready builds with auto-incrementing version

OTA updates

Push JavaScript and asset changes to existing installs without a new store build:
bun run update --branch production --message "Fix: wallet balance display"
Build profileUpdate channelRecipients
developmentdevelopmentDev builds
previewpreviewInternal testers
productionproductionApp store users
OTA updates only work if the JS is compatible with the installed native binary. If you add or change native modules, you must do a full build first and bump version in app.json.

API normalization (Phase 2)

The app is migrating to a standard response envelope for all backend communication:
// Success
{ success: true, data: T }

// Error
{ success: false, error: string, code?: string }
The API client in lib/api/client.ts handles response normalization. As backend routes are migrated, the client will be simplified to remove legacy response-shape detection. See the Phase 2 plan in the repo at docs/plans/PHASE-2-API-NORMALIZATION.md for the full migration status and execution plan.

Ecosystem overview

See how the native app fits with the PWA, site, and Mic’d Up.