Remove eslint and run prettier (changelog ignore)

This commit is contained in:
garronej
2021-10-11 21:35:40 +02:00
parent 9f8218efb7
commit 305ce9e44d
76 changed files with 27255 additions and 22419 deletions

View File

@ -4,33 +4,31 @@ 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();
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>
}
/>
);
});
export const Error = memo(
({ kcContext, ...props }: { kcContext: KcContextBase.Error } & KcProps) => {
const { msg } = useKcMessage();
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>
}
/>
);
},
);

View File

@ -1,4 +1,3 @@
import { memo } from "react";
import { Template } from "./Template";
import type { KcProps } from "./KcProps";
@ -6,68 +5,75 @@ 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) => {
export const Info = memo(
({ kcContext, ...props }: { kcContext: KcContextBase.Info } & KcProps) => {
const { msg } = useKcMessage();
const { msg } = useKcMessage();
assert(kcContext.message !== undefined);
assert(kcContext.message !== undefined);
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}
{
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>
}
</div>
}
/>
);
});
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}
{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>
)
)}
</div>
}
/>
);
},
);

View File

@ -1,4 +1,3 @@
import { memo } from "react";
import type { KcContextBase } from "../getKcContext/KcContextBase";
import type { KcProps } from "./KcProps";
@ -14,18 +13,31 @@ 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

