feat: add cookie consent banner and page

This commit is contained in:
Sosokker 2024-12-14 10:25:47 +07:00
parent 05d2ad739c
commit d9415534fb
4 changed files with 272 additions and 0 deletions

View File

@ -38,6 +38,13 @@ export function NavSidebar() {
</li>
</Link>
<Separator className="bg-gray-200 dark:bg-gray-700" />
<Link href="/cookies">
<li className="flex items-center p-2 relative group hover:scale-105 transition-all duration-200 ease-in-out rounded-md">
<span>Cookies</span>
<div className="absolute bottom-0 left-0 w-full h-[2px] bg-blue-600 scale-x-0 group-hover:scale-x-100 transition-all duration-300"></div>
</li>
</Link>
</ul>
</div>
);

View File

@ -0,0 +1,104 @@
"use client";
import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from "@/components/ui/card";
import TableOfContent from "../Toc";
import { NavSidebar } from "../NavigationSidebar";
const UseOfCookies = () => {
const sections = [
{ id: "introduction", title: "Introduction" },
{ id: "what-are-cookies", title: "What Are Cookies?" },
{ id: "types-of-cookies", title: "Types of Cookies We Use" },
{ id: "why-we-use-cookies", title: "Why We Use Cookies" },
{ id: "managing-cookies", title: "Managing Your Cookie Preferences" },
{ id: "third-party-cookies", title: "Third-Party Cookies" },
{ id: "changes", title: "Changes to Cookie Policy" },
{ id: "contact", title: "Contact Information" },
];
return (
<div className="container max-w-screen-xl flex mt-5">
<div className="flex gap-2">
<NavSidebar />
<TableOfContent sections={sections} />
</div>
<div className="flex-1 ml-4">
<Card className="w-full max-w-3xl bg-white dark:bg-gray-800 shadow-lg rounded-lg">
<CardHeader>
<CardTitle className="text-3xl text-blue-600 dark:text-blue-400">Use of Cookies</CardTitle>
<CardDescription className="text-sm text-gray-500 dark:text-gray-400">
Last Updated: November 17, 2024
</CardDescription>
</CardHeader>
<CardContent>
<div className="prose dark:prose-invert text-gray-800 dark:text-gray-200">
<h2 id="introduction">1. Introduction</h2>
<p>
Our Website uses cookies to improve functionality, analyze performance, and personalize your experience.
This policy explains what cookies are, how we use them, and your options for managing them.
</p>
<h2 id="what-are-cookies">2. What Are Cookies?</h2>
<p>
Cookies are small text files stored on your device when you visit a website. They help the website
remember your preferences, improve functionality, and provide analytical insights.
</p>
<h2 id="types-of-cookies">3. Types of Cookies We Use</h2>
<ul>
<li>
<span className="font-bold">Essential Cookies </span>Required for the core functionality of the
Website, such as navigating pages and accessing secure areas.
</li>
<li>
<span className="font-bold">Analytics Cookies </span>
Collect data on user behavior to improve Website performance and user experience.
</li>
<li>
<span className="font-bold">Personalization Cookies </span>Tailor content and features to match your
preferences.
</li>
</ul>
<h2 id="why-we-use-cookies">4. Why We Use Cookies</h2>
<span>
We use cookies to:
<ul>
<li>Ensure the Website functions properly.</li>
<li>Understand and analyze user behavior.</li>
<li>Provide a personalized browsing experience.</li>
<li>Deliver relevant advertisements and content.</li>
</ul>
</span>
<h2 id="managing-cookies">5. Managing Your Cookie Preferences</h2>
<p>
You can manage or disable cookies through your browser settings. Note that disabling cookies may affect
your experience on our Website. For detailed instructions, refer to your browser&apos;s help section.
</p>
<h2 id="third-party-cookies">6. Third-Party Cookies</h2>
<p>
Some cookies are set by third-party services we use, such as analytics or advertising platforms. These
cookies are subject to the policies of the respective third parties.
</p>
<h2 id="changes">7. Changes to Cookie Policy</h2>
<p>
We may update this cookie policy periodically to reflect changes in technology or legal requirements.
Any updates will be posted on this page with the updated date.
</p>
<h2 id="contact">8. Contact Information</h2>
<p>For questions about this policy or to exercise your rights, contact us at privacy@b2dventure.com.</p>
</div>
</CardContent>
<CardFooter className="flex justify-center"></CardFooter>
</Card>
</div>
</div>
);
};
export default UseOfCookies;

View File

