Mobile app for TIHLDE built with React Native, Expo, and TypeScript. Supports iOS and Android.
The app lets members browse and register for events, view career postings, check in via QR codes, see their groups, give and view fines, and submit expenses.
- Framework: React Native + Expo (SDK 57)
- Routing: Expo Router (file-based)
- Styling: NativeWind (TailwindCSS for React Native)
- State: React Query for server state, React Context for auth
- Language: TypeScript
- Bun 1.4.2 or newer
- Node.js 20.19.4+, 22.13+ or 24.3+ (
.nvmrcpins 24) - iOS (macOS only): Xcode, selected with
sudo xcode-select -s /Applications/Xcode.app/Contents/Developer. Keep the repo out of iCloud-synced folders, or code signing fails. - Android: Android Studio with an emulator, JDK 17 or 21, and
ANDROID_HOMEandJAVA_HOMEset
Expo CLI comes with the project, and bun run ios tries to install CocoaPods if it's missing.
bun installThe app uses native code, so it does not run in Expo Go. Build and install the development app on the simulator or emulator the first time, and again after adding a package with native code, changing app.json, or upgrading the Expo SDK:
bun run ios # Build and run on iOS simulator (the first build is slow)
bun run android # Build and run on Android emulatorBoth also start the dev server, so you can start working right away.
If an iOS build fails with error 65, the real error is in .expo/xcodebuild.log.
When the development app is already installed, start only the dev server instead of rebuilding:
bun x expo start # Start the Expo dev serverFrom the dev server, press i for the iOS simulator or a for the Android emulator. Changes appear when you save.
The app uses production Photon by default. To use a local Photon instead:
- Start Photon with
bun devin the Photon repo. For the Android emulator, runbun dev --filter=@photon/apiinstead, start Kvark separately withbun run dev --host 127.0.0.1inPhoton/apps/kvark(adb reversecan't reach Vite's default IPv6 address), and runadb reverse tcp:4000 tcp:4000 && adb reverse tcp:3000 tcp:3000after each emulator start. - In Kvark (
localhost:3000, Admin → OAuth-klienter), create a client with redirect URItihlde://oauthand "Offentlig klient" checked. - Copy
.env.exampleto.env.local, uncomment both lines, set the client id, and restart withbun x expo start --clear.
bun run test # Run tests in watch mode (`bun test` would run Bun's own runner, not Jest)bun run lint # Run ESLint via ExpoWe use EAS Build and EAS Submit to create production builds and publish to the App Store and Google Play.
Install EAS CLI globally:
bun install -g eas-cliLog in to the TIHLDE Expo account:
eas loginThe project has three build profiles configured in eas.json:
| Profile | Purpose | Distribution |
|---|---|---|
development |
Dev client for local testing | Internal |
preview |
Internal testing builds | Internal |
production |
App Store / Google Play releases | Store |
Build for both platforms:
eas build --platform all --profile productionOr build for a single platform:
eas build --platform ios --profile production
eas build --platform android --profile productionThe production profile auto-increments the build number on each build.
eas submit --platform ios --profile productionThis will prompt you to select a build and submit it to App Store Connect. You can then manage the release from App Store Connect.
eas submit --platform android --profile productionThis uses the service account key (service-account-file.json) configured in eas.json and submits directly to the production track on Google Play Console.
- Bump the version in
app.jsonandpackage.jsonif needed - Build:
eas build --platform all --profile production - Submit:
eas submit --platform iosandeas submit --platform android - iOS: Go to App Store Connect to add release notes and submit for review
- Android: Release goes live automatically (production track)
app/ # Expo Router file-based routes
├── (auth)/ # Login screen
├── (app)/
│ ├── (tabs)/ # Bottom tabs: arrangementer, karriere, bot, grupper, profil
│ └── (modals)/ # Slide-from-right screens: event details, group page,
│ # give-a-fine flow, expenses, notifications, QR
actions/ # API calls and TypeScript types
components/ # UI and feature-specific components
context/ # React Context providers (auth)
lib/ # Hooks, utilities, and storage helpers