Skip to content

Commit

Permalink
Merge pull request #62 from Avantage-Numerique/dev
Browse files Browse the repository at this point in the history
Gestions des cookies pour matomo qui gère aussi le consentement du tracking
  • Loading branch information
mamarmite authored Aug 12, 2024
2 parents 6048146 + da268d9 commit c8bd38d
Show file tree
Hide file tree
Showing 9 changed files with 210 additions and 156 deletions.
19 changes: 7 additions & 12 deletions pages/_app.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,23 +7,18 @@ import Layout from '@/src/layouts/Layout';
import {getVisitorDataFromContext} from "@/src/authentification/context/visitor-context";
import {verifyToken} from "@/auth/callbacks/verify-token.callback";
import CookieBanner from "@/common/widgets/CookieBanner/CookieBanner";
/**
* Import global SCSS files
*/
import '@/styles/main.scss';
import useWebStats from "@/src/monitoring/hooks/useWebStats";
import "@/src/helpers/ExtendedString";

import '@/styles/main.scss';

// Extends basic Javascript for the project.
// import "@/src/helpers/ExtendedString";

function MyApp({Component, pageProps, user, serverCookiesChoices}) {
function AVNU({Component, pageProps, user, serverCookiesChoices}) {

const webStats = useWebStats();
const cookieCHoices = serverCookiesChoices;
const cookieChoices = serverCookiesChoices;

useEffect(() => {
webStats.init(cookieCHoices);
webStats.init(cookieChoices);
}, []);
/**
* Main app render.
Expand All @@ -47,7 +42,7 @@ function MyApp({Component, pageProps, user, serverCookiesChoices}) {
* @return {Promise<{pageProps: {visitor: {ip: string, browser: string}}}>}
* @inheritDoc https://nextjs.org/docs/api-reference/data-fetching/get-initial-props
*/
MyApp.getInitialProps = async (context) => {
AVNU.getInitialProps = async (context) => {

const appProps = await App.getInitialProps(context);
if (context.ctx.req && context.ctx.res) {
Expand Down Expand Up @@ -118,4 +113,4 @@ MyApp.getInitialProps = async (context) => {
}

//it isn't call in _app : noMyApp.getServerSideProps or I didn't declare it the good way.
export default MyApp;
export default AVNU;
69 changes: 49 additions & 20 deletions pages/parametres/cookies.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import PageHeader from "@/layouts/Header/PageHeader";
import {useAuth} from "@/auth/context/auth-context";
import {lang} from "@/common/Data/GlobalConstants";
import Button from "@/FormElements/Button/Button";
import {changeCookieChoices} from "@/common/Cookies/cookiesChoices";
import {changeCookieChoices, cookiesExplanations} from "@/common/Cookies/cookiesChoices";
import Image from 'next/image';
import fetchInternalApi from "@/src/api/fetchInternalApi";

Expand Down Expand Up @@ -43,50 +43,79 @@ const CookiesParams = () => {
/>

<section className={`container pt-5`}>
<div className="row">
<div className={"col-3 d-flex align-items-center justify-content-center"}>
<div className="row align-items-center justify-content-center">
<div className={"col-3"}>
{auth.cookiesChoices.choiceMade === true ?
<Image src={"/general_images/avnu-cookies-confirmed-thumb.png"} alt={"Cookies paramétrés!"} width={226} height={116} />
:
<Image src={"/general_images/avnu-cookies-thumb.png"} alt={"Cookies non paramétrés"} width={226} height={116} />
<Image src={"/general_images/avnu-cookies-confirmed-thumb.png"} alt={"Cookies paramétrés!"}
width={226} height={116}/>
:
<Image src={"/general_images/avnu-cookies-thumb.png"} alt={"Cookies non paramétrés"}
width={226} height={116}/>
}
</div>
<div className={"col-9"}>
</div>
<div className="row">
<div className={"col-12"}>
{!cookieEnabled &&
<p className={"alert alert-primary"}>{lang.cookieDisabled}</p>
}
<h3>{auth.cookiesChoices.choiceMade === true ? lang.cookieMessageThanks : lang.cookieMessageNeedAnswer}</h3>
{cookieEnabled &&
<div className={"d-grid column my-5"}>
<Button onClick={changeChoices} outline={"secondary"} className={"btn-lg"}>{lang.cookieChangeChoice}</Button>
</div>
}
</div>

<div className={"col-12"}>
<ul className={"list-group"}>
<ul className={"list-group mt-3"}>
{Object.keys(auth.cookiesChoices).map((key, index) => {

if (!skipChoicesProperties.includes(key)) {
return (
<li className={"list-group-item d-flex justify-content-between align-items-center"}
key={`cookiesChoices${index}`}>
<p className={"fs-4 m-0 py-1"}>
{lang[`cookie${key.capitalize()}`]}
</p>
<div>
<label className={`me-2 text-${auth.cookiesChoices[key] === true ? "success" : "danger"}`}>{auth.cookiesChoices[key] === true ? lang.cookiePositive : lang.cookieNegative}</label>
<span className={`badge text-bg-${auth.cookiesChoices[key] === true ? "success" : "danger"} m-0`}>&nbsp;</span>
<div className={"pe-5"}>
<p className={"fs-4 m-0 pt-1"}>
{lang[`cookie${key.capitalize()}`]}
</p>
<p className={"m-0 pb-1"}>{cookiesExplanations[key]}</p>
</div>
<div className={"w-25 text-end"}>
{auth.cookiesChoices.choiceMade === true &&
<>
<label
className={`me-2 text-${auth.cookiesChoices[key] === true ? "success" : "danger"}`}>{auth.cookiesChoices[key] === true ? lang.cookiePositive : lang.cookieNegative}</label>
<span
className={`badge text-bg-${auth.cookiesChoices[key] === true ? "success" : "danger"} m-0`}>&nbsp;</span>
</>
}
</div>
</li>
);
}
})
}
</ul>

{cookieEnabled &&
<div className={"d-flex align-items-center justify-content-center my-5"}>
<Button onClick={changeChoices}
color={(auth.cookiesChoices.choiceMade === true ? "danger" : "warning")}
className={"btn-lg"}>{auth.cookiesChoices.choiceMade === true ? lang.cookieChangeChoice : lang.cookieMakeYourChoice}</Button>
</div>
}
</div>

<div className={"col-12 pt-5"}>
<div className={"alert alert-info d-flex justify-content-between align-items-center"}
key={`cookiesChoices123third`}>
<div className={"pe-5"}>
<p className={"fs-5 m-0 pt-1"}>
{cookiesExplanations.third}
</p>
</div>
</div>
</div>
</div>
</section>
</div>
)
)
}

export default CookiesParams;
7 changes: 6 additions & 1 deletion pages/searchResults/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,12 @@ const SearchResults = (props) => {
<h3>{resultMessage}</h3>
{
searchCount > 0 ?
<EntitiesGrid className={"row"} feed={filteredList.filter(el => el.type !== "Taxonomy")} badgesInfo={props.badgesInfo}></EntitiesGrid>
<EntitiesGrid
className={"row"}
feed={filteredList.filter(el => el.type !== "Taxonomy")}
badgesInfo={props.badgesInfo}
columnClass={"col-12 col-sm-6 col-lg-4 g-4 "}
></EntitiesGrid>
:
<div>Aucune entité trouvée, réessayer avec d'autre critère de recherche</div>
}
Expand Down
5 changes: 3 additions & 2 deletions src/authentification/context/auth-context.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import defaultCookiesChoices from "@/src/common/Cookies/cookiesChoices";

import {csSaveCookieChoices} from "@/common/Cookies/clientSideSaveCookiesChoices";
import fetchInternalApi from "@/src/api/fetchInternalApi";
import useWebStats from "@/src/monitoring/hooks/useWebStats";

export const defaultSessionData = {
isPending: false,
Expand Down Expand Up @@ -81,11 +82,11 @@ export function AuthProvider({fromSessionUser, appMode, acceptedCookies, childre

const [cookiesChoices, setCookiesChoices] = useState(acceptedCookies ?? defaultCookiesChoices)
const [choiceHasToBeMade, setChoiceHasToBeMade] = useState(!acceptedCookies?.choiceMade ?? true);

const webStats = useWebStats();
const saveCookieChoices = async (choices) => {
await csSaveCookieChoices(choices);
setCookiesChoices(choices);

webStats.init(choices);
if (!choices.auth) {
await logOutUser();
}
Expand Down
10 changes: 10 additions & 0 deletions src/common/Cookies/cookiesChoices.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import {lang} from "@/common/Data/GlobalConstants";

/**
* Default and choices for cookies
* @type {{all: boolean, third: boolean, stats: boolean, auth: boolean}}
Expand Down Expand Up @@ -34,6 +36,14 @@ export const noCookiesAccepted = {
third:false//no plan of adding that.
}

export const cookiesExplanations = {
choiceMade:"",
all:lang.cookieExplainAll,
stats:lang.cookieExplainStats,
auth:lang.cookieExplainAuth,
third:lang.cookieExplainThird//no plan of adding that.
}

export const changeCookieChoices = (choices) => {
choices.choiceMade = false;
return choices;
Expand Down
5 changes: 5 additions & 0 deletions src/languages/fr-ca/cookies.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,17 @@ const cookies = {
"cookieAuth":"Les cookies d'authentification",
"cookieThird":"Les cookies de partie tier",
"cookieChangeChoice": "Changer mon choix",
"cookieMakeYourChoice": "Faire mon choix",
"cookieMessageThanks": `Vous avez sélectionné vos préférences pour les miettes (cookies) d'${appConfig.name}`,
"cookieMessageNeedAnswer": `Il faut absolument que tu choisisses un niveau de miettes (cookies). Même si on utilise aucun cookie intersite.`,
"cookieMessageNeedAuthCookie": `Il faut absolument accepter les cookies de connexion pour continuer.`,
"cookieDisabled": `${appConfig.name} a besoin d'enregistrer des cookies pour fonctionner. Il faut activer les cookies dans votre navigateur.`,
"cookieNoThirdParty": `${appConfig.name} n'utilise pas de cookie tiers.`,
"cookieDisabledButtonLabel": "Compris",
"cookieExplainAll":"",
"cookieExplainStats":`Nous recueillons des statistiques anonymisées sur l'utilisation de la plateforme. Les pages visitées, les recherches effectuées dans ${appConfig.name}, les endroits où tu as quitter la plateforme. Avec l'outil Matomo.`,
"cookieExplainAuth":`Sans lui tu ne peux pas contribuer à ${appConfig.name}. On en a besoin pour être en mesure de t'identifier et que ton navigateur se souvienne que tu es connecté.`,
"cookieExplainThird":`On ne suit pas les cookies tiers dans ${appConfig.name}. Aucun. Et on ne planifie pas de le faire.`,
}
/*
choiceMade:false,
Expand Down
36 changes: 33 additions & 3 deletions src/monitoring/Matomo.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import {init, push} from "@socialgouv/matomo-next";
/**
* Layer to manage the Matomo API and the Lib @socialgouv/matomo-next
* It use the singleton patern and it's available throught the useWebStats hooks.
* Cookies stored by matomo : https://fr.matomo.org/faq/faq_146/ ‘_pk_ref’, ‘_pk_cvar’, ‘_pk_id’, ‘_pk_ses’, ‘mtm_consent’, ‘mtm_consent_removed’ et ‘mtm_cookie_consent’, matomo_sessid’, ‘_pk_hsr’
*/
class Matomo {
static _instance;
Expand All @@ -29,14 +30,18 @@ class Matomo {

init(applicationCookiesParams) {
this.cookieChoices = applicationCookiesParams;

//https://developer.matomo.org/guides/tracking-consent
if (this.url && this.id) {
init(
{
url: this.url,
siteId: this.id,
onInitialization: this.onInitialization.bind(this),
//onRouteChangeStart: this.onRouteChangeStart.bind(this),
//onRouteChangeComplete: this.onRouteChangeComplete,
//excludeUrlsPatterns: [/^\/login.php/, /\?token=.+/],
disableCookies: this.cookieChoices?.stats === true,
disableCookies: this.cookieChoices?.stats === false,
}
);
return;
Expand All @@ -57,14 +62,39 @@ class Matomo {
push(stats);
}

onInitialization() {
this.pushConsent();
}

pushConsent() {
if (!this.cookieChoices?.stats) {
this.setRequiringConsent();
}
if (this.cookieChoices?.stats) {
this.setConsentGiven();
}
}

setConsentGiven() {
this.push(['setConsentGiven']);
this.push(['setCookieConsentGiven']);
}

setRequiringConsent() {
this.push(['requireConsent']);
this.push(['requireCookieConsent']);
}

onRouteChangeStart(path) {
//this.pushConsent();
}

onRouteChangeComplete(path) {
//needed for the searchCount uri query var ?
if (path.startWidth("/searchResults")) {
this.push(['trackSiteSearch', searchIndex, (nearTaxonomy?.nearestTaxonomy?.name ?? undefined), totalSearchRequestResults]);
//push(["trackSiteSearch", q !== null && q !== void 0 ? q : ""]);
}
};

}

export {Matomo};
Loading

0 comments on commit c8bd38d

Please sign in to comment.