Skip to content

Commit 4c7163e

Browse files
committed
chore: story
1 parent 849a313 commit 4c7163e

File tree

5 files changed

+129
-3
lines changed

5 files changed

+129
-3
lines changed

src/ConsentBanner/index.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ export { consentModalButtonProps };
1616

1717
export type ConsentBannerProps = Omit<ConsentBannerContentProps, "consentModalButtonProps">;
1818

19+
/** @see <https://react-dsfr-components.etalab.studio/?path=/docs/components-consentbanner> */
1920
// TODO handle sub finalities (https://www.systeme-de-design.gouv.fr/uploads/Capture_d_ecran_2021_03_24_a_17_45_33_8ba8e1fabb_1_1dd3309589.png)
2021
export const ConsentBanner = memo((props: ConsentBannerProps) => {
2122
const { gdprPageLink, services } = props;

src/Footer.tsx

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import type { Equals } from "tsafe";
99
import { createComponentI18nApi } from "./i18n";
1010
import type { FrIconClassName, RiIconClassName } from "./fr/generatedFromCss/classNames";
1111
import { id } from "tsafe/id";
12+
import { ModalProps } from "./Modal";
1213

1314
export type FooterProps = {
1415
className?: string;
@@ -20,6 +21,7 @@ export type FooterProps = {
2021
termsLinkProps?: RegisteredLinkProps;
2122
personalDataLinkProps?: RegisteredLinkProps;
2223
cookiesManagementLinkProps?: RegisteredLinkProps;
24+
cookiesManagementButtonProps?: ModalProps.ModalButtonProps;
2325
homeLinkProps: RegisteredLinkProps & { title: string };
2426
bottomItems?: FooterProps.BottomItem[];
2527
partnersLogos?: FooterProps.PartnersLogos;
@@ -146,6 +148,7 @@ export const Footer = memo(
146148
termsLinkProps,
147149
personalDataLinkProps,
148150
cookiesManagementLinkProps,
151+
cookiesManagementButtonProps,
149152
bottomItems = [],
150153
partnersLogos,
151154
operatorLogo,
@@ -418,12 +421,23 @@ export const Footer = memo(
418421
"linkProps": personalDataLinkProps
419422
})
420423
]),
421-
...(cookiesManagementLinkProps === undefined
422-
? []
424+
...(cookiesManagementButtonProps === undefined
425+
? // one or the other, but not both. Priority to button for consent modal control.
426+
cookiesManagementLinkProps === undefined
427+
? []
428+
: [
429+
id<FooterProps.BottomItem>({
430+
"text": t("cookies management"),
431+
"linkProps": cookiesManagementLinkProps
432+
})
433+
]
423434
: [
424435
id<FooterProps.BottomItem>({
425436
"text": t("cookies management"),
426-
"linkProps": cookiesManagementLinkProps
437+
"buttonProps": {
438+
onClick: cookiesManagementButtonProps.onClick,
439+
...cookiesManagementButtonProps.nativeButtonProps
440+
}
427441
})
428442
]),
429443
...bottomItems

src/useGdprStore.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@
33
import { useContext } from "react";
44
import { GdprStoreContext, GdprStore } from "./gdpr/GdprStore";
55

6+
/**
7+
* Zustand like store based on ReactContext. See {@link GdprStore} for store content.
8+
*/
69
export function useGdprStore(): GdprStore;
710
export function useGdprStore<T extends GdprStore[keyof GdprStore]>(
811
slice: (state: GdprStore) => T

stories/ConsentBanner.stories.tsx

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
import * as React from "react";
2+
import { ConsentBanner, ConsentBannerProps, consentModalButtonProps } from "../dist/ConsentBanner";
3+
import { sectionName } from "./sectionName";
4+
import { getStoryFactory } from "./getStory";
5+
import { symToStr } from "tsafe/symToStr";
6+
import { ConsentBannerContent } from "../dist/ConsentBanner/ConsentBannerContent";
7+
8+
const { meta, getStory } = getStoryFactory({
9+
sectionName,
10+
"wrappedComponent": {
11+
[symToStr({ ConsentBanner })]: Story
12+
},
13+
"description": `
14+
Manage cookies and consent with a banner and a dedicated modal.
15+
16+
- [See DSFR documentation](https://www.systeme-de-design.gouv.fr/elements-d-interface/composants/gestionnaire-de-consentement),
17+
- [See source code](https://github.com/codegouvfr/react-dsfr/blob/main/src/ConsentBanner/index.tsx)
18+
19+
Optionally, you can also use \`import { useGdprStore } from "@codegouvfr/react-dsfr/gdpr"\` to manually monitor and controls
20+
the consent state.
21+
22+
## Usage example
23+
24+
\`\`\`tsx
25+
import { Footer } from "@codegouvfr/react-dsfr/Footer";
26+
import { ConsentBanner, consentModalButtonProps } from "@codegouvfr/react-dsfr/ConsentBanner";
27+
28+
function App(){
29+
30+
return (
31+
<>
32+
{/* must be on root level */}
33+
<ConsentBanner
34+
gdprPageLink="#"
35+
services={[
36+
{
37+
name: "mandatory-cookie-consumer",
38+
title: "Any service consuming 🍪",
39+
description: "As a mandatory service, user cannot disable it.",
40+
mandatory: true
41+
},
42+
{
43+
name: "cookie-consumer",
44+
title: "Any service consuming 🍪",
45+
description: "Here you can describe why this service use cookies."
46+
}
47+
]}
48+
siteName={siteName}
49+
/>
50+
{/* ... Header ...*/}
51+
{/* ... your app ...*/}
52+
<Footer
53+
// other Footer props...
54+
cookiesManagementButtonProps={consentModalButtonProps}
55+
/>
56+
<>
57+
);
58+
59+
}
60+
\`\`\`
61+
`,
62+
argTypes: {
63+
gdprPageLink: {
64+
description: "Usually the same as FooterProps.personalDataLinkProps"
65+
},
66+
siteName: {
67+
description: "Current website name"
68+
}
69+
},
70+
"disabledProps": ["containerWidth"]
71+
});
72+
73+
export default meta;
74+
75+
const siteName = "Nom de l’entité (ministère, secrétariat d‘état, gouvernement)";
76+
77+
function Story(props: ConsentBannerProps) {
78+
return (
79+
<>
80+
<ConsentBanner {...props} />
81+
<style>{`
82+
.fr-consent-banner {
83+
position: static;
84+
}
85+
`}</style>
86+
<ConsentBannerContent {...props} consentModalButtonProps={consentModalButtonProps} />
87+
</>
88+
);
89+
}
90+
91+
export const Default = getStory({
92+
gdprPageLink: "#",
93+
services: [
94+
{
95+
name: "mandatory-cookie-consumer",
96+
title: "Any service consuming 🍪",
97+
description: "As a mandatory service, user cannot disable it.",
98+
mandatory: true
99+
},
100+
{
101+
name: "cookie-consumer",
102+
title: "Any service consuming 🍪",
103+
description: "Here you can describe why this service use cookies."
104+
}
105+
],
106+
siteName
107+
});

stories/Display.stories.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ the theme state.
2323
2424
\`\`\`tsx
2525
import { Header } from "@codegouvfr/react-dsfr/Header";
26+
import { Footer } from "@codegouvfr/react-dsfr/Footer";
2627
import { Display, headerFooterDisplayItem } from "@codegouvfr/react-dsfr/Display";
2728
2829
function App(){

0 commit comments

Comments
 (0)