# Mobile App Architecture

# Drop Mobile App

> React Native / Expo Router app in `src/drop-mobile/`.

---

## Tech Stack

| Technology | Version/Details |
|------------|----------------|
| Framework | React Native (Expo) |
| Routing | Expo Router (file-based) |
| Fonts | DM Sans (expo-google-fonts), Fraunces (expo-google-fonts) |
| Navigation | Stack (root) + Tabs (main app) |
| State | React `useState` (no global state library) |
| API | Custom fetch wrapper with Bearer token auth |
| Storage | AsyncStorage (for auth token) |

---

## Directory Structure

```
src/drop-mobile/
├── App.js                    # Expo entry (unused — Expo Router takes over)
├── app/
│   ├── _layout.js            # Root Stack layout + font loading
│   ├── index.js              # Welcome screen
│   ├── login.js              # Login screen
│   ├── register.js           # Registration (2-step)
│   ├── history.js            # Transaction history
│   └── (tabs)/
│       ├── _layout.js        # Tab navigator (4 tabs)
│       ├── index.js          # Dashboard / Home
│       ├── send.js           # Send money
│       ├── scan.js           # QR scanner
│       └── profile.js        # Profile & settings
├── lib/
│   ├── api.js                # API client
│   └── theme.js              # Theme constants
└── assets/                   # Static assets
```

---

## Navigation

### Root Stack (`app/_layout.js`)

```
Stack.Screen: index          (Welcome — no header)
Stack.Screen: login          (Login — no header)
Stack.Screen: register       (Register — no header)
Stack.Screen: (tabs)         (Main app — no header)
Stack.Screen: send           (Send money — modal presentation)
Stack.Screen: scan           (QR scan — modal presentation)
```

Font loading happens here: `Fraunces_600SemiBold`, `Fraunces_700Bold`, `DMSans_400Regular`, `DMSans_500Medium`, `DMSans_700Bold`. App shows nothing until fonts are loaded (SplashScreen.preventAutoHideAsync).

### Tab Navigator (`app/(tabs)/_layout.js`)

| Tab | Label | Icon | Screen |
|-----|-------|------|--------|
| index | Hjem | Unicode house | Dashboard |
| send | Send | Unicode arrow | Send money |
| scan | QR | Unicode QR | QR scanner |
| profile | Profil | Unicode person | Profile |

