diff --git a/src/login/UserProfileFormFields.tsx b/src/login/UserProfileFormFields.tsx index df1a5fc8..846cfb32 100644 --- a/src/login/UserProfileFormFields.tsx +++ b/src/login/UserProfileFormFields.tsx @@ -338,7 +338,6 @@ function InputTag(props: InputFiledByTypeProps & { fieldIndex: number | undefine max={attribute.annotations.inputTypeMax} min={attribute.annotations.inputTypeMin} step={attribute.annotations.inputTypeStep} - // NOTE: The `?? {}` is for backward compatibility with Keycloak prior to 24 {...Object.fromEntries(Object.entries(attribute.html5DataAnnotations ?? {}).map(([key, value]) => [`data-${key}`, value]))} onChange={event => formValidationDispatch({ diff --git a/src/login/kcContext/KcContext.ts b/src/login/kcContext/KcContext.ts index 98b1055b..7950c189 100644 --- a/src/login/kcContext/KcContext.ts +++ b/src/login/kcContext/KcContext.ts @@ -175,11 +175,7 @@ export declare namespace KcContext { export type Register = Common & { pageId: "register.ftl" | "register-user-profile.ftl"; - profile: { - attributes: Attribute[]; - attributesByName: Record; - html5DataAnnotations?: Record; - }; + profile: UserProfile; url: { registrationAction: string; }; @@ -423,39 +419,17 @@ export declare namespace KcContext { export type LoginUpdateProfile = Common & { pageId: "login-update-profile.ftl" | "update-user-profile.ftl"; - profile: { - attributes: Attribute[]; - attributesByName: Record; - }; + profile: UserProfile; }; - /* - export type LoginUpdateProfile = Common & { - pageId: "login-update-profile.ftl"; - user: { - editUsernameAllowed: boolean; - username?: string; - email?: string; - firstName?: string; - lastName?: string; - }; - }; - */ - export type IdpReviewUserProfile = Common & { pageId: "idp-review-user-profile.ftl"; - profile: { - context: "IDP_REVIEW"; - attributes: Attribute[]; - attributesByName: Record; - }; + profile: UserProfile; }; export type UpdateEmail = Common & { pageId: "update-email.ftl"; - email: { - value?: string; - }; + profile: UserProfile; }; export type SelectAuthenticator = Common & { @@ -497,6 +471,12 @@ export declare namespace KcContext { }; } +export type UserProfile = { + attributes: Attribute[]; + attributesByName: Record; + html5DataAnnotations?: Record; +}; + export type Attribute = { name: string; displayName?: string; diff --git a/src/login/lib/useUserProfileForm.tsx b/src/login/lib/useUserProfileForm.tsx index cb43e6da..bd0c7ffe 100644 --- a/src/login/lib/useUserProfileForm.tsx +++ b/src/login/lib/useUserProfileForm.tsx @@ -151,7 +151,7 @@ export function useUserProfileForm(params: ParamsOfUseUserProfileForm): ReturnTy "name": name, "displayName": id<`\${${MessageKey}}`>(`\${${name}}`), "required": true, - "value": (kcContext as any).register.formData[name] ?? "", + "value": (kcContext.register as any).formData[name] ?? "", "html5DataAnnotations": {}, "readOnly": false, "validators": {}, @@ -173,7 +173,7 @@ export function useUserProfileForm(params: ParamsOfUseUserProfileForm): ReturnTy if ("user" in kcContext && kcContext.user instanceof Object) { //NOTE: Handle legacy login-update-profile.ftl return (["username", "email", "firstName", "lastName"] as const) - .filter(name => (name !== "username" ? true : (kcContext as any).user.editUsernameAllowed)) + .filter(name => (name !== "username" ? true : (kcContext.user as any).editUsernameAllowed)) .map(name => id({ "name": name, @@ -198,6 +198,23 @@ export function useUserProfileForm(params: ParamsOfUseUserProfileForm): ReturnTy ); } + if ("email" in kcContext && kcContext.email instanceof Object) { + //NOTE: Handle legacy update-email.ftl + return [ + id({ + "name": "email", + "displayName": id<`\${${MessageKey}}`>(`\${email}`), + "required": true, + "value": (kcContext.email as any).value ?? "", + "html5DataAnnotations": {}, + "readOnly": false, + "validators": {}, + "annotations": {}, + "autocomplete": "email" + }) + ]; + } + assert(false, "Unable to mock user profile from the current kcContext"); } diff --git a/src/login/pages/UpdateEmail.tsx b/src/login/pages/UpdateEmail.tsx index be669b21..2a28cd2c 100644 --- a/src/login/pages/UpdateEmail.tsx +++ b/src/login/pages/UpdateEmail.tsx @@ -1,11 +1,18 @@ +import { useState } from "react"; import { clsx } from "keycloakify/tools/clsx"; +import type { LazyOrNot } from "keycloakify/tools/LazyOrNot"; +import type { UserProfileFormFieldsProps } from "keycloakify/login/UserProfileFormFields"; import type { PageProps } from "keycloakify/login/pages/PageProps"; import { useGetClassName } from "keycloakify/login/lib/useGetClassName"; import type { KcContext } from "../kcContext"; import type { I18n } from "../i18n"; -export default function UpdateEmail(props: PageProps, I18n>) { - const { kcContext, i18n, doUseDefaultCss, Template, classes } = props; +type UpdateEmailProps = PageProps, I18n> & { + UserProfileFormFields: LazyOrNot<(props: UserProfileFormFieldsProps) => JSX.Element>; +}; + +export default function UpdateEmail(props: UpdateEmailProps) { + const { kcContext, i18n, doUseDefaultCss, Template, classes, UserProfileFormFields } = props; const { getClassName } = useGetClassName({ doUseDefaultCss, @@ -14,71 +21,60 @@ export default function UpdateEmail(props: PageProps +