fix(auth): guard stale submissions and rework form error mapping (#2358)

This commit is contained in:
Hampus authored and GitHub committed 2026-09-02 17:26:18 +02:00
1 parent f703969e80
commit 25f4332b9e
43 files changed
+739 -683

No files matched your search

@@ -83,7 +83,7 @@ const EmailRevertPage = observer(function EmailRevertPage() {
label={i18n._(NEW_PASSWORD_DESCRIPTOR)}
value={form.getValue('password')}
onChange={(value) => form.setValue('password', value)}
error={form.getError('password') || fieldErrors?.password}
error={form.getError('password') || fieldErrors?.get('password')}
data-flx="auth.email-revert-page.form-field.set-value.password"
/>
<FormField
@@ -29,13 +29,19 @@ const ForgotPasswordPage = observer(function ForgotPasswordPage() {
useFluxerDocumentTitle(i18n._(FORGOT_PASSWORD_DESCRIPTOR));
const form = useForm({
initialValues: {email: ''},
onSubmit: async (values) => {
onSubmit: async (submission) => {
setError(null);
try {
await AuthenticationCommands.forgotPassword(values.email);
await AuthenticationCommands.forgotPassword(submission.getValue('email'));
if (!submission.isCurrent()) {
return;
}
setIsSuccess(true);
} catch (_err) {
form.setErrors({email: 'Failed to send reset link. Try again.'});
} catch {
if (!submission.isCurrent()) {
return;
}
form.setError('email', 'Failed to send reset link. Try again.');
}
},
});
@@ -32,6 +32,24 @@ const CONFIRM_NEW_PASSWORD_DESCRIPTOR = msg({
type TokenStatus = 'validating' | 'valid' | 'invalid';
const API_RENDERED_FIELDS = new Set(['password']);
function resolveBannerError(
error: string | null,
fieldErrors: ReadonlyMap<string, string> | null | undefined,
): string | null {
if (error != null) {
return error;
}
if (fieldErrors == null) {
return null;
}
for (const [fieldName, message] of fieldErrors) {
if (!API_RENDERED_FIELDS.has(fieldName)) {
return message;
}
}
return null;
}
const ResetPasswordPage = observer(function ResetPasswordPage() {
const {i18n} = useLingui();
const passwordId = useId();
@@ -86,12 +104,7 @@ const ResetPasswordPage = observer(function ResetPasswordPage() {
cancelled = true;
};
}, [token]);
const unrenderedFieldErrors = fieldErrors
? Object.entries(fieldErrors)
.filter(([field]) => !API_RENDERED_FIELDS.has(field))
.map(([, message]) => message)
: [];
const bannerError = error ?? unrenderedFieldErrors[0] ?? null;
const bannerError = resolveBannerError(error, fieldErrors);
if (tokenStatus === 'validating') {
return (
<>
@@ -144,7 +157,7 @@ const ResetPasswordPage = observer(function ResetPasswordPage() {
label={i18n._(NEW_PASSWORD_DESCRIPTOR)}
value={form.getValue('password')}
onChange={(value) => form.setValue('password', value)}
error={form.getError('password') || fieldErrors?.password}
error={form.getError('password') || fieldErrors?.get('password')}
data-flx="auth.reset-password-page.form-field.set-value.password"
/>
<FormField