@ -1,39 +1,39 @@
import { allPropertiesValuesToUndefined } from "../tools/allPropertiesValuesToUndefined";
import { assert } from "tsafe/assert";
import { assert } from "tsafe/assert";
/** Class names can be provided as an array or separated by whitespace */
export type KcPropsGeneric<CssClasses extends string> = { [key in CssClasses]: readonly string[] | string | undefined; };
export type KcPropsGeneric<CssClasses extends string> = {
[key in CssClasses]: readonly string[] | string | undefined;
};
export type KcTemplateClassKey =
"stylesCommon" |
"styles" |
"scripts" |
"kcHtmlClass" |
"kcLoginClass" |
"kcHeaderClass" |
"kcHeaderWrapperClass" |
"kcFormCardClass" |
"kcFormCardAccountClass" |
"kcFormHeaderClass" |
"kcLocaleWrapperClass" |
"kcContentWrapperClass" |
"kcLabelWrapperClass" |
"kcContentWrapperClass" |
"kcLabelWrapperClass" |
"kcFormGroupClass" |
"kcResetFlowIcon" |
"kcResetFlowIcon" |
"kcFeedbackSuccessIcon" |
"kcFeedbackWarningIcon" |
"kcFeedbackErrorIcon" |
"kcFeedbackInfoIcon" |
"kcContentWrapperClass" |
"kcFormSocialAccountContentClass" |
"kcFormSocialAccountClass" |
"kcSignUpClass" |
"kcInfoAreaWrapperClass"
;
| "stylesCommon"
| "styles"
| "scripts"
| "kcHtmlClass"
| "kcLoginClass"
| "kcHeaderClass"
| "kcHeaderWrapperClass"
| "kcFormCardClass"
| "kcFormCardAccountClass"
| "kcFormHeaderClass"
| "kcLocaleWrapperClass"
| "kcContentWrapperClass"
| "kcLabelWrapperClass"
| "kcContentWrapperClass"
| "kcLabelWrapperClass"
| "kcFormGroupClass"
| "kcResetFlowIcon"
| "kcResetFlowIcon"
| "kcFeedbackSuccessIcon"
| "kcFeedbackWarningIcon"
| "kcFeedbackErrorIcon"
| "kcFeedbackInfoIcon"
| "kcContentWrapperClass"
| "kcFormSocialAccountContentClass"
| "kcFormSocialAccountClass"
| "kcSignUpClass"
| "kcInfoAreaWrapperClass";
export type KcTemplateProps = KcPropsGeneric<KcTemplateClassKey>;
@ -41,7 +41,7 @@ export const defaultKcTemplateProps = {
"stylesCommon": [
"node_modules/patternfly/dist/css/patternfly.min.css",
"node_modules/patternfly/dist/css/patternfly-additions.min.css",
"lib/zocial/zocial.css"
"lib/zocial/zocial.css",
],
"styles": ["css/login.css"],
"scripts": [],
@ -64,69 +64,69 @@ export const defaultKcTemplateProps = {
"kcFormGroupClass": ["form-group"],
"kcLabelWrapperClass": ["col-xs-12", "col-sm-12", "col-md-12", "col-lg-12"],
"kcSignUpClass": ["login-pf-signup"],
"kcInfoAreaWrapperClass": []
"kcInfoAreaWrapperClass": [],
} as const;
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>();
assert<typeof allClearKcTemplateProps extends KcTemplateProps ? true : false>();
export type KcProps = KcPropsGeneric<
KcTemplateClassKey |
"kcLogoLink" |
"kcLogoClass" |
"kcContainerClass" |
"kcContentClass" |
"kcFeedbackAreaClass" |
"kcLocaleClass" |
"kcAlertIconClasserror" |
"kcFormAreaClass" |
"kcFormSocialAccountListClass" |
"kcFormSocialAccountDoubleListClass" |
"kcFormSocialAccountListLinkClass" |
"kcWebAuthnKeyIcon" |
"kcFormClass" |
"kcFormGroupErrorClass" |
"kcLabelClass" |
"kcInputClass" |
"kcInputErrorMessageClass" |
"kcInputWrapperClass" |
"kcFormOptionsClass" |
"kcFormButtonsClass" |
"kcFormSettingClass" |
"kcTextareaClass" |
"kcInfoAreaClass" |
"kcFormGroupHeader" |
"kcButtonClass" |
"kcButtonPrimaryClass" |
"kcButtonDefaultClass" |
"kcButtonLargeClass" |
"kcButtonBlockClass" |
"kcInputLargeClass" |
"kcSrOnlyClass" |
"kcSelectAuthListClass" |
"kcSelectAuthListItemClass" |
"kcSelectAuthListItemInfoClass" |
"kcSelectAuthListItemLeftClass" |
"kcSelectAuthListItemBodyClass" |
"kcSelectAuthListItemDescriptionClass" |
"kcSelectAuthListItemHeadingClass" |
"kcSelectAuthListItemHelpTextClass" |
"kcAuthenticatorDefaultClass" |
"kcAuthenticatorPasswordClass" |
"kcAuthenticatorOTPClass" |
"kcAuthenticatorWebAuthnClass" |
"kcAuthenticatorWebAuthnPasswordlessClass" |
"kcSelectOTPListClass" |
"kcSelectOTPListItemClass" |
"kcAuthenticatorOtpCircleClass" |
"kcSelectOTPItemHeadingClass" |
"kcFormOptionsWrapperClass"
| KcTemplateClassKey
| "kcLogoLink"
| "kcLogoClass"
| "kcContainerClass"
| "kcContentClass"
| "kcFeedbackAreaClass"
| "kcLocaleClass"
| "kcAlertIconClasserror"
| "kcFormAreaClass"
| "kcFormSocialAccountListClass"
| "kcFormSocialAccountDoubleListClass"
| "kcFormSocialAccountListLinkClass"
| "kcWebAuthnKeyIcon"
| "kcFormClass"
| "kcFormGroupErrorClass"
| "kcLabelClass"
| "kcInputClass"
| "kcInputErrorMessageClass"
| "kcInputWrapperClass"
| "kcFormOptionsClass"
| "kcFormButtonsClass"
| "kcFormSettingClass"
| "kcTextareaClass"
| "kcInfoAreaClass"
| "kcFormGroupHeader"
| "kcButtonClass"
| "kcButtonPrimaryClass"
| "kcButtonDefaultClass"
| "kcButtonLargeClass"
| "kcButtonBlockClass"
| "kcInputLargeClass"
| "kcSrOnlyClass"
| "kcSelectAuthListClass"
| "kcSelectAuthListItemClass"
| "kcSelectAuthListItemInfoClass"
| "kcSelectAuthListItemLeftClass"
| "kcSelectAuthListItemBodyClass"
| "kcSelectAuthListItemDescriptionClass"
| "kcSelectAuthListItemHeadingClass"
| "kcSelectAuthListItemHelpTextClass"
| "kcAuthenticatorDefaultClass"
| "kcAuthenticatorPasswordClass"
| "kcAuthenticatorOTPClass"
| "kcAuthenticatorWebAuthnClass"
| "kcAuthenticatorWebAuthnPasswordlessClass"
| "kcSelectOTPListClass"
| "kcSelectOTPListItemClass"
| "kcAuthenticatorOtpCircleClass"
| "kcSelectOTPItemHeadingClass"
| "kcFormOptionsWrapperClass"
>;
export const defaultKcProps = {
@ -134,13 +134,31 @@ 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"],
@ -149,14 +167,25 @@ 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"],
@ -191,21 +220,28 @@ 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"],
"kcFormOptionsWrapperClass": []
"kcFormOptionsWrapperClass": [],
} as const;
assert<typeof defaultKcProps extends KcProps ? true : false>();
/** Tu use if you don't want any default */
export const allClearKcProps =
allPropertiesValuesToUndefined(defaultKcProps);
export const allClearKcProps = allPropertiesValuesToUndefined(defaultKcProps);
assert<typeof allClearKcProps extends KcProps ? true : false>();

View File

@ -1,4 +1,3 @@
import { useState, memo } from "react";
import { Template } from "./Template";
import type { KcProps } from "./KcProps";
@ -7,151 +6,241 @@ 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) => {
export const Login = memo(
({ kcContext, ...props }: { kcContext: KcContextBase.Login } & KcProps) => {
const {
social,
realm,
url,
usernameEditDisabled,
login,
auth,
registrationDisabled,
} = kcContext;
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={
<div
id="kc-form"
className={cx(realm.password && social.providers !== undefined && props.kcContentWrapperClass)}
>
return (
<Template
{...{ kcContext, ...props }}
doFetchDefaultThemeResources={true}
displayInfo={social.displayInfo}
displayWide={realm.password && social.providers !== undefined}
headerNode={msg("doLogIn")}
formNode={
<div
id="kc-form-wrapper"
className={cx(realm.password && social.providers && [props.kcFormSocialAccountContentClass, props.kcFormSocialAccountClass])}
>
{
id="kc-form"
className={cx(
realm.password &&
(
<form id="kc-form-login" onSubmit={onSubmit} action={url.loginAction} method="post">
social.providers !== undefined &&
props.kcContentWrapperClass,
)}
>
<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
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 ?? ''}
defaultValue={login.username ?? ""}
type="text"
{...(usernameEditDisabled ? { "disabled": true } : { "autoFocus": true, "autoComplete": "off" })}
{...(usernameEditDisabled
? { "disabled": true }
: {
"autoFocus": true,
"autoComplete": "off",
})}
/>
</div>
<div className={cx(props.kcFormGroupClass)}>
<label htmlFor="password" className={cx(props.kcLabelClass)}>
<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" />
<input
tabIndex={2}
id="password"
className={cx(props.kcInputClass)}
name="password"
type="password"
autoComplete="off"
/>
</div>
<div className={cx(props.kcFormGroupClass, props.kcFormSettingClass)}>
<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>
}
{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 &&
<div
className={cx(
props.kcFormOptionsWrapperClass,
)}
>
{realm.resetPasswordAllowed && (
<span>
<a tabIndex={5} href={url.loginResetCredentialsUrl}>{msg("doForgotPassword")}</a>
<a
tabIndex={5}
href={
url.loginResetCredentialsUrl
}
>
{msg(
"doForgotPassword",
)}
</a>
</span>
}
)}
</div>
</div>
<div id="kc-form-buttons" className={cx(props.kcFormGroupClass)}>
<div
id="kc-form-buttons"
className={cx(props.kcFormGroupClass)}
>
<input
type="hidden"
id="id-hidden-input"
name="credentialId"
{...(auth?.selectedCredential !== undefined ? { "value": auth.selectedCredential } : {})}
{...(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"
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>
{
(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)}>
)}
</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>
}
infoNode={
(
))}
</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>
}
/>
);
});
!registrationDisabled && (
<div id="kc-registration">
<span>
{msg("noAccount")}
<a tabIndex={6} href={url.registrationUrl}>
{msg("doRegister")}
</a>
</span>
</div>
)
}
/>
);
},
);

