Pages Drop Frontend — Pages All pages are in src/drop-app/src/app/ using Next.js App Router file-based routing. Page Index Route File Type Auth Required BottomNav / page.tsx Server No No /login login/page.tsx Client No No /register register/page.tsx Client No No /dashboard dashboard/page.tsx Client Yes Yes /accounts accounts/page.tsx Client Yes Yes /transactions transactions/page.tsx Client Yes Yes /scan scan/page.tsx Client Yes Yes /send send/page.tsx Client Yes No /profile profile/page.tsx Client Yes Yes /profile/personal profile/personal/page.tsx Client Yes No /profile/security profile/security/page.tsx Client Yes No /profile/notifications profile/notifications/page.tsx Client Yes No /profile/language profile/language/page.tsx Client Yes No /notifications notifications/page.tsx Client Yes Yes /cards cards/page.tsx Client Yes No /complaints complaints/page.tsx Client No No /fees fees/page.tsx Client No No /privacy privacy/page.tsx Client No No /terms terms/page.tsx Client No No /withdrawal withdrawal/page.tsx Client No No Page Details / — Home / Marketing Page File: app/page.tsx Type: Server component (no "use client") Auth: None Components used: DropLogoFull, DropAppIcon, Link, Image, custom icons (IconSendMoney, IconQrScan, IconVirtualCard, IconShield, IconFastTransfer, IconCorridors) Data: Static arrays features (3 items) and stats (3 items) defined inline Sections: Header with DropLogoFull + nav links (Tjenester, Priser, Om oss, Logg inn, Kom i gang) Hero with headline, subtext, CTA buttons, phone mockup placeholder Features grid (Send penger, Betal med QR, Virtuelt kort) Stats bar (0.5% Gebyr, <2t Leveringstid, 30+ Land) Trust section (BankID verified, Rask overføring, 30+ land) Merchant CTA section Footer with ALAI Holding AS credit /login — Login File: app/login/page.tsx Type: Client component Auth: None (entry point) Components used: Image, Link, Button, Mail/Lock/Eye/EyeOff/ArrowRight (lucide) State: email, password, showPassword, error, loading Data fetching: POST /api/auth/login with { email, password } Validation: Email regex ^[^\s@]+@[^\s@]+\.[^\s@]+$ , required fields check On success: router.push("/dashboard") Social login buttons: BankID, Vipps (UI only, not functional) Dev mode: Shows demo credentials amir@example.com / demo1234 /register — Registration File: app/register/page.tsx Type: Client component Auth: None Components used: ArrowLeft/ArrowRight/Check/Eye/EyeOff/Phone/Mail/User/Calendar/Lock (lucide), Button State: step (1-4), form fields, otp, pin, errors Steps: Info — firstName, lastName, email, phone (+47 prefix), dateOfBirth, password Verify — 6-digit OTP input (MVP: any 6 digits accepted) PIN — 4-digit PIN with custom numpad UI Success — Welcome message, redirect to /dashboard Validation: Age >= 18 (calculated from dateOfBirth) XSS protection: names reject < > " ' & ; ( ) { } [ ] Password: min 8 chars, must contain letters AND numbers Phone: must be 8 digits (Norwegian format) Data fetching: POST /api/auth/register /dashboard — Main Dashboard File: app/dashboard/page.tsx Type: Client component Auth: Yes ( useAuth() with redirect) Components used: DropLogo, BottomNav, ScrollArea, Bell/LogOut (lucide) State: transactions, loading Data fetching: GET /api/transactions?limit=10 Interfaces: Transaction { id, type, status, amount, currency, recipientName, createdAt } Layout: Header: DropLogo + notification bell + logout + avatar initials Balance card: primary account balance, formatted NOK Action buttons: Send penger (→ /send), Skann QR (→ /scan) Recent transactions list in ScrollArea BottomNav /accounts — Bank Accounts File: app/accounts/page.tsx Type: Client component Auth: Yes ( useAuth() ) Components used: BottomNav, Card, ArrowLeft/Landmark/Plus/ChevronRight (lucide) Data: Reads user.bankAccounts from auth hook (no separate fetch) Layout: PSD2/Open Banking info banner (blue) Account cards: bankName, masked accountNumber, balance, currency, isPrimary badge Total balance summary "Legg til bankkonto" button (BankID connection note) /transactions — Transaction History File: app/transactions/page.tsx Type: Client component Auth: Yes ( useAuth() ) Components used: BottomNav, Tabs/TabsList/TabsTrigger, ArrowLeft/Clock (lucide) State: transactions, filter, loading Data fetching: GET /api/transactions?type={filter}&limit=50 Filters: Alle (all), Overforinger (remittance), QR-betalinger (qr_payment) Grouping: groupByDate() function groups into: I dag, I gar, Denne uken, Eldre Display: Amount with +/- prefix and color coding (green for received, red for sent) /scan — QR Scanner File: app/scan/page.tsx Type: Client component Auth: Yes ( useAuth() ) Components used: BottomNav, Button, ArrowLeft/Camera/Check/X/Store (lucide) State: scanState (scanning | payment | paying | success), scannedMerchant, amount, paymentResult Interfaces: ScannedMerchant { id, name, category } , PaymentResult { id, status, amount, fee, merchant } Flow: Scanning — Camera viewfinder UI with scan frame, "Simuler skanning" button (demo) Payment — Shows merchant info, amount input, 1% fee calculation Paying — Loading spinner Success — Confirmation with transaction details Data fetching: POST /api/transactions/qr-payment with { merchantId, amount } Demo merchant: "Ahmetov Kebab" (id: "merchant_001", category: "Restaurant") /send — Send Money (Remittance) File: app/send/page.tsx Type: Client component Auth: Yes ( useAuth() ) Components used: Button, ArrowLeft/ArrowRight/Check/ChevronDown/Globe/User (lucide) State: step (1-4), selectedRecipient, amount, recipients, rates, sending, txResult Steps: Select Recipient — List from GET /api/recipients , shows name + country flag Enter Amount — NOK input, real-time conversion with exchange rate, 0.5% fee display Review — Summary of recipient, amount, rate, fee, total Success — Confirmation with reference number Data fetching: GET /api/recipients (on mount) GET /api/rates (on mount) POST /api/transactions/remittance with { recipientId, amountNOK, targetCurrency } Country flags: RS (Serbia), BA (Bosnia), TR (Turkey), PK (Pakistan), PL (Poland) Interface: TxResult { id, status, amount, fee, rate, recipientName, targetAmount, targetCurrency } /profile — User Profile File: app/profile/page.tsx Type: Client component Auth: Yes ( useAuth() ) Components used: BottomNav, ArrowLeft/ChevronRight/LogOut/Settings/Shield/HelpCircle/Bell/CreditCard/Landmark (lucide) Data: Reads user from auth hook Layout: User info card with initials avatar (green bg), full name, email Menu items: Mine kontoer (→ /accounts), Varsler, Innstillinger, Sikkerhet, Hjelp og stotte Logout button with confirmation Version: "Drop v0.1.0 · ALAI Holding AS" /withdrawal — Angrerett (Right of Withdrawal) File: app/withdrawal/page.tsx Type: Client component Auth: No Components used: ChevronLeft, RotateCcw, CheckCircle (lucide) State: submitted, loading Purpose: Norwegian angrerettloven compliance — 14-day right of withdrawal form Layout: Info section explaining angrerett (right to cancel service agreement within 14 days) Warning banner: Angrerett does not apply to completed payment transactions, only to the service agreement itself Form with optional reason dropdown (not_needed, alternative, not_satisfied, other) and comment textarea Submit button (red) with AML retention notice (data kept for 5 years per hvitvaskingsloven) Success screen with confirmation message (14-day processing time) /complaints — Send Complaint File: app/complaints/page.tsx Type: Client component Auth: Yes ( useAuth() ) Components used: MessageSquare, CheckCircle, ChevronLeft, ExternalLink (lucide) State: submitted, loading, formData (category, subject, description) Data fetching: POST /api/complaints with { category, subject, description } Purpose: Finansavtaleloven §3-53 compliance — formal complaint submission with 15 business day response requirement Layout: Info text: All complaints taken seriously, up to 15 business days processing time Form with required fields: Category dropdown: transaction, fees, service, privacy, other Subject text input (max 200 chars) Description textarea (max 2000 chars) Submit button with POST to /api/complaints External complaint authority section: Finansklagenemnda (FinKN) contact info with link to finansklagenemnda.no Success screen: Complaint received, 15 business day review commitment /privacy — Privacy Policy File: app/privacy/page.tsx Type: Client component Auth: None Components used: ChevronLeft, Shield (lucide) Purpose: GDPR-compliant privacy policy page (Norwegian language) Sections: Behandlingsansvarlig: ALAI Holding AS as data controller Hvilke opplysninger vi samler inn: Identification (name, email, phone, BankID), Financial data (bank accounts via Open Banking, transaction history), Technical data (IP, device, app version) Formaal med behandlingen: Transaction processing (PSD2/PISP), KYC/AML compliance, AML/terrorism prevention, service improvement Rettslig grunnlag: Contract (GDPR 6(1)(b)), Legal obligation (6(1)(c)) for AML/KYC, Legitimate interest (6(1)(f)) for service improvement Dine rettigheter: Innsyn (access), Retting (rectification), Sletting (erasure with 5-year AML retention), Dataportabilitet (portability) Oppbevaring: Minimum 5 years per hvitvaskingsloven, anonymization on account deletion but AML data retained Kontakt: personvern@getdrop.no, complaint to Datatilsynet /terms — Terms of Service File: app/terms/page.tsx Type: Client component Auth: None Components used: ChevronLeft, FileText (lucide) Purpose: Legal terms of service (Norwegian language) Sections: Om tjenesten: Drop as PISP/AISP under PSD2, provided by ALAI Holding AS Krav til brukere: 18+ age, Norwegian residency with BankID, KYC required, Norwegian phone (+47) Betalingsmodell: Drop never holds customer money, pass-through model via Open Banking Gebyrer: All fees shown before transaction confirmation, see fees page for full list Ansvar: Drop responsible for correct payment execution per betalingstjenesteloven, refund rights per law, not liable for bank/recipient delays Misbruk og sperring: Right to block accounts for suspected AML/fraud, mandatory STR reporting to Økokrim/EFE Angrerett: 14-day withdrawal right per angrerettloven (does not apply to completed transactions) Tvister: Norwegian law, Oslo tingrett jurisdiction, complaint to Finansklagenemnda /fees — Fee Overview File: app/fees/page.tsx Type: Client component Auth: None Components used: ChevronLeft, Receipt (lucide) Purpose: Transparent fee disclosure page (Norwegian language) Sections: Overføring til utlandet: Transaction fee: 1.5% per transfer Currency markup: 0.5% on mid-market rate Typical total: ~2% (compare with banks at 3-7%) QR-betaling i butikk: For customer: Free (no charge to payer) For merchant: 0.5% (lower than card terminals) Kontotjenester: Account creation: Free Monthly fee: Free Bank account linking (AISP): Free Viktig informasjon: Fees can change with 30-day notice Exchange rates updated in real-time from market Always see final amount before confirming /profile/personal — Personal Information File: app/profile/personal/page.tsx Type: Client component Auth: Yes ( useAuth() ) Components used: ChevronLeft, ShieldCheck (lucide), BottomNav State: Reads user from auth hook Layout: User avatar with initials (green gradient) Full name and email display Read-only form fields: firstName, lastName, email, phone (+47 987 65 432), dateOfBirth (15. mars 1995) BankID verification badge (green banner with ShieldCheck icon) Note: All fields are disabled (cannot edit) — verified via BankID /profile/security — Security Settings File: app/profile/security/page.tsx Type: Client component Auth: Yes ( useAuth() ) Components used: ChevronLeft, ChevronRight, Lock, Smartphone, Laptop (lucide), BottomNav Sections: Passord: Change password button (shows "Sist endret: Aldri") To-faktor autentisering: BankID verification: Active (green badge) Vipps verification: Not activated (gray badge) Aktive enheter: iPhone 15 Pro: Oslo, Norge — Aktiv nå (green dot indicator) MacBook Pro: Oslo, Norge — I går kl. 18:45 Footer: Support contact (support@getdrop.no) Note: UI only, no actual functionality connected /profile/notifications — Notification Settings File: app/profile/notifications/page.tsx Type: Client component Auth: Yes ( useAuth() ) Components used: ChevronLeft, Bell, Mail (lucide), BottomNav State: pushEnabled, emailEnabled, settingsLoaded Data fetching: GET /api/settings (on mount) PATCH /api/settings with { pushEnabled: boolean } or { emailEnabled: boolean } (on toggle) Layout: Push-varsler toggle switch (Bell icon) E-postvarsler toggle switch (Mail icon) Behavior: Toggles immediately update state and send PATCH request, revert on failure /profile/language — Language Settings File: app/profile/language/page.tsx Type: Client component Auth: Yes ( useAuth() ) Components used: ChevronLeft, Check (lucide), BottomNav State: selected, saving Data fetching: GET /api/settings (on mount) PATCH /api/settings with { language: string } (on save) Languages: nb (Norsk Bokmål), en (English), bs (Bosanski), sq (Shqip) Layout: Language list with radio selection (green checkmark for selected) "Lagre" button (green) to save selection Behavior: Selection updates local state, user must click "Lagre" to persist /notifications — Notifications Center File: app/notifications/page.tsx Type: Client component Auth: Yes ( useAuth() ) Components used: BottomNav, ArrowLeft, Bell, ArrowUpRight, ScanLine, Smartphone, TrendingUp (lucide) State: notifications, fetching Data fetching: GET /api/notifications (on mount) PATCH /api/notifications with { notificationIds: [ids] } (mark read, fire-and-forget) Interface: Notification { id, type, title, body, read, createdAt } Layout: Header with back button + "Varsler" title Empty state: Bell icon + "Ingen varsler enna" message Grouped notifications: I DAG / I GÅR / date groups Notification cards: icon based on type, title, body, timestamp, unread dot indicator BottomNav Notification types: transaction_complete (green), qr_payment (yellow), security (blue), rate_update (yellow), default (gray) Auto-read: Automatically marks all unread notifications as read on page load Time formatting: "I dag kl. HH:MM", "I går kl. HH:MM", or "DD.MM.YYYY kl. HH:MM" /cards — Card Management (FUTURE — feature-flagged) Note: Cards are a FUTURE feature, gated behind feature flags (all default to false ). Requires a card issuing partner before activation. File: app/cards/page.tsx Type: Client component Auth: Yes ( useAuth() ) Feature flags: virtualCards (gate), physicalCards , cardPin , spendingLimits — all default to false Components used: Button, Dialog, various lucide icons (CreditCard, Plus, ArrowLeft, Smartphone, Eye, EyeOff, Lock, X, Check, Copy, RefreshCw) State: cards, selectedCard, showDetails, showOrderForm, orderForm, loading Data fetching: GET /api/cards (list) POST /api/cards (create virtual) POST /api/cards with type "physical" + address (order physical) PATCH /api/cards/{id} with {status: "frozen" | "active"} DELETE /api/cards/{id} Card visual: Green gradient background, masked card number (•••• •••• •••• 4242), expiry, cardholder name