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 # Browserpnpm testpnpm lintAplikasi 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