Better prettier params (changelog ignore)

This commit is contained in:
garronej
2021-10-12 00:26:29 +02:00
parent ef5b01956a
commit e3df4b83eb
55 changed files with 5103 additions and 10397 deletions

View File

@ -4,31 +4,29 @@ import type { KcProps } from "./KcProps";
import type { KcContextBase } from "../getKcContext/KcContextBase";
import { useKcMessage } from "../i18n/useKcMessage";
export const Error = memo(
({ kcContext, ...props }: { kcContext: KcContextBase.Error } & KcProps) => {
const { msg } = useKcMessage();
export const Error = memo(({ kcContext, ...props }: { kcContext: KcContextBase.Error } & KcProps) => {
const { msg } = useKcMessage();
const { message, client } = kcContext;
const { message, client } = kcContext;
return (
<Template
{...{ kcContext, ...props }}
doFetchDefaultThemeResources={true}
displayMessage={false}
headerNode={msg("errorTitle")}
formNode={
<div id="kc-error-message">
<p className="instruction">{message.summary}</p>
{client !== undefined && client.baseUrl !== undefined && (
<p>
<a id="backToApplication" href={client.baseUrl}>
{msg("backToApplication")}
</a>
</p>
)}
</div>
}
/>
);
},
);
return (
<Template
{...{ kcContext, ...props }}
doFetchDefaultThemeResources={true}
displayMessage={false}
headerNode={msg("errorTitle")}
formNode={
<div id="kc-error-message">
<p className="instruction">{message.summary}</p>
{client !== undefined && client.baseUrl !== undefined && (
<p>
<a id="backToApplication" href={client.baseUrl}>
{msg("backToApplication")}
</a>
</p>
)}
</div>
}
/>
);
});

View File