View File

@ -1,4 +1,3 @@
import { memo } from "react";
import { Template } from "./Template";
import type { KcProps } from "./KcProps";
@ -6,56 +5,61 @@ 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) => {
export const LoginIdpLinkConfirm = memo(
({
kcContext,
...props
}: { kcContext: KcContextBase.LoginIdpLinkConfirm } & KcProps) => {
const { url, idpAlias } = kcContext;
const { url, idpAlias } = kcContext;
const { msg } = useKcMessage();
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>
}
/>
);
});
const { msg } = useKcMessage();
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>
}
/>
);
},
);

View File

@ -1,5 +1,3 @@
import { useEffect, memo } from "react";
import { Template } from "./Template";
import type { KcProps } from "./KcProps";
@ -9,140 +7,169 @@ 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) => {
export const LoginOtp = memo(
({
kcContext,
...props
}: { kcContext: KcContextBase.LoginOtp } & KcProps) => {
const { otpLogin, url } = kcContext;
const { otpLogin, url } = kcContext;
const { cx } = useCssAndCx();
const { cx } = useCssAndCx();
const { msg, msgStr } = useKcMessage();
useEffect(
() => {
const { msg, msgStr } = useKcMessage();
useEffect(() => {
let isCleanedUp = false;
appendHead({
"type": "javascript",
"src": pathJoin(
kcContext.url.resourcesCommonPath,
"node_modules/jquery/dist/jquery.min.js"
)
"node_modules/jquery/dist/jquery.min.js",
),
}).then(() => {
if (isCleanedUp) return;
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>
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>
</div>
)}
<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
/>
</div>
</div>
}
<div className={cx(props.kcFormGroupClass)}>
<div className={cx(props.kcLabelWrapperClass)}>
<label htmlFor="otp" className={cx(props.kcLabelClass)}>
{msg("loginOtpOneTime")}
</label>
<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>
<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 >
}
/>
);
});
</form>
}
/>
);
},
);
declare const $: any;
function evaluateInlineScript() {
$(document).ready(function () {
// Card Single Select
$('.card-pf-view-single-select').click(function (this: any) {
if ($(this).hasClass('active')) { $(this).removeClass('active'); $(this).children().removeAttr('name'); }
else {
$('.card-pf-view-single-select').removeClass('active');
$('.card-pf-view-single-select').children().removeAttr('name');
$(this).addClass('active'); $(this).children().attr('name', 'selectedCredentialId');
$(".card-pf-view-single-select").click(function (this: any) {
if ($(this).hasClass("active")) {
$(this).removeClass("active");
$(this).children().removeAttr("name");
} else {
$(".card-pf-view-single-select").removeClass("active");
$(".card-pf-view-single-select").children().removeAttr("name");
$(this).addClass("active");
$(this).children().attr("name", "selectedCredentialId");
}
});
var defaultCred = $('.card-pf-view-single-select')[0];
var defaultCred = $(".card-pf-view-single-select")[0];
if (defaultCred) {
defaultCred.click();
}
});
}
}

View File

@ -1,4 +1,3 @@
import { memo } from "react";
import { Template } from "./Template";
import type { KcProps } from "./KcProps";
@ -6,78 +5,101 @@ 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) => {
export const LoginResetPassword = memo(
({
kcContext,
...props
}: { kcContext: KcContextBase.LoginResetPassword } & KcProps) => {
const { url, realm, auth } = kcContext;
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
}
/>
</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>
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 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
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>
</div>
</form>
}
infoNode={msg("emailInstruction")}
/>
);
});
</form>
}
infoNode={msg("emailInstruction")}
/>
);
},
);