@ -9,6 +9,8 @@ import { NavigationBar } from "@/components/navigationBar/nav";
import { Toaster } from "react-hot-toast";
import { SiteFooter } from "@/components/siteFooter";
import CookieConsent from "@/components/CookieConsent";
const montserrat = Montserrat({
subsets: ["latin"],
display: "swap",
@ -44,6 +46,7 @@ export default function RootLayout({ children }: RootLayoutProps) {
</div>
<NavigationBar />
<div className="flex-1 bg-background">{children}</div>
<CookieConsent />
</div>
<SiteFooter />
</ThemeProvider>

View File

@ -0,0 +1,158 @@
"use client";
import { CookieIcon } from "lucide-react";
import { Button } from "./ui/button";
import { useEffect, useState } from "react";
import { cn } from "@/lib/utils";
import Link from "next/link";
import { createSupabaseClient } from "@/lib/supabase/clientComponentClient";
import useSession from "@/lib/supabase/useSession";
export default function CookieConsent({
variant = "default",
demo = false,
onAcceptCallback = () => {},
onDeclineCallback = () => {},
}) {
const [isOpen, setIsOpen] = useState(false);
const [hide, setHide] = useState(false);
const supabase = createSupabaseClient();
const { session, loading } = useSession();
const userId = session?.user?.id;
const updateConsent = async (consent: boolean) => {
try {
if (!userId) {
return;
}
const { error } = await supabase.from("profiles").update({ consent }).eq("id", userId);
if (error) {
console.error("Failed to update consent:", error.message);
}
} catch (e) {
console.error("Unexpected error updating consent:", e);
}
};
const accept = () => {
setIsOpen(false);
document.cookie = "cookieConsent=true; expires=Fri, 31 Dec 9999 23:59:59 GMT";
setTimeout(() => {
setHide(true);
}, 700);
onAcceptCallback();
updateConsent(true);
};
const decline = () => {
setIsOpen(false);
setTimeout(() => {
setHide(true);
}, 700);
onDeclineCallback();
updateConsent(false);
};
useEffect(() => {
try {
setIsOpen(true);
if (document.cookie.includes("cookieConsent=true")) {
if (!demo) {
setIsOpen(false);
setTimeout(() => {
setHide(true);
}, 700);
}
}
} catch (e) {
// console.log("Error: ", e);
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
if (loading) {
return null;
}
return variant == "default" ? (
<div
className={cn(
"fixed z-[200] bottom-0 left-0 right-0 sm:left-4 sm:bottom-4 w-full sm:max-w-md duration-700",
!isOpen
? "transition-[opacity,transform] translate-y-8 opacity-0"
: "transition-[opacity,transform] translate-y-0 opacity-100",
hide && "hidden"
)}
>
<div className="dark:bg-card bg-background rounded-md m-3 border border-border shadow-lg">
<div className="grid gap-2">
<div className="border-b border-border h-14 flex items-center justify-between p-4">
<h1 className="text-lg font-medium">We use cookies</h1>
<CookieIcon className="h-[1.2rem] w-[1.2rem]" />
</div>
<div className="p-4">
<p className="text-sm font-normal text-start">
We use cookies to ensure you get the best experience on our website. For more information on how we use
cookies, please see our cookie policy.
<br />
<br />
<span className="text-xs">
By clicking &quot;<span className="font-medium opacity-80">Accept</span>&quot;, you agree to our use of
cookies.
</span>
<br />
<Link href="/cookies" className="text-xs underline">
Learn more.
</Link>
</p>
</div>
<div className="flex gap-2 p-4 py-5 border-t border-border dark:bg-background/20">
<Button onClick={accept} className="w-full">
Accept
</Button>
<Button onClick={decline} className="w-full" variant="secondary">
Decline
</Button>
</div>
</div>
</div>
</div>
) : (
variant == "small" && (
<div
className={cn(
"fixed z-[200] bottom-0 left-0 right-0 sm:left-4 sm:bottom-4 w-full sm:max-w-md duration-700",
!isOpen
? "transition-[opacity,transform] translate-y-8 opacity-0"
: "transition-[opacity,transform] translate-y-0 opacity-100",
hide && "hidden"
)}
>
<div className="m-3 dark:bg-card bg-background border border-border rounded-lg">
<div className="flex items-center justify-between p-3">
<h1 className="text-lg font-medium">We use cookies</h1>
<CookieIcon className="h-[1.2rem] w-[1.2rem]" />
</div>
<div className="p-3 -mt-2">
<p className="text-sm text-left text-muted-foreground">
We use cookies to ensure you get the best experience on our website. For more information on how we use
cookies, please see our cookie policy.
</p>
</div>
<div className="p-3 flex items-center gap-2 mt-2 border-t">
<Button onClick={accept} className="w-full h-9 rounded-full">
accept
</Button>
<Button onClick={decline} className="w-full h-9 rounded-full" variant="outline">
decline
</Button>
</div>
</div>
</div>
)
);
}