diff --git a/src/login/Fallback.tsx b/src/login/Fallback.tsx index 80d5c12b..3e2737c2 100644 --- a/src/login/Fallback.tsx +++ b/src/login/Fallback.tsx @@ -3,10 +3,12 @@ import type { PageProps } from "keycloakify/login/pages/PageProps"; import { assert, type Equals } from "tsafe/assert"; import type { I18n } from "./i18n"; import type { KcContext } from "./kcContext"; +import type { LazyOrNot } from "keycloakify/tools/LazyOrNot"; +import type { UserProfileFormFieldsProps } from "keycloakify/login/UserProfileFormFields"; +import type { TermsAcceptanceProps } from "keycloakify/login/TermsAcceptance"; const Login = lazy(() => import("keycloakify/login/pages/Login")); const Register = lazy(() => import("keycloakify/login/pages/Register")); -const RegisterUserProfile = lazy(() => import("keycloakify/login/pages/RegisterUserProfile")); const Info = lazy(() => import("keycloakify/login/pages/Info")); const Error = lazy(() => import("keycloakify/login/pages/Error")); const LoginResetPassword = lazy(() => import("keycloakify/login/pages/LoginResetPassword")); @@ -31,7 +33,12 @@ const UpdateEmail = lazy(() => import("keycloakify/login/pages/UpdateEmail")); const SelectAuthenticator = lazy(() => import("keycloakify/login/pages/SelectAuthenticator")); const SamlPostForm = lazy(() => import("keycloakify/login/pages/SamlPostForm")); -export default function Fallback(props: PageProps) { +type FallbackProps = PageProps & { + UserProfileFormFields: LazyOrNot<(props: UserProfileFormFieldsProps) => JSX.Element>; + TermsAcceptance: LazyOrNot<(props: TermsAcceptanceProps) => JSX.Element | null>; +}; + +export default function Fallback(props: FallbackProps) { const { kcContext, ...rest } = props; return ( @@ -41,9 +48,8 @@ export default function Fallback(props: PageProps) { case "login.ftl": return ; case "register.ftl": - return ; case "register-user-profile.ftl": - return ; + return ; case "info.ftl": return ; case "error.ftl": diff --git a/src/login/TemplateProps.ts b/src/login/TemplateProps.ts index 8eb9934c..723e6313 100644 --- a/src/login/TemplateProps.ts +++ b/src/login/TemplateProps.ts @@ -27,6 +27,7 @@ export type ClassKey = | "kcInfoAreaWrapperClass" | "kcFormButtonsWrapperClass" | "kcFormOptionsWrapperClass" + | "kcCheckboxInputClass" | "kcLocaleDropDownClass" | "kcLocaleListItemClass" | "kcContentWrapperClass" diff --git a/src/login/TermsAcceptance.tsx b/src/login/TermsAcceptance.tsx index 9d39fbb5..4b417ebe 100644 --- a/src/login/TermsAcceptance.tsx +++ b/src/login/TermsAcceptance.tsx @@ -5,7 +5,7 @@ import { evtTermMarkdown } from "keycloakify/login/lib/useDownloadTerms"; import type { KcContext } from "keycloakify/login/kcContext/KcContext"; import type { I18n } from "./i18n"; -export type PropsOfTermsAcceptance = { +export type TermsAcceptanceProps = { kcContext: KcContextLike; i18n: I18n; getClassName: (classKey: ClassKey) => string; @@ -16,7 +16,7 @@ type KcContextLike = { messagesPerField: Pick; }; -export function TermsAcceptance(props: PropsOfTermsAcceptance) { +export function TermsAcceptance(props: TermsAcceptanceProps) { const { kcContext: { termsAcceptanceRequired = false } } = props; @@ -28,7 +28,7 @@ export function TermsAcceptance(props: PropsOfTermsAcceptance) { return ; } -export function TermsAcceptanceEnabled(props: PropsOfTermsAcceptance) { +export function TermsAcceptanceEnabled(props: TermsAcceptanceProps) { const { i18n, getClassName, diff --git a/src/login/pages/shared/UserProfileFormFields.tsx b/src/login/UserProfileFormFields.tsx similarity index 98% rename from src/login/pages/shared/UserProfileFormFields.tsx rename to src/login/UserProfileFormFields.tsx index 32be7f49..f9edefb9 100644 --- a/src/login/pages/shared/UserProfileFormFields.tsx +++ b/src/login/UserProfileFormFields.tsx @@ -3,8 +3,8 @@ import type { ClassKey } from "keycloakify/login/TemplateProps"; import { clsx } from "keycloakify/tools/clsx"; import { useUserProfileForm, type KcContextLike, type FormAction, type FormFieldError } from "keycloakify/login/lib/useUserProfileForm"; import type { Attribute, LegacyAttribute } from "keycloakify/login/kcContext/KcContext"; -import type { I18n } from "../../i18n"; import { assert } from "tsafe/assert"; +import type { I18n } from "./i18n"; export type UserProfileFormFieldsProps = { kcContext: KcContextLike; @@ -26,7 +26,7 @@ type BeforeAfterFieldProps = { // NOTE: Enabled by default but it's a UX best practice to set it to false. const doMakeUserConfirmPassword = true; -export function UserProfileFormFields(props: UserProfileFormFieldsProps) { +export default function UserProfileFormFields(props: UserProfileFormFieldsProps) { const { kcContext, onIsFormSubmittableValueChange, i18n, getClassName, BeforeField, AfterField } = props; const { advancedMsg } = i18n; @@ -260,7 +260,7 @@ function FieldErrors(props: { ); } -type PropsOfInputFiledByType = { +type InputFiledByTypeProps = { attribute: Attribute; valueOrValues: string | string[]; displayableErrors: FormFieldError[]; @@ -269,7 +269,7 @@ type PropsOfInputFiledByType = { i18n: I18n; }; -function InputFiledByType(props: PropsOfInputFiledByType) { +function InputFiledByType(props: InputFiledByTypeProps) { const { attribute, valueOrValues } = props; switch (attribute.annotations.inputType) { @@ -296,7 +296,7 @@ function InputFiledByType(props: PropsOfInputFiledByType) { } } -function InputTag(props: PropsOfInputFiledByType & { fieldIndex: number | undefined }) { +function InputTag(props: InputFiledByTypeProps & { fieldIndex: number | undefined }) { const { attribute, fieldIndex, getClassName, formValidationDispatch, valueOrValues, i18n, displayableErrors } = props; return ( @@ -511,7 +511,7 @@ function AddRemoveButtonsMultiValuedAttribute(props: { ); } -function InputTagSelects(props: PropsOfInputFiledByType) { +function InputTagSelects(props: InputFiledByTypeProps) { const { attribute, formValidationDispatch, getClassName, valueOrValues } = props; const { advancedMsg } = props.i18n; @@ -619,7 +619,7 @@ function InputTagSelects(props: PropsOfInputFiledByType) { ); } -function TextareaTag(props: PropsOfInputFiledByType) { +function TextareaTag(props: InputFiledByTypeProps) { const { attribute, formValidationDispatch, getClassName, displayableErrors, valueOrValues } = props; assert(typeof valueOrValues === "string"); @@ -655,7 +655,7 @@ function TextareaTag(props: PropsOfInputFiledByType) { ); } -function SelectTag(props: PropsOfInputFiledByType) { +function SelectTag(props: InputFiledByTypeProps) { const { attribute, formValidationDispatch, getClassName, displayableErrors, i18n, valueOrValues } = props; const { advancedMsg } = i18n; diff --git a/src/login/kcContext/KcContext.ts b/src/login/kcContext/KcContext.ts index c1ebbd60..1dd2e286 100644 --- a/src/login/kcContext/KcContext.ts +++ b/src/login/kcContext/KcContext.ts @@ -13,7 +13,6 @@ type ExtractAfterStartingWith = StrEnum extends export type KcContext = | KcContext.Login | KcContext.Register - | KcContext.RegisterUserProfile | KcContext.Info | KcContext.Error | KcContext.LoginResetPassword @@ -190,37 +189,23 @@ export declare namespace KcContext { */ export type Register = Common & { - pageId: "register.ftl"; + pageId: "register.ftl" | "register-user-profile.ftl"; profile: { attributes: Attribute[]; attributesByName: Record; html5DataAnnotations: Record; }; + url: { + registrationAction: string; + }; + passwordRequired: boolean; + recaptchaRequired: boolean; + recaptchaSiteKey?: string; /** * Theses values are added by: https://github.com/jcputney/keycloak-theme-additional-info-extension * A Keycloak Java extension used as dependency in Keycloakify. */ passwordPolicies?: PasswordPolicies; - url: { - registrationAction: string; - }; - passwordRequired: boolean; - recaptchaRequired: boolean; - recaptchaSiteKey?: string; - }; - - export type RegisterUserProfile = Common & { - pageId: "register-user-profile.ftl"; - profile: { - attributes: LegacyAttribute[]; - attributesByName: Record; - }; - url: { - registrationAction: string; - }; - passwordRequired: boolean; - recaptchaRequired: boolean; - recaptchaSiteKey?: string; }; export type Info = Common & { diff --git a/src/login/lib/useGetClassName.ts b/src/login/lib/useGetClassName.ts index 53926083..1bbf546b 100644 --- a/src/login/lib/useGetClassName.ts +++ b/src/login/lib/useGetClassName.ts @@ -12,6 +12,7 @@ export const { useGetClassName } = createUseClassName({ "kcLocaleDropDownClass": undefined, "kcLocaleListItemClass": undefined, "kcContentWrapperClass": undefined, + "kcCheckboxInputClass": undefined, "kcLogoIdP-facebook": "fa fa-facebook", "kcAuthenticatorOTPClass": "fa fa-mobile list-view-pf-icon-lg", diff --git a/src/login/pages/Register.tsx b/src/login/pages/Register.tsx index d3a4c3c3..a5a3d0d0 100644 --- a/src/login/pages/Register.tsx +++ b/src/login/pages/Register.tsx @@ -5,15 +5,15 @@ import { useGetClassName } from "keycloakify/login/lib/useGetClassName"; import type { KcContext } from "../kcContext"; import type { I18n } from "../i18n"; import type { LazyOrNot } from "keycloakify/tools/LazyOrNot"; -import type { PropsOfUserProfileFormFields } from "keycloakify/login/UserProfileFormFields"; -import type { PropsOfTermsAcceptance } from "../TermsAcceptance"; +import type { UserProfileFormFieldsProps } from "keycloakify/login/UserProfileFormFields"; +import type { TermsAcceptanceProps } from "../TermsAcceptance"; -type Props = PageProps, I18n> & { - UserProfileFormFields: LazyOrNot<(props: PropsOfUserProfileFormFields) => JSX.Element>; - TermsAcceptance: LazyOrNot<(props: PropsOfTermsAcceptance) => JSX.Element | null>; +export type PropsOfRegister = PageProps, I18n> & { + UserProfileFormFields: LazyOrNot<(props: UserProfileFormFieldsProps) => JSX.Element>; + TermsAcceptance: LazyOrNot<(props: TermsAcceptanceProps) => JSX.Element | null>; }; -export default function Register(props: Props) { +export default function Register(props: PropsOfRegister) { const { kcContext, i18n, doUseDefaultCss, Template, classes, UserProfileFormFields, TermsAcceptance } = props; const { getClassName } = useGetClassName({ diff --git a/src/login/pages/RegisterUserProfile.tsx b/src/login/pages/RegisterUserProfile.tsx deleted file mode 100644 index d06f3da4..00000000 --- a/src/login/pages/RegisterUserProfile.tsx +++ /dev/null @@ -1,72 +0,0 @@ -import { useState } from "react"; -import { clsx } from "keycloakify/tools/clsx"; -import { UserProfileFormFields } from "./shared/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 RegisterUserProfile(props: PageProps, I18n>) { - const { kcContext, i18n, doUseDefaultCss, Template, classes } = props; - - const { getClassName } = useGetClassName({ - doUseDefaultCss, - classes - }); - - const { url, messagesPerField, recaptchaRequired, recaptchaSiteKey, realm } = kcContext; - - realm.registrationEmailAsUsername; - - const { msg, msgStr } = i18n; - - const [isFormSubmittable, setIsFormSubmittable] = useState(false); - - return ( - - ); -} diff --git a/src/login/pages/Register_legacy.tsx b/src/login/pages/Register_legacy.tsx new file mode 100644 index 00000000..316c9bce --- /dev/null +++ b/src/login/pages/Register_legacy.tsx @@ -0,0 +1,182 @@ +import { clsx } from "keycloakify/tools/clsx"; +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 Register(props: PageProps, I18n>) { + const { kcContext, i18n, doUseDefaultCss, Template, classes } = props; + + const { getClassName } = useGetClassName({ + doUseDefaultCss, + classes + }); + + const { url, messagesPerField, register, realm, passwordRequired, recaptchaRequired, recaptchaSiteKey } = kcContext; + + const { msg, msgStr } = i18n; + + return ( + + ); +}