feat: reorganize admin settings with tabbed interface and documentation
- Reorganized admin settings into tabbed interface (General, Security, Payment Methods) - Vertical tabs on desktop, horizontal scrollable on mobile - Moved Payment Methods from separate menu to Settings tab - Fixed admin profile reuse and dashboard blocking - Fixed maintenance mode guard to use AppConfig model - Added admin auto-redirect after login (admins → /admin, users → /) - Reorganized documentation into docs/ folder structure - Created comprehensive README and documentation index - Added PWA and Web Push notifications to to-do list
This commit is contained in:
248
docs/features/admin-auto-redirect.md
Normal file
248
docs/features/admin-auto-redirect.md
Normal file
@@ -0,0 +1,248 @@
|
||||
# Admin Auto-Redirect Implementation
|
||||
|
||||
## ✅ **COMPLETE: Admins Now Redirect to /admin Automatically**
|
||||
|
||||
### **Overview**
|
||||
Modified all authentication flows to automatically redirect admin users to `/admin` instead of the member dashboard (`/`).
|
||||
|
||||
---
|
||||
|
||||
## **📝 Changes Made**
|
||||
|
||||
### **1. Login Page** (`/apps/web/src/components/pages/Login.tsx`)
|
||||
**Already Implemented** ✅
|
||||
- Lines 42-46: Checks `result.user?.role === 'admin'`
|
||||
- Redirects admins to `/admin`
|
||||
- Redirects regular users to `/`
|
||||
|
||||
```typescript
|
||||
if (result.user?.role === 'admin') {
|
||||
navigate('/admin')
|
||||
} else {
|
||||
navigate('/')
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### **2. OTP Verification** (`/apps/web/src/components/pages/OtpVerification.tsx`)
|
||||
**Fixed** ✅
|
||||
- Lines 60-66: Now checks user role after OTP verification
|
||||
- Redirects based on role
|
||||
|
||||
**Before:**
|
||||
```typescript
|
||||
await verifyOtp(tempToken, code, method)
|
||||
navigate('/') // Always went to member dashboard
|
||||
```
|
||||
|
||||
**After:**
|
||||
```typescript
|
||||
const result = await verifyOtp(tempToken, code, method)
|
||||
if (result.user?.role === 'admin') {
|
||||
navigate('/admin')
|
||||
} else {
|
||||
navigate('/')
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### **3. Auth Callback (Google OAuth)** (`/apps/web/src/components/pages/AuthCallback.tsx`)
|
||||
**Fixed** ✅
|
||||
- Lines 22-36: Fetches user data to check role
|
||||
- Redirects based on role
|
||||
|
||||
**Before:**
|
||||
```typescript
|
||||
localStorage.setItem('token', token)
|
||||
window.location.href = '/' // Always went to member dashboard
|
||||
```
|
||||
|
||||
**After:**
|
||||
```typescript
|
||||
localStorage.setItem('token', token)
|
||||
|
||||
// Fetch user to check role
|
||||
const response = await axios.get(`${API_URL}/api/auth/me`, {
|
||||
headers: { Authorization: `Bearer ${token}` }
|
||||
})
|
||||
|
||||
// Redirect based on role
|
||||
if (response.data.role === 'admin') {
|
||||
window.location.href = '/admin'
|
||||
} else {
|
||||
window.location.href = '/'
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### **4. Public Route Guard** (`/apps/web/src/App.tsx`)
|
||||
**Fixed** ✅
|
||||
- Lines 55-58: Prevents logged-in users from accessing login/register
|
||||
- Now redirects admins to `/admin` instead of `/`
|
||||
|
||||
**Before:**
|
||||
```typescript
|
||||
if (user) {
|
||||
return <Navigate to="/" replace /> // Always went to member dashboard
|
||||
}
|
||||
```
|
||||
|
||||
**After:**
|
||||
```typescript
|
||||
if (user) {
|
||||
// Redirect based on role
|
||||
const redirectTo = user.role === 'admin' ? '/admin' : '/'
|
||||
return <Navigate to={redirectTo} replace />
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## **🎯 User Flows**
|
||||
|
||||
### **Admin Login Flow:**
|
||||
```
|
||||
1. Admin goes to /auth/login
|
||||
2. Enters credentials
|
||||
3. Clicks "Sign In"
|
||||
↓
|
||||
4a. If NO OTP required:
|
||||
→ Redirected to /admin ✅
|
||||
|
||||
4b. If OTP required:
|
||||
→ Goes to /auth/otp
|
||||
→ Enters OTP code
|
||||
→ Redirected to /admin ✅
|
||||
```
|
||||
|
||||
### **Admin Google OAuth Flow:**
|
||||
```
|
||||
1. Admin clicks "Continue with Google"
|
||||
2. Completes Google authentication
|
||||
3. Redirected to /auth/callback
|
||||
↓
|
||||
4a. If NO OTP required:
|
||||
→ Redirected to /admin ✅
|
||||
|
||||
4b. If OTP required:
|
||||
→ Goes to /auth/otp
|
||||
→ Enters OTP code
|
||||
→ Redirected to /admin ✅
|
||||
```
|
||||
|
||||
### **Admin Already Logged In:**
|
||||
```
|
||||
1. Admin is already logged in
|
||||
2. Admin tries to access /auth/login or /auth/register
|
||||
↓
|
||||
3. PublicRoute guard intercepts
|
||||
4. Redirected to /admin ✅
|
||||
```
|
||||
|
||||
### **Regular User Flows:**
|
||||
All regular users continue to be redirected to `/` (member dashboard) as before.
|
||||
|
||||
---
|
||||
|
||||
## **📊 Redirect Matrix**
|
||||
|
||||
| Scenario | User Type | Destination |
|
||||
|----------|-----------|-------------|
|
||||
| Login (no OTP) | Admin | `/admin` ✅ |
|
||||
| Login (no OTP) | User | `/` |
|
||||
| Login → OTP | Admin | `/admin` ✅ |
|
||||
| Login → OTP | User | `/` |
|
||||
| Google OAuth (no OTP) | Admin | `/admin` ✅ |
|
||||
| Google OAuth (no OTP) | User | `/` |
|
||||
| Google OAuth → OTP | Admin | `/admin` ✅ |
|
||||
| Google OAuth → OTP | User | `/` |
|
||||
| Already logged in → /auth/login | Admin | `/admin` ✅ |
|
||||
| Already logged in → /auth/login | User | `/` |
|
||||
|
||||
---
|
||||
|
||||
## **🧪 Testing Instructions**
|
||||
|
||||
### **Test 1: Admin Email Login**
|
||||
```
|
||||
1. Go to http://localhost:5174/auth/login
|
||||
2. Login with admin credentials
|
||||
3. Verify redirected to /admin ✅
|
||||
```
|
||||
|
||||
### **Test 2: Admin Google Login**
|
||||
```
|
||||
1. Go to http://localhost:5174/auth/login
|
||||
2. Click "Continue with Google"
|
||||
3. Complete Google authentication
|
||||
4. Verify redirected to /admin ✅
|
||||
```
|
||||
|
||||
### **Test 3: Admin with OTP**
|
||||
```
|
||||
1. Login as admin (with OTP enabled)
|
||||
2. Enter OTP code
|
||||
3. Verify redirected to /admin ✅
|
||||
```
|
||||
|
||||
### **Test 4: Admin Already Logged In**
|
||||
```
|
||||
1. Login as admin
|
||||
2. Manually navigate to /auth/login
|
||||
3. Verify redirected to /admin ✅
|
||||
```
|
||||
|
||||
### **Test 5: Regular User Login**
|
||||
```
|
||||
1. Login as regular user
|
||||
2. Verify redirected to / (member dashboard) ✅
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## **📁 Files Modified**
|
||||
|
||||
1. `/apps/web/src/components/pages/OtpVerification.tsx`
|
||||
- Added role check after OTP verification
|
||||
- Conditional redirect based on role
|
||||
|
||||
2. `/apps/web/src/components/pages/AuthCallback.tsx`
|
||||
- Fetches user data to determine role
|
||||
- Conditional redirect based on role
|
||||
- Added error handling
|
||||
|
||||
3. `/apps/web/src/App.tsx`
|
||||
- Updated PublicRoute to redirect admins to /admin
|
||||
- Regular users still go to /
|
||||
|
||||
4. `/apps/web/src/components/pages/Login.tsx`
|
||||
- Already had role-based redirect (no changes needed)
|
||||
|
||||
---
|
||||
|
||||
## **✅ Verification Checklist**
|
||||
|
||||
- [x] Admin email login → /admin
|
||||
- [x] Admin Google login → /admin
|
||||
- [x] Admin with OTP → /admin
|
||||
- [x] Admin already logged in → /admin (when accessing login page)
|
||||
- [x] Regular user login → /
|
||||
- [x] Regular user with OTP → /
|
||||
- [x] Regular user already logged in → / (when accessing login page)
|
||||
|
||||
---
|
||||
|
||||
## **🎉 Summary**
|
||||
|
||||
**All authentication flows now correctly redirect admins to `/admin`!**
|
||||
|
||||
- ✅ Email/password login
|
||||
- ✅ Google OAuth login
|
||||
- ✅ OTP verification
|
||||
- ✅ Already logged-in guard
|
||||
- ✅ No changes to regular user flows
|
||||
|
||||
Admins will now land on the admin dashboard immediately after login, providing a better UX and clearer separation between admin and member interfaces.
|
||||
292
docs/features/admin-profile-reuse.md
Normal file
292
docs/features/admin-profile-reuse.md
Normal file
@@ -0,0 +1,292 @@
|
||||
# Admin Profile Page & Dashboard Blocking
|
||||
|
||||
## ✅ **COMPLETE: Profile Page Reused for Admin + Member Dashboard Blocked**
|
||||
|
||||
### **Overview**
|
||||
- Reused the existing Profile page for admin users
|
||||
- Added Profile menu item to admin sidebar
|
||||
- Blocked admins from accessing the member dashboard
|
||||
- Admins are automatically redirected to `/admin` if they try to access member routes
|
||||
|
||||
---
|
||||
|
||||
## **📝 Changes Made**
|
||||
|
||||
### **1. Added Profile to Admin Sidebar** (`AdminSidebar.tsx`)
|
||||
**Changes:**
|
||||
- Added `UserCircle` icon import
|
||||
- Added Profile menu item between Users and Settings
|
||||
- Profile route: `/admin/profile`
|
||||
|
||||
```typescript
|
||||
{
|
||||
title: 'Profile',
|
||||
url: '/admin/profile',
|
||||
icon: UserCircle,
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### **2. Added Profile Route to Admin Panel** (`App.tsx`)
|
||||
**Changes:**
|
||||
- Imported Profile component
|
||||
- Added route: `/admin/profile`
|
||||
|
||||
```typescript
|
||||
<Route path="/admin" element={<ProtectedRoute><AdminLayout /></ProtectedRoute>}>
|
||||
<Route index element={<AdminDashboard />} />
|
||||
<Route path="plans" element={<AdminPlans />} />
|
||||
<Route path="payment-methods" element={<AdminPaymentMethods />} />
|
||||
<Route path="payments" element={<AdminPayments />} />
|
||||
<Route path="users" element={<AdminUsers />} />
|
||||
<Route path="profile" element={<Profile />} /> ✅ NEW
|
||||
<Route path="settings" element={<AdminSettings />} />
|
||||
</Route>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### **3. Blocked Admins from Member Dashboard** (`Dashboard.tsx`)
|
||||
**Changes:**
|
||||
- Added auth check at the top of Dashboard component
|
||||
- Redirects admins to `/admin` if they try to access member routes
|
||||
|
||||
```typescript
|
||||
export function Dashboard() {
|
||||
const { user } = useAuth()
|
||||
|
||||
// Block admins from accessing member dashboard
|
||||
if (user?.role === 'admin') {
|
||||
return <Navigate to="/admin" replace />
|
||||
}
|
||||
|
||||
// ... rest of component
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### **4. Translated AdminLayout** (`AdminLayout.tsx`)
|
||||
**Changes:**
|
||||
- "Akses Ditolak" → "Access Denied"
|
||||
- "Anda tidak memiliki izin..." → "You don't have permission..."
|
||||
- "Kembali ke Dashboard" → "Back to Dashboard"
|
||||
|
||||
---
|
||||
|
||||
## **🎯 User Flows**
|
||||
|
||||
### **Admin Accessing Profile:**
|
||||
```
|
||||
Admin logged in
|
||||
↓
|
||||
Click "Profile" in sidebar
|
||||
↓
|
||||
Navigate to /admin/profile ✅
|
||||
↓
|
||||
See Profile page with all settings
|
||||
```
|
||||
|
||||
### **Admin Trying to Access Member Dashboard:**
|
||||
```
|
||||
Admin logged in
|
||||
↓
|
||||
Try to navigate to / (member dashboard)
|
||||
↓
|
||||
Dashboard component checks role
|
||||
↓
|
||||
Redirected to /admin ✅
|
||||
```
|
||||
|
||||
### **Admin Trying Member Routes:**
|
||||
```
|
||||
Admin tries:
|
||||
- / → Redirected to /admin ✅
|
||||
- /wallets → Redirected to /admin ✅
|
||||
- /transactions → Redirected to /admin ✅
|
||||
- /profile → Redirected to /admin ✅
|
||||
```
|
||||
|
||||
### **Regular User:**
|
||||
```
|
||||
User logged in
|
||||
↓
|
||||
Access / → Works normally ✅
|
||||
Access /wallets → Works normally ✅
|
||||
Access /transactions → Works normally ✅
|
||||
Access /profile → Works normally ✅
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## **📊 Route Access Matrix**
|
||||
|
||||
| Route | Admin Access | User Access |
|
||||
|-------|--------------|-------------|
|
||||
| `/` | ❌ Redirect to /admin | ✅ Member Dashboard |
|
||||
| `/wallets` | ❌ Redirect to /admin | ✅ Wallets Page |
|
||||
| `/transactions` | ❌ Redirect to /admin | ✅ Transactions Page |
|
||||
| `/profile` | ❌ Redirect to /admin | ✅ Profile Page |
|
||||
| `/admin` | ✅ Admin Dashboard | ❌ Access Denied |
|
||||
| `/admin/profile` | ✅ Profile Page | ❌ Access Denied |
|
||||
| `/admin/*` | ✅ All admin routes | ❌ Access Denied |
|
||||
|
||||
---
|
||||
|
||||
## **🎨 Admin Sidebar Menu Order**
|
||||
|
||||
1. 📊 Dashboard (`/admin`)
|
||||
2. 💳 Plans (`/admin/plans`)
|
||||
3. 💰 Payment Methods (`/admin/payment-methods`)
|
||||
4. 💵 Payments (`/admin/payments`)
|
||||
5. 👥 Users (`/admin/users`)
|
||||
6. 👤 **Profile** (`/admin/profile`) ✅ NEW
|
||||
7. ⚙️ Settings (`/admin/settings`)
|
||||
|
||||
---
|
||||
|
||||
## **✨ Benefits**
|
||||
|
||||
### **1. Code Reuse**
|
||||
- ✅ No need to duplicate Profile component
|
||||
- ✅ Same profile settings for both admin and users
|
||||
- ✅ Consistent UI/UX across roles
|
||||
|
||||
### **2. Clear Separation**
|
||||
- ✅ Admins can't access member dashboard
|
||||
- ✅ Users can't access admin panel
|
||||
- ✅ Automatic redirects prevent confusion
|
||||
|
||||
### **3. Better UX**
|
||||
- ✅ Admins have dedicated profile page in admin panel
|
||||
- ✅ No need to switch between interfaces
|
||||
- ✅ All admin features in one place
|
||||
|
||||
---
|
||||
|
||||
## **🧪 Testing Instructions**
|
||||
|
||||
### **Test 1: Admin Profile Access**
|
||||
```
|
||||
1. Login as admin
|
||||
2. Navigate to /admin
|
||||
3. Click "Profile" in sidebar
|
||||
4. Verify you see the profile page ✅
|
||||
5. Test all profile features (edit, OTP, etc.)
|
||||
6. Verify everything works ✅
|
||||
```
|
||||
|
||||
### **Test 2: Admin Dashboard Blocking**
|
||||
```
|
||||
1. Login as admin
|
||||
2. Manually navigate to / (member dashboard)
|
||||
3. Verify redirected to /admin ✅
|
||||
4. Try /wallets
|
||||
5. Verify redirected to /admin ✅
|
||||
6. Try /transactions
|
||||
7. Verify redirected to /admin ✅
|
||||
```
|
||||
|
||||
### **Test 3: Regular User Access**
|
||||
```
|
||||
1. Login as regular user
|
||||
2. Navigate to / (member dashboard)
|
||||
3. Verify dashboard loads ✅
|
||||
4. Navigate to /wallets
|
||||
5. Verify wallets page loads ✅
|
||||
6. Navigate to /profile
|
||||
7. Verify profile page loads ✅
|
||||
8. Try to access /admin
|
||||
9. Verify "Access Denied" message ✅
|
||||
```
|
||||
|
||||
### **Test 4: Profile Functionality**
|
||||
```
|
||||
As Admin (/admin/profile):
|
||||
- ✅ Edit profile information
|
||||
- ✅ Change password
|
||||
- ✅ Enable/disable OTP methods
|
||||
- ✅ Setup TOTP
|
||||
- ✅ All features work
|
||||
|
||||
As User (/profile):
|
||||
- ✅ Same features work
|
||||
- ✅ No differences in functionality
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## **📁 Files Modified**
|
||||
|
||||
1. **`/apps/web/src/components/admin/AdminSidebar.tsx`**
|
||||
- Added UserCircle icon import
|
||||
- Added Profile menu item
|
||||
|
||||
2. **`/apps/web/src/App.tsx`**
|
||||
- Imported Profile component
|
||||
- Added `/admin/profile` route
|
||||
|
||||
3. **`/apps/web/src/components/Dashboard.tsx`**
|
||||
- Added auth check
|
||||
- Blocks admins from accessing member dashboard
|
||||
|
||||
4. **`/apps/web/src/components/admin/AdminLayout.tsx`**
|
||||
- Translated access denied message to English
|
||||
|
||||
---
|
||||
|
||||
## **🔒 Security Notes**
|
||||
|
||||
### **Frontend Guards:**
|
||||
- ✅ Dashboard component blocks admins
|
||||
- ✅ AdminLayout blocks non-admins
|
||||
- ✅ Automatic redirects prevent access
|
||||
|
||||
### **Backend Protection:**
|
||||
- ✅ API endpoints already have role-based guards
|
||||
- ✅ Admin routes require admin role
|
||||
- ✅ User routes work for all authenticated users
|
||||
|
||||
### **Important:**
|
||||
Frontend guards are for UX only. Backend API guards provide actual security. The frontend redirects just prevent confusion and provide better user experience.
|
||||
|
||||
---
|
||||
|
||||
## **✅ Verification Checklist**
|
||||
|
||||
- [x] Profile menu item added to admin sidebar
|
||||
- [x] Profile route added to admin panel
|
||||
- [x] Profile page accessible at /admin/profile
|
||||
- [x] Admins blocked from / (member dashboard)
|
||||
- [x] Admins blocked from /wallets
|
||||
- [x] Admins blocked from /transactions
|
||||
- [x] Admins blocked from /profile (member route)
|
||||
- [x] Regular users can still access all member routes
|
||||
- [x] Regular users blocked from /admin routes
|
||||
- [x] AdminLayout access denied message translated
|
||||
|
||||
---
|
||||
|
||||
## **🎉 Summary**
|
||||
|
||||
**Profile page successfully reused for admins!**
|
||||
|
||||
✅ **Admins can:**
|
||||
- Access profile at `/admin/profile`
|
||||
- Edit their profile information
|
||||
- Manage OTP settings
|
||||
- Change password
|
||||
- All from within the admin panel
|
||||
|
||||
❌ **Admins cannot:**
|
||||
- Access member dashboard (`/`)
|
||||
- Access member routes (`/wallets`, `/transactions`, etc.)
|
||||
- They are automatically redirected to `/admin`
|
||||
|
||||
✅ **Regular users:**
|
||||
- Continue to use profile at `/profile`
|
||||
- Full access to member dashboard
|
||||
- Cannot access admin panel
|
||||
|
||||
**Clean separation of concerns with maximum code reuse!** 🎊
|
||||
131
docs/features/admin-settings-tabs.md
Normal file
131
docs/features/admin-settings-tabs.md
Normal file
@@ -0,0 +1,131 @@
|
||||
# Admin Settings - Tabbed Interface
|
||||
|
||||
## Overview
|
||||
Reorganized admin settings page into a clean tabbed interface with vertical tabs on desktop and horizontal scrollable tabs on mobile.
|
||||
|
||||
## Implementation Date
|
||||
October 13, 2025
|
||||
|
||||
## Structure
|
||||
|
||||
### Tab Layout
|
||||
```
|
||||
Settings Page
|
||||
├── Tabs (Vertical on Desktop, Horizontal on Mobile)
|
||||
│ ├── 🌐 General
|
||||
│ ├── 🛡️ Security
|
||||
│ └── 💰 Payment Methods
|
||||
│
|
||||
└── Content Area (Dynamic based on active tab)
|
||||
```
|
||||
|
||||
### Tab Contents
|
||||
|
||||
#### 1. General Tab
|
||||
- **General Settings Card**
|
||||
- Application Name
|
||||
- Application URL
|
||||
- Support Email
|
||||
|
||||
- **Maintenance Mode Card**
|
||||
- Maintenance Mode Toggle
|
||||
- Maintenance Message (when enabled)
|
||||
|
||||
#### 2. Security Tab
|
||||
- **Features & Security Card**
|
||||
- New User Registration Toggle
|
||||
- Email Verification Toggle
|
||||
- Manual Payment Verification Toggle
|
||||
|
||||
#### 3. Payment Methods Tab
|
||||
- Full payment methods management
|
||||
- Drag-and-drop reordering
|
||||
- Add/Edit/Delete payment methods
|
||||
- Active/Inactive status toggle
|
||||
|
||||
## Files Created
|
||||
|
||||
1. **`AdminSettingsNew.tsx`**
|
||||
- Main settings page with tab navigation
|
||||
- Responsive layout (vertical/horizontal)
|
||||
|
||||
2. **`settings/AdminSettingsGeneral.tsx`**
|
||||
- General settings + Maintenance mode
|
||||
- Handles app configuration
|
||||
|
||||
3. **`settings/AdminSettingsSecurity.tsx`**
|
||||
- Feature toggles
|
||||
- Security settings
|
||||
|
||||
4. **`settings/AdminSettingsPaymentMethods.tsx`**
|
||||
- Wrapper for existing AdminPaymentMethods component
|
||||
|
||||
## Files Modified
|
||||
|
||||
1. **`App.tsx`**
|
||||
- Removed `/admin/payment-methods` route
|
||||
- Updated import to use `AdminSettingsNew`
|
||||
|
||||
2. **`AdminSidebar.tsx`**
|
||||
- Removed "Payment Methods" menu item
|
||||
- Consolidated under Settings
|
||||
|
||||
3. **`AdminPaymentMethods.tsx`**
|
||||
- Changed heading from h1 to h4 for tab context
|
||||
|
||||
## UI/UX Improvements
|
||||
|
||||
### Desktop
|
||||
- Vertical tabs on the left (fixed width: 256px)
|
||||
- Large content area on the right
|
||||
- Clear visual separation
|
||||
- Icons + text labels
|
||||
|
||||
### Mobile
|
||||
- Horizontal scrollable tabs at top
|
||||
- Full-width content below
|
||||
- Icons + text labels visible
|
||||
- Touch-friendly tap targets
|
||||
|
||||
### Responsive Breakpoint
|
||||
- Mobile: `< 768px` (md breakpoint)
|
||||
- Desktop: `≥ 768px`
|
||||
|
||||
## Benefits
|
||||
|
||||
1. **Cleaner Navigation**
|
||||
- Reduced sidebar clutter
|
||||
- Grouped related settings
|
||||
- Better information architecture
|
||||
|
||||
2. **Better UX**
|
||||
- All settings in one place
|
||||
- No page navigation needed
|
||||
- Faster access to configuration
|
||||
|
||||
3. **Scalability**
|
||||
- Easy to add new tabs
|
||||
- Modular component structure
|
||||
- Clear separation of concerns
|
||||
|
||||
## Testing
|
||||
|
||||
### Desktop
|
||||
- [x] Vertical tabs display correctly
|
||||
- [x] Tab switching works
|
||||
- [x] All settings save properly
|
||||
- [x] Icons and labels visible
|
||||
|
||||
### Mobile
|
||||
- [x] Horizontal scrollable tabs
|
||||
- [x] Tab switching works
|
||||
- [x] Content responsive
|
||||
- [x] Touch targets adequate
|
||||
|
||||
## Future Enhancements
|
||||
|
||||
Potential additions:
|
||||
- Notifications tab (Email/Push settings)
|
||||
- Integrations tab (Third-party services)
|
||||
- Appearance tab (Theme, branding)
|
||||
- Advanced tab (Developer settings)
|
||||
293
docs/features/maintenance-mode.md
Normal file
293
docs/features/maintenance-mode.md
Normal file
@@ -0,0 +1,293 @@
|
||||
# Maintenance Mode - Visual Flow Diagram
|
||||
|
||||
## 🎯 **Where Does the Maintenance Page Appear?**
|
||||
|
||||
### **Answer: It appears AFTER successful login, when trying to access protected routes**
|
||||
|
||||
---
|
||||
|
||||
## **📊 Complete User Journey**
|
||||
|
||||
### **Scenario 1: Non-Logged-In User (Maintenance ON)**
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ User opens: http://localhost:5174 │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
↓
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ App.tsx checks: Is user logged in? │
|
||||
│ Answer: NO │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
↓
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ Redirect to: /auth/login │
|
||||
│ (Login page loads normally - @SkipMaintenance) │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
↓
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ User enters credentials and clicks Login │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
↓
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ POST /auth/login (Works - @SkipMaintenance) │
|
||||
│ Returns: { token: "...", user: {...} } │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
↓
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ Token saved to localStorage │
|
||||
│ Redirect to: / │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
↓
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ Dashboard tries to load │
|
||||
│ Makes API call: GET /api/users/me │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
↓
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ MaintenanceGuard intercepts request │
|
||||
│ - Checks: Is maintenance ON? YES │
|
||||
│ - Checks: Is user admin? NO (role: 'user') │
|
||||
│ - Returns: 503 Service Unavailable │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
↓
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ Axios interceptor catches 503 error │
|
||||
│ Calls: setMaintenanceMode(true) │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
↓
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ ⚠️ MAINTENANCE PAGE DISPLAYED │
|
||||
│ │
|
||||
│ 🔧 Under Maintenance │
|
||||
│ Your custom message here │
|
||||
│ [Refresh Page] │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### **Scenario 2: Logged-In User (Maintenance Turns ON)**
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ User is already logged in, using the app normally │
|
||||
│ Currently on: /wallets │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
↓
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ Admin enables maintenance mode in /admin/settings │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
↓
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ User clicks on "Transactions" menu │
|
||||
│ OR tries to create a new transaction │
|
||||
│ OR any action that makes an API call │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
↓
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ API call: POST /api/transactions │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
↓
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ MaintenanceGuard intercepts │
|
||||
│ - Maintenance is ON │
|
||||
│ - User is not admin │
|
||||
│ - Returns: 503 │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
↓
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ Axios interceptor triggers │
|
||||
│ setMaintenanceMode(true) │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
↓
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ ⚠️ MAINTENANCE PAGE REPLACES CURRENT VIEW │
|
||||
│ │
|
||||
│ 🔧 Under Maintenance │
|
||||
│ System is being upgraded... │
|
||||
│ [Refresh Page] │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### **Scenario 3: Admin User (Maintenance ON)**
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ Admin logs in at: /auth/login │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
↓
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ Redirected to: / │
|
||||
│ Makes API call: GET /api/users/me │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
↓
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ MaintenanceGuard intercepts │
|
||||
│ - Maintenance is ON │
|
||||
│ - Extracts JWT token │
|
||||
│ - Checks role: 'admin' │
|
||||
│ - Returns: 503 (Even for admin on main app!) │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
↓
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ ⚠️ MAINTENANCE PAGE SHOWN │
|
||||
│ │
|
||||
│ (Admin sees maintenance on main app) │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
↓
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ Admin navigates to: /admin │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
↓
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ Makes API call: GET /api/admin/users/stats │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
↓
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ MaintenanceGuard intercepts │
|
||||
│ - Route has @SkipMaintenance decorator │
|
||||
│ - Returns: ALLOW (200 OK) │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
↓
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ ✅ ADMIN PANEL WORKS NORMALLY │
|
||||
│ │
|
||||
│ Admin can: │
|
||||
│ - View dashboard │
|
||||
│ - Manage users │
|
||||
│ - Disable maintenance mode │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## **🎨 Visual Representation**
|
||||
|
||||
### **App Structure During Maintenance:**
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ TABUNGIN APP │
|
||||
├─────────────────────────────────────────────────────────────┤
|
||||
│ │
|
||||
│ PUBLIC ROUTES (Always Work) │
|
||||
│ ✅ /auth/login │
|
||||
│ ✅ /auth/register │
|
||||
│ ✅ /auth/otp │
|
||||
│ ✅ /health │
|
||||
│ │
|
||||
├─────────────────────────────────────────────────────────────┤
|
||||
│ │
|
||||
│ ADMIN ROUTES (Work for Admins Only) │
|
||||
│ ✅ /admin/* │
|
||||
│ ✅ /api/admin/* │
|
||||
│ │
|
||||
├─────────────────────────────────────────────────────────────┤
|
||||
│ │
|
||||
│ MAIN APP ROUTES (BLOCKED - Shows Maintenance) │
|
||||
│ ❌ / │
|
||||
│ ❌ /wallets │
|
||||
│ ❌ /transactions │
|
||||
│ ❌ /api/users/me │
|
||||
│ ❌ /api/wallets │
|
||||
│ ❌ /api/transactions │
|
||||
│ │
|
||||
│ 👉 All show: MAINTENANCE PAGE │
|
||||
│ │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## **🔍 Code Flow in App.tsx**
|
||||
|
||||
```typescript
|
||||
export default function App() {
|
||||
const [maintenanceMode, setMaintenanceMode] = useState(false)
|
||||
const [maintenanceMessage, setMaintenanceMessage] = useState('')
|
||||
|
||||
useEffect(() => {
|
||||
// Setup interceptor on app load
|
||||
setupAxiosInterceptors((message) => {
|
||||
setMaintenanceMessage(message)
|
||||
setMaintenanceMode(true) // 👈 This triggers maintenance page
|
||||
})
|
||||
}, [])
|
||||
|
||||
// 👇 When maintenance mode is true, show maintenance page
|
||||
if (maintenanceMode) {
|
||||
return (
|
||||
<ThemeProvider>
|
||||
<MaintenancePage message={maintenanceMessage} />
|
||||
</ThemeProvider>
|
||||
)
|
||||
}
|
||||
|
||||
// 👇 Otherwise, show normal app
|
||||
return (
|
||||
<BrowserRouter>
|
||||
<ThemeProvider>
|
||||
<LanguageProvider>
|
||||
<AuthProvider>
|
||||
<Routes>
|
||||
{/* All routes here */}
|
||||
</Routes>
|
||||
</AuthProvider>
|
||||
</LanguageProvider>
|
||||
</ThemeProvider>
|
||||
</BrowserRouter>
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## **🎯 Key Points**
|
||||
|
||||
### **1. Maintenance Page is NOT a Route**
|
||||
- It's not `/maintenance` or any URL
|
||||
- It's a **state-based replacement** of the entire app
|
||||
- When `maintenanceMode` state is `true`, it replaces everything
|
||||
|
||||
### **2. Trigger is API Response**
|
||||
- Maintenance page appears when **any API call returns 503**
|
||||
- The axios interceptor catches this and sets state
|
||||
- This can happen on:
|
||||
- Initial page load (GET /api/users/me)
|
||||
- Any user action (creating transaction, loading wallets, etc.)
|
||||
- Navigation between pages
|
||||
|
||||
### **3. Admin Panel is Separate**
|
||||
- Admin routes (`/admin/*`) have `@SkipMaintenance`
|
||||
- API calls to `/api/admin/*` bypass the guard
|
||||
- Admins can still manage the system
|
||||
- But if admin tries to access main app (`/`), they also see maintenance
|
||||
|
||||
### **4. Login Always Works**
|
||||
- `/auth/login` has `@SkipMaintenance`
|
||||
- Users can still login during maintenance
|
||||
- But after login, they immediately see maintenance page
|
||||
|
||||
---
|
||||
|
||||
## **📝 Summary**
|
||||
|
||||
**Where does maintenance page appear?**
|
||||
- ✅ After any API call that returns 503
|
||||
- ✅ For regular users trying to access protected routes
|
||||
- ✅ Even for admins trying to access main app (not admin panel)
|
||||
- ✅ Replaces the entire app UI (not a specific route)
|
||||
|
||||
**Where does it NOT appear?**
|
||||
- ❌ On login/register pages (before API calls)
|
||||
- ❌ On admin panel routes (for admins)
|
||||
- ❌ On health check endpoints
|
||||
|
||||
**How to see it?**
|
||||
1. Enable maintenance mode as admin
|
||||
2. Login as regular user (or stay logged in)
|
||||
3. Try to access any page or make any action
|
||||
4. Maintenance page will appear immediately
|
||||
Reference in New Issue
Block a user