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.
Run: bunx expo start — then press a for Android, i for iOS, or scan the QR code with Expo Go.
Version: 1.10.5
Bundle ID: com.dsports.wallet.beta (iOS and Android)
Tech stack
Category Technology Framework Expo 54, React Native 0.81, React 19 Auth Clerk (@clerk/clerk-expo) Payments RevenueCat (react-native-purchases) Web3 Thirdweb SDK State Zustand 5 + React Context Storage MMKV (synchronous persistence) UI Lucide React Native Navigation Expo Router 6 (file-based routing) Animations React Native Reanimated 4 Monitoring Sentry (@sentry/react-native) Package Bun
Features
Wallet — token balances, holdings, pack opening, crypto checkout (via PWA backend), PIN verification
Shop — collectibles, cart, coin bundles, crypto and fiat checkout
Leaderboard — rankings and filters
Locker room — social feed, teams, quests, daily games (Pick’Em, Spin Wheel, Guess the Player)
Profile — user profile, settings, and account management
Theme — dark/light mode (default dark)
PWA support — display: standalone, responsive desktop layout (max 480 px), web hover states
Getting started
Configure environment
Create a .env file in the project root with the following variables: Variable Description EXPO_PUBLIC_CLERK_PUBLISHABLE_KEYClerk publishable key EXPO_PUBLIC_API_URLAPI backend URL (e.g. https://api.d-sports.org) EXPO_PUBLIC_TW_CLIENT_IDThirdweb client ID EXPO_PUBLIC_REVENUECAT_API_KEYRevenueCat API key EXPO_PUBLIC_REVENUECAT_APPSTORE_IDRevenueCat App Store ID EXPO_PUBLIC_REVENUECAT_ENTITLEMENTRevenueCat entitlement name EXPO_PUBLIC_SUPABASE_URLSupabase project URL EXPO_PUBLIC_SUPABASE_KEYSupabase publishable key
Only EXPO_PUBLIC_* variables are accessible at runtime in the Expo app.
Start the dev server
Press a for Android, i for iOS, or scan the QR code with Expo Go.
Project structure
app/
├── (auth)/ # Login, signup, password reset, SSO callback
├── (onboarding)/ # New user onboarding flow
├── (tabs)/ # Main tab navigation (wallet, shop, leaderboard, locker room, profile)
├── settings/ # Settings pages with nested modals and tabs
└── _layout.tsx # Root layout with providers and auth protection
components/
├── wallet/ # Wallet sub-components (TokenRow, HoldingRow, PackOpeningModal, etc.)
├── shop/ # Shop sub-components (CartModal, CryptoCheckoutModal, etc.)
├── locker-room/ # Locker room components (feed, quests, games, teams)
├── leaderboard/ # Leaderboard components
├── settings/ # Settings components, modals, and tabs
├── ui/ # Reusable UI primitives (Button, TextField, WebHoverWrapper)
├── Icon/ # Icon wrapper using lucide-react-native
└── theme-provider.tsx # Theme context (dark/light)
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 data and interaction logic
lib/
├── api/ # API client modules (wallet, shop, user, quests, checkout, etc.)
├── revenuecat/ # RevenueCat in-app purchases provider
└── crypto/ # On-chain transaction helpers
context/ # React Context providers (user, collectibles, navbar visibility)
services/ # Zustand store, MMKV storage adapter, core types
types/ # TypeScript types (wallet, shop, checkout, API responses)
constants/ # Static data (tokens, coin bundles, locker room config)
theme/ # Brand colors, spacing, typography tokens
Architecture
Screen pattern
Screen files under app/(tabs)/ contain only JSX . All state, effects, and handlers live in dedicated hooks:
hooks/use-wallet-screen.ts — wallet/token fetching, PIN verification, transaction handlers
hooks/use-shop-screen.ts — cart state, product queries, carousel auto-scroll, checkout logic
Sub-components are extracted into components/wallet/ and components/shop/ with barrel exports.
State management
Zustand store (services/store.ts) with MMKV persistence for theme, cart, and points
React Context providers for authentication (UserContext), collectibles (CollectiblesContext), and navbar visibility
API client layer
lib/api/client.ts is the base HTTP client with Clerk auth token injection. Domain-specific 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) are surfaced through a single useApi() hook from lib/api/index.ts.
Responses are cached with MMKV via lib/api/cache.ts for offline-first fallback.
Payments
Fiat: RevenueCat handles Apple IAP (native), Google Play (native), and Stripe (web) via lib/revenuecat/provider.tsx
Crypto: Thirdweb SDK signs on-chain transactions against the PWA backend (POST /api/checkout/crypto and POST /api/checkout/crypto/verify). Supported chains: Arbitrum (default), Ethereum, Polygon.
Path alias
Use the @/* alias to import from the project root:
import { useUser } from "@/context/user-context" ;
import type { Token } from "@/types/wallet.types" ;
EAS builds and deployment
The app uses Expo Application Services (EAS) for native builds, OTA updates, and store submissions.
Build profiles
Profile Purpose Command developmentDev client (simulator) bun run build:devpreviewInternal QA (APK/ad hoc) bun run build:previewproductionStore-ready bun run build:prod
OTA updates
Push JS-only changes without a new store build:
bun run update --branch production --message "Fix: wallet balance display"
Build profile Update channel Audience developmentdevelopmentDev builds previewpreviewInternal testers productionproductionApp Store users
OTA updates only work when the JS bundle is compatible with the installed native binary. If you add or change native modules, do a full build first and bump the version in app.json.
Store submission
bun run submit # both platforms
bun run submit:ios # iOS only
bun run submit:android # Android only
Branding
Token Value Base background #0a0e1aAccent gold #F5C842Primary blue #4169E1Default theme Dark
Ecosystem overview See how the native app fits with the PWA, site, and Mic’d Up.