Compare commits
5 Commits
v10.0.0-rc
...
v10.0.0-rc
Author | SHA1 | Date | |
---|---|---|---|
c7d47f128e | |||
14cb07efb2 | |||
a51724208c | |||
050e2b2b99 | |||
3706f15f7e |
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "keycloakify",
|
||||
"version": "10.0.0-rc.95",
|
||||
"version": "10.0.0-rc.97",
|
||||
"description": "Create Keycloak themes using React",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
@ -81,7 +81,8 @@ export async function command(params: { cliCommandOptions: CliCommandOptions })
|
||||
)
|
||||
)
|
||||
.toString("utf8")
|
||||
.replace('import React from "react";\n', "");
|
||||
.replace('import React from "react";\n', "")
|
||||
.replace(/from "[./]+dist\//, 'from "keycloakify/');
|
||||
|
||||
{
|
||||
const targetDirPath = pathDirname(targetFilePath);
|
||||
|
@ -259,8 +259,16 @@ function createI18nTranslationFunctionsFactory<MessageKey extends string, ExtraM
|
||||
function resolveMsgAdvanced(props: { key: string; args: (string | undefined)[]; doRenderAsHtml: boolean }): JSX.Element | string {
|
||||
const { key, args, doRenderAsHtml } = props;
|
||||
|
||||
if (realmMessageBundleUserProfile !== undefined && key in realmMessageBundleUserProfile) {
|
||||
const resolvedMessage = realmMessageBundleUserProfile[key];
|
||||
user_profile: {
|
||||
if (realmMessageBundleUserProfile === undefined) {
|
||||
break user_profile;
|
||||
}
|
||||
|
||||
const resolvedMessage = realmMessageBundleUserProfile[key] ?? realmMessageBundleUserProfile["${" + key + "}"];
|
||||
|
||||
if (resolvedMessage === undefined) {
|
||||
break user_profile;
|
||||
}
|
||||
|
||||
return doRenderAsHtml ? (
|
||||
<span
|
||||
|
@ -24,6 +24,7 @@ export default function Register(props: RegisterProps) {
|
||||
const { msg, msgStr } = i18n;
|
||||
|
||||
const [isFormSubmittable, setIsFormSubmittable] = useState(false);
|
||||
const [areTermsAccepted, setAreTermsAccepted] = useState(false);
|
||||
|
||||
return (
|
||||
<Template
|
||||
@ -43,7 +44,15 @@ export default function Register(props: RegisterProps) {
|
||||
onIsFormSubmittableValueChange={setIsFormSubmittable}
|
||||
doMakeUserConfirmPassword={doMakeUserConfirmPassword}
|
||||
/>
|
||||
{termsAcceptanceRequired && <TermsAcceptance i18n={i18n} kcClsx={kcClsx} messagesPerField={messagesPerField} />}
|
||||
{termsAcceptanceRequired && (
|
||||
<TermsAcceptance
|
||||
i18n={i18n}
|
||||
kcClsx={kcClsx}
|
||||
messagesPerField={messagesPerField}
|
||||
areTermsAccepted={areTermsAccepted}
|
||||
onAreTermsAcceptedValueChange={setAreTermsAccepted}
|
||||
/>
|
||||
)}
|
||||
{recaptchaRequired && (
|
||||
<div className="form-group">
|
||||
<div className={kcClsx("kcInputWrapperClass")}>
|
||||
@ -61,7 +70,7 @@ export default function Register(props: RegisterProps) {
|
||||
</div>
|
||||
<div id="kc-form-buttons" className={kcClsx("kcFormButtonsClass")}>
|
||||
<input
|
||||
disabled={!isFormSubmittable}
|
||||
disabled={!isFormSubmittable || (termsAcceptanceRequired && !areTermsAccepted)}
|
||||
className={kcClsx("kcButtonClass", "kcButtonPrimaryClass", "kcButtonBlockClass", "kcButtonLargeClass")}
|
||||
type="submit"
|
||||
value={msgStr("doRegister")}
|
||||
@ -73,8 +82,14 @@ export default function Register(props: RegisterProps) {
|
||||
);
|
||||
}
|
||||
|
||||
function TermsAcceptance(props: { i18n: I18n; kcClsx: KcClsx; messagesPerField: Pick<KcContext["messagesPerField"], "existsError" | "get"> }) {
|
||||
const { i18n, kcClsx, messagesPerField } = props;
|
||||
function TermsAcceptance(props: {
|
||||
i18n: I18n;
|
||||
kcClsx: KcClsx;
|
||||
messagesPerField: Pick<KcContext["messagesPerField"], "existsError" | "get">;
|
||||
areTermsAccepted: boolean;
|
||||
onAreTermsAcceptedValueChange: (areTermsAccepted: boolean) => void;
|
||||
}) {
|
||||
const { i18n, kcClsx, messagesPerField, areTermsAccepted, onAreTermsAcceptedValueChange } = props;
|
||||
|
||||
const { msg } = i18n;
|
||||
|
||||
@ -93,6 +108,8 @@ function TermsAcceptance(props: { i18n: I18n; kcClsx: KcClsx; messagesPerField:
|
||||
id="termsAccepted"
|
||||
name="termsAccepted"
|
||||
className={kcClsx("kcCheckboxInputClass")}
|
||||
checked={areTermsAccepted}
|
||||
onChange={e => onAreTermsAcceptedValueChange(e.target.checked)}
|
||||
aria-invalid={messagesPerField.existsError("termsAccepted")}
|
||||
/>
|
||||
<label htmlFor="termsAccepted" className={kcClsx("kcLabelClass")}>
|
||||
|
@ -1,6 +1,7 @@
|
||||
import React from "react";
|
||||
import type { Meta, StoryObj } from "@storybook/react";
|
||||
import { createKcPageStory } from "../KcPageStory";
|
||||
import type { Attribute } from "../../../dist/login";
|
||||
|
||||
const { KcPageStory } = createKcPageStory({ pageId: "register.ftl" });
|
||||
|
||||
@ -48,23 +49,84 @@ export const WithEmailAlreadyExists: Story = {
|
||||
)
|
||||
};
|
||||
|
||||
export const WithEmailAsUsername: Story = {
|
||||
export const WithRestrictedToMITStudents: Story = {
|
||||
render: () => (
|
||||
<KcPageStory
|
||||
kcContext={{
|
||||
realm: {
|
||||
registrationEmailAsUsername: true
|
||||
profile: {
|
||||
attributesByName: {
|
||||
email: {
|
||||
validators: {
|
||||
pattern: {
|
||||
pattern: "^[^@]+@([^.]+\\.)*((mit\\.edu)|(berkeley\\.edu))$",
|
||||
"error-message": "${profile.attributes.email.pattern.error}"
|
||||
}
|
||||
},
|
||||
annotations: {
|
||||
inputHelperTextBefore: "${profile.attributes.email.inputHelperTextBefore}"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"x-keycloakify": {
|
||||
realmMessageBundleUserProfile: {
|
||||
"${profile.attributes.email.inputHelperTextBefore}": "Please use your MIT or Berkeley email.",
|
||||
"${profile.attributes.email.pattern.error}":
|
||||
"This is not an MIT (<strong>@mit.edu</strong>) nor a Berkeley (<strong>@berkeley.edu</strong>) email."
|
||||
}
|
||||
}
|
||||
}}
|
||||
/>
|
||||
)
|
||||
};
|
||||
|
||||
export const WithoutPassword: Story = {
|
||||
export const WithFavoritePet: Story = {
|
||||
render: () => (
|
||||
<KcPageStory
|
||||
kcContext={{
|
||||
passwordRequired: false
|
||||
profile: {
|
||||
attributesByName: {
|
||||
favoritePet: {
|
||||
name: "favorite-pet",
|
||||
displayName: "${profile.attributes.favoritePet}",
|
||||
validators: {
|
||||
options: {
|
||||
options: ["cat", "dog", "fish"]
|
||||
}
|
||||
},
|
||||
annotations: {
|
||||
inputOptionLabelsI18nPrefix: "profile.attributes.favoritePet.options"
|
||||
},
|
||||
required: false,
|
||||
readOnly: false
|
||||
} satisfies Attribute
|
||||
}
|
||||
},
|
||||
"x-keycloakify": {
|
||||
realmMessageBundleUserProfile: {
|
||||
"${profile.attributes.favoritePet}": "Favorite Pet",
|
||||
"${profile.attributes.favoritePet.options.cat}": "Fluffy Cat",
|
||||
"${profile.attributes.favoritePet.options.dog}": "Loyal Dog",
|
||||
"${profile.attributes.favoritePet.options.fish}": "Peaceful Fish"
|
||||
}
|
||||
}
|
||||
}}
|
||||
/>
|
||||
)
|
||||
};
|
||||
|
||||
export const WithEmailAsUsername: Story = {
|
||||
render: () => (
|
||||
<KcPageStory
|
||||
kcContext={{
|
||||
realm: {
|
||||
registrationEmailAsUsername: true
|
||||
},
|
||||
profile: {
|
||||
attributesByName: {
|
||||
username: undefined
|
||||
}
|
||||
}
|
||||
}}
|
||||
/>
|
||||
)
|
||||
@ -97,31 +159,6 @@ export const WithRecaptchaFrench: Story = {
|
||||
)
|
||||
};
|
||||
|
||||
export const WithPresets: Story = {
|
||||
render: () => (
|
||||
<KcPageStory
|
||||
kcContext={{
|
||||
profile: {
|
||||
attributesByName: {
|
||||
firstName: {
|
||||
value: "Max"
|
||||
},
|
||||
lastName: {
|
||||
value: "Mustermann"
|
||||
},
|
||||
email: {
|
||||
value: "max.mustermann@gmail.com"
|
||||
},
|
||||
username: {
|
||||
value: "max.mustermann"
|
||||
}
|
||||
}
|
||||
}
|
||||
}}
|
||||
/>
|
||||
)
|
||||
};
|
||||
|
||||
export const WithPasswordMinLength8: Story = {
|
||||
render: () => (
|
||||
<KcPageStory
|
||||
@ -133,3 +170,16 @@ export const WithPasswordMinLength8: Story = {
|
||||
/>
|
||||
)
|
||||
};
|
||||
|
||||
export const WithTermsAcceptance: Story = {
|
||||
render: () => (
|
||||
<KcPageStory
|
||||
kcContext={{
|
||||
termsAcceptanceRequired: true,
|
||||
"x-keycloakify": {
|
||||
realmMessageBundleTermsText: "<a href='https://example.com/terms'>Service Terms of Use</a>"
|
||||
}
|
||||
}}
|
||||
/>
|
||||
)
|
||||
};
|
||||
|
Reference in New Issue
Block a user