diff --git a/package.json b/package.json
index 7960676..8a24f90 100755
--- a/package.json
+++ b/package.json
@@ -13,6 +13,12 @@
"keycloak": "yarn build && keycloakify",
"download-builtin-keycloak-theme": "download-builtin-keycloak-theme 15.0.2"
},
+ "keycloakify": {
+ "extraPages": [
+ "my-extra-page-1.ftl",
+ "my-extra-page-2.ftl"
+ ]
+ },
"author": "u/garronej",
"license": "MIT",
"keywords": [],
@@ -20,7 +26,8 @@
"@emotion/react": "^11.9.0",
"keycloakify": "^6.0.0",
"react": "18.1.0",
- "react-dom": "18.1.0"
+ "react-dom": "18.1.0",
+ "evt": "^2.4.1"
},
"devDependencies": {
"@types/node": "^15.3.1",
diff --git a/src/KcApp/KcApp.tsx b/src/KcApp/KcApp.tsx
index ca05e14..1f5ea8e 100644
--- a/src/KcApp/KcApp.tsx
+++ b/src/KcApp/KcApp.tsx
@@ -1,70 +1,41 @@
-import "./KcApp.css";
+import { lazy, Suspense } from "react";
import type { KcContext } from "./kcContext";
-import KcAppBase, { defaultKcProps, useDownloadTerms, useI18n } from "keycloakify";
-import tos_en_url from "./tos_en.md";
-import tos_fr_url from "./tos_fr.md";
+import KcAppBase, { defaultKcProps } from "keycloakify";
+import { useI18n } from "./i18n";
+
+const Terms = lazy(() => import("./Terms"));
export type Props = {
kcContext: KcContext;
};
-export default function KcApp(props: Props) {
- const { kcContext } = props;
+export default function KcApp({ kcContext }: Props) {
+ const i18n = useI18n({ kcContext });
- useDownloadTerms({
- kcContext,
- "downloadTermMarkdown": async ({ currentLanguageTag }) => {
- const markdownString = await fetch(
- (() => {
- switch (currentLanguageTag) {
- case "fr":
- return tos_fr_url;
- default:
- return tos_en_url;
- }
- })(),
- ).then(response => response.text());
-
- return markdownString;
- },
- });
-
- const i18n = useI18n({
- kcContext,
- // NOTE: Here you can override the default i18n messages
- // or define new ones that, for example, you would have
- // defined in the Keycloak admin UI for UserProfile
- // https://user-images.githubusercontent.com/6702424/182050652-522b6fe6-8ee5-49df-aca3-dba2d33f24a5.png
- "extraMessages": {
- "en": {
- "foo": "foo in English",
- // Here we overwrite the default english value for the message "doForgotPassword"
- // that is "Forgot Password?" see: https://github.com/InseeFrLab/keycloakify/blob/f0ae5ea908e0aa42391af323b6d5e2fd371af851/src/lib/i18n/generated_messages/18.0.1/login/en.ts#L17
- "doForgotPassword": "I forgot my password"
- },
- "fr": {
- /* spell-checker: disable */
- "foo": "foo en Francais",
- "doForgotPassword": "J'ai oublié mon mot de passe"
- /* spell-checker: enable */
- },
- },
- });
-
- //NOTE: Locale not yet downloaded
+ //NOTE: Locales not yet downloaded
if (i18n === null) {
return null;
}
+ const props = {
+ i18n,
+ ...defaultKcProps,
+ // NOTE: The classes are defined in ./KcApp.css
+ "kcHeaderWrapperClass": "my-color my-font",
+ };
+
return (
-
+
+ {(() => {
+ switch (kcContext.pageId) {
+ case "register.ftl": return ;
+ case "terms.ftl": return ;
+ case "my-extra-page-1.ftl": return ;
+ case "my-extra-page-2.ftl": return ;
+ default: return ;
+ }
+ })()}
+
);
+
}
diff --git a/src/KcApp/Terms.tsx b/src/KcApp/Terms.tsx
new file mode 100644
index 0000000..c3364df
--- /dev/null
+++ b/src/KcApp/Terms.tsx
@@ -0,0 +1,96 @@
+import { memo } from "react";
+import Template from "keycloakify/lib/components/Template";
+import type { KcProps } from "keycloakify";
+import { useDownloadTerms } from "keycloakify";
+import type { KcContext } from "./kcContext";
+import type { I18n } from "./i18n";
+import { evtTermMarkdown } from "keycloakify/lib/components/Terms";
+import { useRerenderOnStateChange } from "evt/hooks";
+import tos_en_url from "./tos_en.md";
+import tos_fr_url from "./tos_fr.md";
+import { useCssAndCx } from "keycloakify/lib/tools/useCssAndCx";
+
+/**
+ * NOTE: Yo do not need to do all this to put your own Terms and conditions
+ * this is if you want component level customization.
+ * If the default works for you you can just use the useDownloadTerms hook
+ * in the KcApp.tsx
+ * Example: https://github.com/garronej/keycloakify-starter/blob/a20c21b2aae7c6dc6dbea294f3d321955ddf9355/src/KcApp/KcApp.tsx#L14-L30
+ */
+
+type KcContext_Terms = Extract;
+
+const Terms = memo(
+ ({
+ kcContext,
+ i18n,
+ ...props
+ }: { kcContext: KcContext_Terms; i18n: I18n } & KcProps) => {
+ const { url } = kcContext;
+
+ useDownloadTerms({
+ kcContext,
+ "downloadTermMarkdown": async ({ currentLanguageTag }) => {
+
+ const markdownString = await fetch((() => {
+ switch (currentLanguageTag) {
+ case "fr": return tos_fr_url;
+ default: return tos_en_url;
+ }
+ })()).then(response => response.text());
+
+ return markdownString;
+ },
+ });
+
+ useRerenderOnStateChange(evtTermMarkdown);
+
+ const { cx } = useCssAndCx();
+
+ if (evtTermMarkdown.state === undefined) {
+ return null;
+ }
+
+ const { msg, msgStr } = i18n;
+
+ return (
+
+ {evtTermMarkdown.state}
+
+
+ >
+ }
+ />
+ );
+
+ },
+);
+
+export default Terms;
diff --git a/src/KcApp/i18n.ts b/src/KcApp/i18n.ts
new file mode 100644
index 0000000..f780b2f
--- /dev/null
+++ b/src/KcApp/i18n.ts
@@ -0,0 +1,28 @@
+import { useI18n as useI18nBase } from "keycloakify";
+
+type Props = Omit[0], "extraMessages">;
+
+export function useI18n(props: Props) {
+ const { kcContext } = props;
+ return useI18nBase({
+ kcContext,
+ "extraMessages": {
+ "en": {
+ "alphanumericalCharsOnly": "Only alphanumerical characters",
+ "gender": "Gender",
+ // Here we overwrite the default english value for the message "doForgotPassword"
+ // that is "Forgot Password?" see: https://github.com/InseeFrLab/keycloakify/blob/f0ae5ea908e0aa42391af323b6d5e2fd371af851/src/lib/i18n/generated_messages/18.0.1/login/en.ts#L17
+ "doForgotPassword": "I forgot my password"
+ },
+ "fr": {
+ /* spell-checker: disable */
+ "alphanumericalCharsOnly": "Caractère alphanumérique uniquement",
+ "gender": "Genre",
+ "doForgotPassword": "J'ai oublié mon mot de passe"
+ /* spell-checker: enable */
+ },
+ },
+ });
+}
+
+export type I18n = NonNullable>;
\ No newline at end of file
diff --git a/src/KcApp/kcContext.ts b/src/KcApp/kcContext.ts
index 4b6319a..1d90156 100644
--- a/src/KcApp/kcContext.ts
+++ b/src/KcApp/kcContext.ts
@@ -1,16 +1,81 @@
import { getKcContext } from "keycloakify/lib/getKcContext";
-export const { kcContext } = getKcContext({
- /* Uncomment to test th({
+ // Uncomment to test the login page for development.
+ // Try with another page like "register-user-profile.ftl"
+ // DON'T forget to re-comment before publishing to production.
//"mockPageId": "login.ftl",
"mockData": [
{
"pageId": "login.ftl",
"locale": {
- "currentLanguageTag": "fr", //When we test the login page we do it in french
+ //When we test the login page we do it in french
+ "currentLanguageTag": "fr",
},
},
- ],
+ {
+ "pageId": "my-extra-page-2.ftl",
+ "someCustomValue": "foo bar baz"
+ },
+ {
+ "pageId": "register.ftl",
+ "authorizedMailDomains": [
+ "example.com",
+ "another-example.com",
+ "*.yet-another-example.com",
+ "*.example.com",
+ "hello-world.com"
+ ]
+ },
+ {
+ //NOTE: You will either use register.ftl (legacy) or register-user-profile.ftl, not both
+ "pageId": "register-user-profile.ftl",
+ "locale": {
+ "currentLanguageTag": "fr"
+ },
+ "profile": {
+ "attributes": [
+ {
+ "validators": {
+ "pattern": {
+ "pattern": "^[a-zA-Z0-9]+$",
+ "ignore.empty.value": true,
+ // eslint-disable-next-line no-template-curly-in-string
+ "error-message": "${alphanumericalCharsOnly}",
+ },
+ },
+ //NOTE: To override the default mock value
+ "value": undefined,
+ "name": "username"
+ },
+ {
+ "validators": {
+ "options": {
+ "options": ["male", "female", "non-binary", "transgender", "intersex", "non_communicated"]
+ }
+ },
+ // eslint-disable-next-line no-template-curly-in-string
+ "displayName": "${gender}",
+ "annotations": {},
+ "required": true,
+ "groupAnnotations": {},
+ "readOnly": false,
+ "name": "gender"
+ }
+ ]
+ }
+ }
+ ]
});
-export type KcContext = NonNullable;
+export type KcContext = NonNullable;
\ No newline at end of file