From 4a2700197fe65d874335b8b760120c097e753741 Mon Sep 17 00:00:00 2001 From: Martin Kanis Date: Fri, 28 Nov 2025 13:39:02 +0100 Subject: [PATCH] Reviewing the email verification field and reset action (#44466) (cherry picked from commit c4edb97e68688472e5cd58fdb30bdd193d721cd2) Signed-off-by: Pedro Igor Co-authored-by: Pedro Igor --- .../admin/messages/messages_en.properties | 8 +- js/apps/admin-ui/src/user/UserForm.tsx | 101 ++++++++++-------- 2 files changed, 60 insertions(+), 49 deletions(-) diff --git a/js/apps/admin-ui/maven-resources/theme/keycloak.v2/admin/messages/messages_en.properties b/js/apps/admin-ui/maven-resources/theme/keycloak.v2/admin/messages/messages_en.properties index 2c85833991e..4f64e43033c 100644 --- a/js/apps/admin-ui/maven-resources/theme/keycloak.v2/admin/messages/messages_en.properties +++ b/js/apps/admin-ui/maven-resources/theme/keycloak.v2/admin/messages/messages_en.properties @@ -329,8 +329,12 @@ loginScreenCustomization=Login screen customization policiesConfigType=Configure via\: exportWarningTitle=Export with caution emailVerifiedHelp=Has the user's email been verified? -emailPendingVerification=Email pending verification -emailPendingVerificationHelp=This field can only be cleared. Clearing it will invalidate the verification link. +emailPendingVerificationAlertTitle=Email pending verification +emailPendingVerificationResetAction=Click here to keep the current email. +emailPendingVerificationActionMessage=This action will remove the email pending verification for this user. +confirmEmailPendingVerificationAction=Keep current email +emailPendingVerificationUpdateError=Could not unset email pending verification. +userNotYetConfirmedNewEmail=The user has not confirmed the new email address {{email}}. duplicateFlow=Duplicate flow addExecution=Add execution noSearchResultsInstructions=Click on the search bar above to search again diff --git a/js/apps/admin-ui/src/user/UserForm.tsx b/js/apps/admin-ui/src/user/UserForm.tsx index 39abb95d1c6..0f9ec34911e 100644 --- a/js/apps/admin-ui/src/user/UserForm.tsx +++ b/js/apps/admin-ui/src/user/UserForm.tsx @@ -1,6 +1,9 @@ import type GroupRepresentation from "@keycloak/keycloak-admin-client/lib/defs/groupRepresentation"; import type RealmRepresentation from "@keycloak/keycloak-admin-client/lib/defs/realmRepresentation"; -import { UserProfileMetadata } from "@keycloak/keycloak-admin-client/lib/defs/userProfileMetadata"; +import { + UserProfileAttributeMetadata, + UserProfileMetadata, +} from "@keycloak/keycloak-admin-client/lib/defs/userProfileMetadata"; import type UserRepresentation from "@keycloak/keycloak-admin-client/lib/defs/userRepresentation"; import { FormErrorText, @@ -8,9 +11,10 @@ import { SwitchControl, TextControl, UserProfileFields, - beerify, + ContinueCancelModal, } from "@keycloak/keycloak-ui-shared"; import { + Alert, AlertVariant, Button, Chip, @@ -22,7 +26,7 @@ import { TextInput, } from "@patternfly/react-core"; import { TFunction } from "i18next"; -import { useCallback, useEffect, useState } from "react"; +import { useEffect, useState } from "react"; import { Controller, FormProvider, UseFormReturn } from "react-hook-form"; import { useTranslation } from "react-i18next"; import { useAdminClient } from "../admin-client"; @@ -151,45 +155,32 @@ export const UserForm = ({ ?.map((a) => a.readOnly) .reduce((p, c) => p && c, true); - const validateAndSave = useCallback( - (formData: UserFormFields) => { - const originalEmailPendingValue = - user?.attributes?.["kc.email.pending"]?.[0]; - - if ( - formData.attributes && - !Array.isArray(formData.attributes) && - originalEmailPendingValue - ) { - const emailPendingValue = ( - formData.attributes as Record - )[beerify("kc.email.pending")]; - const currentValue = Array.isArray(emailPendingValue) - ? emailPendingValue[0] - : emailPendingValue; - - if (currentValue === "") { - // Field was cleared - keep as empty string to clear the value - (formData.attributes as Record)[ - beerify("kc.email.pending") - ] = ""; - } else if (currentValue && currentValue !== originalEmailPendingValue) { - // Field was modified (not cleared) - revert to original value - (formData.attributes as Record)[ - beerify("kc.email.pending") - ] = originalEmailPendingValue; - } + const handleEmailVerificationReset = async () => { + try { + save( + toUserFormFields({ + ...user, + requiredActions: user?.requiredActions?.filter( + (action) => action !== "UPDATE_EMAIL", + ), + attributes: { + ...user?.attributes, + "kc.email.pending": "", + }, + }), + ); + if (refresh) { + refresh(); } - - save(formData); - }, - [save, user], - ); + } catch (error) { + addError("emailPendingVerificationUpdateError", error); + } + }; return ( + {user?.attributes?.["kc.email.pending"] && ( + + {t("userNotYetConfirmedNewEmail", { + email: user.attributes!["kc.email.pending"], + })} + + {t("emailPendingVerificationActionMessage")} + + + )} - attr.name === "kc.email.pending" - ? { - ...attr, - annotations: { - ...attr.annotations, - inputHelperTextBefore: "emailPendingVerificationHelp", - }, - } - : attr, + attributes: userProfileMetadata.attributes?.filter( + (attribute: UserProfileAttributeMetadata) => { + return attribute.name !== "kc.email.pending"; + }, ), }} hideReadOnly={!user}