diff --git a/dashboard/app/(auth)/register/RegisterContent.tsx b/dashboard/app/(auth)/register/RegisterContent.tsx index 16591f6..43a3c7e 100644 --- a/dashboard/app/(auth)/register/RegisterContent.tsx +++ b/dashboard/app/(auth)/register/RegisterContent.tsx @@ -22,7 +22,7 @@ import { translations } from '@i18n/translations' import { WeChatIcon } from '../../components/icons/WeChatIcon' -type AlertState = { type: 'error' | 'success'; message: string } +type AlertState = { type: 'error' | 'success' | 'info'; message: string } const VERIFICATION_CODE_LENGTH = 6 const RESEND_COOLDOWN_SECONDS = 60 @@ -279,6 +279,10 @@ export default function RegisterContent() { setAlert({ type: 'error', message }) } + const showStatus = (message: string) => { + setAlert({ type: 'info', message }) + } + if (!hasRequestedCode) { if (!emailInput || !EMAIL_PATTERN.test(emailInput)) { showError(alerts.invalidEmail) @@ -306,7 +310,11 @@ export default function RegisterContent() { } setIsSubmitting(true) - setAlert(null) + showStatus( + t.form.validation?.submitting ?? + t.form.submitting ?? + 'Submitting registration request…', + ) try { const response = await fetch('/api/auth/register/send', { @@ -351,9 +359,6 @@ export default function RegisterContent() { const successMessage = alerts.verificationSent ?? alerts.genericError setAlert({ type: 'success', message: successMessage }) - if (typeof window !== 'undefined') { - window.alert(successMessage) - } } catch (error) { console.error('Failed to request verification code', error) showError(alerts.genericError) @@ -376,7 +381,12 @@ export default function RegisterContent() { } setIsSubmitting(true) - setAlert(null) + showStatus( + t.form.validation?.verifying ?? + t.form.verifying ?? + t.form.verifySubmit ?? + t.form.submit, + ) try { const response = await fetch('/api/auth/register/verify', { @@ -401,7 +411,8 @@ export default function RegisterContent() { const errorMap: Record = { invalid_request: alerts.genericError, missing_verification: alerts.codeRequired ?? alerts.missingFields, - invalid_code: alerts.invalidCode ?? alerts.genericError, + invalid_code: + alerts.verificationFailed ?? alerts.invalidCode ?? alerts.genericError, verification_failed: alerts.verificationFailed ?? alerts.genericError, account_service_unreachable: alerts.genericError, } @@ -414,9 +425,6 @@ export default function RegisterContent() { setIsVerified(true) const successMessage = alerts.verificationReady ?? alerts.success setAlert({ type: 'success', message: successMessage }) - if (typeof window !== 'undefined') { - window.alert(successMessage) - } } catch (error) { console.error('Failed to verify email', error) showError(alerts.genericError) @@ -437,7 +445,12 @@ export default function RegisterContent() { } setIsSubmitting(true) - setAlert(null) + showStatus( + t.form.validation?.completing ?? + t.form.completing ?? + t.form.completeSubmit ?? + t.form.submit, + ) try { const registerResponse = await fetch('/api/auth/register', { @@ -476,7 +489,8 @@ export default function RegisterContent() { user_creation_failed: alerts.genericError, credentials_in_query: alerts.genericError, verification_required: alerts.codeRequired ?? alerts.genericError, - invalid_code: alerts.invalidCode ?? alerts.genericError, + invalid_code: + alerts.verificationFailed ?? alerts.invalidCode ?? alerts.genericError, account_service_unreachable: alerts.genericError, } @@ -528,9 +542,6 @@ export default function RegisterContent() { const successMessage = alerts.registrationComplete ?? alerts.success setAlert({ type: 'success', message: successMessage }) - if (typeof window !== 'undefined') { - window.alert(successMessage) - } router.push(loginData?.redirectTo || '/') router.refresh() @@ -553,6 +564,7 @@ export default function RegisterContent() { pendingPassword, resetCodeDigits, router, + t.form, ], ) @@ -573,6 +585,10 @@ export default function RegisterContent() { const emailFromForm = emailFromFormRaw.trim() setIsResending(true) + const resendStatusMessage = + t.form.verificationCodeResending ?? + (t.form.verificationCodeResend ? `${t.form.verificationCodeResend}…` : 'Resending verification code…') + setAlert({ type: 'info', message: resendStatusMessage }) try { const response = await fetch('/api/auth/register/send', { @@ -616,16 +632,24 @@ export default function RegisterContent() { setResendCooldown(RESEND_COOLDOWN_SECONDS) const message = alerts.verificationResent ?? alerts.verificationSent ?? 'Verification code resent.' setAlert({ type: 'success', message }) - if (typeof window !== 'undefined') { - window.alert(message) - } setIsResending(false) } catch (error) { console.error('Failed to resend verification code', error) setAlert({ type: 'error', message: alerts.genericError }) setIsResending(false) } - }, [alerts, focusCodeInput, isResending, isVerified, normalize, pendingEmail, resetCodeDigits, resendCooldown]) + }, [ + alerts, + focusCodeInput, + isResending, + isVerified, + normalize, + pendingEmail, + resetCodeDigits, + resendCooldown, + t.form.verificationCodeResend, + t.form.verificationCodeResending, + ]) const aboveForm = t.uuidNote ? (
diff --git a/dashboard/components/auth/AuthLayout.tsx b/dashboard/components/auth/AuthLayout.tsx index f58374b..9442caa 100644 --- a/dashboard/components/auth/AuthLayout.tsx +++ b/dashboard/components/auth/AuthLayout.tsx @@ -18,12 +18,14 @@ export type AuthLayoutSocialButton = { onClick?: (event: MouseEvent) => void } +type AlertType = 'error' | 'success' | 'info' + type AuthLayoutProps = { mode: 'login' | 'register' badge?: string title: string description?: string - alert?: { type: 'error' | 'success'; message: string } | null + alert?: { type: AlertType; message: string } | null socialHeading?: string socialButtons?: AuthLayoutSocialButton[] aboveForm?: ReactNode @@ -134,8 +136,12 @@ export function AuthLayout({ 'rounded-2xl border px-4 py-3 text-sm font-medium', alert.type === 'error' ? 'border-red-200 bg-red-50 text-red-700' - : 'border-emerald-200 bg-emerald-50 text-emerald-700', + : alert.type === 'success' + ? 'border-emerald-200 bg-emerald-50 text-emerald-700' + : 'border-sky-200 bg-sky-50 text-sky-700', )} + role="status" + aria-live="polite" > {alert.message}