Skip to content

Commit d9f9573

Browse files
authored
Merge branch 'main' into feature/add-login-page-expired-page
Signed-off-by: Joseph Garrone <joseph.garrone@data.gouv.fr>
2 parents 9209333 + 5e3f222 commit d9f9573

File tree

8 files changed

+142
-3
lines changed

8 files changed

+142
-3
lines changed

README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ Several environment variables can be used to tailor the theme to your needs:
2828
```env
2929
DSFR_THEME_HOME_URL
3030
DSFR_THEME_SERVICE_TITLE
31+
DSFR_THEME_SERVICE_TAG_LINE
3132
DSFR_THEME_BRAND_TOP
3233
DSFR_NOTICE_TITLE
3334
DSFR_NOTICE_DESCRIPTION
@@ -45,6 +46,8 @@ If you are deploying Keycloak on Kubernetes using Helm, here's how to configure
4546
value: https://code.gouv.fr
4647
- name: DSFR_THEME_SERVICE_TITLE
4748
value: CodeGouv
49+
- name: DSFR_THEME_SERVICE_TAG_LINE
50+
value: My tag line
4851
- name: DSFR_THEME_BRAND_TOP
4952
value: "République<br/>Française"
5053
- name: DSFR_NOTICE_TITLE

src/account/Template.tsx

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,14 @@ export default function Template(props: TemplateProps<KcContext, I18n>) {
7171
}}
7272
/>
7373
}
74+
serviceTagline={
75+
<span
76+
dangerouslySetInnerHTML={{
77+
__html:
78+
kcContext.properties.DSFR_THEME_SERVICE_TAG_LINE || ""
79+
}}
80+
/>
81+
}
7482
quickAccessItems={[
7583
...(referrer?.url
7684
? [

src/kc.gen.tsx

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
// This file is auto-generated by the `update-kc-gen` command. Do not edit it manually.
2-
// Hash: 415229e332a814cae52152aa8f2b43dab69ceadc6ed220a115d8a8349abbde0b
2+
// Hash: 1ded21a7b8002bb4044342419812de41d9262e5530b9ef4de8909352536a5744
33

44
/* eslint-disable */
55

@@ -16,6 +16,7 @@ export const themeNames: ThemeName[] = ["DSFR"];
1616
export type KcEnvName =
1717
| "DSFR_THEME_HOME_URL"
1818
| "DSFR_THEME_SERVICE_TITLE"
19+
| "DSFR_THEME_SERVICE_TAG_LINE"
1920
| "DSFR_THEME_BRAND_TOP"
2021
| "DSFR_NOTICE_TITLE"
2122
| "DSFR_NOTICE_DESCRIPTION"
@@ -24,6 +25,7 @@ export type KcEnvName =
2425
export const kcEnvNames: KcEnvName[] = [
2526
"DSFR_THEME_HOME_URL",
2627
"DSFR_THEME_SERVICE_TITLE",
28+
"DSFR_THEME_SERVICE_TAG_LINE",
2729
"DSFR_THEME_BRAND_TOP",
2830
"DSFR_NOTICE_TITLE",
2931
"DSFR_NOTICE_DESCRIPTION",
@@ -33,9 +35,10 @@ export const kcEnvNames: KcEnvName[] = [
3335
export const kcEnvDefaults: Record<KcEnvName, string> = {
3436
DSFR_THEME_HOME_URL: "",
3537
DSFR_THEME_SERVICE_TITLE: "",
38+
DSFR_THEME_SERVICE_TAG_LINE: "",
3639
DSFR_THEME_BRAND_TOP: "République<br/>Française",
37-
DSFR_NOTICE_TITLE: "Mon super titre",
38-
DSFR_NOTICE_DESCRIPTION: "Ma super description",
40+
DSFR_NOTICE_TITLE: "",
41+
DSFR_NOTICE_DESCRIPTION: "",
3942
DSFR_NOTICE_SEVERITY: "info"
4043
};
4144

src/login/KcPage.tsx

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ const Register = lazy(() => import("./pages/Register"));
1414
const LoginUpdateProfile = lazy(() => import("./pages/LoginUpdateProfile"));
1515
const LoginUpdatePassword = lazy(() => import("./pages/LoginUpdatePassword"));
1616
const LoginPageExpired = lazy(() => import("./pages/LoginPageExpired"));
17+
const LoginVerifyEmail = lazy(() => import("./pages/LoginVerifyEmail"));
1718

1819
const doMakeUserConfirmPassword = false;
1920

@@ -81,6 +82,14 @@ export default function KcPage(props: { kcContext: KcContext }) {
8182
case "login-page-expired.ftl":
8283
return (
8384
<LoginPageExpired
85+
{...{ kcContext, i18n, classes }}
86+
Template={Template}
87+
doUseDefaultCss={false}
88+
/>
89+
);
90+
case "login-verify-email.ftl":
91+
return (
92+
<LoginVerifyEmail
8493
{...{ kcContext, i18n, classes }}
8594
Template={Template}
8695
doUseDefaultCss={false}

src/login/Template.tsx

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,14 @@ export default function Template(props: Props) {
9090
}}
9191
/>
9292
}
93+
serviceTagline={
94+
<span
95+
dangerouslySetInnerHTML={{
96+
__html:
97+
kcContext.properties.DSFR_THEME_SERVICE_TAG_LINE || ""
98+
}}
99+
/>
100+
}
93101
/>
94102
<main role="main" id="content">
95103
{(kcContext.properties.DSFR_NOTICE_TITLE || kcContext.properties.DSFR_NOTICE_DESCRIPTION) && (
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
import type { Meta, StoryObj } from "@storybook/react";
2+
import { createKcPageStory } from "../KcPageStory";
3+
4+
const { KcPageStory } = createKcPageStory({ pageId: "login-verify-email.ftl" });
5+
6+
const meta = {
7+
title: "login/login-verify-email.ftl",
8+
component: KcPageStory
9+
} satisfies Meta<typeof KcPageStory>;
10+
11+
export default meta;
12+
13+
type Story = StoryObj<typeof meta>;
14+
15+
export const Default: Story = {
16+
render: () => (
17+
<KcPageStory
18+
kcContext={{
19+
user: {
20+
email: "user@example.com"
21+
}
22+
}}
23+
/>
24+
)
25+
};
26+
27+
/**
28+
* WithCustomEmail:
29+
* - Purpose: Tests the page with a specific email address.
30+
* - Scenario: Simulates a user with a custom email address to verify the display.
31+
* - Key Aspect: Ensures the email is correctly displayed in the verification message.
32+
*/
33+
export const WithCustomEmail: Story = {
34+
render: () => (
35+
<KcPageStory
36+
kcContext={{
37+
user: {
38+
email: "thais@hubee.com"
39+
}
40+
}}
41+
/>
42+
)
43+
};
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
import { getKcClsx } from "keycloakify/login/lib/kcClsx";
2+
import type { PageProps } from "keycloakify/login/pages/PageProps";
3+
import type { KcContext } from "../KcContext";
4+
import type { I18n } from "../i18n";
5+
import Alert from "@codegouvfr/react-dsfr/Alert";
6+
import { fr } from "@codegouvfr/react-dsfr";
7+
8+
export default function LoginVerifyEmail(props: PageProps<Extract<KcContext, { pageId: "login-verify-email.ftl" }>, I18n>) {
9+
const { kcContext, i18n, doUseDefaultCss, Template, classes } = props;
10+
11+
const { kcClsx } = getKcClsx({
12+
doUseDefaultCss,
13+
classes
14+
});
15+
16+
const { url, user } = kcContext;
17+
18+
const { msg, msgStr } = i18n;
19+
20+
return (
21+
<Template
22+
kcContext={kcContext}
23+
i18n={i18n}
24+
doUseDefaultCss={doUseDefaultCss}
25+
classes={classes}
26+
displayMessage={false}
27+
headerNode={msg("emailVerifyTitle")}
28+
>
29+
<Alert
30+
severity="info"
31+
description={msgStr("emailVerifyInstruction1", user?.email ?? "")}
32+
className={fr.cx("fr-mb-4w")}
33+
small
34+
/>
35+
36+
<div className={kcClsx("kcFormGroupClass")}>
37+
<p className={fr.cx("fr-text--sm", "fr-mb-3w")}>
38+
{msgStr("emailVerifyInstruction2")}{" "}
39+
<form action={url.loginAction} method="post" style={{ display: "inline" }}>
40+
<input type="hidden" name="email" value={user?.email ?? ""} />
41+
<button
42+
type="submit"
43+
className={fr.cx("fr-link")}
44+
style={{
45+
background: "none",
46+
border: "none",
47+
padding: 0,
48+
cursor: "pointer"
49+
}}
50+
>
51+
{msgStr("doClickHere")} {msgStr("emailVerifyInstruction3")}
52+
</button>
53+
</form>
54+
</p>
55+
</div>
56+
57+
<div className={kcClsx("kcFormGroupClass")} style={{ display: "flex", justifyContent: "flex-end" }}>
58+
<a className={fr.cx("fr-link")} href={url.loginUrl}>
59+
{msg("backToLogin")}
60+
</a>
61+
</div>
62+
</Template>
63+
);
64+
}

vite.config.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ export default defineConfig({
1212
environmentVariables: [
1313
{ name: "DSFR_THEME_HOME_URL", default: "" },
1414
{ name: "DSFR_THEME_SERVICE_TITLE", default: "" },
15+
{ name: "DSFR_THEME_SERVICE_TAG_LINE", default: "" },
1516
{ name: "DSFR_THEME_BRAND_TOP", default: "République<br/>Française" },
1617
{ name: "DSFR_NOTICE_TITLE", default: "" },
1718
{ name: "DSFR_NOTICE_DESCRIPTION", default: "" },

0 commit comments

Comments
 (0)