@ -5,75 +5,45 @@ import { assert } from "../tools/assert";
import type { KcContextBase } from "../getKcContext/KcContextBase";
import { useKcMessage } from "../i18n/useKcMessage";
export const Info = memo(
({ kcContext, ...props }: { kcContext: KcContextBase.Info } & KcProps) => {
const { msg } = useKcMessage();
export const Info = memo(({ kcContext, ...props }: { kcContext: KcContextBase.Info } & KcProps) => {
const { msg } = useKcMessage();
assert(kcContext.message !== undefined);
assert(kcContext.message !== undefined);
const {
messageHeader,
message,
requiredActions,
skipLink,
pageRedirectUri,
actionUri,
client,
} = kcContext;
const { messageHeader, message, requiredActions, skipLink, pageRedirectUri, actionUri, client } = kcContext;
return (
<Template
{...{ kcContext, ...props }}
doFetchDefaultThemeResources={true}
displayMessage={false}
headerNode={
messageHeader !== undefined ? (
<>{messageHeader}</>
) : (
<>{message.summary}</>
)
}
formNode={
<div id="kc-info-message">
<p className="instruction">
{message.summary}
return (
<Template
{...{ kcContext, ...props }}
doFetchDefaultThemeResources={true}
displayMessage={false}
headerNode={messageHeader !== undefined ? <>{messageHeader}</> : <>{message.summary}</>}
formNode={
<div id="kc-info-message">
<p className="instruction">
{message.summary}
{requiredActions !== undefined && (
<b>
{requiredActions
.map(requiredAction =>
msg(
`requiredAction.${requiredAction}` as const,
),
)
.join(",")}
</b>
)}
</p>
{!skipLink && pageRedirectUri !== undefined ? (
<p>
<a href={pageRedirectUri}>
{msg("backToApplication")}
</a>
</p>
) : actionUri !== undefined ? (
<p>
<a href={actionUri}>
{msg("proceedWithAction")}
</a>
</p>
) : (
client.baseUrl !== undefined && (
<p>
<a href={client.baseUrl}>
{msg("backToApplication")}
</a>
</p>
)
{requiredActions !== undefined && (
<b>{requiredActions.map(requiredAction => msg(`requiredAction.${requiredAction}` as const)).join(",")}</b>
)}
</div>
}
/>
);
},
);
</p>
{!skipLink && pageRedirectUri !== undefined ? (
<p>
<a href={pageRedirectUri}>{msg("backToApplication")}</a>
</p>
) : actionUri !== undefined ? (
<p>
<a href={actionUri}>{msg("proceedWithAction")}</a>
</p>
) : (
client.baseUrl !== undefined && (
<p>
<a href={client.baseUrl}>{msg("backToApplication")}</a>
</p>
)
)}
</div>
}
/>
);
});

View File

@ -13,31 +13,29 @@ import { LoginOtp } from "./LoginOtp";
import { LoginUpdateProfile } from "./LoginUpdateProfile";
import { LoginIdpLinkConfirm } from "./LoginIdpLinkConfirm";
export const KcApp = memo(
({ kcContext, ...props }: { kcContext: KcContextBase } & KcProps) => {
switch (kcContext.pageId) {
case "login.ftl":
return <Login {...{ kcContext, ...props }} />;
case "register.ftl":
return <Register {...{ kcContext, ...props }} />;
case "register-user-profile.ftl":
return <RegisterUserProfile {...{ kcContext, ...props }} />;
case "info.ftl":
return <Info {...{ kcContext, ...props }} />;
case "error.ftl":
return <Error {...{ kcContext, ...props }} />;
case "login-reset-password.ftl":
return <LoginResetPassword {...{ kcContext, ...props }} />;
case "login-verify-email.ftl":
return <LoginVerifyEmail {...{ kcContext, ...props }} />;
case "terms.ftl":
return <Terms {...{ kcContext, ...props }} />;
case "login-otp.ftl":
return <LoginOtp {...{ kcContext, ...props }} />;
case "login-update-profile.ftl":
return <LoginUpdateProfile {...{ kcContext, ...props }} />;
case "login-idp-link-confirm.ftl":
return <LoginIdpLinkConfirm {...{ kcContext, ...props }} />;
}
},
);
export const KcApp = memo(({ kcContext, ...props }: { kcContext: KcContextBase } & KcProps) => {
switch (kcContext.pageId) {
case "login.ftl":
return <Login {...{ kcContext, ...props }} />;
case "register.ftl":
return <Register {...{ kcContext, ...props }} />;
case "register-user-profile.ftl":
return <RegisterUserProfile {...{ kcContext, ...props }} />;
case "info.ftl":
return <Info {...{ kcContext, ...props }} />;
case "error.ftl":
return <Error {...{ kcContext, ...props }} />;
case "login-reset-password.ftl":
return <LoginResetPassword {...{ kcContext, ...props }} />;
case "login-verify-email.ftl":
return <LoginVerifyEmail {...{ kcContext, ...props }} />;
case "terms.ftl":
return <Terms {...{ kcContext, ...props }} />;
case "login-otp.ftl":
return <LoginOtp {...{ kcContext, ...props }} />;
case "login-update-profile.ftl":
return <LoginUpdateProfile {...{ kcContext, ...props }} />;
case "login-idp-link-confirm.ftl":
return <LoginIdpLinkConfirm {...{ kcContext, ...props }} />;
}
});

View File

@ -70,9 +70,7 @@ export const defaultKcTemplateProps = {
assert<typeof defaultKcTemplateProps extends KcTemplateProps ? true : false>();
/** Tu use if you don't want any default */
export const allClearKcTemplateProps = allPropertiesValuesToUndefined(
defaultKcTemplateProps,
);
export const allClearKcTemplateProps = allPropertiesValuesToUndefined(defaultKcTemplateProps);
assert<typeof allClearKcTemplateProps extends KcTemplateProps ? true : false>();
@ -134,31 +132,13 @@ export const defaultKcProps = {
"kcLogoLink": "http://www.keycloak.org",
"kcLogoClass": "login-pf-brand",
"kcContainerClass": "container-fluid",
"kcContentClass": [
"col-sm-8",
"col-sm-offset-2",
"col-md-6",
"col-md-offset-3",
"col-lg-6",
"col-lg-offset-3",
],
"kcContentClass": ["col-sm-8", "col-sm-offset-2", "col-md-6", "col-md-offset-3", "col-lg-6", "col-lg-offset-3"],
"kcFeedbackAreaClass": ["col-md-12"],
"kcLocaleClass": ["col-xs-12", "col-sm-1"],
"kcAlertIconClasserror": ["pficon", "pficon-error-circle-o"],
"kcFormAreaClass": [
"col-sm-10",
"col-sm-offset-1",
"col-md-8",
"col-md-offset-2",
"col-lg-8",
"col-lg-offset-2",
],
"kcFormSocialAccountListClass": [
"login-pf-social",
"list-unstyled",
"login-pf-social-all",
],
"kcFormAreaClass": ["col-sm-10", "col-sm-offset-1", "col-md-8", "col-md-offset-2", "col-lg-8", "col-lg-offset-2"],
"kcFormSocialAccountListClass": ["login-pf-social", "list-unstyled", "login-pf-social-all"],
"kcFormSocialAccountDoubleListClass": ["login-pf-social-double-col"],
"kcFormSocialAccountListLinkClass": ["login-pf-social-link"],
"kcWebAuthnKeyIcon": ["pficon", "pficon-key"],
@ -167,25 +147,14 @@ export const defaultKcProps = {
"kcFormGroupErrorClass": ["has-error"],
"kcLabelClass": ["control-label"],
"kcInputClass": ["form-control"],
"kcInputErrorMessageClass": [
"pf-c-form__helper-text",
"pf-m-error",
"required",
"kc-feedback-text",
],
"kcInputErrorMessageClass": ["pf-c-form__helper-text", "pf-m-error", "required", "kc-feedback-text"],
"kcInputWrapperClass": ["col-xs-12", "col-sm-12", "col-md-12", "col-lg-12"],
"kcFormOptionsClass": ["col-xs-12", "col-sm-12", "col-md-12", "col-lg-12"],
"kcFormButtonsClass": ["col-xs-12", "col-sm-12", "col-md-12", "col-lg-12"],
"kcFormSettingClass": ["login-pf-settings"],
"kcTextareaClass": ["form-control"],
"kcInfoAreaClass": [
"col-xs-12",
"col-sm-4",
"col-md-4",
"col-lg-5",
"details",
],
"kcInfoAreaClass": ["col-xs-12", "col-sm-4", "col-md-4", "col-lg-5", "details"],
// user-profile grouping
"kcFormGroupHeader": ["pf-c-form__group"],
@ -220,19 +189,10 @@ export const defaultKcProps = {
"kcAuthenticatorPasswordClass": ["fa", "fa-unlock list-view-pf-icon-lg"],
"kcAuthenticatorOTPClass": ["fa", "fa-mobile", "list-view-pf-icon-lg"],
"kcAuthenticatorWebAuthnClass": ["fa", "fa-key", "list-view-pf-icon-lg"],
"kcAuthenticatorWebAuthnPasswordlessClass": [
"fa",
"fa-key",
"list-view-pf-icon-lg",
],
"kcAuthenticatorWebAuthnPasswordlessClass": ["fa", "fa-key", "list-view-pf-icon-lg"],
//css classes for the OTP Login Form
"kcSelectOTPListClass": [
"card-pf",
"card-pf-view",
"card-pf-view-select",
"card-pf-view-single-select",
],
"kcSelectOTPListClass": ["card-pf", "card-pf-view", "card-pf-view-select", "card-pf-view-single-select"],
"kcSelectOTPListItemClass": ["card-pf-body", "card-pf-top-element"],
"kcAuthenticatorOtpCircleClass": ["fa", "fa-mobile", "card-pf-icon-circle"],
"kcSelectOTPItemHeadingClass": ["card-pf-title", "text-center"],

View File

@ -6,241 +6,162 @@ import { useKcMessage } from "../i18n/useKcMessage";
import { useCssAndCx } from "tss-react";
import { useConstCallback } from "powerhooks/useConstCallback";
export const Login = memo(
({ kcContext, ...props }: { kcContext: KcContextBase.Login } & KcProps) => {
const {
social,
realm,
url,
usernameEditDisabled,
login,
auth,
registrationDisabled,
} = kcContext;
export const Login = memo(({ kcContext, ...props }: { kcContext: KcContextBase.Login } & KcProps) => {
const { social, realm, url, usernameEditDisabled, login, auth, registrationDisabled } = kcContext;
const { msg, msgStr } = useKcMessage();
const { msg, msgStr } = useKcMessage();
const { cx } = useCssAndCx();
const { cx } = useCssAndCx();
const [isLoginButtonDisabled, setIsLoginButtonDisabled] =
useState(false);
const [isLoginButtonDisabled, setIsLoginButtonDisabled] = useState(false);
const onSubmit = useConstCallback(
() => (setIsLoginButtonDisabled(true), true),
);
const onSubmit = useConstCallback(() => (setIsLoginButtonDisabled(true), true));
return (
<Template
{...{ kcContext, ...props }}
doFetchDefaultThemeResources={true}
displayInfo={social.displayInfo}
displayWide={realm.password && social.providers !== undefined}
headerNode={msg("doLogIn")}
formNode={
return (
<Template
{...{ kcContext, ...props }}
doFetchDefaultThemeResources={true}
displayInfo={social.displayInfo}
displayWide={realm.password && social.providers !== undefined}
headerNode={msg("doLogIn")}
formNode={
<div id="kc-form" className={cx(realm.password && social.providers !== undefined && props.kcContentWrapperClass)}>
<div
id="kc-form"
className={cx(
realm.password &&
social.providers !== undefined &&
props.kcContentWrapperClass,
)}
id="kc-form-wrapper"
className={cx(realm.password && social.providers && [props.kcFormSocialAccountContentClass, props.kcFormSocialAccountClass])}
>
<div
id="kc-form-wrapper"
className={cx(
realm.password &&
social.providers && [
props.kcFormSocialAccountContentClass,
props.kcFormSocialAccountClass,
],
)}
>
{realm.password && (
<form
id="kc-form-login"
onSubmit={onSubmit}
action={url.loginAction}
method="post"
>
<div className={cx(props.kcFormGroupClass)}>
<label
htmlFor="username"
className={cx(props.kcLabelClass)}
>
{!realm.loginWithEmailAllowed
? msg("username")
: !realm.registrationEmailAsUsername
? msg("usernameOrEmail")
: msg("email")}
</label>
<input
tabIndex={1}
id="username"
className={cx(props.kcInputClass)}
name="username"
defaultValue={login.username ?? ""}
type="text"
{...(usernameEditDisabled
? { "disabled": true }
: {
"autoFocus": true,
"autoComplete": "off",
})}
/>
</div>
<div className={cx(props.kcFormGroupClass)}>
<label
htmlFor="password"
className={cx(props.kcLabelClass)}
>
{msg("password")}
</label>
<input
tabIndex={2}
id="password"
className={cx(props.kcInputClass)}
name="password"
type="password"
autoComplete="off"
/>
</div>
<div
className={cx(
props.kcFormGroupClass,
props.kcFormSettingClass,
{realm.password && (
<form id="kc-form-login" onSubmit={onSubmit} action={url.loginAction} method="post">
<div className={cx(props.kcFormGroupClass)}>
<label htmlFor="username" className={cx(props.kcLabelClass)}>
{!realm.loginWithEmailAllowed
? msg("username")
: !realm.registrationEmailAsUsername
? msg("usernameOrEmail")
: msg("email")}
</label>
<input
tabIndex={1}
id="username"
className={cx(props.kcInputClass)}
name="username"
defaultValue={login.username ?? ""}
type="text"
{...(usernameEditDisabled
? { "disabled": true }
: {
"autoFocus": true,
"autoComplete": "off",
})}
/>
</div>
<div className={cx(props.kcFormGroupClass)}>
<label htmlFor="password" className={cx(props.kcLabelClass)}>
{msg("password")}
</label>
<input
tabIndex={2}
id="password"
className={cx(props.kcInputClass)}
name="password"
type="password"
autoComplete="off"
/>
</div>
<div className={cx(props.kcFormGroupClass, props.kcFormSettingClass)}>
<div id="kc-form-options">
{realm.rememberMe && !usernameEditDisabled && (
<div className="checkbox">
<label>
<input
tabIndex={3}
id="rememberMe"
name="rememberMe"
type="checkbox"
{...(login.rememberMe
? {
"checked": true,
}
: {})}
/>
{msg("rememberMe")}
</label>
</div>
)}
>
<div id="kc-form-options">
{realm.rememberMe &&
!usernameEditDisabled && (
<div className="checkbox">
<label>
<input
tabIndex={3}
id="rememberMe"
name="rememberMe"
type="checkbox"
{...(login.rememberMe
? {
"checked":
true,
}
: {})}
/>
{msg("rememberMe")}
</label>
</div>
)}
</div>
<div
className={cx(
props.kcFormOptionsWrapperClass,
)}
>
{realm.resetPasswordAllowed && (
<span>
<a
tabIndex={5}
href={
url.loginResetCredentialsUrl
}
>
{msg(
"doForgotPassword",
)}
</a>
</span>
)}
</div>
</div>
<div
id="kc-form-buttons"
className={cx(props.kcFormGroupClass)}
>
<input
type="hidden"
id="id-hidden-input"
name="credentialId"
{...(auth?.selectedCredential !==
undefined
? {
"value":
auth.selectedCredential,
}
: {})}
/>
<input
tabIndex={4}
className={cx(
props.kcButtonClass,
props.kcButtonPrimaryClass,
props.kcButtonBlockClass,
props.kcButtonLargeClass,
)}
name="login"
id="kc-login"
type="submit"
value={msgStr("doLogIn")}
disabled={isLoginButtonDisabled}
/>
<div className={cx(props.kcFormOptionsWrapperClass)}>
{realm.resetPasswordAllowed && (
<span>
<a tabIndex={5} href={url.loginResetCredentialsUrl}>
{msg("doForgotPassword")}
</a>
</span>
)}
</div>
</form>
)}
</div>
{realm.password && social.providers !== undefined && (
<div
id="kc-social-providers"
className={cx(
props.kcFormSocialAccountContentClass,
props.kcFormSocialAccountClass,
)}
>
<ul
className={cx(
props.kcFormSocialAccountListClass,
social.providers.length > 4 &&
props.kcFormSocialAccountDoubleListClass,
)}
>
{social.providers.map(p => (
<li
key={p.providerId}
className={cx(
props.kcFormSocialAccountListLinkClass,
)}
>
<a
href={p.loginUrl}
id={`zocial-${p.alias}`}
className={cx(
"zocial",
p.providerId,
)}
>
<span>{p.displayName}</span>
</a>
</li>
))}
</ul>
</div>
</div>
<div id="kc-form-buttons" className={cx(props.kcFormGroupClass)}>
<input
type="hidden"
id="id-hidden-input"
name="credentialId"
{...(auth?.selectedCredential !== undefined
? {
"value": auth.selectedCredential,
}
: {})}
/>
<input
tabIndex={4}
className={cx(
props.kcButtonClass,
props.kcButtonPrimaryClass,
props.kcButtonBlockClass,
props.kcButtonLargeClass,
)}
name="login"
id="kc-login"
type="submit"
value={msgStr("doLogIn")}
disabled={isLoginButtonDisabled}
/>
</div>
</form>
)}
</div>
}
infoNode={
realm.password &&
realm.registrationAllowed &&
!registrationDisabled && (
<div id="kc-registration">
<span>
{msg("noAccount")}
<a tabIndex={6} href={url.registrationUrl}>
{msg("doRegister")}
</a>
</span>
{realm.password && social.providers !== undefined && (
<div id="kc-social-providers" className={cx(props.kcFormSocialAccountContentClass, props.kcFormSocialAccountClass)}>
<ul
className={cx(
props.kcFormSocialAccountListClass,
social.providers.length > 4 && props.kcFormSocialAccountDoubleListClass,
)}
>
{social.providers.map(p => (
<li key={p.providerId} className={cx(props.kcFormSocialAccountListLinkClass)}>
<a href={p.loginUrl} id={`zocial-${p.alias}`} className={cx("zocial", p.providerId)}>
<span>{p.displayName}</span>
</a>
</li>
))}
</ul>
</div>
)
}
/>
);
},
);
)}
</div>
}
infoNode={
realm.password &&
realm.registrationAllowed &&
!registrationDisabled && (
<div id="kc-registration">
<span>
{msg("noAccount")}
<a tabIndex={6} href={url.registrationUrl}>
{msg("doRegister")}
</a>
</span>
</div>
)
}
/>
);
});

View File

@ -5,61 +5,42 @@ import type { KcContextBase } from "../getKcContext/KcContextBase";
import { useKcMessage } from "../i18n/useKcMessage";
import { useCssAndCx } from "tss-react";
export const LoginIdpLinkConfirm = memo(
({
kcContext,
...props
}: { kcContext: KcContextBase.LoginIdpLinkConfirm } & KcProps) => {
const { url, idpAlias } = kcContext;
export const LoginIdpLinkConfirm = memo(({ kcContext, ...props }: { kcContext: KcContextBase.LoginIdpLinkConfirm } & KcProps) => {
const { url, idpAlias } = kcContext;
const { msg } = useKcMessage();
const { msg } = useKcMessage();
const { cx } = useCssAndCx();
const { cx } = useCssAndCx();
return (
<Template
{...{ kcContext, ...props }}
doFetchDefaultThemeResources={true}
headerNode={msg("confirmLinkIdpTitle")}
formNode={
<form
id="kc-register-form"
action={url.loginAction}
method="post"
>
<div className={cx(props.kcFormGroupClass)}>
<button
type="submit"
className={cx(
props.kcButtonClass,
props.kcButtonDefaultClass,
props.kcButtonBlockClass,
props.kcButtonLargeClass,
)}
name="submitAction"
id="updateProfile"
value="updateProfile"
>
{msg("confirmLinkIdpReviewProfile")}
</button>
<button
type="submit"
className={cx(
props.kcButtonClass,
props.kcButtonDefaultClass,
props.kcButtonBlockClass,
props.kcButtonLargeClass,
)}
name="submitAction"
id="linkAccount"
value="linkAccount"
>
{msg("confirmLinkIdpContinue", idpAlias)}
</button>
</div>
</form>
}
/>
);
},
);
return (
<Template
{...{ kcContext, ...props }}
doFetchDefaultThemeResources={true}
headerNode={msg("confirmLinkIdpTitle")}
formNode={
<form id="kc-register-form" action={url.loginAction} method="post">
<div className={cx(props.kcFormGroupClass)}>
<button
type="submit"
className={cx(props.kcButtonClass, props.kcButtonDefaultClass, props.kcButtonBlockClass, props.kcButtonLargeClass)}
name="submitAction"
id="updateProfile"
value="updateProfile"
>
{msg("confirmLinkIdpReviewProfile")}
</button>
<button
type="submit"
className={cx(props.kcButtonClass, props.kcButtonDefaultClass, props.kcButtonBlockClass, props.kcButtonLargeClass)}
name="submitAction"
id="linkAccount"
value="linkAccount"
>
{msg("confirmLinkIdpContinue", idpAlias)}
</button>
</div>
</form>
}
/>
);
});

View File

@ -7,148 +7,84 @@ import { appendHead } from "../tools/appendHead";
import { join as pathJoin } from "path";
import { useCssAndCx } from "tss-react";
export const LoginOtp = memo(
({
kcContext,
...props
}: { kcContext: KcContextBase.LoginOtp } & KcProps) => {
const { otpLogin, url } = kcContext;
export const LoginOtp = memo(({ kcContext, ...props }: { kcContext: KcContextBase.LoginOtp } & KcProps) => {
const { otpLogin, url } = kcContext;
const { cx } = useCssAndCx();
const { cx } = useCssAndCx();
const { msg, msgStr } = useKcMessage();
const { msg, msgStr } = useKcMessage();
useEffect(() => {
let isCleanedUp = false;
useEffect(() => {
let isCleanedUp = false;
appendHead({
"type": "javascript",
"src": pathJoin(
kcContext.url.resourcesCommonPath,
"node_modules/jquery/dist/jquery.min.js",
),
}).then(() => {
if (isCleanedUp) return;
appendHead({
"type": "javascript",
"src": pathJoin(kcContext.url.resourcesCommonPath, "node_modules/jquery/dist/jquery.min.js"),
}).then(() => {
if (isCleanedUp) return;
evaluateInlineScript();
});
evaluateInlineScript();
});
return () => {
isCleanedUp = true;
};
}, []);
return () => {
isCleanedUp = true;
};
}, []);
return (
<Template
{...{ kcContext, ...props }}
doFetchDefaultThemeResources={true}
headerNode={msg("doLogIn")}
formNode={
<form
id="kc-otp-login-form"
className={cx(props.kcFormClass)}
action={url.loginAction}
method="post"
>
{otpLogin.userOtpCredentials.length > 1 && (
<div className={cx(props.kcFormGroupClass)}>
<div className={cx(props.kcInputWrapperClass)}>
{otpLogin.userOtpCredentials.map(
otpCredential => (
<div
key={otpCredential.id}
className={cx(
props.kcSelectOTPListClass,
)}
>
<input
type="hidden"
value="${otpCredential.id}"
/>
<div
className={cx(
props.kcSelectOTPListItemClass,
)}
>
<span
className={cx(
props.kcAuthenticatorOtpCircleClass,
)}
/>
<h2
className={cx(
props.kcSelectOTPItemHeadingClass,
)}
>
{
otpCredential.userLabel
}
</h2>
</div>
</div>
),
)}
</div>
</div>
)}
return (
<Template
{...{ kcContext, ...props }}
doFetchDefaultThemeResources={true}
headerNode={msg("doLogIn")}
formNode={
<form id="kc-otp-login-form" className={cx(props.kcFormClass)} action={url.loginAction} method="post">
{otpLogin.userOtpCredentials.length > 1 && (
<div className={cx(props.kcFormGroupClass)}>
<div className={cx(props.kcLabelWrapperClass)}>
<label
htmlFor="otp"
className={cx(props.kcLabelClass)}
>
{msg("loginOtpOneTime")}
</label>
</div>
<div className={cx(props.kcInputWrapperClass)}>
<input
id="otp"
name="otp"
autoComplete="off"
type="text"
className={cx(props.kcInputClass)}
autoFocus
/>
{otpLogin.userOtpCredentials.map(otpCredential => (
<div key={otpCredential.id} className={cx(props.kcSelectOTPListClass)}>
<input type="hidden" value="${otpCredential.id}" />
<div className={cx(props.kcSelectOTPListItemClass)}>
<span className={cx(props.kcAuthenticatorOtpCircleClass)} />
<h2 className={cx(props.kcSelectOTPItemHeadingClass)}>{otpCredential.userLabel}</h2>
</div>
</div>
))}
</div>
</div>
<div className={cx(props.kcFormGroupClass)}>
<div
id="kc-form-options"
className={cx(props.kcFormOptionsClass)}
>
<div
className={cx(
props.kcFormOptionsWrapperClass,
)}
/>
</div>
<div
id="kc-form-buttons"
className={cx(props.kcFormButtonsClass)}
>
<input
className={cx(
props.kcButtonClass,
props.kcButtonPrimaryClass,
props.kcButtonBlockClass,
props.kcButtonLargeClass,
)}
name="login"
id="kc-login"
type="submit"
value={msgStr("doLogIn")}
/>
</div>
)}
<div className={cx(props.kcFormGroupClass)}>
<div className={cx(props.kcLabelWrapperClass)}>
<label htmlFor="otp" className={cx(props.kcLabelClass)}>
{msg("loginOtpOneTime")}
</label>
</div>
</form>
}
/>
);
},
);
<div className={cx(props.kcInputWrapperClass)}>
<input id="otp" name="otp" autoComplete="off" type="text" className={cx(props.kcInputClass)} autoFocus />
</div>
</div>
<div className={cx(props.kcFormGroupClass)}>
<div id="kc-form-options" className={cx(props.kcFormOptionsClass)}>
<div className={cx(props.kcFormOptionsWrapperClass)} />
</div>
<div id="kc-form-buttons" className={cx(props.kcFormButtonsClass)}>
<input
className={cx(props.kcButtonClass, props.kcButtonPrimaryClass, props.kcButtonBlockClass, props.kcButtonLargeClass)}
name="login"
id="kc-login"
type="submit"
value={msgStr("doLogIn")}
/>
</div>
</div>
</form>
}
/>
);
});
declare const $: any;

View File

@ -5,101 +5,62 @@ import type { KcContextBase } from "../getKcContext/KcContextBase";
import { useKcMessage } from "../i18n/useKcMessage";
import { useCssAndCx } from "tss-react";
export const LoginResetPassword = memo(
({
kcContext,
...props
}: { kcContext: KcContextBase.LoginResetPassword } & KcProps) => {
const { url, realm, auth } = kcContext;
export const LoginResetPassword = memo(({ kcContext, ...props }: { kcContext: KcContextBase.LoginResetPassword } & KcProps) => {
const { url, realm, auth } = kcContext;
const { msg, msgStr } = useKcMessage();
const { msg, msgStr } = useKcMessage();
const { cx } = useCssAndCx();
const { cx } = useCssAndCx();
return (
<Template
{...{ kcContext, ...props }}
doFetchDefaultThemeResources={true}
displayMessage={false}
headerNode={msg("emailForgotTitle")}
formNode={
<form
id="kc-reset-password-form"
className={cx(props.kcFormClass)}
action={url.loginAction}
method="post"
>
<div className={cx(props.kcFormGroupClass)}>
<div className={cx(props.kcLabelWrapperClass)}>
<label
htmlFor="username"
className={cx(props.kcLabelClass)}
>
{!realm.loginWithEmailAllowed
? msg("username")
: !realm.registrationEmailAsUsername
? msg("usernameOrEmail")
: msg("email")}
</label>
</div>
<div className={cx(props.kcInputWrapperClass)}>
<input
type="text"
id="username"
name="username"
className={cx(props.kcInputClass)}
autoFocus
defaultValue={
auth !== undefined && auth.showUsername
? auth.attemptedUsername
: undefined
}
/>
return (
<Template
{...{ kcContext, ...props }}
doFetchDefaultThemeResources={true}
displayMessage={false}
headerNode={msg("emailForgotTitle")}
formNode={
<form id="kc-reset-password-form" className={cx(props.kcFormClass)} action={url.loginAction} method="post">
<div className={cx(props.kcFormGroupClass)}>
<div className={cx(props.kcLabelWrapperClass)}>
<label htmlFor="username" className={cx(props.kcLabelClass)}>
{!realm.loginWithEmailAllowed
? msg("username")
: !realm.registrationEmailAsUsername
? msg("usernameOrEmail")
: msg("email")}
</label>
</div>
<div className={cx(props.kcInputWrapperClass)}>
<input
type="text"
id="username"
name="username"
className={cx(props.kcInputClass)}
autoFocus
defaultValue={auth !== undefined && auth.showUsername ? auth.attemptedUsername : undefined}
/>
</div>
</div>
<div className={cx(props.kcFormGroupClass, props.kcFormSettingClass)}>
<div id="kc-form-options" className={cx(props.kcFormOptionsClass)}>
<div className={cx(props.kcFormOptionsWrapperClass)}>
<span>
<a href={url.loginUrl}>{msg("backToLogin")}</a>
</span>
</div>
</div>
<div
className={cx(
props.kcFormGroupClass,
props.kcFormSettingClass,
)}
>
<div
id="kc-form-options"
className={cx(props.kcFormOptionsClass)}
>
<div
className={cx(
props.kcFormOptionsWrapperClass,
)}
>
<span>
<a href={url.loginUrl}>
{msg("backToLogin")}
</a>
</span>
</div>
</div>
<div
id="kc-form-buttons"
className={cx(props.kcFormButtonsClass)}
>
<input
className={cx(
props.kcButtonClass,
props.kcButtonPrimaryClass,
props.kcButtonBlockClass,
props.kcButtonLargeClass,
)}
type="submit"
value={msgStr("doSubmit")}
/>
</div>
<div id="kc-form-buttons" className={cx(props.kcFormButtonsClass)}>
<input
className={cx(props.kcButtonClass, props.kcButtonPrimaryClass, props.kcButtonBlockClass, props.kcButtonLargeClass)}
type="submit"
value={msgStr("doSubmit")}
/>
</div>
</form>
}
infoNode={msg("emailInstruction")}
/>
);
},
);
</div>
</form>
}
infoNode={msg("emailInstruction")}
/>
);
});

View File

@ -5,200 +5,116 @@ import type { KcContextBase } from "../getKcContext/KcContextBase";
import { useKcMessage } from "../i18n/useKcMessage";
import { useCssAndCx } from "tss-react";
export const LoginUpdateProfile = memo(
({
kcContext,
...props
}: { kcContext: KcContextBase.LoginUpdateProfile } & KcProps) => {
const { cx } = useCssAndCx();
export const LoginUpdateProfile = memo(({ kcContext, ...props }: { kcContext: KcContextBase.LoginUpdateProfile } & KcProps) => {
const { cx } = useCssAndCx();
const { msg, msgStr } = useKcMessage();
const { msg, msgStr } = useKcMessage();
const { url, user, messagesPerField, isAppInitiatedAction } = kcContext;
const { url, user, messagesPerField, isAppInitiatedAction } = kcContext;
return (
<Template
{...{ kcContext, ...props }}
doFetchDefaultThemeResources={true}
headerNode={msg("loginProfileTitle")}
formNode={
<form
id="kc-update-profile-form"
className={cx(props.kcFormClass)}
action={url.loginAction}
method="post"
>
{user.editUsernameAllowed && (
<div
className={cx(
props.kcFormGroupClass,
messagesPerField.printIfExists(
"username",
props.kcFormGroupErrorClass,
),
)}
>
<div className={cx(props.kcLabelWrapperClass)}>
<label
htmlFor="username"
className={cx(props.kcLabelClass)}
>
{msg("username")}
</label>
</div>
<div className={cx(props.kcInputWrapperClass)}>
return (
<Template
{...{ kcContext, ...props }}
doFetchDefaultThemeResources={true}
headerNode={msg("loginProfileTitle")}
formNode={
<form id="kc-update-profile-form" className={cx(props.kcFormClass)} action={url.loginAction} method="post">
{user.editUsernameAllowed && (
<div className={cx(props.kcFormGroupClass, messagesPerField.printIfExists("username", props.kcFormGroupErrorClass))}>
<div className={cx(props.kcLabelWrapperClass)}>
<label htmlFor="username" className={cx(props.kcLabelClass)}>
{msg("username")}
</label>
</div>
<div className={cx(props.kcInputWrapperClass)}>
<input
type="text"
id="username"
name="username"
defaultValue={user.username ?? ""}
className={cx(props.kcInputClass)}
/>
</div>
</div>
)}
<div className={cx(props.kcFormGroupClass, messagesPerField.printIfExists("email", props.kcFormGroupErrorClass))}>
<div className={cx(props.kcLabelWrapperClass)}>
<label htmlFor="email" className={cx(props.kcLabelClass)}>
{msg("email")}
</label>
</div>
<div className={cx(props.kcInputWrapperClass)}>
<input type="text" id="email" name="email" defaultValue={user.email ?? ""} className={cx(props.kcInputClass)} />
</div>
</div>
<div className={cx(props.kcFormGroupClass, messagesPerField.printIfExists("firstName", props.kcFormGroupErrorClass))}>
<div className={cx(props.kcLabelWrapperClass)}>
<label htmlFor="firstName" className={cx(props.kcLabelClass)}>
{msg("firstName")}
</label>
</div>
<div className={cx(props.kcInputWrapperClass)}>
<input
type="text"
id="firstName"
name="firstName"
defaultValue={user.firstName ?? ""}
className={cx(props.kcInputClass)}
/>
</div>
</div>
<div className={cx(props.kcFormGroupClass, messagesPerField.printIfExists("lastName", props.kcFormGroupErrorClass))}>
<div className={cx(props.kcLabelWrapperClass)}>
<label htmlFor="lastName" className={cx(props.kcLabelClass)}>
{msg("lastName")}
</label>
</div>
<div className={cx(props.kcInputWrapperClass)}>
<input type="text" id="lastName" name="lastName" defaultValue={user.lastName ?? ""} className={cx(props.kcInputClass)} />
</div>
</div>
<div className={cx(props.kcFormGroupClass)}>
<div id="kc-form-options" className={cx(props.kcFormOptionsClass)}>
<div className={cx(props.kcFormOptionsWrapperClass)} />
</div>
<div id="kc-form-buttons" className={cx(props.kcFormButtonsClass)}>
{isAppInitiatedAction ? (
<>
<input
type="text"
id="username"
name="username"
defaultValue={user.username ?? ""}
className={cx(props.kcInputClass)}
/>
</div>
</div>
)}
<div
className={cx(
props.kcFormGroupClass,
messagesPerField.printIfExists(
"email",
props.kcFormGroupErrorClass,
),
)}
>
<div className={cx(props.kcLabelWrapperClass)}>
<label
htmlFor="email"
className={cx(props.kcLabelClass)}
>
{msg("email")}
</label>
</div>
<div className={cx(props.kcInputWrapperClass)}>
<input
type="text"
id="email"
name="email"
defaultValue={user.email ?? ""}
className={cx(props.kcInputClass)}
/>
</div>
</div>
<div
className={cx(
props.kcFormGroupClass,
messagesPerField.printIfExists(
"firstName",
props.kcFormGroupErrorClass,
),
)}
>
<div className={cx(props.kcLabelWrapperClass)}>
<label
htmlFor="firstName"
className={cx(props.kcLabelClass)}
>
{msg("firstName")}
</label>
</div>
<div className={cx(props.kcInputWrapperClass)}>
<input
type="text"
id="firstName"
name="firstName"
defaultValue={user.firstName ?? ""}
className={cx(props.kcInputClass)}
/>
</div>
</div>
<div
className={cx(
props.kcFormGroupClass,
messagesPerField.printIfExists(
"lastName",
props.kcFormGroupErrorClass,
),
)}
>
<div className={cx(props.kcLabelWrapperClass)}>
<label
htmlFor="lastName"
className={cx(props.kcLabelClass)}
>
{msg("lastName")}
</label>
</div>
<div className={cx(props.kcInputWrapperClass)}>
<input
type="text"
id="lastName"
name="lastName"
defaultValue={user.lastName ?? ""}
className={cx(props.kcInputClass)}
/>
</div>
</div>
<div className={cx(props.kcFormGroupClass)}>
<div
id="kc-form-options"
className={cx(props.kcFormOptionsClass)}
>
<div
className={cx(
props.kcFormOptionsWrapperClass,
)}
/>
</div>
<div
id="kc-form-buttons"
className={cx(props.kcFormButtonsClass)}
>
{isAppInitiatedAction ? (
<>
<input
className={cx(
props.kcButtonClass,
props.kcButtonPrimaryClass,
props.kcButtonLargeClass,
)}
type="submit"
defaultValue={msgStr("doSubmit")}
/>
<button
className={cx(
props.kcButtonClass,
props.kcButtonDefaultClass,
props.kcButtonLargeClass,
)}
type="submit"
name="cancel-aia"
value="true"
>
{msg("doCancel")}
</button>
</>
) : (
<input
className={cx(
props.kcButtonClass,
props.kcButtonPrimaryClass,
props.kcButtonBlockClass,
props.kcButtonLargeClass,
)}
className={cx(props.kcButtonClass, props.kcButtonPrimaryClass, props.kcButtonLargeClass)}
type="submit"
defaultValue={msgStr("doSubmit")}
/>
)}
</div>
<button
className={cx(props.kcButtonClass, props.kcButtonDefaultClass, props.kcButtonLargeClass)}
type="submit"
name="cancel-aia"
value="true"
>
{msg("doCancel")}
</button>
</>
) : (
<input
className={cx(
props.kcButtonClass,
props.kcButtonPrimaryClass,
props.kcButtonBlockClass,
props.kcButtonLargeClass,
)}
type="submit"
defaultValue={msgStr("doSubmit")}
/>
)}
</div>
</form>
}
/>
);
},
);
</div>
</form>
}
/>
);
});

View File

@ -4,34 +4,27 @@ import type { KcProps } from "./KcProps";
import type { KcContextBase } from "../getKcContext/KcContextBase";
import { useKcMessage } from "../i18n/useKcMessage";
export const LoginVerifyEmail = memo(
({
kcContext,
...props
}: { kcContext: KcContextBase.LoginVerifyEmail } & KcProps) => {
const { msg } = useKcMessage();
export const LoginVerifyEmail = memo(({ kcContext, ...props }: { kcContext: KcContextBase.LoginVerifyEmail } & KcProps) => {
const { msg } = useKcMessage();
const { url } = kcContext;
const { url } = kcContext;
return (
<Template
{...{ kcContext, ...props }}
doFetchDefaultThemeResources={true}
displayMessage={false}
headerNode={msg("emailVerifyTitle")}
formNode={
<>
<p className="instruction">
{msg("emailVerifyInstruction1")}
</p>
<p className="instruction">
{msg("emailVerifyInstruction2")}
<a href={url.loginAction}>{msg("doClickHere")}</a>
{msg("emailVerifyInstruction3")}
</p>
</>
}
/>
);
},
);
return (
<Template
{...{ kcContext, ...props }}
doFetchDefaultThemeResources={true}
displayMessage={false}
headerNode={msg("emailVerifyTitle")}
formNode={
<>
<p className="instruction">{msg("emailVerifyInstruction1")}</p>
<p className="instruction">
{msg("emailVerifyInstruction2")}
<a href={url.loginAction}>{msg("doClickHere")}</a>
{msg("emailVerifyInstruction3")}
</p>
</>
}
/>
);
});

View File

@ -5,279 +5,152 @@ import type { KcContextBase } from "../getKcContext/KcContextBase";
import { useKcMessage } from "../i18n/useKcMessage";
import { useCssAndCx } from "tss-react";
export const Register = memo(
({
kcContext,
...props
}: { kcContext: KcContextBase.Register } & KcProps) => {
const {
url,
messagesPerField,
register,
realm,
passwordRequired,
recaptchaRequired,
recaptchaSiteKey,
} = kcContext;
export const Register = memo(({ kcContext, ...props }: { kcContext: KcContextBase.Register } & KcProps) => {
const { url, messagesPerField, register, realm, passwordRequired, recaptchaRequired, recaptchaSiteKey } = kcContext;
const { msg, msgStr } = useKcMessage();
const { msg, msgStr } = useKcMessage();
const { cx } = useCssAndCx();
const { cx } = useCssAndCx();
return (
<Template
{...{ kcContext, ...props }}
doFetchDefaultThemeResources={true}
headerNode={msg("registerTitle")}
formNode={
<form
id="kc-register-form"
className={cx(props.kcFormClass)}
action={url.registrationAction}
method="post"
>
<div
className={cx(
props.kcFormGroupClass,
messagesPerField.printIfExists(
"firstName",
props.kcFormGroupErrorClass,
),
)}
>
return (
<Template
{...{ kcContext, ...props }}
doFetchDefaultThemeResources={true}
headerNode={msg("registerTitle")}
formNode={
<form id="kc-register-form" className={cx(props.kcFormClass)} action={url.registrationAction} method="post">
<div className={cx(props.kcFormGroupClass, messagesPerField.printIfExists("firstName", props.kcFormGroupErrorClass))}>
<div className={cx(props.kcLabelWrapperClass)}>
<label htmlFor="firstName" className={cx(props.kcLabelClass)}>
{msg("firstName")}
</label>
</div>
<div className={cx(props.kcInputWrapperClass)}>
<input
type="text"
id="firstName"
className={cx(props.kcInputClass)}
name="firstName"
defaultValue={register.formData.firstName ?? ""}
/>
</div>
</div>
<div className={cx(props.kcFormGroupClass, messagesPerField.printIfExists("lastName", props.kcFormGroupErrorClass))}>
<div className={cx(props.kcLabelWrapperClass)}>
<label htmlFor="lastName" className={cx(props.kcLabelClass)}>
{msg("lastName")}
</label>
</div>
<div className={cx(props.kcInputWrapperClass)}>
<input
type="text"
id="lastName"
className={cx(props.kcInputClass)}
name="lastName"
defaultValue={register.formData.lastName ?? ""}
/>
</div>
</div>
<div className={cx(props.kcFormGroupClass, messagesPerField.printIfExists("email", props.kcFormGroupErrorClass))}>
<div className={cx(props.kcLabelWrapperClass)}>
<label htmlFor="email" className={cx(props.kcLabelClass)}>
{msg("email")}
</label>
</div>
<div className={cx(props.kcInputWrapperClass)}>
<input
type="text"
id="email"
className={cx(props.kcInputClass)}
name="email"
defaultValue={register.formData.email ?? ""}
autoComplete="email"
/>
</div>
</div>
{!realm.registrationEmailAsUsername && (
<div className={cx(props.kcFormGroupClass, messagesPerField.printIfExists("username", props.kcFormGroupErrorClass))}>
<div className={cx(props.kcLabelWrapperClass)}>
<label
htmlFor="firstName"
className={cx(props.kcLabelClass)}
>
{msg("firstName")}
<label htmlFor="username" className={cx(props.kcLabelClass)}>
{msg("username")}
</label>
</div>
<div className={cx(props.kcInputWrapperClass)}>
<input
type="text"
id="firstName"
id="username"
className={cx(props.kcInputClass)}
name="firstName"
defaultValue={
register.formData.firstName ?? ""
}
name="username"
defaultValue={register.formData.username ?? ""}
autoComplete="username"
/>
</div>
</div>
<div
className={cx(
props.kcFormGroupClass,
messagesPerField.printIfExists(
"lastName",
props.kcFormGroupErrorClass,
),
)}
>
<div className={cx(props.kcLabelWrapperClass)}>
<label
htmlFor="lastName"
className={cx(props.kcLabelClass)}
>
{msg("lastName")}
</label>
</div>
<div className={cx(props.kcInputWrapperClass)}>
<input
type="text"
id="lastName"
className={cx(props.kcInputClass)}
name="lastName"
defaultValue={
register.formData.lastName ?? ""
}
/>
</div>
</div>
<div
className={cx(
props.kcFormGroupClass,
messagesPerField.printIfExists(
"email",
props.kcFormGroupErrorClass,
),
)}
>
<div className={cx(props.kcLabelWrapperClass)}>
<label
htmlFor="email"
className={cx(props.kcLabelClass)}
>
{msg("email")}
</label>
</div>
<div className={cx(props.kcInputWrapperClass)}>
<input
type="text"
id="email"
className={cx(props.kcInputClass)}
name="email"
defaultValue={register.formData.email ?? ""}
autoComplete="email"
/>
</div>
</div>
{!realm.registrationEmailAsUsername && (
<div
className={cx(
props.kcFormGroupClass,
messagesPerField.printIfExists(
"username",
props.kcFormGroupErrorClass,
),
)}
>
)}
{passwordRequired && (
<>
<div className={cx(props.kcFormGroupClass, messagesPerField.printIfExists("password", props.kcFormGroupErrorClass))}>
<div className={cx(props.kcLabelWrapperClass)}>
<label
htmlFor="username"
className={cx(props.kcLabelClass)}
>
{msg("username")}
<label htmlFor="password" className={cx(props.kcLabelClass)}>
{msg("password")}
</label>
</div>
<div className={cx(props.kcInputWrapperClass)}>
<input
type="text"
id="username"
type="password"
id="password"
className={cx(props.kcInputClass)}
name="username"
defaultValue={
register.formData.username ?? ""
}
autoComplete="username"
name="password"
autoComplete="new-password"
/>
</div>
</div>
)}
{passwordRequired && (
<>
<div
className={cx(
props.kcFormGroupClass,
messagesPerField.printIfExists(
"password",
props.kcFormGroupErrorClass,
),
)}
>
<div
className={cx(
props.kcLabelWrapperClass,
)}
>
<label
htmlFor="password"
className={cx(props.kcLabelClass)}
>
{msg("password")}
</label>
</div>
<div
className={cx(
props.kcInputWrapperClass,
)}
>
<input
type="password"
id="password"
className={cx(props.kcInputClass)}
name="password"
autoComplete="new-password"
/>
</div>
</div>
<div
className={cx(
props.kcFormGroupClass,
messagesPerField.printIfExists(
"password-confirm",
props.kcFormGroupErrorClass,
),
)}
>
<div
className={cx(
props.kcLabelWrapperClass,
)}
>
<label
htmlFor="password-confirm"
className={cx(props.kcLabelClass)}
>
{msg("passwordConfirm")}
</label>
</div>
<div
className={cx(
props.kcInputWrapperClass,
)}
>
<input
type="password"
id="password-confirm"
className={cx(props.kcInputClass)}
name="password-confirm"
/>
</div>
<div
className={cx(
props.kcFormGroupClass,
messagesPerField.printIfExists("password-confirm", props.kcFormGroupErrorClass),
)}
>
<div className={cx(props.kcLabelWrapperClass)}>
<label htmlFor="password-confirm" className={cx(props.kcLabelClass)}>
{msg("passwordConfirm")}
</label>
</div>
</>
)}
{recaptchaRequired && (
<div className="form-group">
<div className={cx(props.kcInputWrapperClass)}>
<div
className="g-recaptcha"
data-size="compact"
data-sitekey={recaptchaSiteKey}
></div>
<input type="password" id="password-confirm" className={cx(props.kcInputClass)} name="password-confirm" />
</div>
</div>
)}
<div className={cx(props.kcFormGroupClass)}>
<div
id="kc-form-options"
className={cx(props.kcFormOptionsClass)}
>
<div
className={cx(
props.kcFormOptionsWrapperClass,
)}
>
<span>
<a href={url.loginUrl}>
{msg("backToLogin")}
</a>
</span>
</div>
</div>
<div
id="kc-form-buttons"
className={cx(props.kcFormButtonsClass)}
>
<input
className={cx(
props.kcButtonClass,
props.kcButtonPrimaryClass,
props.kcButtonBlockClass,
props.kcButtonLargeClass,
)}
type="submit"
value={msgStr("doRegister")}
/>
</>
)}
{recaptchaRequired && (
<div className="form-group">
<div className={cx(props.kcInputWrapperClass)}>
<div className="g-recaptcha" data-size="compact" data-sitekey={recaptchaSiteKey}></div>
</div>
</div>
</form>
}
/>
);
},
);
)}
<div className={cx(props.kcFormGroupClass)}>
<div id="kc-form-options" className={cx(props.kcFormOptionsClass)}>
<div className={cx(props.kcFormOptionsWrapperClass)}>
<span>
<a href={url.loginUrl}>{msg("backToLogin")}</a>
</span>
</div>
</div>
<div id="kc-form-buttons" className={cx(props.kcFormButtonsClass)}>
<input
className={cx(props.kcButtonClass, props.kcButtonPrimaryClass, props.kcButtonBlockClass, props.kcButtonLargeClass)}
type="submit"
value={msgStr("doRegister")}
/>
</div>
</div>
</form>
}
/>
);
});

View File

@ -6,216 +6,115 @@ import { useKcMessage } from "../i18n/useKcMessage";
import { useCssAndCx } from "tss-react";
import type { ReactComponent } from "../tools/ReactComponent";
export const RegisterUserProfile = memo(
({
kcContext,
...props
}: { kcContext: KcContextBase.RegisterUserProfile } & KcProps) => {
const {
url,
messagesPerField,
realm,
passwordRequired,
recaptchaRequired,
recaptchaSiteKey,
} = kcContext;
export const RegisterUserProfile = memo(({ kcContext, ...props }: { kcContext: KcContextBase.RegisterUserProfile } & KcProps) => {
const { url, messagesPerField, realm, passwordRequired, recaptchaRequired, recaptchaSiteKey } = kcContext;
const { msg, msgStr } = useKcMessage();
const { msg, msgStr } = useKcMessage();
const { cx } = useCssAndCx();
const { cx } = useCssAndCx();
return (
<Template
{...{ kcContext, ...props }}
displayMessage={messagesPerField.exists("global")}
displayRequiredFields={true}
doFetchDefaultThemeResources={true}
headerNode={msg("registerTitle")}
formNode={
<form
id="kc-register-form"
className={cx(props.kcFormClass)}
action={url.registrationAction}
method="post"
>
<UserProfileFormFields
kcContext={kcContext}
{...props}
AfterField={({ attribute }) =>
/*render password fields just under the username or email (if used as username)*/
(passwordRequired &&
(attribute.name == "username" ||
(attribute.name == "email" &&
realm.registrationEmailAsUsername)) && (
<>
<div
className={cx(
props.kcFormGroupClass,
)}
>
<div
className={cx(
props.kcLabelWrapperClass,
)}
>
<label
htmlFor="password"
className={cx(
props.kcLabelClass,
)}
>
{msg("password")}
</label>{" "}
*
</div>
<div
className={cx(
props.kcInputWrapperClass,
)}
>
<input
type="password"
id="password"
className={cx(
props.kcInputClass,
)}
name="password"
autoComplete="new-password"
aria-invalid={
messagesPerField.existsError(
"password",
) ||
messagesPerField.existsError(
"password-confirm",
)
}
/>
{messagesPerField.existsError(
"password",
) && (
<span
id="input-error-password"
className={cx(
props.kcInputErrorMessageClass,
)}
aria-live="polite"
>
{messagesPerField.get(
"password",
)}
</span>
)}
</div>
return (
<Template
{...{ kcContext, ...props }}
displayMessage={messagesPerField.exists("global")}
displayRequiredFields={true}
doFetchDefaultThemeResources={true}
headerNode={msg("registerTitle")}
formNode={
<form id="kc-register-form" className={cx(props.kcFormClass)} action={url.registrationAction} method="post">
<UserProfileFormFields
kcContext={kcContext}
{...props}
AfterField={({ attribute }) =>
/*render password fields just under the username or email (if used as username)*/
(passwordRequired &&
(attribute.name == "username" || (attribute.name == "email" && realm.registrationEmailAsUsername)) && (
<>
<div className={cx(props.kcFormGroupClass)}>
<div className={cx(props.kcLabelWrapperClass)}>
<label htmlFor="password" className={cx(props.kcLabelClass)}>
{msg("password")}
</label>{" "}
*
</div>
<div
className={cx(
props.kcFormGroupClass,
<div className={cx(props.kcInputWrapperClass)}>
<input
type="password"
id="password"
className={cx(props.kcInputClass)}
name="password"
autoComplete="new-password"
aria-invalid={
messagesPerField.existsError("password") || messagesPerField.existsError("password-confirm")
}
/>
{messagesPerField.existsError("password") && (
<span id="input-error-password" className={cx(props.kcInputErrorMessageClass)} aria-live="polite">
{messagesPerField.get("password")}
</span>
)}
>
<div
className={cx(
props.kcLabelWrapperClass,
)}
>
<label
htmlFor="password-confirm"
className={cx(
props.kcLabelClass,
)}
>
{msg("passwordConfirm")}
</label>{" "}
*
</div>
<div
className={cx(
props.kcInputWrapperClass,
)}
>
<input
type="password"
id="password-confirm"
className={cx(
props.kcInputClass,
)}
name="password-confirm"
aria-invalid={messagesPerField.existsError(
"password-confirm",
)}
/>
{messagesPerField.existsError(
"password-confirm",
) && (
<span
id="input-error-password-confirm"
className={cx(
props.kcInputErrorMessageClass,
)}
aria-live="polite"
>
{messagesPerField.get(
"password-confirm",
)}
</span>
)}
</div>
</div>
</>
)) ||
null
}
/>
{recaptchaRequired && (
<div className="form-group">
<div className={cx(props.kcInputWrapperClass)}>
<div
className="g-recaptcha"
data-size="compact"
data-sitekey={recaptchaSiteKey}
/>
</div>
</div>
)}
<div className={cx(props.kcFormGroupClass)}>
<div
id="kc-form-options"
className={cx(props.kcFormOptionsClass)}
>
<div
className={cx(
props.kcFormOptionsWrapperClass,
)}
>
<span>
<a href={url.loginUrl}>
{msg("backToLogin")}
</a>
</span>
</div>
</div>
<div
id="kc-form-buttons"
className={cx(props.kcFormButtonsClass)}
>
<input
className={cx(
props.kcButtonClass,
props.kcButtonPrimaryClass,
props.kcButtonBlockClass,
props.kcButtonLargeClass,
)}
type="submit"
value={msgStr("doRegister")}
/>
</div>
<div className={cx(props.kcFormGroupClass)}>
<div className={cx(props.kcLabelWrapperClass)}>
<label htmlFor="password-confirm" className={cx(props.kcLabelClass)}>
{msg("passwordConfirm")}
</label>{" "}
*
</div>
<div className={cx(props.kcInputWrapperClass)}>
<input
type="password"
id="password-confirm"
className={cx(props.kcInputClass)}
name="password-confirm"
aria-invalid={messagesPerField.existsError("password-confirm")}
/>
{messagesPerField.existsError("password-confirm") && (
<span
id="input-error-password-confirm"
className={cx(props.kcInputErrorMessageClass)}
aria-live="polite"
>
{messagesPerField.get("password-confirm")}
</span>
)}
</div>
</div>
</>
)) ||
null
}
/>
{recaptchaRequired && (
<div className="form-group">
<div className={cx(props.kcInputWrapperClass)}>
<div className="g-recaptcha" data-size="compact" data-sitekey={recaptchaSiteKey} />
</div>
</div>
</form>
}
/>
);
},
);
)}
<div className={cx(props.kcFormGroupClass)}>
<div id="kc-form-options" className={cx(props.kcFormOptionsClass)}>
<div className={cx(props.kcFormOptionsWrapperClass)}>
<span>
<a href={url.loginUrl}>{msg("backToLogin")}</a>
</span>
</div>
</div>
<div id="kc-form-buttons" className={cx(props.kcFormButtonsClass)}>
<input
className={cx(props.kcButtonClass, props.kcButtonPrimaryClass, props.kcButtonBlockClass, props.kcButtonLargeClass)}
type="submit"
value={msgStr("doRegister")}
/>
</div>
</div>
</form>
}
/>
);
});
const UserProfileFormFields = memo(
({
@ -243,13 +142,11 @@ const UserProfileFormFields = memo(
return (
<>
{kcContext.profile.attributes.map((attribute, i) => {
const {
group = "",
groupDisplayHeader = "",
groupDisplayDescription = "",
} = attribute;
const { group = "", groupDisplayHeader = "", groupDisplayDescription = "" } = attribute;
if (group === currentGroup) return null;
console.log(JSON.stringify(attribute, null, 2));
//if (group === currentGroup) return null;
currentGroup = group;
@ -257,39 +154,15 @@ const UserProfileFormFields = memo(
<Fragment key={i}>
{group !== "" && (
<div className={cx(props.kcFormGroupClass)}>
<div
className={cx(
props.kcContentWrapperClass,
)}
>
<label
id={`header-${group}`}
className={cx(
props.kcFormGroupHeader,
)}
>
{(groupDisplayHeader !== "" &&
advancedMsg(
groupDisplayHeader,
)) ||
currentGroup}
<div className={cx(props.kcContentWrapperClass)}>
<label id={`header-${group}`} className={cx(props.kcFormGroupHeader)}>
{(groupDisplayHeader !== "" && advancedMsg(groupDisplayHeader)) || currentGroup}
</label>
</div>
{groupDisplayDescription !== "" && (
<div
className={cx(
props.kcLabelWrapperClass,
)}
>
<label
id={`description-${group}`}
className={`${cx(
props.kcLabelClass,
)}`}
>
{advancedMsg(
groupDisplayDescription,
) ?? ""}
<div className={cx(props.kcLabelWrapperClass)}>
<label id={`description-${group}`} className={`${cx(props.kcLabelClass)}`}>
{advancedMsg(groupDisplayDescription) ?? ""}
</label>
</div>
)}
@ -298,13 +171,8 @@ const UserProfileFormFields = memo(
<BeforeField attribute={attribute} />
<div className={cx(props.kcFormGroupClass)}>
<div className={cx(props.kcLabelWrapperClass)}>
<label
htmlFor={attribute.name}
className={cx(props.kcLabelClass)}
>
{advancedMsg(
attribute.displayName ?? "",
)}
<label htmlFor={attribute.name} className={cx(props.kcLabelClass)}>
{advancedMsg(attribute.displayName ?? "")}
</label>
{attribute.required && <>*</>}
</div>
@ -313,33 +181,19 @@ const UserProfileFormFields = memo(
type="text"
id={attribute.name}
name={attribute.name}
value={attribute.value ?? ""}
defaultValue={attribute.value ?? ""}
className={cx(props.kcInputClass)}
aria-invalid={messagesPerField.existsError(
attribute.name,
)}
aria-invalid={messagesPerField.existsError(attribute.name)}
disabled={attribute.readOnly}
{...(attribute.autocomplete ===
undefined
{...(attribute.autocomplete === undefined
? {}
: {
"autoComplete":
attribute.autocomplete,
"autoComplete": attribute.autocomplete,
})}
/>
{kcContext.messagesPerField.existsError(
attribute.name,
) && (
<span
id={`input-error-${attribute.name}`}
className={cx(
props.kcInputErrorMessageClass,
)}
aria-live="polite"
>
{messagesPerField.get(
attribute.name,
)}
{kcContext.messagesPerField.existsError(attribute.name) && (
<span id={`input-error-${attribute.name}`} className={cx(props.kcInputErrorMessageClass)} aria-live="polite">
{messagesPerField.get(attribute.name)}
</span>
)}
</div>

View File

@ -55,19 +55,11 @@ export const Template = memo((props: TemplateProps) => {
const { kcLanguageTag, setKcLanguageTag } = useKcLanguageTag();
const onChangeLanguageClickFactory = useCallbackFactory(
([languageTag]: [KcLanguageTag]) => setKcLanguageTag(languageTag),
);
const onChangeLanguageClickFactory = useCallbackFactory(([languageTag]: [KcLanguageTag]) => setKcLanguageTag(languageTag));
const onTryAnotherWayClick = useConstCallback(
() => (
document.forms["kc-select-try-another-way-form" as never].submit(),
false
),
);
const onTryAnotherWayClick = useConstCallback(() => (document.forms["kc-select-try-another-way-form" as never].submit(), false));
const { realm, locale, auth, url, message, isAppInitiatedAction } =
kcContext;
const { realm, locale, auth, url, message, isAppInitiatedAction } = kcContext;
useEffect(() => {
if (!realm.internationalizationEnabled) {
@ -80,9 +72,7 @@ export const Template = memo((props: TemplateProps) => {
return;
}
window.location.href = locale.supported.find(
({ languageTag }) => languageTag === kcLanguageTag,
)!.url;
window.location.href = locale.supported.find(({ languageTag }) => languageTag === kcLanguageTag)!.url;
}, [kcLanguageTag]);
const [isExtraCssLoaded, setExtraCssLoaded] = useReducer(() => true, false);
@ -96,17 +86,12 @@ export const Template = memo((props: TemplateProps) => {
let isUnmounted = false;
const cleanups: (() => void)[] = [];
const toArr = (x: string | readonly string[] | undefined) =>
typeof x === "string" ? x.split(" ") : x ?? [];
const toArr = (x: string | readonly string[] | undefined) => (typeof x === "string" ? x.split(" ") : x ?? []);
Promise.all(
[
...toArr(props.stylesCommon).map(relativePath =>
pathJoin(url.resourcesCommonPath, relativePath),
),
...toArr(props.styles).map(relativePath =>
pathJoin(url.resourcesPath, relativePath),
),
...toArr(props.stylesCommon).map(relativePath => pathJoin(url.resourcesCommonPath, relativePath)),
...toArr(props.styles).map(relativePath => pathJoin(url.resourcesPath, relativePath)),
].map(href =>
appendHead({
"type": "css",
@ -129,8 +114,7 @@ export const Template = memo((props: TemplateProps) => {
);
if (props.kcHtmlClass !== undefined) {
const htmlClassList =
document.getElementsByTagName("html")[0].classList;
const htmlClassList = document.getElementsByTagName("html")[0].classList;
const tokens = cx(props.kcHtmlClass).split(" ");
@ -153,76 +137,37 @@ export const Template = memo((props: TemplateProps) => {
return (
<div className={cx(props.kcLoginClass)}>
<div id="kc-header" className={cx(props.kcHeaderClass)}>
<div
id="kc-header-wrapper"
className={cx(props.kcHeaderWrapperClass)}
>
<div id="kc-header-wrapper" className={cx(props.kcHeaderWrapperClass)}>
{msg("loginTitleHtml", realm.displayNameHtml)}
</div>
</div>
<div
className={cx(
props.kcFormCardClass,
displayWide && props.kcFormCardAccountClass,
)}
>
<div className={cx(props.kcFormCardClass, displayWide && props.kcFormCardAccountClass)}>
<header className={cx(props.kcFormHeaderClass)}>
{realm.internationalizationEnabled &&
(assert(locale !== undefined), true) &&
locale.supported.length > 1 && (
<div id="kc-locale">
<div
id="kc-locale-wrapper"
className={cx(props.kcLocaleWrapperClass)}
>
<div
className="kc-dropdown"
id="kc-locale-dropdown"
>
<a href="#" id="kc-current-locale-link">
{getKcLanguageTagLabel(
kcLanguageTag,
)}
</a>
<ul>
{locale.supported.map(
({ languageTag }) => (
<li
key={languageTag}
className="kc-dropdown-item"
>
<a
href="#"
onClick={onChangeLanguageClickFactory(
languageTag,
)}
>
{getKcLanguageTagLabel(
languageTag,
)}
</a>
</li>
),
)}
</ul>
</div>
{realm.internationalizationEnabled && (assert(locale !== undefined), true) && locale.supported.length > 1 && (
<div id="kc-locale">
<div id="kc-locale-wrapper" className={cx(props.kcLocaleWrapperClass)}>
<div className="kc-dropdown" id="kc-locale-dropdown">
<a href="#" id="kc-current-locale-link">
{getKcLanguageTagLabel(kcLanguageTag)}
</a>
<ul>
{locale.supported.map(({ languageTag }) => (
<li key={languageTag} className="kc-dropdown-item">
<a href="#" onClick={onChangeLanguageClickFactory(languageTag)}>
{getKcLanguageTagLabel(languageTag)}
</a>
</li>
))}
</ul>
</div>
</div>
)}
{!(
auth !== undefined &&
auth.showUsername &&
!auth.showResetCredentials
) ? (
</div>
)}
{!(auth !== undefined && auth.showUsername && !auth.showResetCredentials) ? (
displayRequiredFields ? (
<div className={cx(props.kcContentWrapperClass)}>
<div
className={cx(
props.kcLabelWrapperClass,
"subtitle",
)}
>
<div className={cx(props.kcLabelWrapperClass, "subtitle")}>
<span className="subtitle">
<span className="required">*</span>
{msg("requiredFields")}
@ -237,37 +182,20 @@ export const Template = memo((props: TemplateProps) => {
)
) : displayRequiredFields ? (
<div className={cx(props.kcContentWrapperClass)}>
<div
className={cx(
props.kcLabelWrapperClass,
"subtitle",
)}
>
<div className={cx(props.kcLabelWrapperClass, "subtitle")}>
<span className="subtitle">
<span className="required">*</span>{" "}
{msg("requiredFields")}
<span className="required">*</span> {msg("requiredFields")}
</span>
</div>
<div className="col-md-10">
{showUsernameNode}
<div className={cx(props.kcFormGroupClass)}>
<div id="kc-username">
<label id="kc-attempted-username">
{auth?.attemptedUsername}
</label>
<a
id="reset-login"
href={url.loginRestartFlowUrl}
>
<label id="kc-attempted-username">{auth?.attemptedUsername}</label>
<a id="reset-login" href={url.loginRestartFlowUrl}>
<div className="kc-login-tooltip">
<i
className={cx(
props.kcResetFlowIcon,
)}
></i>
<span className="kc-tooltip-text">
{msg("restartLoginTooltip")}
</span>
<i className={cx(props.kcResetFlowIcon)}></i>
<span className="kc-tooltip-text">{msg("restartLoginTooltip")}</span>
</div>
</a>
</div>
@ -279,22 +207,11 @@ export const Template = memo((props: TemplateProps) => {
{showUsernameNode}
<div className={cx(props.kcFormGroupClass)}>
<div id="kc-username">
<label id="kc-attempted-username">
{auth?.attemptedUsername}
</label>
<a
id="reset-login"
href={url.loginRestartFlowUrl}
>
<label id="kc-attempted-username">{auth?.attemptedUsername}</label>
<a id="reset-login" href={url.loginRestartFlowUrl}>
<div className="kc-login-tooltip">
<i
className={cx(
props.kcResetFlowIcon,
)}
></i>
<span className="kc-tooltip-text">
{msg("restartLoginTooltip")}
</span>
<i className={cx(props.kcResetFlowIcon)}></i>
<span className="kc-tooltip-text">{msg("restartLoginTooltip")}</span>
</div>
</a>
</div>
@ -305,103 +222,41 @@ export const Template = memo((props: TemplateProps) => {
<div id="kc-content">
<div id="kc-content-wrapper">
{/* App-initiated actions should not see warning messages about the need to complete the action during login. */}
{displayMessage &&
message !== undefined &&
(message.type !== "warning" ||
!isAppInitiatedAction) && (
<div
className={cx(
"alert",
`alert-${message.type}`,
)}
>
{message.type === "success" && (
<span
className={cx(
props.kcFeedbackSuccessIcon,
)}
></span>
)}
{message.type === "warning" && (
<span
className={cx(
props.kcFeedbackWarningIcon,
)}
></span>
)}
{message.type === "error" && (
<span
className={cx(
props.kcFeedbackErrorIcon,
)}
></span>
)}
{message.type === "info" && (
<span
className={cx(
props.kcFeedbackInfoIcon,
)}
></span>
)}
<span
className="kc-feedback-text"
dangerouslySetInnerHTML={{
"__html": message.summary,
}}
/>
</div>
)}
{displayMessage && message !== undefined && (message.type !== "warning" || !isAppInitiatedAction) && (
<div className={cx("alert", `alert-${message.type}`)}>
{message.type === "success" && <span className={cx(props.kcFeedbackSuccessIcon)}></span>}
{message.type === "warning" && <span className={cx(props.kcFeedbackWarningIcon)}></span>}
{message.type === "error" && <span className={cx(props.kcFeedbackErrorIcon)}></span>}
{message.type === "info" && <span className={cx(props.kcFeedbackInfoIcon)}></span>}
<span
className="kc-feedback-text"
dangerouslySetInnerHTML={{
"__html": message.summary,
}}
/>
</div>
)}
{formNode}
{auth !== undefined &&
auth.showTryAnotherWayLink &&
showAnotherWayIfPresent && (
<form
id="kc-select-try-another-way-form"
action={url.loginAction}
method="post"
className={cx(
displayWide &&
props.kcContentWrapperClass,
)}
>
<div
className={cx(
displayWide && [
props.kcFormSocialAccountContentClass,
props.kcFormSocialAccountClass,
],
)}
>
<div
className={cx(
props.kcFormGroupClass,
)}
>
<input
type="hidden"
name="tryAnotherWay"
value="on"
/>
<a
href="#"
id="try-another-way"
onClick={onTryAnotherWayClick}
>
{msg("doTryAnotherWay")}
</a>
</div>
</div>
</form>
)}
{displayInfo && (
<div
id="kc-info"
className={cx(props.kcSignUpClass)}
{auth !== undefined && auth.showTryAnotherWayLink && showAnotherWayIfPresent && (
<form
id="kc-select-try-another-way-form"
action={url.loginAction}
method="post"
className={cx(displayWide && props.kcContentWrapperClass)}
>
<div
id="kc-info-wrapper"
className={cx(props.kcInfoAreaWrapperClass)}
>
<div className={cx(displayWide && [props.kcFormSocialAccountContentClass, props.kcFormSocialAccountClass])}>
<div className={cx(props.kcFormGroupClass)}>
<input type="hidden" name="tryAnotherWay" value="on" />
<a href="#" id="try-another-way" onClick={onTryAnotherWayClick}>
{msg("doTryAnotherWay")}
</a>
</div>
</div>
</form>
)}
{displayInfo && (
<div id="kc-info" className={cx(props.kcSignUpClass)}>
<div id="kc-info-wrapper" className={cx(props.kcInfoAreaWrapperClass)}>
{infoNode}
</div>
</div>

View File

@ -5,57 +5,47 @@ import type { KcContextBase } from "../getKcContext/KcContextBase";
import { useKcMessage } from "../i18n/useKcMessage";
import { useCssAndCx } from "tss-react";
export const Terms = memo(
({ kcContext, ...props }: { kcContext: KcContextBase.Terms } & KcProps) => {
const { msg, msgStr } = useKcMessage();
export const Terms = memo(({ kcContext, ...props }: { kcContext: KcContextBase.Terms } & KcProps) => {
const { msg, msgStr } = useKcMessage();
const { cx } = useCssAndCx();
const { cx } = useCssAndCx();
const { url } = kcContext;
const { url } = kcContext;
return (
<Template
{...{ kcContext, ...props }}
doFetchDefaultThemeResources={true}
displayMessage={false}
headerNode={msg("termsTitle")}
formNode={
<>
<div id="kc-terms-text">{msg("termsText")}</div>
<form
className="form-actions"
action={url.loginAction}
method="POST"
>
<input
className={cx(
props.kcButtonClass,
props.kcButtonClass,
props.kcButtonClass,
props.kcButtonPrimaryClass,
props.kcButtonLargeClass,
)}
name="accept"
id="kc-accept"
type="submit"
value={msgStr("doAccept")}
/>
<input
className={cx(
props.kcButtonClass,
props.kcButtonDefaultClass,
props.kcButtonLargeClass,
)}
name="cancel"
id="kc-decline"
type="submit"
value={msgStr("doDecline")}
/>
</form>
<div className="clearfix" />
</>
}
/>
);
},
);
return (
<Template
{...{ kcContext, ...props }}
doFetchDefaultThemeResources={true}
displayMessage={false}
headerNode={msg("termsTitle")}
formNode={
<>
<div id="kc-terms-text">{msg("termsText")}</div>
<form className="form-actions" action={url.loginAction} method="POST">
<input
className={cx(
props.kcButtonClass,
props.kcButtonClass,
props.kcButtonClass,
props.kcButtonPrimaryClass,
props.kcButtonLargeClass,
)}
name="accept"
id="kc-accept"
type="submit"
value={msgStr("doAccept")}
/>
<input
className={cx(props.kcButtonClass, props.kcButtonDefaultClass, props.kcButtonLargeClass)}
name="cancel"
id="kc-decline"
type="submit"
value={msgStr("doDecline")}
/>
</form>
<div className="clearfix" />
</>
}
/>
);
});