mirror of
https://github.com/XFox111/my-website.git
synced 2026-04-22 07:28:01 +03:00
feat!: added cookie consent banner and management system
This commit is contained in:
@@ -0,0 +1,83 @@
|
||||
@import "../theme.scss";
|
||||
|
||||
.banner
|
||||
{
|
||||
@include flex(row);
|
||||
position: fixed;
|
||||
left: 0;
|
||||
bottom: 8%;
|
||||
background-color: $colorNeutralBackground2;
|
||||
z-index: 20;
|
||||
|
||||
.learnMore
|
||||
{
|
||||
gap: $spacingL;
|
||||
padding: $spacingMNudge $spacingL;
|
||||
background-size: $spacingMNudge 100%;
|
||||
flex-grow: 1;
|
||||
justify-content: flex-start;
|
||||
|
||||
p
|
||||
{
|
||||
color: $colorNeutralForeground2;
|
||||
@include body1;
|
||||
|
||||
span
|
||||
{
|
||||
color: $colorNeutralForeground1;
|
||||
@include body2($fontFamilyBaseAlt);
|
||||
}
|
||||
}
|
||||
|
||||
&:hover,
|
||||
&:focus-visible
|
||||
{
|
||||
|
||||
p,
|
||||
p > span
|
||||
{
|
||||
color: $colorNeutralForegroundInverted;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.dismiss
|
||||
{
|
||||
border-left: none;
|
||||
}
|
||||
|
||||
.controls
|
||||
{
|
||||
display: grid;
|
||||
grid-auto-flow: column;
|
||||
|
||||
@media screen and (min-width: 769px)
|
||||
{
|
||||
> button
|
||||
{
|
||||
border-left: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (max-width: 768px)
|
||||
{
|
||||
width: 100%;
|
||||
bottom: 0;
|
||||
|
||||
&:not(:has(> .dismiss))
|
||||
{
|
||||
flex-flow: column;
|
||||
|
||||
.learnMore
|
||||
{
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.controls > button:last-child
|
||||
{
|
||||
border-left: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
"use client";
|
||||
|
||||
import { acceptCookies, dismissCookies, getCookieChoice, rejectCookies, requireExcplicitConsent } from "@/_utils/analytics/client";
|
||||
import { Dismiss24Regular } from "@fluentui/react-icons";
|
||||
import React, { useCallback, useEffect, useState } from "react";
|
||||
import Button from "./Button";
|
||||
import cls from "./CookieBanner.module.scss";
|
||||
|
||||
const CookieBanner: React.FC = () =>
|
||||
{
|
||||
const [visible, setVisible] = useState(false);
|
||||
|
||||
useEffect(() =>
|
||||
{
|
||||
const choice = getCookieChoice();
|
||||
setVisible(choice === "none");
|
||||
|
||||
// Since Clarity cookies expiration dates extend well beyond 60 days,
|
||||
// we need to terminate them manually once our consent tracking cookie expires.
|
||||
if (choice !== "accepted")
|
||||
window.clarity?.("consent", false);
|
||||
}, []);
|
||||
|
||||
const accept = useCallback(() =>
|
||||
{
|
||||
acceptCookies();
|
||||
setVisible(false);
|
||||
}, []);
|
||||
|
||||
const reject = useCallback(() =>
|
||||
{
|
||||
rejectCookies();
|
||||
setVisible(false);
|
||||
}, []);
|
||||
|
||||
const dismiss = useCallback(() =>
|
||||
{
|
||||
dismissCookies();
|
||||
setVisible(false);
|
||||
}, []);
|
||||
|
||||
if (!visible)
|
||||
return null;
|
||||
|
||||
return (
|
||||
<div className={ `cookie-banner ${cls.banner}` }>
|
||||
<Button
|
||||
as="next" href="/attribution"
|
||||
className={ cls.learnMore }
|
||||
aria-label="We use cookies for analytics purposes. Click to learn more"
|
||||
icon={ <span>🍪</span> }>
|
||||
|
||||
<p aria-hidden>
|
||||
<span>We use cookies for analytics purposes</span><br />
|
||||
Click to learn more
|
||||
</p>
|
||||
</Button>
|
||||
|
||||
{ requireExcplicitConsent ?
|
||||
<div className={ cls.controls }>
|
||||
<Button onClick={ accept }>Accept</Button>
|
||||
<Button onClick={ reject }>Reject</Button>
|
||||
</div>
|
||||
:
|
||||
<Button
|
||||
title="Dismiss" icon={ <Dismiss24Regular /> }
|
||||
onClick={ dismiss } className={ cls.dismiss } />
|
||||
}
|
||||
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default CookieBanner;
|
||||
@@ -0,0 +1,30 @@
|
||||
"use client";
|
||||
|
||||
import Button from "@/_components/Button";
|
||||
import React, { useCallback, useEffect, useState } from "react";
|
||||
import { getCookieChoice, rejectCookies } from "../_utils/analytics/client";
|
||||
|
||||
const RevokeConsentButton: React.FC = () =>
|
||||
{
|
||||
const [hasConsent, setHasConsent] = useState<boolean>(false);
|
||||
|
||||
useEffect(() =>
|
||||
{
|
||||
console.log("getCookieChoice", getCookieChoice());
|
||||
setHasConsent(getCookieChoice() === "accepted");
|
||||
}, []);
|
||||
|
||||
const revoke = useCallback(() =>
|
||||
{
|
||||
rejectCookies();
|
||||
setHasConsent(false);
|
||||
window.alert("Your consent has been revoked");
|
||||
}, []);
|
||||
|
||||
if (!hasConsent)
|
||||
return null;
|
||||
|
||||
return <Button onClick={ revoke }>Revoke my consent</Button>;
|
||||
};
|
||||
|
||||
export default RevokeConsentButton;
|
||||
Reference in New Issue
Block a user