Files
keycloak_theme/src/login/pages/Register.tsx
Joseph Garrone 7c257d97a7 #577
2024-07-04 19:53:57 +02:00

135 lines
5.7 KiB
TypeScript

import { useState } from "react";
import type { LazyOrNot } from "keycloakify/tools/LazyOrNot";
import { getKcClsx, type KcClsx } from "keycloakify/login/lib/kcClsx";
import type { UserProfileFormFieldsProps } from "keycloakify/login/UserProfileFormFieldsProps";
import type { PageProps } from "keycloakify/login/pages/PageProps";
import type { KcContext } from "../KcContext";
import type { I18n } from "../i18n";
type RegisterProps = PageProps<Extract<KcContext, { pageId: "register.ftl" }>, I18n> & {
UserProfileFormFields: LazyOrNot<(props: UserProfileFormFieldsProps) => JSX.Element>;
doMakeUserConfirmPassword: boolean;
};
export default function Register(props: RegisterProps) {
const { kcContext, i18n, doUseDefaultCss, Template, classes, UserProfileFormFields, doMakeUserConfirmPassword } = props;
const { kcClsx } = getKcClsx({
doUseDefaultCss,
classes
});
const { url, messagesPerField, recaptchaRequired, recaptchaSiteKey, termsAcceptanceRequired } = kcContext;
const { msg, msgStr } = i18n;
const [isFormSubmittable, setIsFormSubmittable] = useState(false);
const [areTermsAccepted, setAreTermsAccepted] = useState(false);
return (
<Template
kcContext={kcContext}
i18n={i18n}
doUseDefaultCss={doUseDefaultCss}
classes={classes}
headerNode={msg("registerTitle")}
displayMessage={messagesPerField.exists("global")}
displayRequiredFields
>
<form id="kc-register-form" className={kcClsx("kcFormClass")} action={url.registrationAction} method="post">
<UserProfileFormFields
kcContext={kcContext}
i18n={i18n}
kcClsx={kcClsx}
onIsFormSubmittableValueChange={setIsFormSubmittable}
doMakeUserConfirmPassword={doMakeUserConfirmPassword}
/>
{termsAcceptanceRequired && (
<TermsAcceptance
i18n={i18n}
kcClsx={kcClsx}
messagesPerField={messagesPerField}
areTermsAccepted={areTermsAccepted}
onAreTermsAcceptedValueChange={setAreTermsAccepted}
/>
)}
{recaptchaRequired && (
<div className="form-group">
<div className={kcClsx("kcInputWrapperClass")}>
<div className="g-recaptcha" data-size="compact" data-sitekey={recaptchaSiteKey}></div>
</div>
</div>
)}
<div className={kcClsx("kcFormGroupClass")}>
<div id="kc-form-options" className={kcClsx("kcFormOptionsClass")}>
<div className={kcClsx("kcFormOptionsWrapperClass")}>
<span>
<a href={url.loginUrl}>{msg("backToLogin")}</a>
</span>
</div>
</div>
<div id="kc-form-buttons" className={kcClsx("kcFormButtonsClass")}>
<input
disabled={!isFormSubmittable || (termsAcceptanceRequired && !areTermsAccepted)}
className={kcClsx("kcButtonClass", "kcButtonPrimaryClass", "kcButtonBlockClass", "kcButtonLargeClass")}
type="submit"
value={msgStr("doRegister")}
/>
</div>
</div>
</form>
</Template>
);
}
function TermsAcceptance(props: {
i18n: I18n;
kcClsx: KcClsx;
messagesPerField: Pick<KcContext["messagesPerField"], "existsError" | "get">;
areTermsAccepted: boolean;
onAreTermsAcceptedValueChange: (areTermsAccepted: boolean) => void;
}) {
const { i18n, kcClsx, messagesPerField, areTermsAccepted, onAreTermsAcceptedValueChange } = props;
const { msg } = i18n;
return (
<>
<div className="form-group">
<div className={kcClsx("kcInputWrapperClass")}>
{msg("termsTitle")}
<div id="kc-registration-terms-text">{msg("termsText")}</div>
</div>
</div>
<div className="form-group">
<div className={kcClsx("kcLabelWrapperClass")}>
<input
type="checkbox"
id="termsAccepted"
name="termsAccepted"
className={kcClsx("kcCheckboxInputClass")}
checked={areTermsAccepted}
onChange={e => onAreTermsAcceptedValueChange(e.target.checked)}
aria-invalid={messagesPerField.existsError("termsAccepted")}
/>
<label htmlFor="termsAccepted" className={kcClsx("kcLabelClass")}>
{msg("acceptTerms")}
</label>
</div>
{messagesPerField.existsError("termsAccepted") && (
<div className={kcClsx("kcLabelWrapperClass")}>
<span
id="input-error-terms-accepted"
className={kcClsx("kcInputErrorMessageClass")}
aria-live="polite"
dangerouslySetInnerHTML={{
__html: messagesPerField.get("termsAccepted")
}}
/>
</div>
)}
</div>
</>
);
}