- 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
156 lines
3.9 KiB
Markdown
156 lines
3.9 KiB
Markdown
# ✅ 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!** 🚀
|