Skip to content

Commit 528ac63

Browse files
committed
feat: finish consent banner and gdpr store
1 parent 8d92cea commit 528ac63

File tree

17 files changed

+323
-200
lines changed

17 files changed

+323
-200
lines changed

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,7 @@
129129
"./next-appdir/getColorSchemeHtmlAttributes": "./dist/next-appdir/getColorSchemeHtmlAttributes.js",
130130
"./next-pagesdir": "./dist/next-pagesdir.js",
131131
"./useIsDark": "./dist/useIsDark/index.js",
132+
"./useGdprStore": "./dist/useGdprStore.js",
132133
"./useColors": "./dist/useColors.js",
133134
"./useBreakpointsValues": "./dist/useBreakpointsValues.js",
134135
"./mui": "./dist/mui.js",
@@ -161,7 +162,7 @@
161162
"./Footer": "./dist/Footer.js",
162163
"./Download": "./dist/Download.js",
163164
"./Display": "./dist/Display.js",
164-
"./ConsentBanner": "./dist/ConsentBanner.js",
165+
"./ConsentBanner": "./dist/ConsentBanner/index.js",
165166
"./Checkbox": "./dist/Checkbox.js",
166167
"./Card": "./dist/Card.js",
167168
"./CallOut": "./dist/CallOut.js",
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
"use client";
2+
3+
import { ButtonsGroup } from "../ButtonsGroup";
4+
import { fr } from "../fr";
5+
import React from "react";
6+
import { useGdprStore } from "../useGdprStore";
7+
import { GdprService } from "../gdpr";
8+
import { ModalProps } from "../Modal";
9+
10+
export interface ConsentBannerActionsProps {
11+
services: GdprService[];
12+
consentModalButtonProps: ModalProps.ModalButtonProps;
13+
}
14+
15+
export const ConsentBannerActions = ({
16+
services,
17+
consentModalButtonProps
18+
}: ConsentBannerActionsProps) => {
19+
const setConsent = useGdprStore(state => state.setConsent);
20+
const setFirstChoiceMade = useGdprStore(state => state.setFirstChoiceMade);
21+
const acceptAll = () => {
22+
services.forEach(service => {
23+
if (!service.mandatory) setConsent(service.name, true);
24+
});
25+
setFirstChoiceMade();
26+
};
27+
28+
const refuseAll = () => {
29+
services.forEach(service => {
30+
if (!service.mandatory) setConsent(service.name, false);
31+
});
32+
setFirstChoiceMade();
33+
};
34+
return (
35+
<ButtonsGroup
36+
className={fr.cx("fr-consent-banner__buttons")}
37+
alignment="right"
38+
isReverseOrder
39+
inlineLayoutWhen="sm and up"
40+
buttons={[
41+
{
42+
children: "Tout accepter",
43+
title: "Autoriser tous les cookies",
44+
onClick: () => acceptAll()
45+
},
46+
{
47+
children: "Tout refuser",
48+
title: "Refuser tous les cookies",
49+
onClick: () => refuseAll()
50+
},
51+
{
52+
children: "Personnaliser",
53+
title: "Personnaliser les cookies",
54+
priority: "secondary",
55+
...consentModalButtonProps
56+
}
57+
]}
58+
/>
59+
);
60+
};
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
import React, { ElementType, PropsWithChildren } from "react";
2+
import { fr } from "../fr";
3+
import { ConsentBannerActions, ConsentBannerActionsProps } from "./ConsentBannerActions";
4+
5+
export interface ConsentBannerContentProps extends ConsentBannerActionsProps {
6+
gdprPageLink: string;
7+
gdprPageLinkAs?: ElementType<PropsWithChildren<{ href: any }>> | string;
8+
siteName: string;
9+
}
10+
11+
export const ConsentBannerContent = ({
12+
gdprPageLink,
13+
gdprPageLinkAs: GdprPageLinkAs = "a",
14+
siteName,
15+
services,
16+
consentModalButtonProps
17+
}: ConsentBannerContentProps) => {
18+
return (
19+
<div className={fr.cx("fr-consent-banner")}>
20+
<h2 className={fr.cx("fr-h6")}>À propos des cookies sur {siteName}</h2>
21+
<div className="fr-consent-banner__content">
22+
<p className="fr-text--sm">
23+
Bienvenue ! Nous utilisons des cookies pour améliorer votre expérience et les
24+
services disponibles sur ce site. Pour en savoir plus, visitez la page{" "}
25+
<GdprPageLinkAs href={gdprPageLink}>
26+
Données personnelles et cookies
27+
</GdprPageLinkAs>
28+
. Vous pouvez, à tout moment, avoir le contrôle sur les cookies que vous
29+
souhaitez activer.
30+
</p>
31+
</div>
32+
<ConsentBannerActions
33+
services={services}
34+
consentModalButtonProps={consentModalButtonProps}
35+
/>
36+
</div>
37+
);
38+
};

