Skip to content

Commit

Permalink
feat: add logout-confirm (#28)
Browse files Browse the repository at this point in the history
* feat: add logout-confirm

* feat: add logout-confirm

* fix

* clean

* cleanup

* cleanup
  • Loading branch information
Julien Bouquillon committed Jul 7, 2022
1 parent e76c831 commit bf11ad5
Show file tree
Hide file tree
Showing 7 changed files with 163 additions and 61 deletions.
9 changes: 5 additions & 4 deletions src/KcApp.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { memo } from "react";
import type { KcContext } from "./kcContext";
import { defaultKcProps } from "keycloakify";
import { KcApp as KcAppBase, defaultKcProps } from "keycloakify";
import { Login } from "./Login";
import { LogoutConfirm } from "./LogoutConfirm";
import { Register } from "./Register";
import { KcApp as KcAppBase } from "keycloakify/lib/components/KcApp";
import { makeStyles } from "makeStyles";

export type Props = {
Expand All @@ -24,18 +24,19 @@ export const KcApp = memo((props: Props) => {
classes.kcFormCardClass,
],
};

switch (kcContext.pageId) {
case "login.ftl":
return <Login {...{ kcContext, ...kcProps }} />;
case "logout-confirm.ftl":
return <LogoutConfirm {...{ kcContext, ...kcProps }} />;
case "register.ftl":
return <Register {...{ kcContext, ...kcProps }} />;
default:
return <KcAppBase {...{ kcContext, ...kcProps }} />;
}
});

