Skip to main content

Overview

d-sports-engage-native (package name: engage-native, version 1.10.0) 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 Metro bundler with PWA capabilities (display: standalone).

Tech stack

CategoryTechnology
FrameworkExpo 54, React Native 0.81, React 19
AuthClerk (Expo)
PaymentsRevenueCat (react-native-purchases)
Web3Thirdweb SDK
StateZustand
StorageMMKV (synchronous persistence)
UILucide React Native
NavigationExpo Router 6 (file-based routing)
MonitoringSentry (@sentry/react-native)
Package mgrBun

Features

  • Wallet — token balances, holdings, pack opening animations, and crypto checkout via the PWA backend
  • Shop — collectibles, cart, coin bundles, and crypto checkout with Thirdweb
  • Leaderboard — rankings with filters and user stats
  • Locker room — social feed, daily Pick’Em and Spin-the-Wheel games, quests, team exploration, and fan profiles
  • Profile — user profile, team membership, and full settings suite
  • Theme — dark/light mode (dark by default)
  • Onboarding — guided first-run flow for new users

Project structure

app/
├── (auth)/              # Login, sign-up, 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 and tabs
└── _layout.tsx          # Root layout with providers and auth protection

components/
├── wallet/              # Wallet sub-components (TokenRow, PackOpeningModal, etc.)
├── shop/                # Shop sub-components (CartModal, CryptoCheckoutModal, etc.)
├── locker-room/         # Locker room components (DailyPickEmGame, FeedSection, etc.)
├── leaderboard/         # Leaderboard components
├── settings/            # Settings components (SettingItem, modals, tabs)
├── ui/                  # Reusable primitives (Button, TextField, TutorialOverlay)
├── Icon/                # Icon wrapper using lucide-react-native
└── theme-provider.tsx   # Theme context (dark/light)

hooks/
├── use-wallet-screen.ts # Wallet state, effects, and handlers
├── use-shop-screen.ts   # Shop state, effects, and handlers
├── use-feed-section.ts  # Feed section logic
└── use-carousel-scroll.ts

lib/
├── api/                 # API client modules (user, wallet, shop, quests, checkout, etc.)
│   ├── client.ts        # Authenticated fetch wrapper using Clerk tokens
│   ├── cache.ts         # MMKV-backed API cache layer
│   └── index.ts         # useApi() hook exposing all API modules
├── crypto/              # On-chain transaction helpers (native + web)
├── revenuecat/          # RevenueCat in-app purchases provider
└── logger.ts            # Structured logger

context/
├── user-context.tsx     # Auth state, user profile, team membership
├── collectibles-context.tsx
├── navbar-visibility-context.tsx
└── accessibility-context.tsx

services/
├── store.ts             # Zustand global store (theme, cart, points)
├── storage.ts           # MMKV persistence adapter
└── RevenueCatService.ts # RevenueCat wrapper

Getting started

1

Install dependencies

bun install
2

Configure environment variables

Create a .env file in the project root. Only EXPO_PUBLIC_* keys are accessible at runtime:
VariablePurpose
EXPO_PUBLIC_CLERK_PUBLISHABLE_KEYClerk authentication
EXPO_PUBLIC_API_URLBackend API base URL (defaults to https://api.d-sports.org)
EXPO_PUBLIC_TW_CLIENT_IDThirdweb client ID for web3
EXPO_PUBLIC_REVENUECAT_API_KEYRevenueCat API key
EXPO_PUBLIC_REVENUECAT_APPSTORE_IDRevenueCat App Store identifier
EXPO_PUBLIC_REVENUECAT_ENTITLEMENTRevenueCat entitlement name
EXPO_PUBLIC_SUPABASE_URLSupabase project URL
EXPO_PUBLIC_SUPABASE_KEYSupabase publishable key
3

Start the development server

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

Build and deploy

The project uses EAS Build for native builds. Build profiles are defined in eas.json:
ProfilePurposeCommand
developmentDev client with simulator supportbun run build:dev
previewInternal distribution (APK on Android)bun run build:preview
stagingStaging channel with auto-incrementbunx eas-cli build --profile staging
productionProduction release with auto-incrementbun run build:prod
For OTA updates, run bun run update (uses eas-cli update).
The EAS CI workflow (.github/workflows/eas-update.yml) automatically triggers updates on push.

Architecture patterns

  • File-based routing — Expo Router with route groups (tabs), (auth), and (onboarding)
  • Modular screens — screen files contain only JSX; state, effects, and handlers live in dedicated hooks (e.g., use-wallet-screen.ts)
  • API client layerlib/api/client.ts wraps fetch with automatic Clerk token injection and parses the normalized { success, data, error, code } envelope from d-sports-api
  • MMKV cache fallbacklib/api/cache.ts caches API responses in MMKV so screens can render instantly from cache while refreshing in the background
  • Zustand + MMKV — global store (services/store.ts) persists theme, cart, and points via synchronous MMKV
  • React Context — auth/user state, collectibles, navbar visibility, and accessibility settings
  • Path alias@/* maps to the project root

API integration

The app connects to the same backend as the PWA (d-sports-api). The useApi() hook in lib/api/index.ts provides access to all API modules:
import { useApi } from "@/lib/api";

const api = useApi();
const profile = await api.user.getProfile();
const leaderboard = await api.leaderboard.getLeaderboard();
Available API modules: user, quests, leaderboard, wallet, lockerRoom, teams, collectibles, shop, and checkout.

Ecosystem overview

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