src/ConsentBanner.tsx renamed to src/ConsentBanner/ConsentManager.tsx

Lines changed: 35 additions & 118 deletions
Original file line numberDiff line numberDiff line change
@@ -1,114 +1,24 @@
1-
"use client";
2-
3-
import React from "react";
4-
import { type ElementType, type PropsWithChildren, useEffect, useState } from "react";
5-
6-
import ButtonsGroup from "./ButtonsGroup";
7-
import { ConsentModal, consentModalButtonProps } from "./gdpr/ConsentModal";
8-
import { useGdprStore, useSetterStore } from "./gdpr/useGdprStore";
9-
import { GdprService } from "./gdpr/types";
1+
import React, { useState, useEffect } from "react";
2+
import ButtonsGroup from "../ButtonsGroup";
3+
import { fr } from "../fr";
4+
import { GdprService } from "../gdpr";
5+
import { useGdprStore } from "../useGdprStore";
6+
import { ConsentBannerContentProps } from "./ConsentBannerContent";
107

118
const partition = <T,>(arr: T[], criteria: (item: T) => boolean): [T[], T[]] => [
129
arr.filter(item => criteria(item)),
1310
arr.filter(item => !criteria(item))
1411
];
1512

16-
export interface ConsentBannerProps {
17-
gdprPageLink: string;
18-
gdprPageLinkAs?: ElementType<PropsWithChildren<{ href: any }>> | string;
19-
services: GdprService[];
20-
siteName: string;
21-
}
22-
23-
export const ConsentBanner = ({
24-
gdprPageLink,
25-
gdprPageLinkAs: GdprPageLinkAs = "a",
26-
siteName,
27-
services
28-
}: ConsentBannerProps) => {
29-
const { setConsent, setFirstChoiceMade } = useSetterStore();
30-
const [stateFCM, setStateFCM] = useState(true);
31-
const firstChoiceMade = useGdprStore(state => state.firstChoiceMade);
32-
33-
const acceptAll = () => {
34-
services.forEach(service => {
35-
if (!service.mandatory) setConsent(service.name, true);
36-
});
37-
setFirstChoiceMade();
38-
};
39-
40-
const refuseAll = () => {
41-
services.forEach(service => {
42-
if (!service.mandatory) setConsent(service.name, false);
43-
});
44-
setFirstChoiceMade();
45-
};
46-
47-
useEffect(() => {
48-
setStateFCM(firstChoiceMade);
49-
}, [firstChoiceMade]);
50-
51-
return (
52-
<>
53-
<ConsentModal title="Panneau de gestion des cookies" size="large">
54-
<ConsentManager
55-
gdprPageLink={gdprPageLink}
56-
gdprPageLinkAs={GdprPageLinkAs}
57-
services={services}
58-
/>
59-
</ConsentModal>
60-
{!stateFCM && (
61-
<div className="fr-consent-banner">
62-
<h2 className="fr-h6">À propos des cookies sur {siteName}</h2>
63-
<div className="fr-consent-banner__content">
64-
<p className="fr-text--sm">
65-
Bienvenue ! Nous utilisons des cookies pour améliorer votre expérience
66-
et les services disponibles sur ce site. Pour en savoir plus, visitez la
67-
page{" "}
68-
<GdprPageLinkAs href={gdprPageLink}>
69-
Données personnelles et cookies
70-
</GdprPageLinkAs>
71-
. Vous pouvez, à tout moment, avoir le contrôle sur les cookies que vous
72-
souhaitez activer.
73-
</p>
74-
</div>
75-
<ButtonsGroup
76-
className="fr-consent-banner__buttons"
77-
alignment="right"
78-
isReverseOrder
79-
inlineLayoutWhen="sm and up"
80-
buttons={[
81-
{
82-
children: "Tout accepter",
83-
title: "Autoriser tous les cookies",
84-
onClick: () => acceptAll()
85-
},
86-
{
87-
children: "Tout refuser",
88-
title: "Refuser tous les cookies",
89-
onClick: () => refuseAll()
90-
},
91-
{
92-
children: "Personnaliser",
93-
title: "Personnaliser les cookies",
94-
priority: "secondary",
95-
...consentModalButtonProps
96-
}
97-
]}
98-
/>
99-
</div>
100-
)}
101-
</>
102-
);
103-
};
104-
105-
type ConsentManagerProps = Required<Omit<ConsentBannerProps, "siteName">>;
106-
const ConsentManager = ({
13+
type ConsentManagerProps = Required<Omit<ConsentBannerContentProps, "siteName">>;
14+
export const ConsentManager = ({
10715
gdprPageLink,
10816
services,
109-
gdprPageLinkAs: GdprPageLinkAs
17+
gdprPageLinkAs: GdprPageLinkAs,
18+
consentModalButtonProps
11019
}: ConsentManagerProps) => {
111-
const { setConsent, setFirstChoiceMade } = useSetterStore();
20+
const setConsent = useGdprStore(state => state.setConsent);
21+
const setFirstChoiceMade = useGdprStore(state => state.setFirstChoiceMade);
11222
const consents = useGdprStore(state => state.consents);
11323
const [accepted, setAccepted] = useState<string[]>([]);
11424

@@ -121,7 +31,6 @@ const ConsentManager = ({
12131
}, [consents]);
12232

12333
const accept = (service?: GdprService) => {
124-
console.info("GDPR accept", service?.name ?? "all services");
12534
if (service && !service.mandatory && !accepted.includes(service.name)) {
12635
return setAccepted([...accepted, service.name]);
12736
}
@@ -133,7 +42,6 @@ const ConsentManager = ({
13342
};
13443

13544
const refuse = (service?: GdprService) => {
136-
console.info("GDPR refuse", service?.name ?? "all services");
13745
if (service && !service.mandatory && accepted.includes(service.name))
13846
return setAccepted(accepted.filter(name => service.name !== name));
13947

@@ -151,16 +59,22 @@ const ConsentManager = ({
15159

15260
return (
15361
<div className="fr-consent-manager">
154-
<div className="fr-consent-service fr-consent-manager__header">
155-
<fieldset className="fr-fieldset fr-fieldset--inline">
156-
<legend className="fr-consent-service__title">
62+
<div className={fr.cx("fr-consent-service", "fr-consent-manager__header")}>
63+
<fieldset
64+
className={fr.cx("fr-fieldset", "fr-fieldset--inline")}
65+
aria-describedby="fr-consent-service__title"
66+
>
67+
<legend
68+
className={fr.cx("fr-consent-service__title")}
69+
id="fr-consent-service__title"
70+
>
15771
Préférences pour tous les services.
15872
<br />
15973
<GdprPageLinkAs href={gdprPageLink}>
16074
Données personnelles et cookies
16175
</GdprPageLinkAs>
16276
</legend>
163-
<div className="fr-consent-service__radios">
77+
<div className={fr.cx("fr-consent-service__radios")}>
16478
<ButtonsGroup
16579
inlineLayoutWhen="always"
16680
alignment="right"
@@ -182,16 +96,16 @@ const ConsentManager = ({
18296
</fieldset>
18397
</div>
18498
{services.map((service, index) => (
185-
<div className="fr-consent-service" key={`consent-service-${index}`}>
186-
<fieldset className="fr-fieldset fr-fieldset--inline">
99+
<div className={fr.cx("fr-consent-service")} key={`consent-service-${index}`}>
100+
<fieldset className={fr.cx("fr-fieldset", "fr-fieldset--inline")}>
187101
<legend
188102
aria-describedby={`finality-${index}-desc`}
189-
className="fr-consent-service__title"
103+
className={fr.cx("fr-consent-service__title")}
190104
>
191105
{service.title}
192106
</legend>
193-
<div className="fr-consent-service__radios">
194-
<div className="fr-radio-group">
107+
<div className={fr.cx("fr-consent-service__radios")}>
108+
<div className={fr.cx("fr-radio-group")}>
195109
<input
196110
type="radio"
197111
id={`consent-finality-${index}-accept`}
@@ -204,12 +118,12 @@ const ConsentManager = ({
204118
/>
205119
<label
206120
htmlFor={`consent-finality-${index}-accept`}
207-
className="fr-label"
121+
className={fr.cx("fr-label")}
208122
>
209123
Accepter
210124
</label>
211125
</div>
212-
<div className="fr-radio-group">
126+
<div className={fr.cx("fr-radio-group")}>
213127
<input
214128
{...(service.mandatory
215129
? { disabled: true, checked: false }
@@ -222,20 +136,23 @@ const ConsentManager = ({
222136
/>
223137
<label
224138
htmlFor={`consent-finality-${index}-refuse`}
225-
className="fr-label"
139+
className={fr.cx("fr-label")}
226140
>
227141
Refuser
228142
</label>
229143
</div>
230144
</div>
231-
<p id={`finality-${index}-desc`} className="fr-consent-service__desc">
145+
<p
146+
id={`finality-${index}-desc`}
147+
className={fr.cx("fr-consent-service__desc")}
148+
>
232149
{service.description}
233150
</p>
234151
</fieldset>
235152
</div>
236153
))}
237154
<ButtonsGroup
238-
className="fr-consent-manager__buttons"
155+
className={fr.cx("fr-consent-manager__buttons")}
239156
alignment="right"
240157
inlineLayoutWhen="sm and up"
241158
buttons={[

0 commit comments

Comments
 (0)