const useStyles = makeStyles({ name: { KcApp } })(theme => ({
const useStyles = makeStyles({ name: { KcApp } })((theme) => ({
kcLoginClass: {
"& #kc-locale": {
zIndex: 5,
Expand Down
31 changes: 16 additions & 15 deletions src/Login.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import type { FormEventHandler } from "react";
import { KcContextBase, KcProps, getMsg } from "keycloakify";
import { Template } from "./Template";


export const Login = memo(
({ kcContext, ...props }: { kcContext: KcContextBase.Login } & KcProps) => {
const {
Expand All @@ -17,25 +16,27 @@ export const Login = memo(
registrationDisabled,
} = kcContext;

const { msg, msgStr } = getMsg(kcContext);

const [isLoginButtonDisabled, setIsLoginButtonDisabled] = useState(false);

const onSubmit = useConstCallback<FormEventHandler<HTMLFormElement>>(e => {
e.preventDefault();
const { msg, msgStr } = getMsg(kcContext);

const onSubmit = useConstCallback<FormEventHandler<HTMLFormElement>>(
(e) => {
e.preventDefault();

setIsLoginButtonDisabled(true);
setIsLoginButtonDisabled(true);

const formElement = e.target as HTMLFormElement;
const formElement = e.target as HTMLFormElement;

//NOTE: Even if we login with email Keycloak expect username and password in
//the POST request.
formElement
.querySelector("input[name='email']")
?.setAttribute("name", "username");
//NOTE: Even if we login with email Keycloak expect username and password in
//the POST request.
formElement
.querySelector("input[name='email']")
?.setAttribute("name", "username");

formElement.submit();
});
formElement.submit();
}
);

return (
<Template
Expand Down Expand Up @@ -163,7 +164,7 @@ export const Login = memo(
{realm.password && social.providers !== undefined && (
<div id="kc-social-providers" className="fr-mt-3w">
<ul>
{social.providers.map(p => (
{social.providers.map((p) => (
<Fragment key={p.alias}>
{p.providerId === "franceconnect-particulier" ? (
<div
Expand Down
75 changes: 75 additions & 0 deletions src/LogoutConfirm.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
import { memo } from "react";
import { getMsg, KcContextBase, KcProps } from "keycloakify";
import { useCssAndCx } from "tss-react";
import { Template } from "./Template";

export const LogoutConfirm = memo(
({
kcContext,
...props
}: { kcContext: KcContextBase.LogoutConfirm } & KcProps) => {
const { url, client, logoutConfirm } = kcContext;

const { msg, msgStr } = getMsg(kcContext);

const { cx } = useCssAndCx();

return (
<Template
{...{ kcContext, ...props }}
doFetchDefaultThemeResources={true}
displayMessage={false}
headerNode={msg("logoutConfirmTitle")}
formNode={
<>
<div id="kc-logout-confirm" className="content-area">
<p className="instruction">{msg("logoutConfirmHeader")}</p>
<form
className="form-actions"
action={url.logoutConfirmAction}
method="POST"
>
<input
type="hidden"
name="session_code"
value={logoutConfirm.code}
/>
<div className={cx(props.kcFormGroupClass)}>
<div id="kc-form-options">
<div className={cx(props.kcFormOptionsWrapperClass)}></div>
</div>
<div
id="kc-form-buttons"
className={cx(props.kcFormGroupClass)}
>
<button
tabIndex={4}
type="submit"
className="fr-btn fr-btn--lg"
name="confirmLogout"
id="kc-logout"
>
{msgStr("doLogout")}
</button>
</div>
</div>
</form>
<div id="kc-info-message">
{!logoutConfirm.skipLink && client.baseUrl && (
<p style={{ marginTop: 20 }}>
<a
href={client.baseUrl}
dangerouslySetInnerHTML={{
__html: msgStr("backToApplication"),
}}
/>
</p>
)}
</div>
</div>
</>
}
/>
);
}
);
4 changes: 2 additions & 2 deletions src/Register.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,9 @@ export const Register = memo(
recaptchaSiteKey,
} = kcContext;

const { msg, msgStr } = getMsg();
const { msg, msgStr } = getMsg(kcContext);

console.log(`TODO: Do something with ${kcContext.authorizedMailDomains}`);
//console.log(`TODO: Do something with ${kcContext.authorizedMailDomains}`);

return (
<Template
Expand Down
67 changes: 44 additions & 23 deletions src/Template.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
import { useReducer, useEffect, memo } from "react";
import type { ReactNode } from "react";
import { getMsg, getCurrentKcLanguageTag, changeLocale, getTagLabel } from "keycloakify/lib/i18n";
import {
getMsg,
getCurrentKcLanguageTag,
changeLocale,
getTagLabel,
} from "keycloakify/lib/i18n";
import type { KcLanguageTag } from "keycloakify/lib/i18n";
import type { KcContextBase } from "keycloakify/lib/getKcContext/KcContextBase";
import { assert } from "keycloakify/lib/tools/assert";
Expand Down Expand Up @@ -46,14 +51,19 @@ export const Template = memo((props: TemplateProps) => {

const { msg } = getMsg(kcContext);

const onChangeLanguageClickFactory = useCallbackFactory(([kcLanguageTag]: [KcLanguageTag]) =>
changeLocale({
kcContext,
kcLanguageTag,
}),
const onChangeLanguageClickFactory = useCallbackFactory(
([kcLanguageTag]: [KcLanguageTag]) =>
changeLocale({
kcContext,
kcLanguageTag,
})
);

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;

Expand All @@ -68,21 +78,26 @@ export const Template = memo((props: TemplateProps) => {
let isUnmounted = false;
const cleanups: (() => void)[] = [];

const toArr = (x: string | readonly string[] | undefined) => (typeof x === "string" ? x.split(" ") : x ?? []);
const toArr = (x: string | readonly string[] | undefined) =>
typeof x === "string" ? x.split(" ") : x ?? [];

Promise.all(
[
...toArr(props.stylesCommon).map(relativePath => pathJoin(url.resourcesCommonPath, relativePath)),
...toArr(props.styles).map(relativePath => pathJoin(url.resourcesPath, relativePath)),
...toArr(props.stylesCommon).map((relativePath) =>
pathJoin(url.resourcesCommonPath, relativePath)
),
...toArr(props.styles).map((relativePath) =>
pathJoin(url.resourcesPath, relativePath)
),
]
.reverse()
.map(href =>
.map((href) =>
headInsert({
"type": "css",
type: "css",
href,
"position": "prepend",
}),
),
position: "prepend",
})
)
).then(() => {
if (isUnmounted) {
return;
Expand All @@ -91,11 +106,11 @@ export const Template = memo((props: TemplateProps) => {
setExtraCssLoaded();
});

toArr(props.scripts).forEach(relativePath =>
toArr(props.scripts).forEach((relativePath) =>
headInsert({
"type": "javascript",
"src": pathJoin(url.resourcesPath, relativePath),
}),
type: "javascript",
src: pathJoin(url.resourcesPath, relativePath),
})
);

if (props.kcHtmlClass !== undefined) {
Expand All @@ -111,7 +126,7 @@ export const Template = memo((props: TemplateProps) => {
return () => {
isUnmounted = true;

cleanups.forEach(f => f());
cleanups.forEach((f) => f());
};
}, [props.kcHtmlClass]);

Expand Down Expand Up @@ -144,7 +159,10 @@ export const Template = memo((props: TemplateProps) => {
>
<div className="kc-dropdown" id="kc-locale-dropdown">
<a href="#" id="kc-current-locale-link">
{getTagLabel({ "kcLanguageTag": getCurrentKcLanguageTag(kcContext), kcContext })}
{getTagLabel({
kcLanguageTag: getCurrentKcLanguageTag(kcContext),
kcContext,
})}
</a>
<ul>
{locale.supported.map(({ languageTag }) => (
Expand All @@ -153,7 +171,10 @@ export const Template = memo((props: TemplateProps) => {
href="#"
onClick={onChangeLanguageClickFactory(languageTag)}
>
{getTagLabel({ "kcLanguageTag": languageTag, kcContext })}
{getTagLabel({
kcLanguageTag: languageTag,
kcContext,
})}
</a>
</li>
))}
Expand Down Expand Up @@ -295,4 +316,4 @@ export const Template = memo((props: TemplateProps) => {
</div>
</div>
);
});
});
4 changes: 4 additions & 0 deletions src/kcContext.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,10 @@ export const { kcContext } = getKcContext<
],
},
},
{
pageId: "logout-confirm.ftl",
locale: { currentLanguageTag: "fr" },
},
],
});

Expand Down
34 changes: 17 additions & 17 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -1824,16 +1824,16 @@
integrity sha512-L28j2FcJfSZOnL1WBjDYp2vUHCeIFlyYI/53EwD/rKUBQ7MtUUfbQWiyKJGpcnv4/WgrhWsFKrcPstcAt/J0tQ==

"@types/react-dom@^18.0.0":
version "18.0.3"
resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-18.0.3.tgz#a022ea08c75a476fe5e96b675c3e673363853831"
integrity sha512-1RRW9kst+67gveJRYPxGmVy8eVJ05O43hg77G2j5m76/RFJtMbcfAs2viQ2UNsvvDg8F7OfQZx8qQcl6ymygaQ==
version "18.0.5"
resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-18.0.5.tgz#330b2d472c22f796e5531446939eacef8378444a"
integrity sha512-OWPWTUrY/NIrjsAPkAk1wW9LZeIjSvkXRhclsFO8CZcZGCOg2G0YZy4ft+rOyYxy8B7ui5iZzi9OkDebZ7/QSA==
dependencies:
"@types/react" "*"

"@types/react@*", "@types/react@^18.0.0":
version "18.0.8"
resolved "https://registry.yarnpkg.com/@types/react/-/react-18.0.8.tgz#a051eb380a9fbcaa404550543c58e1cf5ce4ab87"
integrity sha512-+j2hk9BzCOrrOSJASi5XiOyBbERk9jG5O73Ya4M0env5Ixi6vUNli4qy994AINcEF+1IEHISYFfIT4zwr++LKw==
version "18.0.14"
resolved "https://registry.yarnpkg.com/@types/react/-/react-18.0.14.tgz#e016616ffff51dba01b04945610fe3671fdbe06d"
integrity sha512-x4gGuASSiWmo0xjDLpm5mPb52syZHJx02VKbqUKdLmKtAwIh63XClGsiTI1K6DO5q7ox4xAsQrU+Gl3+gGXF9Q==
dependencies:
"@types/prop-types" "*"
"@types/scheduler" "*"
Expand Down Expand Up @@ -7334,12 +7334,12 @@ react-dev-utils@^12.0.1:
text-table "^0.2.0"

react-dom@^18.0.0:
version "18.1.0"
resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-18.1.0.tgz#7f6dd84b706408adde05e1df575b3a024d7e8a2f"
integrity sha512-fU1Txz7Budmvamp7bshe4Zi32d0ll7ect+ccxNu9FlObT605GOEB8BfO4tmRJ39R5Zj831VCpvQ05QPBW5yb+w==
version "18.2.0"
resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-18.2.0.tgz#22aaf38708db2674ed9ada224ca4aa708d821e3d"
integrity sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==
dependencies:
loose-envify "^1.1.0"
scheduler "^0.22.0"
scheduler "^0.23.0"

react-error-overlay@^6.0.11:
version "6.0.11"
Expand Down Expand Up @@ -7433,9 +7433,9 @@ react-scripts@5.0.1:
fsevents "^2.3.2"

react@^18.0.0:
version "18.1.0"
resolved "https://registry.yarnpkg.com/react/-/react-18.1.0.tgz#6f8620382decb17fdc5cc223a115e2adbf104890"
integrity sha512-4oL8ivCz5ZEPyclFQXaNksK3adutVS8l2xzZU0cqEFrE9Sb7fC0EFK5uEk74wIreL1DERyjvsU915j1pcT2uEQ==
version "18.2.0"
resolved "https://registry.yarnpkg.com/react/-/react-18.2.0.tgz#555bd98592883255fa00de14f1151a917b5d77d5"
integrity sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==
dependencies:
loose-envify "^1.1.0"

Expand Down Expand Up @@ -7721,10 +7721,10 @@ saxes@^5.0.1:
dependencies:
xmlchars "^2.2.0"

scheduler@^0.22.0:
version "0.22.0"
resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.22.0.tgz#83a5d63594edf074add9a7198b1bae76c3db01b8"
integrity sha512-6QAm1BgQI88NPYymgGQLCZgvep4FyePDWFpXVK+zNSUgHwlqpJy8VEh8Et0KxTACS4VWwMousBElAZOH9nkkoQ==
scheduler@^0.23.0:
version "0.23.0"
resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.23.0.tgz#ba8041afc3d30eb206a487b6b384002e4e61fdfe"
integrity sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==
dependencies:
loose-envify "^1.1.0"

Expand Down

0 comments on commit bf11ad5

Please sign in to comment.