- 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
3.9 KiB
3.9 KiB
✅ 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:
// 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:
<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:
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:
- Disable TOTP → QR code and secret cleared
- Enable TOTP again → Fresh QR code generated
- QR code displays properly ✅
📝 Files Modified:
1. apps/web/src/components/pages/OtpVerification.tsx
- Added
useStatefor resend timer and loading states - Added
useEffectfor countdown timer - Added
handleResendEmail()function - Added resend button with timer in email OTP tab
- Imported
RefreshCwicon andaxios
2. apps/web/src/components/pages/Profile.tsx
- Updated
handleTotpDisable()to clear QR code state - Clears
totpSecretandtotpQrCodewhen disabling
🧪 Testing:
Test Email OTP Resend:
- ✅ Login with email/password (has email OTP enabled)
- ✅ On OTP page, see "Resend in 30s" button (disabled)
- ✅ Wait for countdown
- ✅ After 30s, button shows "Resend Code" (enabled)
- ✅ Click button → New OTP sent
- ✅ Timer resets to 30s
- ✅ Check console for new OTP code
Test TOTP QR Code:
- ✅ Go to Profile page
- ✅ Setup Google Authenticator → QR code displays
- ✅ Verify and enable TOTP
- ✅ Disable TOTP
- ✅ 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:
- Countdown (0-29s): "Resend in Xs" - Disabled, gray
- Ready (30s+): "Resend Code" - Enabled, clickable
- Sending: "Sending..." - Disabled, loading spinner
- 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! 🚀