import { useEffect, Fragment } from "react"; import type { ClassKey } from "keycloakify/login/TemplateProps"; import { clsx } from "keycloakify/tools/clsx"; import { useProfileAttributeForm, type KcContextLike } from "keycloakify/login/lib/useProfileAttributeForm"; import type { Attribute, LegacyAttribute } from "keycloakify/login/kcContext/KcContext"; import type { I18n } from "../../i18n"; import { assert } from "tsafe/assert"; export type UserProfileFormFieldsProps = { kcContext: KcContextLike; i18n: I18n; getClassName: (classKey: ClassKey) => string; onIsFormSubmittableValueChange: (isFormSubmittable: boolean) => void; BeforeField?: (props: { attribute: Attribute }) => JSX.Element | null; AfterField?: (props: { attribute: Attribute }) => JSX.Element | null; }; export function UserProfileFormFields(props: UserProfileFormFieldsProps) { const { kcContext, onIsFormSubmittableValueChange, i18n, getClassName, BeforeField, AfterField } = props; const { advancedMsg, msg } = i18n; const { formValidationState: { fieldStateByAttributeName, isFormSubmittable }, formValidationDispatch, attributesWithPassword } = useProfileAttributeForm({ kcContext, i18n // NOTE: Uncomment the following line if you don't want for force the user to enter the password twice. //"requirePasswordConfirmation": false }); useEffect(() => { onIsFormSubmittableValueChange(isFormSubmittable); }, [isFormSubmittable]); let currentGroupName = ""; return ( <> {attributesWithPassword.map((attribute, i) => { const { displayableErrors, value } = fieldStateByAttributeName[attribute.name]; const formGroupClassName = clsx( getClassName("kcFormGroupClass"), displayableErrors.length !== 0 && getClassName("kcFormGroupErrorClass") ); return ( {(() => { keycloak_prior_to_24: { if (attribute.html5DataAnnotations !== undefined) { break keycloak_prior_to_24; } const { group = "", groupDisplayHeader = "", groupDisplayDescription = "" } = attribute as any as LegacyAttribute; return ( group !== currentGroupName && (currentGroupName = group) !== "" && (
{groupDisplayDescription !== "" && (
)}
) ); } if (attribute.group?.name !== currentGroupName) { currentGroupName = attribute.group?.name ?? ""; if (currentGroupName !== "") { assert(attribute.group !== undefined); return (
[`data-${key}`, value]) )} > {(() => { const groupDisplayHeader = attribute.group.displayHeader ?? ""; const groupHeaderText = groupDisplayHeader !== "" ? advancedMsg(groupDisplayHeader) : attribute.group.name; return (
); })()} {(() => { const groupDisplayDescription = attribute.group.displayDescription ?? ""; if (groupDisplayDescription !== "") { const groupDescriptionText = advancedMsg(groupDisplayDescription); return (
); } return null; })()}
); } } return null; })()} {BeforeField && }
{attribute.required && <>*}
{(() => { const { options } = attribute.validators; if (options !== undefined) { return ( ); } return ( { switch (attribute.name) { case "password-confirm": case "password": return "password"; default: return "text"; } })()} id={attribute.name} name={attribute.name} value={value} onChange={event => formValidationDispatch({ "action": "update value", "name": attribute.name, "newValue": event.target.value }) } onBlur={() => formValidationDispatch({ "action": "focus lost", "name": attribute.name }) } className={getClassName("kcInputClass")} aria-invalid={displayableErrors.length !== 0} disabled={attribute.readOnly} autoComplete={attribute.autocomplete} /> ); })()} {displayableErrors.length !== 0 && (() => { const divId = `input-error-${attribute.name}`; return ( <> {displayableErrors.map(({ errorMessage }) => errorMessage)} ); })()}
{AfterField && }
); })} ); }