feat: add Matomo opt-out form
Some checks failed
Deploy Next.js application / deploy (push) Has been cancelled
Some checks failed
Deploy Next.js application / deploy (push) Has been cancelled
This commit is contained in:
parent
e48ee91f03
commit
8afbb6ae44
3 changed files with 246 additions and 33 deletions
35
app/(root)/privacy/layout.jsx
Normal file
35
app/(root)/privacy/layout.jsx
Normal file
|
@ -0,0 +1,35 @@
|
|||
export const metadata = {
|
||||
title: "Privacy Policy - MERNMail",
|
||||
description:
|
||||
"Learn how we collect, use, and protect your data. Our Privacy Policy outlines our commitment to your privacy and the measures we take to safeguard your information when visiting our website.",
|
||||
openGraph: {
|
||||
title: "Privacy Policy - MERNMail",
|
||||
description:
|
||||
"Learn how we collect, use, and protect your data. Our Privacy Policy outlines our commitment to your privacy and the measures we take to safeguard your information when visiting our website.",
|
||||
url: `${process.env.NEXT_PUBLIC_WEBSITE_URL}/privacy`,
|
||||
type: "website",
|
||||
images: [
|
||||
{
|
||||
url: `${process.env.NEXT_PUBLIC_WEBSITE_URL}/metadata/mernmail-cover.png`,
|
||||
width: 2560,
|
||||
height: 1440,
|
||||
alt: "Privacy Policy - MERNMail"
|
||||
}
|
||||
]
|
||||
},
|
||||
twitter: {
|
||||
card: "summary_large_image",
|
||||
site: "@MERNMail",
|
||||
title: "Privacy Policy - MERNMail",
|
||||
description:
|
||||
"Learn how we collect, use, and protect your data. Our Privacy Policy outlines our commitment to your privacy and the measures we take to safeguard your information when visiting our website.",
|
||||
images: [
|
||||
`${process.env.NEXT_PUBLIC_WEBSITE_URL}/metadata/mernmail-cover.png`
|
||||
],
|
||||
creator: "@MERNMail"
|
||||
}
|
||||
};
|
||||
|
||||
export default function PrivacyPolicyLayout({ children }) {
|
||||
return <>{children}</>;
|
||||
}
|
|
@ -1,39 +1,215 @@
|
|||
"use client";
|
||||
import ReactMarkdown from "react-markdown";
|
||||
import { privacyPolicy } from "@/constants/guidelines";
|
||||
import { useEffect } from "react";
|
||||
|
||||
export const metadata = {
|
||||
title: "Privacy Policy - MERNMail",
|
||||
description:
|
||||
"Learn how we collect, use, and protect your data. Our Privacy Policy outlines our commitment to your privacy and the measures we take to safeguard your information when visiting our website.",
|
||||
openGraph: {
|
||||
title: "Privacy Policy - MERNMail",
|
||||
description:
|
||||
"Learn how we collect, use, and protect your data. Our Privacy Policy outlines our commitment to your privacy and the measures we take to safeguard your information when visiting our website.",
|
||||
url: `${process.env.NEXT_PUBLIC_WEBSITE_URL}/privacy`,
|
||||
type: "website",
|
||||
images: [
|
||||
{
|
||||
url: `${process.env.NEXT_PUBLIC_WEBSITE_URL}/metadata/mernmail-cover.png`,
|
||||
width: 2560,
|
||||
height: 1440,
|
||||
alt: "Privacy Policy - MERNMail"
|
||||
}
|
||||
]
|
||||
function matomoOptOutPlugin() {
|
||||
return (tree) => {
|
||||
const paragraph = tree.children.find(
|
||||
(node) =>
|
||||
node.type === "element" &&
|
||||
node.tagName == "p" &&
|
||||
node.children[0].value === "MATOMOOPTOUT"
|
||||
);
|
||||
|
||||
if (paragraph) {
|
||||
const div = {
|
||||
type: "element",
|
||||
tagName: "div",
|
||||
properties: {
|
||||
id: "matomo-opt-out"
|
||||
},
|
||||
twitter: {
|
||||
card: "summary_large_image",
|
||||
site: "@MERNMail",
|
||||
title: "Privacy Policy - MERNMail",
|
||||
description:
|
||||
"Learn how we collect, use, and protect your data. Our Privacy Policy outlines our commitment to your privacy and the measures we take to safeguard your information when visiting our website.",
|
||||
images: [
|
||||
`${process.env.NEXT_PUBLIC_WEBSITE_URL}/metadata/mernmail-cover.png`
|
||||
],
|
||||
creator: "@MERNMail"
|
||||
children: []
|
||||
};
|
||||
|
||||
tree.children.splice(tree.children.indexOf(paragraph), 1, div);
|
||||
}
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
function Contribute() {
|
||||
useEffect(() => {
|
||||
const settings = {
|
||||
showIntro: true,
|
||||
divId: "matomo-opt-out",
|
||||
useSecureCookies: true,
|
||||
cookiePath: null,
|
||||
cookieDomain: null,
|
||||
cookieSameSite: "Lax",
|
||||
OptOutComplete:
|
||||
"Opt-out complete; your visits to this website will not be recorded by the Web Analytics tool.",
|
||||
OptOutCompleteBis:
|
||||
"Note that if you clear your cookies, delete the opt-out cookie, or if you change computers or Web browsers, you will need to perform the opt-out procedure again.",
|
||||
YouMayOptOut2:
|
||||
"You may choose to prevent this website from aggregating and analyzing the actions you take here.",
|
||||
YouMayOptOut3:
|
||||
"Doing so will protect your privacy, but will also prevent the owner from learning from your actions and creating a better experience for you and other users.",
|
||||
OptOutErrorNoCookies:
|
||||
"The tracking opt-out feature requires cookies to be enabled.",
|
||||
OptOutErrorNotHttps:
|
||||
"The tracking opt-out feature may not work because this site was not loaded over HTTPS. Please reload the page to check if your opt out status changed.",
|
||||
YouAreNotOptedOut: "You are not opted out.",
|
||||
UncheckToOptOut: "Uncheck this box to opt-out.",
|
||||
YouAreOptedOut: "You are currently opted out.",
|
||||
CheckToOptIn: "Check this box to opt-in."
|
||||
};
|
||||
|
||||
window.showContent = function (
|
||||
consent,
|
||||
errorMessage = null,
|
||||
useTracker = false
|
||||
) {
|
||||
const errorBlock = '<p style="color: red; font-weight: bold;">';
|
||||
|
||||
const div = document.getElementById(settings.divId);
|
||||
if (!div) {
|
||||
const warningDiv = document.createElement("div");
|
||||
const msg = `Unable to find opt-out content div: "${settings.divId}"`;
|
||||
warningDiv.id = `${settings.divId}-warning`;
|
||||
warningDiv.innerHTML = `${errorBlock}${msg}</p>`;
|
||||
document.body.insertBefore(warningDiv, document.body.firstChild);
|
||||
console.log(msg);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!navigator || !navigator.cookieEnabled) {
|
||||
div.innerHTML = `${errorBlock}${settings.OptOutErrorNoCookies}</p>`;
|
||||
return;
|
||||
}
|
||||
|
||||
if (errorMessage !== null) {
|
||||
div.innerHTML = `${errorBlock}${errorMessage}</p>`;
|
||||
return;
|
||||
}
|
||||
|
||||
let content = "";
|
||||
|
||||
if (location.protocol !== "https:") {
|
||||
content += `${errorBlock}${settings.OptOutErrorNotHttps}</p>`;
|
||||
}
|
||||
|
||||
if (consent) {
|
||||
if (settings.showIntro) {
|
||||
content += `<p>${settings.YouMayOptOut2} ${settings.YouMayOptOut3}</p>`;
|
||||
}
|
||||
if (useTracker) {
|
||||
content +=
|
||||
'<input onclick="_paq.push([\'optUserOut\']);showContent(false, null, true);" id="trackVisits" type="checkbox" checked="checked" />';
|
||||
} else {
|
||||
content +=
|
||||
'<input onclick="window.MatomoConsent.consentRevoked();showContent(false);" id="trackVisits" type="checkbox" checked="checked" />';
|
||||
}
|
||||
content += `<label for="trackVisits"><strong><span>${settings.YouAreNotOptedOut} ${settings.UncheckToOptOut}</span></strong></label>`;
|
||||
} else {
|
||||
if (settings.showIntro) {
|
||||
content += `<p>${settings.OptOutComplete} ${settings.OptOutCompleteBis}</p>`;
|
||||
}
|
||||
if (useTracker) {
|
||||
content +=
|
||||
'<input onclick="_paq.push([\'forgetUserOptOut\']);showContent(true, null, true);" id="trackVisits" type="checkbox" />';
|
||||
} else {
|
||||
content +=
|
||||
'<input onclick="window.MatomoConsent.consentGiven();showContent(true);" id="trackVisits" type="checkbox" />';
|
||||
}
|
||||
content += `<label for="trackVisits"><strong><span>${settings.YouAreOptedOut} ${settings.CheckToOptIn}</span></strong></label>`;
|
||||
}
|
||||
div.innerHTML = content;
|
||||
};
|
||||
|
||||
window.MatomoConsent = {
|
||||
cookiesDisabled: !navigator || !navigator.cookieEnabled,
|
||||
CONSENT_COOKIE_NAME: "mtm_consent",
|
||||
CONSENT_REMOVED_COOKIE_NAME: "mtm_consent_removed",
|
||||
cookieIsSecure: false,
|
||||
useSecureCookies: true,
|
||||
cookiePath: "",
|
||||
cookieDomain: "",
|
||||
cookieSameSite: "Lax",
|
||||
init: function (
|
||||
useSecureCookies,
|
||||
cookiePath,
|
||||
cookieDomain,
|
||||
cookieSameSite
|
||||
) {
|
||||
this.useSecureCookies = useSecureCookies;
|
||||
this.cookiePath = cookiePath;
|
||||
this.cookieDomain = cookieDomain;
|
||||
this.cookieSameSite = cookieSameSite;
|
||||
if (useSecureCookies && location.protocol !== "https:") {
|
||||
console.log(
|
||||
"Error with setting useSecureCookies: You cannot use this option on http."
|
||||
);
|
||||
} else {
|
||||
this.cookieIsSecure = useSecureCookies;
|
||||
}
|
||||
},
|
||||
hasConsent: function () {
|
||||
const consentCookie = this.getCookie(this.CONSENT_COOKIE_NAME);
|
||||
const removedCookie = this.getCookie(this.CONSENT_REMOVED_COOKIE_NAME);
|
||||
if (!consentCookie && !removedCookie) {
|
||||
return true; // No cookies set, so opted in
|
||||
}
|
||||
if (removedCookie && consentCookie) {
|
||||
this.setCookie(this.CONSENT_COOKIE_NAME, "", -129600000);
|
||||
return false;
|
||||
}
|
||||
return consentCookie || consentCookie !== 0;
|
||||
},
|
||||
consentGiven: function () {
|
||||
this.setCookie(this.CONSENT_REMOVED_COOKIE_NAME, "", -129600000);
|
||||
this.setCookie(
|
||||
this.CONSENT_COOKIE_NAME,
|
||||
new Date().getTime(),
|
||||
946080000000
|
||||
);
|
||||
},
|
||||
consentRevoked: function () {
|
||||
this.setCookie(this.CONSENT_COOKIE_NAME, "", -129600000);
|
||||
this.setCookie(
|
||||
this.CONSENT_REMOVED_COOKIE_NAME,
|
||||
new Date().getTime(),
|
||||
946080000000
|
||||
);
|
||||
},
|
||||
getCookie: function (cookieName) {
|
||||
const cookiePattern = new RegExp("(^|;)[ ]*" + cookieName + "=([^;]*)");
|
||||
const cookieMatch = cookiePattern.exec(document.cookie);
|
||||
return cookieMatch ? window.decodeURIComponent(cookieMatch[2]) : 0;
|
||||
},
|
||||
setCookie: function (cookieName, value, msToExpire) {
|
||||
const expiryDate = new Date();
|
||||
expiryDate.setTime(new Date().getTime() + msToExpire);
|
||||
document.cookie =
|
||||
cookieName +
|
||||
"=" +
|
||||
window.encodeURIComponent(value) +
|
||||
(msToExpire ? ";expires=" + expiryDate.toGMTString() : "") +
|
||||
";path=" +
|
||||
(this.cookiePath || "/") +
|
||||
(this.cookieDomain ? ";domain=" + this.cookieDomain : "") +
|
||||
(this.cookieIsSecure ? ";secure" : "") +
|
||||
";SameSite=" +
|
||||
this.cookieSameSite;
|
||||
if (
|
||||
(!msToExpire || msToExpire >= 0) &&
|
||||
this.getCookie(cookieName) !== String(value)
|
||||
) {
|
||||
console.log(
|
||||
`There was an error setting cookie \`${cookieName}\`. Please check domain and path.`
|
||||
);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
window.MatomoConsent.init(
|
||||
settings.useSecureCookies,
|
||||
settings.cookiePath,
|
||||
settings.cookieDomain,
|
||||
settings.cookieSameSite
|
||||
);
|
||||
showContent(window.MatomoConsent.hasConsent());
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<main className="max-w-screen-xl mx-auto px-4 py-6 md:py-28 gap-2 flex flex-col">
|
||||
<h1 className="text-3xl md:text-5xl pb-1 md:pb-2 font-bold">
|
||||
|
@ -43,7 +219,9 @@ function Contribute() {
|
|||
Effective date: November 7, 2024
|
||||
</p>
|
||||
<div className="prose prose-a:text-primary max-w-full md:prose-lg dark:prose-invert">
|
||||
<ReactMarkdown>{privacyPolicy}</ReactMarkdown>
|
||||
<ReactMarkdown rehypePlugins={[matomoOptOutPlugin]}>
|
||||
{privacyPolicy}
|
||||
</ReactMarkdown>
|
||||
</div>
|
||||
</main>
|
||||
);
|
||||
|
|
|
@ -160,7 +160,7 @@ These third parties have access to your Personal Data only to perform these task
|
|||
|
||||
We are using a self-hosted Matomo instance at _analytics.svrjs.org_ to monitor and analyze the use of our Service.
|
||||
|
||||
You may choose to prevent this website from aggregating and analyzing the actions you take here. Doing so will protect your privacy, but will also prevent the owner from learning from your actions and creating a better experience for you and other users. You can visit the [opt-out form there](https://analytics.svrjs.org/index.php?module=CoreAdminHome&action=optOut&language=en-US).
|
||||
MATOMOOPTOUT
|
||||
|
||||
## 15\. CI/CD tools
|
||||
|
||||
|
|
Loading…
Reference in a new issue