View File

@ -5,129 +5,200 @@ 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) => {
export const LoginUpdateProfile = memo(
({
kcContext,
...props
}: { kcContext: KcContextBase.LoginUpdateProfile } & KcProps) => {
const { cx } = useCssAndCx();
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)}>
<input
type="text"
id="username"
name="username"
defaultValue={user.username ?? ""}
className={cx(props.kcInputClass)}
/>
</div>
</div>
)}
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("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("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)}
type="submit"
defaultValue={msgStr("doSubmit")}
/>
}
</div>
</div>
</form>
}
/>
);
});
<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,
)}
type="submit"
defaultValue={msgStr("doSubmit")}
/>
)}
</div>
</div>
</form>
}
/>
);
},
);

View File

@ -1,39 +1,37 @@
import { memo } from "react";
import { Template } from "./Template";
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();
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>
</>
}
/>
);
});
export const LoginVerifyEmail = memo(
({
kcContext,
...props
}: { kcContext: KcContextBase.LoginVerifyEmail } & KcProps) => {
const { msg } = useKcMessage();
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>
</>
}
/>
);
},
);

View File

@ -5,122 +5,279 @@ 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) => {
export const Register = memo(
({
kcContext,
...props
}: { kcContext: KcContextBase.Register } & KcProps) => {
const {
url,
messagesPerField,
register,
realm,
passwordRequired,
recaptchaRequired,
recaptchaSiteKey,
} = kcContext;
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))}>
<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))}>
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="username" className={cx(props.kcLabelClass)}>{msg("username")}</label>
<label
htmlFor="firstName"
className={cx(props.kcLabelClass)}
>
{msg("firstName")}
</label>
</div>
<div className={cx(props.kcInputWrapperClass)}>
<input type="text" id="username" className={cx(props.kcInputClass)} name="username"
defaultValue={register.formData.username ?? ""} autoComplete="username" />
<input
type="text"
id="firstName"
className={cx(props.kcInputClass)}
name="firstName"
defaultValue={
register.formData.firstName ?? ""
}
/>
</div>
</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
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.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>
</>
}
{
recaptchaRequired &&
<div className="form-group">
<div className={cx(props.kcInputWrapperClass)}>
<div className="g-recaptcha" data-size="compact" data-sitekey={recaptchaSiteKey}></div>
</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>
<input
type="text"
id="lastName"
className={cx(props.kcInputClass)}
name="lastName"
defaultValue={
register.formData.lastName ?? ""
}
/>
</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
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>
</div>
</form >
}
/>
);
});
{!realm.registrationEmailAsUsername && (
<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"
className={cx(props.kcInputClass)}
name="username"
defaultValue={
register.formData.username ?? ""
}
autoComplete="username"
/>
</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>
</>
)}
{recaptchaRequired && (
<div className="form-group">
<div className={cx(props.kcInputWrapperClass)}>
<div
className="g-recaptcha"
data-size="compact"
data-sitekey={recaptchaSiteKey}
></div>
</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>
</form>
}
/>
);
},
);

