Support register-user-profile.ftl
This commit is contained in:
parent
c388c77f4a
commit
4ca2bc59b6
@ -134,97 +134,67 @@
|
|||||||
obj,
|
obj,
|
||||||
{
|
{
|
||||||
"messagesPerField": {
|
"messagesPerField": {
|
||||||
"printIfExists": function (key, x) {
|
|
||||||
switch(key){
|
<#assign fieldNames = ["global", "userLabel", "username", "email", "firstName", "lastName", "password", "password-confirm"]>
|
||||||
case "userLabel": return (function (){
|
|
||||||
<#attempt>
|
|
||||||
return "${messagesPerField.printIfExists('userLabel','1')}" ? x : undefined;
|
|
||||||
<#recover>
|
|
||||||
</#attempt>
|
|
||||||
})();
|
|
||||||
case "username": return (function (){
|
|
||||||
<#attempt>
|
|
||||||
return "${messagesPerField.printIfExists('username','1')}" ? x : undefined;
|
|
||||||
<#recover>
|
|
||||||
</#attempt>
|
|
||||||
})();
|
|
||||||
case "email": return (function (){
|
|
||||||
<#attempt>
|
|
||||||
return "${messagesPerField.printIfExists('email','1')}" ? x : undefined;
|
|
||||||
<#recover>
|
|
||||||
</#attempt>
|
|
||||||
})();
|
|
||||||
case "firstName": return (function (){
|
|
||||||
<#attempt>
|
|
||||||
return "${messagesPerField.printIfExists('firstName','1')}" ? x : undefined;
|
|
||||||
<#recover>
|
|
||||||
</#attempt>
|
|
||||||
})();
|
|
||||||
case "lastName": return (function (){
|
|
||||||
<#attempt>
|
|
||||||
return "${messagesPerField.printIfExists('lastName','1')}" ? x : undefined;
|
|
||||||
<#recover>
|
|
||||||
</#attempt>
|
|
||||||
})();
|
|
||||||
case "password": return (function (){
|
|
||||||
<#attempt>
|
|
||||||
return "${messagesPerField.printIfExists('password','1')}" ? x : undefined;
|
|
||||||
<#recover>
|
|
||||||
</#attempt>
|
|
||||||
})();
|
|
||||||
case "password-confirm": return (function (){
|
|
||||||
<#attempt>
|
|
||||||
return "${messagesPerField.printIfExists('password-confirm','1')}" ? x : undefined;
|
|
||||||
<#recover>
|
|
||||||
</#attempt>
|
|
||||||
})();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"existsError": function (key) {
|
|
||||||
|
|
||||||
<#attempt>
|
<#attempt>
|
||||||
|
|
||||||
<#list profile.attributes as attribute>
|
<#list profile.attributes as attribute>
|
||||||
|
<#assign fieldNames += [attribute.name]>
|
||||||
if(key === "${attribute.name}" ){
|
|
||||||
|
|
||||||
return <#if messagesPerField.existsError('${attribute.name}')>true<#else>false</#if>;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
</#list>
|
</#list>
|
||||||
|
|
||||||
<#recover>
|
<#recover>
|
||||||
</#attempt>
|
</#attempt>
|
||||||
|
|
||||||
throw new Error(key + " is not an exsisting profile attribute name");
|
"printIfExists": function (fieldName, x) {
|
||||||
|
<#list fieldNames as fieldName>
|
||||||
},
|
if(fieldName === "${fieldName}" ){
|
||||||
"get": function (key) {
|
|
||||||
|
|
||||||
<#attempt>
|
<#attempt>
|
||||||
|
return "${messagesPerField.printIfExists(fieldName,'1')}" ? x : undefined;
|
||||||
<#list profile.attributes as attribute>
|
<#recover>
|
||||||
|
</#attempt>
|
||||||
<#if messagesPerField.existsError('${attribute.name}')>
|
}
|
||||||
|
</#list>
|
||||||
if(key === "${attribute.name}" ){
|
throw new Error("There is no " + fieldName " field");
|
||||||
return "${messagesPerField.get('${attribute.name}')?no_esc}"
|
},
|
||||||
|
"existsError": function (fieldName) {
|
||||||
|
<#list fieldNames as fieldName>
|
||||||
|
if(fieldName === "${fieldName}" ){
|
||||||
|
<#attempt>
|
||||||
|
return <#if messagesPerField.existsError('${fieldName}')>true<#else>false</#if>;
|
||||||
|
<#recover>
|
||||||
|
</#attempt>
|
||||||
|
}
|
||||||
|
</#list>
|
||||||
|
throw new Error("There is no " + fieldName " field");
|
||||||
|
},
|
||||||
|
"get": function (fieldName) {
|
||||||
|
<#list fieldNames as fieldName>
|
||||||
|
if(fieldName === "${fieldName}" ){
|
||||||
|
<#attempt>
|
||||||
|
<#if messagesPerField.existsError('${fieldName}')>
|
||||||
|
if(fieldName === "${fieldName}" ){
|
||||||
|
return "${messagesPerField.get('${fieldName}')?no_esc}";
|
||||||
}
|
}
|
||||||
|
|
||||||
</#if>
|
</#if>
|
||||||
|
|
||||||
</#list>
|
|
||||||
|
|
||||||
<#recover>
|
<#recover>
|
||||||
</#attempt>
|
</#attempt>
|
||||||
|
}
|
||||||
throw new Error(" there is no message for " + key);
|
</#list>
|
||||||
|
throw new Error("There is no " + fieldName " field");
|
||||||
|
},
|
||||||
|
"exists": function (fieldName) {
|
||||||
|
<#list fieldNames as fieldName>
|
||||||
|
if(fieldName === "${fieldName}" ){
|
||||||
|
<#attempt>
|
||||||
|
return <#if messagesPerField.exists('${fieldName}')>true<#else>false</#if>;
|
||||||
|
<#recover>
|
||||||
|
</#attempt>
|
||||||
|
}
|
||||||
|
</#list>
|
||||||
|
throw new Error("There is no " + fieldName " field");
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"msg": function(){ throw new Error("use import { useKcMessage } from 'keycloakify'"); },
|
"msg": function(){ throw new Error("use import { useKcMessage } from 'keycloakify'"); },
|
||||||
"advancedMsg": function(){ throw new Error("use import { useKcMessage } from 'keycloakify'"); },
|
"advancedMsg": function(){ throw new Error("use import { useKcMessage } from 'keycloakify'"); }
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -1,5 +1,3 @@
|
|||||||
|
|
||||||
|
|
||||||
import cheerio from "cheerio";
|
import cheerio from "cheerio";
|
||||||
import {
|
import {
|
||||||
replaceImportsFromStaticInJsCode,
|
replaceImportsFromStaticInJsCode,
|
||||||
@ -12,11 +10,10 @@ import { objectKeys } from "tsafe/objectKeys";
|
|||||||
import { ftlValuesGlobalName } from "../ftlValuesGlobalName";
|
import { ftlValuesGlobalName } from "../ftlValuesGlobalName";
|
||||||
|
|
||||||
export const pageIds = [
|
export const pageIds = [
|
||||||
"login.ftl", "register.ftl", "info.ftl",
|
"login.ftl", "register.ftl", "register-user-profile.ftl",
|
||||||
"error.ftl", "login-reset-password.ftl",
|
"info.ftl", "error.ftl", "login-reset-password.ftl",
|
||||||
"login-verify-email.ftl", "terms.ftl",
|
"login-verify-email.ftl", "terms.ftl", "login-otp.ftl",
|
||||||
"login-otp.ftl", "login-update-profile.ftl",
|
"login-update-profile.ftl", "login-idp-link-confirm.ftl"
|
||||||
"login-idp-link-confirm.ftl"
|
|
||||||
] as const;
|
] as const;
|
||||||
|
|
||||||
export type PageId = typeof pageIds[number];
|
export type PageId = typeof pageIds[number];
|
||||||
|
@ -4,6 +4,7 @@ import type { KcContextBase } from "../getKcContext/KcContextBase";
|
|||||||
import type { KcProps } from "./KcProps";
|
import type { KcProps } from "./KcProps";
|
||||||
import { Login } from "./Login";
|
import { Login } from "./Login";
|
||||||
import { Register } from "./Register";
|
import { Register } from "./Register";
|
||||||
|
import { RegisterUserProfile } from "./RegisterUserProfile";
|
||||||
import { Info } from "./Info";
|
import { Info } from "./Info";
|
||||||
import { Error } from "./Error";
|
import { Error } from "./Error";
|
||||||
import { LoginResetPassword } from "./LoginResetPassword";
|
import { LoginResetPassword } from "./LoginResetPassword";
|
||||||
@ -17,6 +18,7 @@ export const KcApp = memo(({ kcContext, ...props }: { kcContext: KcContextBase;
|
|||||||
switch (kcContext.pageId) {
|
switch (kcContext.pageId) {
|
||||||
case "login.ftl": return <Login {...{ kcContext, ...props }} />;
|
case "login.ftl": return <Login {...{ kcContext, ...props }} />;
|
||||||
case "register.ftl": return <Register {...{ 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 "info.ftl": return <Info {...{ kcContext, ...props }} />;
|
||||||
case "error.ftl": return <Error {...{ kcContext, ...props }} />;
|
case "error.ftl": return <Error {...{ kcContext, ...props }} />;
|
||||||
case "login-reset-password.ftl": return <LoginResetPassword {...{ kcContext, ...props }} />;
|
case "login-reset-password.ftl": return <LoginResetPassword {...{ kcContext, ...props }} />;
|
||||||
|
@ -94,12 +94,14 @@ export type KcProps = KcPropsGeneric<
|
|||||||
"kcFormGroupErrorClass" |
|
"kcFormGroupErrorClass" |
|
||||||
"kcLabelClass" |
|
"kcLabelClass" |
|
||||||
"kcInputClass" |
|
"kcInputClass" |
|
||||||
|
"kcInputErrorMessageClass" |
|
||||||
"kcInputWrapperClass" |
|
"kcInputWrapperClass" |
|
||||||
"kcFormOptionsClass" |
|
"kcFormOptionsClass" |
|
||||||
"kcFormButtonsClass" |
|
"kcFormButtonsClass" |
|
||||||
"kcFormSettingClass" |
|
"kcFormSettingClass" |
|
||||||
"kcTextareaClass" |
|
"kcTextareaClass" |
|
||||||
"kcInfoAreaClass" |
|
"kcInfoAreaClass" |
|
||||||
|
"kcFormGroupHeader" |
|
||||||
"kcButtonClass" |
|
"kcButtonClass" |
|
||||||
"kcButtonPrimaryClass" |
|
"kcButtonPrimaryClass" |
|
||||||
"kcButtonDefaultClass" |
|
"kcButtonDefaultClass" |
|
||||||
@ -147,6 +149,7 @@ export const defaultKcProps = {
|
|||||||
"kcFormGroupErrorClass": ["has-error"],
|
"kcFormGroupErrorClass": ["has-error"],
|
||||||
"kcLabelClass": ["control-label"],
|
"kcLabelClass": ["control-label"],
|
||||||
"kcInputClass": ["form-control"],
|
"kcInputClass": ["form-control"],
|
||||||
|
"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"],
|
"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"],
|
"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"],
|
"kcFormButtonsClass": ["col-xs-12", "col-sm-12", "col-md-12", "col-lg-12"],
|
||||||
@ -155,6 +158,9 @@ export const defaultKcProps = {
|
|||||||
|
|
||||||
"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"],
|
||||||
|
|
||||||
// css classes for form buttons main class used for all buttons
|
// css classes for form buttons main class used for all buttons
|
||||||
"kcButtonClass": ["btn"],
|
"kcButtonClass": ["btn"],
|
||||||
// classes defining priority of the button - primary or default (there is typically only one priority button for the form)
|
// classes defining priority of the button - primary or default (there is typically only one priority button for the form)
|
||||||
|
226
src/lib/components/RegisterUserProfile.tsx
Normal file
226
src/lib/components/RegisterUserProfile.tsx
Normal file
@ -0,0 +1,226 @@
|
|||||||
|
|
||||||
|
import { memo, Fragment } from "react";
|
||||||
|
import { Template } from "./Template";
|
||||||
|
import type { KcProps } from "./KcProps";
|
||||||
|
import type { KcContextBase } from "../getKcContext/KcContextBase";
|
||||||
|
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;
|
||||||
|
|
||||||
|
const { msg, msgStr } = useKcMessage();
|
||||||
|
|
||||||
|
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>
|
||||||
|
|
||||||
|
<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]; }>
|
||||||
|
>>
|
||||||
|
) => {
|
||||||
|
|
||||||
|
const { messagesPerField } = kcContext;
|
||||||
|
|
||||||
|
const { cx } = useCssAndCx();
|
||||||
|
|
||||||
|
const { advancedMsg } = useKcMessage();
|
||||||
|
|
||||||
|
let currentGroup = "";
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{kcContext.profile.attributes.map((attribute, i) => {
|
||||||
|
|
||||||
|
const {
|
||||||
|
group = "",
|
||||||
|
groupDisplayHeader = "",
|
||||||
|
groupDisplayDescription = ""
|
||||||
|
} = attribute;
|
||||||
|
|
||||||
|
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>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
|
||||||
|
}
|
||||||
|
);
|
@ -13,7 +13,7 @@ type ExtractAfterStartingWith<Prefix extends string, StrEnum> =
|
|||||||
* (ex: url.loginAction is undefined on error.ftl)
|
* (ex: url.loginAction is undefined on error.ftl)
|
||||||
*/
|
*/
|
||||||
export type KcContextBase =
|
export type KcContextBase =
|
||||||
KcContextBase.Login | KcContextBase.Register | KcContextBase.Info |
|
KcContextBase.Login | KcContextBase.Register | KcContextBase.RegisterUserProfile | KcContextBase.Info |
|
||||||
KcContextBase.Error | KcContextBase.LoginResetPassword | KcContextBase.LoginVerifyEmail |
|
KcContextBase.Error | KcContextBase.LoginResetPassword | KcContextBase.LoginVerifyEmail |
|
||||||
KcContextBase.Terms | KcContextBase.LoginOtp | KcContextBase.LoginUpdateProfile |
|
KcContextBase.Terms | KcContextBase.LoginOtp | KcContextBase.LoginUpdateProfile |
|
||||||
KcContextBase.LoginIdpLinkConfirm;
|
KcContextBase.LoginIdpLinkConfirm;
|
||||||
@ -62,6 +62,12 @@ export declare namespace KcContextBase {
|
|||||||
name?: string;
|
name?: string;
|
||||||
}
|
}
|
||||||
isAppInitiatedAction: boolean;
|
isAppInitiatedAction: boolean;
|
||||||
|
messagesPerField: {
|
||||||
|
printIfExists: <T>(fieldName: string, x: T) => T | undefined;
|
||||||
|
existsError: (fieldName: string) => boolean;
|
||||||
|
get: (fieldName: string) => string;
|
||||||
|
exists: (fieldName: string) => boolean;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export type Login = Common & {
|
export type Login = Common & {
|
||||||
@ -97,35 +103,10 @@ export declare namespace KcContextBase {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export type Register = Common & {
|
export type RegisterCommon = Common & {
|
||||||
pageId: "register.ftl";
|
|
||||||
url: {
|
url: {
|
||||||
registrationAction: string;
|
registrationAction: string;
|
||||||
};
|
};
|
||||||
messagesPerField: {
|
|
||||||
printIfExists: <T>(
|
|
||||||
key:
|
|
||||||
"userLabel" |
|
|
||||||
"username" |
|
|
||||||
"email" |
|
|
||||||
"firstName" |
|
|
||||||
"lastName" |
|
|
||||||
"password" |
|
|
||||||
"password-confirm",
|
|
||||||
x: T
|
|
||||||
)=> T | undefined;
|
|
||||||
existsError: (key: string)=> boolean;
|
|
||||||
get: (key: string) => string;
|
|
||||||
};
|
|
||||||
register: {
|
|
||||||
formData: {
|
|
||||||
firstName?: string;
|
|
||||||
displayName?: string;
|
|
||||||
lastName?: string;
|
|
||||||
email?: string;
|
|
||||||
username?: string;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
passwordRequired: boolean;
|
passwordRequired: boolean;
|
||||||
recaptchaRequired: boolean;
|
recaptchaRequired: boolean;
|
||||||
recaptchaSiteKey?: string;
|
recaptchaSiteKey?: string;
|
||||||
@ -140,6 +121,37 @@ export declare namespace KcContextBase {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type Register = RegisterCommon & {
|
||||||
|
pageId: "register.ftl";
|
||||||
|
register: {
|
||||||
|
formData: {
|
||||||
|
firstName?: string;
|
||||||
|
displayName?: string;
|
||||||
|
lastName?: string;
|
||||||
|
email?: string;
|
||||||
|
username?: string;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export type RegisterUserProfile = RegisterCommon & {
|
||||||
|
pageId: "register-user-profile.ftl";
|
||||||
|
profile: {
|
||||||
|
attributes: {
|
||||||
|
name: string;
|
||||||
|
displayName?: string;
|
||||||
|
required: boolean;
|
||||||
|
value?: string;
|
||||||
|
group?: string;
|
||||||
|
groupDisplayHeader?: string;
|
||||||
|
groupDisplayDescription?: string;
|
||||||
|
readOnly: boolean;
|
||||||
|
autocomplete?: string;
|
||||||
|
}[];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
export type Info = Common & {
|
export type Info = Common & {
|
||||||
pageId: "info.ftl";
|
pageId: "info.ftl";
|
||||||
messageHeader?: string;
|
messageHeader?: string;
|
||||||
@ -191,13 +203,6 @@ export declare namespace KcContextBase {
|
|||||||
firstName?: string;
|
firstName?: string;
|
||||||
lastName?: string;
|
lastName?: string;
|
||||||
};
|
};
|
||||||
messagesPerField: {
|
|
||||||
printIfExists<T>(
|
|
||||||
key: "username" | "email" | "firstName" | "lastName",
|
|
||||||
x: T
|
|
||||||
): T | undefined;
|
|
||||||
};
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export type LoginIdpLinkConfirm = Common & {
|
export type LoginIdpLinkConfirm = Common & {
|
||||||
|
@ -5,6 +5,9 @@ import { kcMessages, evtTermsUpdated } from "./kcMessages/login";
|
|||||||
import { useEvt } from "evt/hooks";
|
import { useEvt } from "evt/hooks";
|
||||||
//NOTE for later: https://github.com/remarkjs/react-markdown/blob/236182ecf30bd89c1e5a7652acaf8d0bf81e6170/src/renderers.js#L7-L35
|
//NOTE for later: https://github.com/remarkjs/react-markdown/blob/236182ecf30bd89c1e5a7652acaf8d0bf81e6170/src/renderers.js#L7-L35
|
||||||
import ReactMarkdown from "react-markdown";
|
import ReactMarkdown from "react-markdown";
|
||||||
|
import { id } from "tsafe/id";
|
||||||
|
import { assert } from "tsafe/assert";
|
||||||
|
import { is } from "tsafe/is";
|
||||||
|
|
||||||
export type MessageKey = keyof typeof kcMessages["en"];
|
export type MessageKey = keyof typeof kcMessages["en"];
|
||||||
|
|
||||||
@ -53,7 +56,7 @@ export function useKcMessage() {
|
|||||||
);
|
);
|
||||||
|
|
||||||
const advancedMsg = useCallback(
|
const advancedMsg = useCallback(
|
||||||
(key: string): string => {
|
(key: string): string | undefined => {
|
||||||
|
|
||||||
const match = key.match(/^\$\{([^{]+)\}$/);
|
const match = key.match(/^\$\{([^{]+)\}$/);
|
||||||
|
|
||||||
@ -61,7 +64,10 @@ export function useKcMessage() {
|
|||||||
return key;
|
return key;
|
||||||
}
|
}
|
||||||
|
|
||||||
return msgStr(match[1] as MessageKey);
|
return (
|
||||||
|
id<Record<string, string | undefined>>(kcMessages[kcLanguageTag])[key] ??
|
||||||
|
id<Record<string, string | undefined>>(kcMessages["en"])[key]
|
||||||
|
);
|
||||||
|
|
||||||
},
|
},
|
||||||
[msgStr]
|
[msgStr]
|
||||||
|
6
src/lib/tools/ReactComponent.ts
Normal file
6
src/lib/tools/ReactComponent.ts
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
|
||||||
|
import type { FC, ComponentClass } from "react";
|
||||||
|
|
||||||
|
export type ReactComponent<Props extends Record<string, unknown> = {}> =
|
||||||
|
| ((props: Props) => ReturnType<FC>)
|
||||||
|
| ComponentClass<Props>;
|
Loading…
x
Reference in New Issue
Block a user