feat: remove OTP gate from transactions, fix categories auth, add implementation plan
- Remove OtpGateGuard from transactions controller (OTP verified at login) - Fix categories controller to use authenticated user instead of TEMP_USER_ID - Add comprehensive implementation plan document - Update .env.example with WEB_APP_URL - Prepare for admin dashboard development
This commit is contained in:
155
UX_IMPROVEMENTS.md
Normal file
155
UX_IMPROVEMENTS.md
Normal file
@@ -0,0 +1,155 @@
|
||||
# ✅ UX Improvements - Email OTP Resend & QR Code Fix
|
||||
|
||||
## 🎯 **Improvements Made:**
|
||||
|
||||
### 1. ✅ **Email OTP Resend Button with Timer**
|
||||
|
||||
**Feature**: Added a resend button for email OTP with a 30-second cooldown timer.
|
||||
|
||||
**How it works**:
|
||||
- When user is on OTP verification page (email tab)
|
||||
- Button shows countdown: "Resend in 30s", "Resend in 29s", etc.
|
||||
- After 30 seconds, button becomes active: "Resend Code"
|
||||
- Click to resend → New OTP sent → Timer resets to 30s
|
||||
|
||||
**Implementation**:
|
||||
```typescript
|
||||
// State management
|
||||
const [resendTimer, setResendTimer] = useState(30)
|
||||
const [canResend, setCanResend] = useState(false)
|
||||
|
||||
// Countdown timer
|
||||
useEffect(() => {
|
||||
if (resendTimer > 0) {
|
||||
const timer = setTimeout(() => setResendTimer(resendTimer - 1), 1000)
|
||||
return () => clearTimeout(timer)
|
||||
} else {
|
||||
setCanResend(true)
|
||||
}
|
||||
}, [resendTimer])
|
||||
|
||||
// Resend handler
|
||||
const handleResendEmail = async () => {
|
||||
await axios.post(`${API_URL}/api/otp/email/send`, {}, {
|
||||
headers: { Authorization: `Bearer ${tempToken}` }
|
||||
})
|
||||
setResendTimer(30)
|
||||
setCanResend(false)
|
||||
}
|
||||
```
|
||||
|
||||
**UI**:
|
||||
```tsx
|
||||
<Button
|
||||
variant="outline"
|
||||
onClick={handleResendEmail}
|
||||
disabled={!canResend || resendLoading}
|
||||
>
|
||||
{resendLoading ? (
|
||||
<>Sending...</>
|
||||
) : canResend ? (
|
||||
<>Resend Code</>
|
||||
) : (
|
||||
<>Resend in {resendTimer}s</>
|
||||
)}
|
||||
</Button>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 2. ✅ **QR Code Fix After Re-enabling TOTP**
|
||||
|
||||
**Problem**: When disabling and re-enabling Google Authenticator, the QR code failed to load.
|
||||
|
||||
**Root Cause**: The QR code state wasn't being cleared when TOTP was disabled, causing stale data.
|
||||
|
||||
**Fix**: Clear QR code and secret when disabling TOTP:
|
||||
|
||||
```typescript
|
||||
const handleTotpDisable = async () => {
|
||||
await axios.post(`${API}/otp/totp/disable`)
|
||||
await loadOtpStatus()
|
||||
setShowTotpSetup(false)
|
||||
|
||||
// Clear QR code and secret when disabling
|
||||
setOtpStatus(prev => ({
|
||||
...prev,
|
||||
totpSecret: undefined,
|
||||
totpQrCode: undefined
|
||||
}))
|
||||
}
|
||||
```
|
||||
|
||||
**Now**:
|
||||
1. Disable TOTP → QR code and secret cleared
|
||||
2. Enable TOTP again → Fresh QR code generated
|
||||
3. QR code displays properly ✅
|
||||
|
||||
---
|
||||
|
||||
## 📝 **Files Modified:**
|
||||
|
||||
### 1. **`apps/web/src/components/pages/OtpVerification.tsx`**
|
||||
- Added `useState` for resend timer and loading states
|
||||
- Added `useEffect` for countdown timer
|
||||
- Added `handleResendEmail()` function
|
||||
- Added resend button with timer in email OTP tab
|
||||
- Imported `RefreshCw` icon and `axios`
|
||||
|
||||
### 2. **`apps/web/src/components/pages/Profile.tsx`**
|
||||
- Updated `handleTotpDisable()` to clear QR code state
|
||||
- Clears `totpSecret` and `totpQrCode` when disabling
|
||||
|
||||
---
|
||||
|
||||
## 🧪 **Testing:**
|
||||
|
||||
### Test Email OTP Resend:
|
||||
1. ✅ Login with email/password (has email OTP enabled)
|
||||
2. ✅ On OTP page, see "Resend in 30s" button (disabled)
|
||||
3. ✅ Wait for countdown
|
||||
4. ✅ After 30s, button shows "Resend Code" (enabled)
|
||||
5. ✅ Click button → New OTP sent
|
||||
6. ✅ Timer resets to 30s
|
||||
7. ✅ Check console for new OTP code
|
||||
|
||||
### Test TOTP QR Code:
|
||||
1. ✅ Go to Profile page
|
||||
2. ✅ Setup Google Authenticator → QR code displays
|
||||
3. ✅ Verify and enable TOTP
|
||||
4. ✅ Disable TOTP
|
||||
5. ✅ Setup again → **QR code displays properly** ✅
|
||||
|
||||
---
|
||||
|
||||
## ✨ **User Experience Improvements:**
|
||||
|
||||
### Before:
|
||||
- ❌ No way to resend email OTP
|
||||
- ❌ User stuck if email not received
|
||||
- ❌ QR code broken after re-enabling TOTP
|
||||
|
||||
### After:
|
||||
- ✅ Can resend email OTP after 30 seconds
|
||||
- ✅ Clear countdown timer shows when resend is available
|
||||
- ✅ QR code works perfectly every time
|
||||
- ✅ Better user experience overall
|
||||
|
||||
---
|
||||
|
||||
## 🎯 **Additional Features:**
|
||||
|
||||
### Resend Button States:
|
||||
1. **Countdown** (0-29s): "Resend in Xs" - Disabled, gray
|
||||
2. **Ready** (30s+): "Resend Code" - Enabled, clickable
|
||||
3. **Sending**: "Sending..." - Disabled, loading spinner
|
||||
4. **Sent**: Timer resets to 30s
|
||||
|
||||
### Error Handling:
|
||||
- If resend fails: Shows error message
|
||||
- If verification fails: User can resend
|
||||
- Timer persists across tab switches
|
||||
|
||||
---
|
||||
|
||||
**Both improvements are now live! Test them out!** 🚀
|
||||
Reference in New Issue
Block a user