WIP
This commit is contained in:
parent
184139f284
commit
2a10ec9a20
|
@ -24,7 +24,7 @@
|
||||||
"keywords": [],
|
"keywords": [],
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@emotion/react": "^11.9.0",
|
"@emotion/react": "^11.9.0",
|
||||||
"keycloakify": "^6.0.0",
|
"keycloakify": "^6.0.2",
|
||||||
"react": "18.1.0",
|
"react": "18.1.0",
|
||||||
"react-dom": "18.1.0",
|
"react-dom": "18.1.0",
|
||||||
"evt": "^2.4.1"
|
"evt": "^2.4.1"
|
||||||
|
|
|
@ -3,7 +3,10 @@ import type { KcContext } from "./kcContext";
|
||||||
import KcAppBase, { defaultKcProps } from "keycloakify";
|
import KcAppBase, { defaultKcProps } from "keycloakify";
|
||||||
import { useI18n } from "./i18n";
|
import { useI18n } from "./i18n";
|
||||||
|
|
||||||
|
const Register = lazy(() => import("./Register"));
|
||||||
const Terms = lazy(() => import("./Terms"));
|
const Terms = lazy(() => import("./Terms"));
|
||||||
|
const MyExtraPage1 = lazy(() => import("./MyExtraPage1"));
|
||||||
|
const MyExtraPage2 = lazy(() => import("./MyExtraPage2"));
|
||||||
|
|
||||||
export type Props = {
|
export type Props = {
|
||||||
kcContext: KcContext;
|
kcContext: KcContext;
|
||||||
|
|
14
src/KcApp/MyExtraPage1.tsx
Normal file
14
src/KcApp/MyExtraPage1.tsx
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
import { memo } from "react";
|
||||||
|
import type { KcProps } from "keycloakify";
|
||||||
|
import type { KcContext } from "./kcContext";
|
||||||
|
import type { I18n } from "./i18n";
|
||||||
|
|
||||||
|
type KcContext_MyExtraPage1 = Extract<KcContext, { pageId: "my-extra-page-1.ftl"; }>;
|
||||||
|
|
||||||
|
const MyExtraPage1 = memo(({ kcContext, i18n, ...props }: { kcContext: KcContext_MyExtraPage1; i18n: I18n; } & KcProps) => {
|
||||||
|
|
||||||
|
return <>It is up to you to implement this page</>
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
export default MyExtraPage1;
|
16
src/KcApp/MyExtraPage2.tsx
Normal file
16
src/KcApp/MyExtraPage2.tsx
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
import { memo } from "react";
|
||||||
|
import type { KcProps } from "keycloakify";
|
||||||
|
import type { KcContext } from "./kcContext";
|
||||||
|
import type { I18n } from "./i18n";
|
||||||
|
|
||||||
|
type KcContext_MyExtraPage2 = Extract<KcContext, { pageId: "my-extra-page-2.ftl"; }>;
|
||||||
|
|
||||||
|
const MyExtraPage2 = memo(({ kcContext, i18n, ...props }: { kcContext: KcContext_MyExtraPage2; i18n: I18n; } & KcProps) => {
|
||||||
|
|
||||||
|
console.log(`TODO: Do something with: ${kcContext.someCustomValue}`);
|
||||||
|
|
||||||
|
return <>It is up to you to implement this page</>
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
export default MyExtraPage2;
|
168
src/KcApp/Register.tsx
Normal file
168
src/KcApp/Register.tsx
Normal file
|
@ -0,0 +1,168 @@
|
||||||
|
// This is a copy paste from https://github.com/InseeFrLab/keycloakify/blob/main/src/lib/components/Register.tsx
|
||||||
|
// It is now up to us to implement a special behavior to leverage the non standard authorizedMailDomains
|
||||||
|
// provided by the plugin: https://github.com/micedre/keycloak-mail-whitelisting installed on our keycloak server.
|
||||||
|
// Note that it is no longer recommended to use register.ftl, it's best to use register-user-profile.ftl
|
||||||
|
// See: https://docs.keycloakify.dev/realtime-input-validation
|
||||||
|
|
||||||
|
import { memo } from "react";
|
||||||
|
import Template from "keycloakify/lib/components/Template";
|
||||||
|
import type { KcProps } from "keycloakify";
|
||||||
|
import type { KcContext } from "./kcContext";
|
||||||
|
import { useCssAndCx } from "keycloakify/lib/tools/useCssAndCx";
|
||||||
|
import type { I18n } from "./i18n";
|
||||||
|
|
||||||
|
type KcContext_Register = Extract<KcContext, { pageId: "register.ftl"; }>;
|
||||||
|
|
||||||
|
const Register = memo(({ kcContext, i18n, ...props }: { kcContext: KcContext_Register; i18n: I18n; } & KcProps) => {
|
||||||
|
const { url, messagesPerField, register, realm, passwordRequired, recaptchaRequired, recaptchaSiteKey } = kcContext;
|
||||||
|
|
||||||
|
const { msg, msgStr } = i18n;
|
||||||
|
|
||||||
|
const { cx } = useCssAndCx();
|
||||||
|
|
||||||
|
console.log(`NOTE: It is up to you do do something meaningful with ${kcContext.authorizedMailDomains}`)
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Template
|
||||||
|
{...{ kcContext, i18n, ...props }}
|
||||||
|
doFetchDefaultThemeResources={true}
|
||||||
|
headerNode={msg("registerTitle")}
|
||||||
|
formNode={
|
||||||
|
<form id="kc-register-form" className={cx(props.kcFormClass)} action={url.registrationAction} method="post">
|
||||||
|
<div className={cx(props.kcFormGroupClass, messagesPerField.printIfExists("firstName", props.kcFormGroupErrorClass))}>
|
||||||
|
<div className={cx(props.kcLabelWrapperClass)}>
|
||||||
|
<label htmlFor="firstName" className={cx(props.kcLabelClass)}>
|
||||||
|
{msg("firstName")}
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
<div className={cx(props.kcInputWrapperClass)}>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
id="firstName"
|
||||||
|
className={cx(props.kcInputClass)}
|
||||||
|
name="firstName"
|
||||||
|
defaultValue={register.formData.firstName ?? ""}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className={cx(props.kcFormGroupClass, messagesPerField.printIfExists("lastName", props.kcFormGroupErrorClass))}>
|
||||||
|
<div className={cx(props.kcLabelWrapperClass)}>
|
||||||
|
<label htmlFor="lastName" className={cx(props.kcLabelClass)}>
|
||||||
|
{msg("lastName")}
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
<div className={cx(props.kcInputWrapperClass)}>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
id="lastName"
|
||||||
|
className={cx(props.kcInputClass)}
|
||||||
|
name="lastName"
|
||||||
|
defaultValue={register.formData.lastName ?? ""}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className={cx(props.kcFormGroupClass, messagesPerField.printIfExists("email", props.kcFormGroupErrorClass))}>
|
||||||
|
<div className={cx(props.kcLabelWrapperClass)}>
|
||||||
|
<label htmlFor="email" className={cx(props.kcLabelClass)}>
|
||||||
|
{msg("email")}
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
<div className={cx(props.kcInputWrapperClass)}>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
id="email"
|
||||||
|
className={cx(props.kcInputClass)}
|
||||||
|
name="email"
|
||||||
|
defaultValue={register.formData.email ?? ""}
|
||||||
|
autoComplete="email"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{!realm.registrationEmailAsUsername && (
|
||||||
|
<div className={cx(props.kcFormGroupClass, messagesPerField.printIfExists("username", props.kcFormGroupErrorClass))}>
|
||||||
|
<div className={cx(props.kcLabelWrapperClass)}>
|
||||||
|
<label htmlFor="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>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
export default Register;
|
|
@ -14,7 +14,7 @@ export const { kcContext } = getKcContext<
|
||||||
// Uncomment to test the login page for development.
|
// Uncomment to test the login page for development.
|
||||||
// Try with another page like "register-user-profile.ftl"
|
// Try with another page like "register-user-profile.ftl"
|
||||||
// DON'T forget to re-comment before publishing to production.
|
// DON'T forget to re-comment before publishing to production.
|
||||||
//"mockPageId": "login.ftl",
|
"mockPageId": "login.ftl",
|
||||||
"mockData": [
|
"mockData": [
|
||||||
{
|
{
|
||||||
"pageId": "login.ftl",
|
"pageId": "login.ftl",
|
||||||
|
|
17
yarn.lock
17
yarn.lock
|
@ -4401,6 +4401,15 @@ evt@^2.4.0:
|
||||||
run-exclusive "^2.2.16"
|
run-exclusive "^2.2.16"
|
||||||
tsafe "^1.0.1"
|
tsafe "^1.0.1"
|
||||||
|
|
||||||
|
evt@^2.4.1:
|
||||||
|
version "2.4.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/evt/-/evt-2.4.1.tgz#68beca2f7bd7eb755fdda5b263a80b934100e046"
|
||||||
|
integrity sha512-eo7sZcfDbiVWD5Aw6STkIEMmchYLdeGnJB6tVaM9AXZc7pViin3PmQhb6fgFIFHfl0re9zSEHtSjyu70Y7dRJg==
|
||||||
|
dependencies:
|
||||||
|
minimal-polyfills "^2.2.2"
|
||||||
|
run-exclusive "^2.2.16"
|
||||||
|
tsafe "^1.0.1"
|
||||||
|
|
||||||
execa@^5.0.0:
|
execa@^5.0.0:
|
||||||
version "5.1.1"
|
version "5.1.1"
|
||||||
resolved "https://registry.yarnpkg.com/execa/-/execa-5.1.1.tgz#f80ad9cbf4298f7bd1d4c9555c21e93741c411dd"
|
resolved "https://registry.yarnpkg.com/execa/-/execa-5.1.1.tgz#f80ad9cbf4298f7bd1d4c9555c21e93741c411dd"
|
||||||
|
@ -6075,10 +6084,10 @@ jsonpointer@^5.0.0:
|
||||||
array-includes "^3.1.5"
|
array-includes "^3.1.5"
|
||||||
object.assign "^4.1.2"
|
object.assign "^4.1.2"
|
||||||
|
|
||||||
keycloakify@^6.0.0:
|
keycloakify@^6.0.2:
|
||||||
version "6.0.0"
|
version "6.0.2"
|
||||||
resolved "https://registry.yarnpkg.com/keycloakify/-/keycloakify-6.0.0.tgz#3a3f71a14514d6b2a5fbfe3517d74ac974224a3d"
|
resolved "https://registry.yarnpkg.com/keycloakify/-/keycloakify-6.0.2.tgz#0bc95111117b6bc28e4668c335948c5ae70da7f0"
|
||||||
integrity sha512-9SZAEuBiOTxfd0dOYdb+RJAaYq6eTc7SaoM7LTQuw/JqQfUM7x6/kOHUNOP7x9iTs6vptHRfSUZb52ydp8fltA==
|
integrity sha512-/Y4YaWUB/rzXAwL1StEIYnVwKLmePlHcqqKC6ZrfhEaf02N0EWxqS9oZNrE1wU3mrD9xDSe5qcYMr/mgxkYAoQ==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@octokit/rest" "^18.12.0"
|
"@octokit/rest" "^18.12.0"
|
||||||
cheerio "^1.0.0-rc.5"
|
cheerio "^1.0.0-rc.5"
|
||||||
|
|
Loading…
Reference in a new issue