Tab bar style: `backgroundColor: colors.white`, `borderTopColor: colors.border`, `height: 60`.
Active tint: `colors.green` (#0B6E35), inactive: `colors.textLight` (#9CA3AF).

---

## Screens

### Welcome (`app/index.js`)
- Green background (`colors.green`)
- "drop." wordmark in white Fraunces font
- Headline: "Enklere betalinger. Lavere gebyrer."
- Two buttons: "Logg inn" (outline) → /login, "Opprett konto" (solid white) → /register

### Login (`app/login.js`)
- White background
- Email + password fields
- "Logg inn" green button → calls `api.login(email, password)`
- On success: stores token, navigates to `/(tabs)`
- "Opprett konto" link → /register
- Pre-filled demo credentials in dev

### Register (`app/register.js`)
- 2-step flow with progress dots indicator
- **Step 1:** firstName, lastName, email, phone
- **Step 2:** password, confirmPassword
- Calls `api.register(data)`, on success navigates to `/(tabs)`

### Dashboard (`app/(tabs)/index.js`)
- Greeting: "Hei, {firstName}" with hand wave emoji
- Green balance card: "Total saldo" with formatted NOK amount
- Quick stats row: Sendt, Mottatt, Ventende (sent, received, pending)
- "Siste transaksjoner" section with FlatList
- Each transaction: icon (arrow up=sent, arrow down=received), name, date, amount with color coding
- "Se alle" link → /history
- Pull-to-refresh via `RefreshControl`

### Send Money (`app/(tabs)/send.js`)
- 2-step flow:
- **Step 1:** Recipient name input + currency picker (5 currencies with flags)
  - Currencies: BAM (Bosnia), RSD (Serbia), PKR (Pakistan), TRY (Turkey), PLN (Poland)
- **Step 2:** Amount input (NOK) + conversion card showing:
  - Exchange rate (fetched from `api.getRate`)
  - Fee (0.5%)
  - "Mottaker far" (recipient gets) calculated amount
- "Bekreft og send" button → `api.sendRemittance(data)`
- Success: shows confirmation, "Tilbake til hjem" button

### QR Scanner (`app/(tabs)/scan.js`)
- Camera placeholder (gray box with QR icon)
- "Skann QR-kode" instruction text
- "Simuler skanning" button for demo
- Nearby merchants list (hardcoded: Ahmetov Kebab, Kafe Oslo, Narvesen)
- Payment flow: merchant info → amount input → confirm → success
- Calls `api.payQR({ merchantId, amount })`

### Transaction History (`app/history.js`)
- Filter tabs: Alle, Sendinger (remittance), QR (qr_payment)
- FlatList with transaction items
- Each item: direction icon, recipient/merchant name, date, amount
- Pull-to-refresh
- Filter changes trigger re-fetch via `api.getTransactions({ type })`

### Profile (`app/(tabs)/profile.js`)
- User info section: initials avatar, name, email
- "Mine mottakere" section with recipients list (fetched from `api.getRecipients()`)
- Each recipient: name, country, account number
- Settings menu: Sprak, Varsler, Personvern, Vilkar
- Logout button → clears token, navigates to /index

---

## API Client

**File:** `lib/api.js`

### Configuration
```javascript
const API_URL = __DEV__
  ? "http://localhost:3000/api"
  : "https://drop-app.vercel.app/api";
```

### Auth Pattern
- Token stored in module-level variable `let token = null`
- All requests include `Authorization: Bearer ${token}` header
- `setToken(t)` / `getToken()` exported for auth management

### Available Methods

| Method | HTTP | Endpoint | Returns |
|--------|------|----------|---------|
| `api.login(email, password)` | POST | `/auth/login` | `{ token, user }` |
| `api.register(data)` | POST | `/auth/register` | `{ token, user }` |
| `api.logout()` | POST | `/auth/logout` | — |
| `api.getMe()` | GET | `/auth/me` | `{ user }` |
| `api.getTransactions(params)` | GET | `/transactions` | `{ transactions }` |
| `api.sendRemittance(data)` | POST | `/transactions/remittance` | `{ transaction }` |
| `api.payQR(data)` | POST | `/transactions/qr-payment` | `{ transaction }` |
| `api.getRecipients()` | GET | `/recipients` | `{ recipients }` |
| `api.addRecipient(data)` | POST | `/recipients` | `{ recipient }` |
| `api.getMerchants()` | GET | `/merchants` | `{ merchants }` |
| `api.getRates()` | GET | `/rates` | `{ rates }` |
| `api.getRate(currency)` | GET | `/rates/{currency}` | `{ rate }` |
| `api.health()` | GET | `/health` | `{ status }` |

### Error Handling
All methods use a shared `request(endpoint, options)` function that:
- Adds auth header if token exists
- Parses JSON response
- Throws on non-OK status with `error.status` and `error.data`

---

## Theme

**File:** `lib/theme.js`

### Colors
```javascript
colors: {
  green: '#0B6E35',       // Primary — matches web app
  greenDark: '#095C2C',   // Hover/pressed state
  greenLight: '#E8F5E9',  // Light green bg
  gold: '#D4A017',        // Accent
  white: '#FFFFFF',
  bg: '#FAFCF8',          // Off-white background
  card: '#FFFFFF',
  text: '#1A1A1A',        // Primary text
  textSecondary: '#6B7280', // Secondary text
  textLight: '#9CA3AF',   // Muted text
  border: '#E5E7EB',      // Borders
  error: '#EF4444',       // Errors
  success: '#10B981',     // Success/positive
}
```

### Fonts
```javascript
fonts: {
  display: 'Fraunces_700Bold',
  heading: 'Fraunces_600SemiBold',
  body: 'DMSans_400Regular',
  bodyMedium: 'DMSans_500Medium',
  bodyBold: 'DMSans_700Bold',
}
```

### Spacing
```javascript
spacing: { xs: 4, sm: 8, md: 16, lg: 24, xl: 32, xxl: 48 }
```

### Border Radius
```javascript
radius: { sm: 8, md: 12, lg: 16, full: 9999 }
```

---

## Web App vs Mobile App Comparison

| Feature | Web (`drop-app`) | Mobile (`drop-mobile`) |
|---------|-----------------|----------------------|
| Auth storage | httpOnly cookie | Bearer token (in-memory) |
| Navigation | Next.js App Router | Expo Router (Stack + Tabs) |
| Send flow | 4 steps | 2 steps |
| Onboarding | 4 steps (info, OTP, PIN, success) | 2 steps (info, password) |
| QR scanner | Simulated camera UI | Simulated camera UI |
| Bottom nav | 5 tabs (Hjem, Aktivitet, Skann, Kontoer, Profil) | 4 tabs (Hjem, Send, QR, Profil) |
| Cards page | Yes (feature-flagged) | No |
| Merchant page | Yes (feature-flagged) | No |
| Accounts page | Yes (dedicated) | No (balance on dashboard) |
| History | Dedicated page with filters | Dedicated screen with filters |
| Feature flags | Environment variables | Not implemented |
| UI components | shadcn/ui (Radix) | React Native StyleSheet |
| State | useState + useAuth hook | useState + api module |

---

## Development Notes

- **API compatibility:** Mobile app calls the same API endpoints as the web app (same backend)
- **Dev API URL:** `http://localhost:3000/api` — requires the Next.js dev server running
- **Prod API URL:** `https://drop-app.vercel.app/api`
- **No deep linking** configured yet
- **No push notifications** implemented yet
- **No offline support** — requires network for all operations
- **No biometric auth** — login is email/password only