View File

@ -1,4 +1,3 @@
import { memo, Fragment } from "react";
import { Template } from "./Template";
import type { KcProps } from "./KcProps";
@ -7,220 +6,349 @@ 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) => {
export const RegisterUserProfile = memo(
({
kcContext,
...props
}: { kcContext: KcContextBase.RegisterUserProfile } & KcProps) => {
const {
url,
messagesPerField,
realm,
passwordRequired,
recaptchaRequired,
recaptchaSiteKey,
} = kcContext;
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>
</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>
)}
<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>
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>
</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>
}
<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 >
}
/>
);
});
<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(
(
{
kcContext,
BeforeField = () => null,
AfterField = () => null,
...props
}:
{ kcContext: KcContextBase.RegisterUserProfile; } &
KcProps &
Partial<Record<
"BeforeField" | "AfterField",
ReactComponent<{ attribute: KcContextBase.RegisterUserProfile["profile"]["attributes"][number]; }>
>>
) => {
({
kcContext,
BeforeField = () => null,
AfterField = () => null,
...props
}: { kcContext: KcContextBase.RegisterUserProfile } & KcProps &
Partial<
Record<
"BeforeField" | "AfterField",
ReactComponent<{
attribute: KcContextBase.RegisterUserProfile["profile"]["attributes"][number];
}>
>
>) => {
const { messagesPerField } = kcContext;
const { messagesPerField } = kcContext;
const { cx } = useCssAndCx();
const { cx } = useCssAndCx();
const { advancedMsg } = useKcMessage();
const { advancedMsg } = useKcMessage();
let currentGroup = "";
let currentGroup = "";
return (
<>
{kcContext.profile.attributes.map((attribute, i) => {
const {
group = "",
groupDisplayHeader = "",
groupDisplayDescription = "",
} = attribute;
return (
<>
{kcContext.profile.attributes.map((attribute, i) => {
if (group === currentGroup) return null;
const {
group = "",
groupDisplayHeader = "",
groupDisplayDescription = ""
} = attribute;
currentGroup = group;
if (group === currentGroup) return null;
currentGroup = group;
return (
<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}
</label>
</div>
{groupDisplayDescription !== "" &&
<div className={cx(props.kcLabelWrapperClass)}>
<label
id={`description-${group}`}
className={`${cx(props.kcLabelClass)}`}
>
{advancedMsg(groupDisplayDescription) ?? ""}
</label>
</div>
}
</div>}
<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>
{attribute.required && <>*</>}
</div>
<div className={cx(props.kcInputWrapperClass)}>
<input
type="text"
id={attribute.name}
name={attribute.name}
value={attribute.value ?? ""}
className={cx(props.kcInputClass)}
aria-invalid={messagesPerField.existsError(attribute.name)}
disabled={attribute.readOnly}
{...(attribute.autocomplete === undefined ? {} : {
"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)}
</span>
}
</div >
</div >
<AfterField attribute={attribute} />
</Fragment>
);
})}
</>
);
}
);
return (
<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}
</label>
</div>
{groupDisplayDescription !== "" && (
<div
className={cx(
props.kcLabelWrapperClass,
)}
>
<label
id={`description-${group}`}
className={`${cx(
props.kcLabelClass,
)}`}
>
{advancedMsg(
groupDisplayDescription,
) ?? ""}
</label>
</div>
)}
</div>
)}
<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>
{attribute.required && <>*</>}
</div>
<div className={cx(props.kcInputWrapperClass)}>
<input
type="text"
id={attribute.name}
name={attribute.name}
value={attribute.value ?? ""}
className={cx(props.kcInputClass)}
aria-invalid={messagesPerField.existsError(
attribute.name,
)}
disabled={attribute.readOnly}
{...(attribute.autocomplete ===
undefined
? {}
: {
"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,
)}
</span>
)}
</div>
</div>
<AfterField attribute={attribute} />
</Fragment>
);
})}
</>
);
},
);

