Skip to content

Commit 45f49b0

Browse files
committed
Split up ConsentBannerAndConsentManagment into multiple files
1 parent f437e50 commit 45f49b0

File tree

5 files changed

+377
-362
lines changed

5 files changed

+377
-362
lines changed
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
import React, { useEffect, useState } from "react";
2+
import { fr } from "../../fr";
3+
import type { RegisteredLinkProps } from "../../link";
4+
import type { ProcessConsentChanges } from "../processConsentChanges";
5+
import { isBrowser } from "../../tools/isBrowser";
6+
import { useTranslation } from "./translation";
7+
8+
export function createConsentBanner<Finality extends string>(params: {
9+
personalDataPolicyLinkProps: RegisteredLinkProps | undefined;
10+
processConsentChanges: ProcessConsentChanges<Finality>;
11+
consentModalButtonProps: {
12+
"aria-controls": string;
13+
"data-fr-opened": boolean;
14+
};
15+
}) {
16+
const { personalDataPolicyLinkProps, processConsentChanges, consentModalButtonProps } = params;
17+
18+
function ConsentBanner() {
19+
const { t } = useTranslation();
20+
21+
const [hostname, setHostname] = useState("");
22+
23+
const [isProcessingChanges, setIsProcessingChanges] = useState(false);
24+
25+
useEffect(() => {
26+
if (!isBrowser) {
27+
return;
28+
}
29+
30+
setHostname(location.host);
31+
}, []);
32+
33+
return (
34+
<>
35+
<div className={fr.cx("fr-consent-banner")}>
36+
<h2 className={fr.cx("fr-h6")}>{t("about cookies", { hostname })}</h2>
37+
<div /*className={fr.cx("fr-consent-banner__content")}*/>
38+
<p className={fr.cx("fr-text--sm")}>
39+
{t("welcome message", { personalDataPolicyLinkProps })}
40+
</p>
41+
</div>
42+
<ul
43+
className={fr.cx(
44+
"fr-consent-banner__buttons",
45+
"fr-btns-group",
46+
"fr-btns-group--right",
47+
"fr-btns-group--inline-reverse",
48+
"fr-btns-group--inline-sm"
49+
)}
50+
>
51+
<li>
52+
<button
53+
className={fr.cx("fr-btn")}
54+
title={t("accept all - title")}
55+
onClick={async () => {
56+
setIsProcessingChanges(true);
57+
await processConsentChanges({ "type": "grantAll" });
58+
setIsProcessingChanges(false);
59+
}}
60+
disabled={isProcessingChanges}
61+
>
62+
{t("accept all")}
63+
</button>
64+
</li>
65+
<li>
66+
<button
67+
className={fr.cx("fr-btn")}
68+
title={t("refuse all - title")}
69+
onClick={() => {
70+
setIsProcessingChanges(true);
71+
processConsentChanges({ "type": "denyAll" });
72+
setIsProcessingChanges(false);
73+
}}
74+
disabled={isProcessingChanges}
75+
>
76+
{t("refuse all")}
77+
</button>
78+
</li>
79+
<li>
80+
<button
81+
className={fr.cx("fr-btn", "fr-btn--secondary")}
82+
title={t("customize cookies - title")}
83+
disabled={isProcessingChanges}
84+
{...consentModalButtonProps}
85+
>
86+
{t("customize")}
87+
</button>
88+
</li>
89+
</ul>
90+
</div>
91+
</>
92+
);
93+
}
94+
95+
return { ConsentBanner };
96+
}
Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
import React, { useReducer, useEffect, type ReactNode } from "react";
2+
import type { RegisteredLinkProps } from "../../link";
3+
import type { ExtractFinalityFromFinalityDescription, FinalityConsent } from "../types";
4+
import type { ProcessConsentChanges } from "../processConsentChanges";
5+
import { FooterBottomItem } from "../../Footer";
6+
import { createConsentBanner } from "./ConsentBanner";
7+
import { createConsentManagement } from "./ConsentConsentManagement";
8+
import { useTranslation } from "./translation";
9+
10+
export function createConsentBannerAndConsentManagement<
11+
FinalityDescription extends Record<
12+
string,
13+
{ title: ReactNode; description?: ReactNode; subFinalities?: Record<string, ReactNode> }
14+
>
15+
>(params: {
16+
finalityDescription: ((params: { lang: string }) => FinalityDescription) | FinalityDescription;
17+
useFinalityConsent: () =>
18+
| FinalityConsent<ExtractFinalityFromFinalityDescription<FinalityDescription>>
19+
| undefined;
20+
processConsentChanges: ProcessConsentChanges<
21+
ExtractFinalityFromFinalityDescription<FinalityDescription>
22+
>;
23+
personalDataPolicyLinkProps?: RegisteredLinkProps;
24+
finalities: ExtractFinalityFromFinalityDescription<FinalityDescription>[];
25+
}) {
26+
const {
27+
finalityDescription,
28+
useFinalityConsent,
29+
processConsentChanges,
30+
personalDataPolicyLinkProps,
31+
finalities
32+
} = params;
33+
34+
const { ConsentManagement, consentModalButtonProps, useIsConsentManagementOpen } =
35+
createConsentManagement({
36+
finalityDescription,
37+
personalDataPolicyLinkProps,
38+
useFinalityConsent,
39+
processConsentChanges,
40+
finalities
41+
});
42+
43+
const { ConsentBanner } = createConsentBanner({
44+
personalDataPolicyLinkProps,
45+
processConsentChanges,
46+
consentModalButtonProps
47+
});
48+
49+
const { FooterConsentManagementItem } = createFooterConsentManagementItem({
50+
consentModalButtonProps
51+
});
52+
53+
function ConsentBannerAndConsentManagement() {
54+
const [isHydrated, setIsHydrated] = useReducer(() => true, false);
55+
56+
useEffect(() => {
57+
processConsentChanges({ "type": "no changes but trigger consent callbacks" });
58+
59+
setIsHydrated();
60+
}, []);
61+
62+
const finalityConsent = useFinalityConsent();
63+
64+
const isConsentManagementOpen = useIsConsentManagementOpen();
65+
66+
if (!isHydrated) {
67+
return null;
68+
}
69+
70+
return (
71+
<>
72+
{finalityConsent === undefined && !isConsentManagementOpen && <ConsentBanner />}
73+
<ConsentManagement />
74+
</>
75+
);
76+
}
77+
78+
const { FooterPersonalDataPolicyItem } = createFooterPersonalDataPolicyItem({
79+
personalDataPolicyLinkProps
80+
});
81+
82+
return {
83+
ConsentBannerAndConsentManagement,
84+
FooterConsentManagementItem,
85+
FooterPersonalDataPolicyItem
86+
};
87+
}
88+
89+
function createFooterConsentManagementItem(params: {
90+
consentModalButtonProps: {
91+
"aria-controls": string;
92+
"data-fr-opened": boolean;
93+
};
94+
}) {
95+
const { consentModalButtonProps } = params;
96+
97+
function FooterConsentManagementItem() {
98+
const { t } = useTranslation();
99+
100+
return (
101+
<FooterBottomItem
102+
bottomItem={{
103+
"buttonProps": consentModalButtonProps,
104+
"text": t("cookies management")
105+
}}
106+
/>
107+
);
108+
}
109+
110+
return { FooterConsentManagementItem };
111+
}
112+
113+
function createFooterPersonalDataPolicyItem(params: {
114+
personalDataPolicyLinkProps: RegisteredLinkProps | undefined;
115+
}) {
116+
const { personalDataPolicyLinkProps } = params;
117+
118+
function FooterPersonalDataPolicyItem() {
119+
const { t } = useTranslation();
120+
121+
if (personalDataPolicyLinkProps === undefined) {
122+
throw new Error(
123+
[
124+
"You should provide a personalDataPolicyLinkProps to createGdprApi if",
125+
"you want to add a link to the personal data policy in the footer"
126+
].join(" ")
127+
);
128+
}
129+
130+
return (
131+
<FooterBottomItem
132+
bottomItem={{
133+
"text": t("personal data"),
134+
"linkProps": personalDataPolicyLinkProps
135+
}}
136+
/>
137+
);
138+
}
139+
return { FooterPersonalDataPolicyItem };
140+
}

0 commit comments

Comments
 (0)