Aplikasi TOTP (Time-based One-Time Password) authenticator yang dibangun dengan React Native + Expo. Mirip seperti Google Authenticator β menampilkan kode OTP 6-digit yang berubah setiap 30 detik, lengkap dengan countdown ring dan fitur tap-to-copy.
- Framework: Expo (SDK 54) dengan Expo Router (file-based routing)
- UI Library: Tamagui (2.0.0-rc.41)
- Language: TypeScript
- OTP Generation: otplib (TOTP)
- Secure Storage: expo-secure-store (native) / localStorage (web)
- Animation: react-native-reanimated
- Testing: Jest + jest-expo
- Package Manager: pnpm
- π Autentikasi β Login & Register dengan email/password, terhubung ke backend NestJS
- π TOTP Code Generation β Generate kode OTP 6-digit setiap 30 detik
- β±οΈ Countdown Ring β Visual countdown circular yang menunjukkan sisa waktu kode aktif
- π Tap to Copy β Tap kode untuk copy ke clipboard dengan haptic feedback
- π Dark/Light Mode β Theme toggle dengan dukungan system preference
- π± Multi-platform β Berjalan di iOS, Android, dan Web
- π Secure Token Storage β Token tersimpan di SecureStore (native) atau localStorage (web)
app/ # Routes (file-based routing)
βββ _layout.tsx # Root layout (providers, navigation)
βββ index.tsx # Home screen (OTP list)
βββ login.tsx # Login screen
βββ register.tsx # Register screen
components/ # Reusable UI components
βββ auth-form.tsx # Form login/register
βββ brand.tsx # Brand/logo component
βββ theme-toggle.tsx # Dark/light mode toggle
βββ ...
contexts/ # React Context providers
βββ auth-context.tsx # Auth state management
βββ theme-context.tsx # Theme preference management
services/ # API & storage layer
βββ api.ts # HTTP client untuk backend NestJS
βββ storage.ts # Abstraksi secure storage
constants/ # App-wide constants
βββ colors.ts # Color palette
βββ totp.ts # TOTP config (period, warn threshold)
βββ validation.ts # Password policy rules
lib/ # Utility functions
βββ utils.ts # Password validation, color helper, OTP formatting
hooks/ # Custom React hooks
βββ use-theme-color.ts
βββ use-color-scheme.ts
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β App Launch β
β β β
β βββββββββΌβββββββββ β
β β Animated Splash β β
β βββββββββ¬βββββββββ β
β β β
β βββββββββΌβββββββββ β
β β Auth Check β β
β β (SecureStore) β β
β βββββ¬ββββββββ¬ββββ β
β β β β
β token ada β β token kosong β
β β β β
β βββββββββΌβββ βββΌβββββββββββ β
β β Home / β β Login β β
β β OTP Listβ β Screen β β
β ββββββββββββ ββββ¬ββββββ¬βββ β
β β β β
β login β β tap "Sign up" β
β berhasil β β β
β β βββΌβββββββββββ β
β ββββββββββββββββββ β Register β β
β β β Screen β β
β β ββββ¬ββββββββββ β
β β β β
β β register berhasil β
β β (redirect ke login) β
β β β β
β β ββββββββββΌβββ β
β β β Login β β
β β β Screen β β
β β ββββββ¬βββββββ β
β β β login berhasil β
β βΌ βΌ β
β ββββββββββββββββββββββββββββββββ β
β β Home Screen (index) β β
β β βββββββββββββββββββββββββββ β β
β β β Header: Brand + Logout β β β
β β βββββββββββββββββββββββββββ€ β β
β β β OTP Card (Google) β β β
β β β β’ Kode 6-digit β β β
β β β β’ Countdown Ring β β β
β β β β’ Tap β Copy β β β
β β βββββββββββββββββββββββββββ€ β β
β β β OTP Card (GitHub) β β β
β β βββββββββββββββββββββββββββ€ β β
β β β OTP Card (Email) β β β
β β βββββββββββββββββββββββββββ β β
β ββββββββββββββββββββββββββββββββ β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
- App Launch β Menampilkan animated splash screen, lalu mengecek token di SecureStore/localStorage.
- Belum login β Redirect otomatis ke
/login. - Login Screen β User mengisi email & password β hit API
POST /api/v1/auth/loginβ token disimpan di SecureStore β redirect ke Home. - Register Screen β User mengisi email & password (harus memenuhi password policy) β hit API
POST /api/v1/auth/registerβ tampilkan notifikasi sukses β redirect ke Login. - Home Screen (Authenticated) β Menampilkan daftar kode OTP 6-digit yang di-generate setiap 30 detik menggunakan TOTP. Setiap kode memiliki countdown ring dan bisa di-tap untuk copy ke clipboard (dengan haptic feedback di native).
- Logout β Hapus token dari SecureStore β redirect kembali ke Login.
AuthProvider (Context)
βββ initializing: true β Loading spinner
βββ isAuthenticated: false β Redirect ke /login
βββ isAuthenticated: true β Tampilkan Home
βββ login(email, pw) β API call β simpan token β set isAuthenticated = true
βββ register(email, pw) β API call β redirect ke login (TANPA auto-login)
βββ logout() β hapus token β set isAuthenticated = false
- Node.js (v18+)
- pnpm
- Backend NestJS yang berjalan (lihat konfigurasi API di bawah)
-
Clone repository dan install dependencies:
pnpm install
-
Salin file environment:
cp .env.example .env
-
Edit
.envsesuai platform yang digunakan:# Web / iOS simulator EXPO_PUBLIC_API_URL=http://localhost:3000 # Android emulator EXPO_PUBLIC_API_URL=http://10.0.2.2:3000 # Physical device (ganti dengan IP LAN mesin kamu) EXPO_PUBLIC_API_URL=http://192.168.1.10:3000
# Start Expo dev server pnpm start # Langsung buka di platform tertentu pnpm ios # iOS Simulator pnpm android # Android Emulator pnpm web # Browser
pnpm testpnpm lint
Aplikasi ini terhubung ke backend NestJS dengan endpoint:
POST /api/v1/auth/registerβ Registrasi user baruPOST /api/v1/auth/loginβ Login user
Backend harus berjalan dan accessible sesuai EXPO_PUBLIC_API_URL yang dikonfigurasi.
Password harus memenuhi kriteria berikut:
- Minimal 8 karakter
- Mengandung huruf besar (A-Z)
- Mengandung huruf kecil (a-z)
- Mengandung angka (0-9)
- Mengandung karakter spesial
Untuk memulai dari awal (memindahkan starter code ke app-example):
pnpm reset-project