diff --git a/src/bin/build-keycloak-theme/generateFtl/index.ts b/src/bin/build-keycloak-theme/generateFtl/index.ts index 65ba9a8d..08ae61d5 100644 --- a/src/bin/build-keycloak-theme/generateFtl/index.ts +++ b/src/bin/build-keycloak-theme/generateFtl/index.ts @@ -14,7 +14,8 @@ import { ftlValuesGlobalName } from "../ftlValuesGlobalName"; export const pageIds = [ "login.ftl", "register.ftl", "info.ftl", "error.ftl", "login-reset-password.ftl", - "login-verify-email.ftl", "terms.ftl" + "login-verify-email.ftl", "terms.ftl", + "login-otp.ftl" ] as const; export type PageId = typeof pageIds[number]; diff --git a/src/bin/build-keycloak-theme/generateFtl/login-otp.ftl b/src/bin/build-keycloak-theme/generateFtl/login-otp.ftl new file mode 100644 index 00000000..a2cc9e41 --- /dev/null +++ b/src/bin/build-keycloak-theme/generateFtl/login-otp.ftl @@ -0,0 +1,37 @@ + \ No newline at end of file diff --git a/src/lib/components/KcApp.tsx b/src/lib/components/KcApp.tsx index 6fe86fa2..b84d534c 100644 --- a/src/lib/components/KcApp.tsx +++ b/src/lib/components/KcApp.tsx @@ -9,6 +9,7 @@ import { Error } from "./Error"; import { LoginResetPassword } from "./LoginResetPassword"; import { LoginVerifyEmail } from "./LoginVerifyEmail"; import { Terms } from "./Terms"; +import { LoginOtp } from "./LoginOtp"; export const KcApp = memo(({ kcContext, ...props }: { kcContext: KcContext; } & KcProps ) => { switch (kcContext.pageId) { @@ -19,5 +20,6 @@ export const KcApp = memo(({ kcContext, ...props }: { kcContext: KcContext; } & case "login-reset-password.ftl": return ; case "login-verify-email.ftl": return ; case "terms.ftl": return ; + case "login-otp.ftl": return ; } }); \ No newline at end of file diff --git a/src/lib/components/LoginOtp.tsx b/src/lib/components/LoginOtp.tsx new file mode 100644 index 00000000..e3612293 --- /dev/null +++ b/src/lib/components/LoginOtp.tsx @@ -0,0 +1,145 @@ + + +import { useEffect, memo } from "react"; +import { Template } from "./Template"; +import type { KcProps } from "./KcProps"; +import type { KcContext } from "../KcContext"; +import { useKcMessage } from "../i18n/useKcMessage"; +import { appendHead } from "../tools/appendHead"; +import { join as pathJoin } from "path"; +import { cx } from "tss-react"; + +export const LoginOtp = memo(({ kcContext, ...props }: { kcContext: KcContext.LoginOtp; } & KcProps) => { + + const { otpLogin, url } = kcContext; + + const { msg, msgStr } = useKcMessage(); + + useEffect( + () => { + + let isCleanedUp = false; + + appendHead({ + "type": "javascript", + "src": pathJoin( + kcContext.url.resourcesCommonPath, + "node_modules/jquery/dist/jquery.min.js" + ) + }).then(() => { + + if (isCleanedUp) return; + + evaluateInlineScript(); + + }); + + return () => { isCleanedUp = true }; + + }, + [] + ); + + return ( + + { + otpLogin.userOtpCredentials.length > 1 && + + + { + otpLogin.userOtpCredentials.map(otpCredential => + + + + + + {otpCredential.userLabel} + + + + ) + } + + + } + + + + {msg("loginOtpOneTime")} + + + + + + + + + + + + + + + + + + + + } + /> + ); +}); + + + + +declare const $: any; + +function evaluateInlineScript() { + + $(document).ready(function () { + // Card Single Select + $('.card-pf-view-single-select').click(function (this: any) { + if ($(this).hasClass('active')) { $(this).removeClass('active'); $(this).children().removeAttr('name'); } + else { + $('.card-pf-view-single-select').removeClass('active'); + $('.card-pf-view-single-select').children().removeAttr('name'); + $(this).addClass('active'); $(this).children().attr('name', 'selectedCredentialId'); + } + }); + + var defaultCred = $('.card-pf-view-single-select')[0]; + if (defaultCred) { + defaultCred.click(); + } + }); + +} \ No newline at end of file diff --git a/src/lib/kcContext.ts b/src/lib/kcContext.ts index b7c6bfee..516d2150 100644 --- a/src/lib/kcContext.ts +++ b/src/lib/kcContext.ts @@ -17,7 +17,7 @@ type ExtractAfterStartingWith = export type KcContext = KcContext.Login | KcContext.Register | KcContext.Info | KcContext.Error | KcContext.LoginResetPassword | KcContext.LoginVerifyEmail | - KcContext.Terms; + KcContext.Terms | KcContext.LoginOtp; export declare namespace KcContext { @@ -165,6 +165,13 @@ export declare namespace KcContext { pageId: "terms.ftl"; }; + export type LoginOtp = Common & { + pageId: "login-otp.ftl"; + otpLogin: { + userOtpCredentials: { id: string; userLabel: string; }[]; + } + }; + } doExtends(); diff --git a/src/lib/kcContextMocks/index.ts b/src/lib/kcContextMocks/index.ts index 01d90d4d..29a6b013 100644 --- a/src/lib/kcContextMocks/index.ts +++ b/src/lib/kcContextMocks/index.ts @@ -211,3 +211,20 @@ export const kcTermsContext: KcContext.Terms = { "pageId": "terms.ftl" }; +export const kcLoginOtcContext: KcContext.LoginOtp = { + ...kcCommonContext, + "pageId": "login-otp.ftl", + "otpLogin": { + "userOtpCredentials": [ + { + "id": "id1", + "userLabel": "label1" + }, + { + "id": "id2", + "userLabel": "label2" + } + ] + } +}; +