diff --git a/web/frontend/app/features/auth/components/AuthErrorAlert.tsx b/web/frontend/app/features/auth/components/AuthErrorAlert.tsx index 4892d919..98f2b77d 100644 --- a/web/frontend/app/features/auth/components/AuthErrorAlert.tsx +++ b/web/frontend/app/features/auth/components/AuthErrorAlert.tsx @@ -1,10 +1,20 @@ interface AuthErrorAlertProps { message: string; + /** Per-field messages to list beneath the summary. */ + details?: readonly string[]; } -const AuthErrorAlert = ({ message }: AuthErrorAlertProps) => ( -
+const AuthErrorAlert = ({ message, details }: AuthErrorAlertProps) => ( +
{message} + + {details?.length ? ( + + ) : null}
); diff --git a/web/frontend/app/features/auth/routes/register.tsx b/web/frontend/app/features/auth/routes/register.tsx index fd6492b7..73cec5bd 100644 --- a/web/frontend/app/features/auth/routes/register.tsx +++ b/web/frontend/app/features/auth/routes/register.tsx @@ -51,6 +51,12 @@ const Register = ({ actionData }: Route.ComponentProps) => { submit(data, { method: 'post' }); }); + // A request that reached the action without passing client validation, so the + // rejected fields may well sit on a step other than the one on screen. + const rejectedFields = Object.values(actionData?.fieldErrors ?? {}).flatMap( + (messages) => messages ?? [], + ); + useActionErrorToast(actionData?.error); return ( @@ -68,6 +74,13 @@ const Register = ({ actionData }: Route.ComponentProps) => { {actionData?.error && } + {rejectedFields.length > 0 && ( + + )} +