View File

@ -1,4 +1,3 @@
import { useReducer, useEffect, memo } from "react";
import type { ReactNode } from "react";
import { useKcMessage } from "../i18n/useKcMessage";
@ -29,10 +28,9 @@ export type TemplateProps = {
* to avoid pulling the default theme assets.
*/
doFetchDefaultThemeResources: boolean;
} & { kcContext: KcContextBase; } & KcTemplateProps;
} & { kcContext: KcContextBase } & KcTemplateProps;
export const Template = memo((props: TemplateProps) => {
const {
displayInfo = false,
displayMessage = true,
@ -44,34 +42,34 @@ export const Template = memo((props: TemplateProps) => {
formNode,
infoNode = null,
kcContext,
doFetchDefaultThemeResources
doFetchDefaultThemeResources,
} = props;
const { cx } = useCssAndCx();
useEffect(() => { console.log("Rendering this page with react using keycloakify") }, []);
useEffect(() => {
console.log("Rendering this page with react using keycloakify");
}, []);
const { msg } = useKcMessage();
const { kcLanguageTag, setKcLanguageTag } = useKcLanguageTag();
const onChangeLanguageClickFactory = useCallbackFactory(
([languageTag]: [KcLanguageTag]) =>
setKcLanguageTag(languageTag)
([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) {
return;
}
@ -82,15 +80,14 @@ 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);
useEffect(() => {
if (!doFetchDefaultThemeResources) {
setExtraCssLoaded();
return;
@ -104,50 +101,49 @@ export const Template = memo((props: TemplateProps) => {
Promise.all(
[
...toArr(props.stylesCommon).map(relativePath => pathJoin(url.resourcesCommonPath, relativePath)),
...toArr(props.styles).map(relativePath => pathJoin(url.resourcesPath, relativePath))
].map(href => appendHead({
"type": "css",
href
}))).then(() => {
...toArr(props.stylesCommon).map(relativePath =>
pathJoin(url.resourcesCommonPath, relativePath),
),
...toArr(props.styles).map(relativePath =>
pathJoin(url.resourcesPath, relativePath),
),
].map(href =>
appendHead({
"type": "css",
href,
}),
),
).then(() => {
if (isUnmounted) {
return;
}
if (isUnmounted) {
return;
}
setExtraCssLoaded();
});
setExtraCssLoaded();
});
toArr(props.scripts).forEach(
relativePath => appendHead({
toArr(props.scripts).forEach(relativePath =>
appendHead({
"type": "javascript",
"src": pathJoin(url.resourcesPath, relativePath)
})
"src": pathJoin(url.resourcesPath, relativePath),
}),
);
if (props.kcHtmlClass !== undefined) {
const htmlClassList =
document.getElementsByTagName("html")[0]
.classList;
document.getElementsByTagName("html")[0].classList;
const tokens = cx(props.kcHtmlClass).split(" ")
const tokens = cx(props.kcHtmlClass).split(" ");
htmlClassList.add(...tokens);
cleanups.push(() => htmlClassList.remove(...tokens));
}
return () => {
isUnmounted = true;
cleanups.forEach(f => f());
};
}, [props.kcHtmlClass]);
if (!isExtraCssLoaded) {
@ -156,163 +152,260 @@ 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)}
{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>
),
)}
</ul>
</div>
</div>
</div>
)}
{!(
auth !== undefined &&
auth.showUsername &&
!auth.showResetCredentials
) ? (
displayRequiredFields ? (
<div className={cx(props.kcContentWrapperClass)}>
<div
className={cx(
props.kcLabelWrapperClass,
"subtitle",
)}
>
<span className="subtitle">
<span className="required">*</span>
{msg("requiredFields")}
</span>
</div>
<div className="col-md-10">
<h1 id="kc-page-title">{headerNode}</h1>
</div>
</div>
) : (
<h1 id="kc-page-title">{headerNode}</h1>
)
) : displayRequiredFields ? (
<div className={cx(props.kcContentWrapperClass)}>
<div
className={cx(
props.kcLabelWrapperClass,
"subtitle",
)}
>
<span className="subtitle">
<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}
>
<div className="kc-login-tooltip">
<i
className={cx(
props.kcResetFlowIcon,
)}
></i>
<span className="kc-tooltip-text">
{msg("restartLoginTooltip")}
</span>
</div>
</a>
</div>
</div>
</div>
</div>
}
{
!(
auth !== undefined &&
auth.showUsername &&
!auth.showResetCredentials
) ?
(
displayRequiredFields ?
(
<div className={cx(props.kcContentWrapperClass)}>
<div className={cx(props.kcLabelWrapperClass, "subtitle")}>
<span className="subtitle">
<span className="required">*</span>
{msg("requiredFields")}
</span>
</div>
<div className="col-md-10">
<h1 id="kc-page-title">{headerNode}</h1>
</div>
) : (
<>
{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}
>
<div className="kc-login-tooltip">
<i
className={cx(
props.kcResetFlowIcon,
)}
></i>
<span className="kc-tooltip-text">
{msg("restartLoginTooltip")}
</span>
</div>
)
:
(
<h1 id="kc-page-title">{headerNode}</h1>
)
) : (
displayRequiredFields ? (
<div className={cx(props.kcContentWrapperClass)}>
<div className={cx(props.kcLabelWrapperClass, "subtitle")}>
<span className="subtitle"><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}>
<div className="kc-login-tooltip">
<i className={cx(props.kcResetFlowIcon)}></i>
<span className="kc-tooltip-text">{msg("restartLoginTooltip")}</span>
</div>
</a>
</div>
</div>
</div>
</div>
) : (
<>
{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}>
<div className="kc-login-tooltip">
<i className={cx(props.kcResetFlowIcon)}></i>
<span className="kc-tooltip-text">{msg("restartLoginTooltip")}</span>
</div>
</a>
</div>
</div>
</>
)
)
}
</a>
</div>
</div>
</>
)}
</header>
<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>
{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>
</div >
</form>
}
{
displayInfo &&
<div id="kc-info" className={cx(props.kcSignUpClass)}>
<div id="kc-info-wrapper" className={cx(props.kcInfoAreaWrapperClass)}>
</form>
)}
{displayInfo && (
<div
id="kc-info"
className={cx(props.kcSignUpClass)}
>
<div
id="kc-info-wrapper"
className={cx(props.kcInfoAreaWrapperClass)}
>
{infoNode}
</div>
</div>
}
)}
</div>
</div>
</div>

View File

@ -5,56 +5,57 @@ 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) => {
export const Terms = memo(
({ kcContext, ...props }: { kcContext: KcContextBase.Terms } & KcProps) => {
const { msg, msgStr } = useKcMessage();
const { msg, msgStr } = useKcMessage();
const { cx } = useCssAndCx();
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" />
</>
}
/>
);
});
const { cx } = useCssAndCx();
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" />
</>
}
/>
);
},
);