Files
appforge/src/components/CookieConsent.tsx
T

216 lines
7.2 KiB
TypeScript
Raw Normal View History

import { useState, useEffect } from "react";
import { Button } from "@/components/ui/button";
import { Card, CardContent } from "@/components/ui/card";
import { Switch } from "@/components/ui/switch";
import { Label } from "@/components/ui/label";
import { Cookie, X, Settings, Shield } from "lucide-react";
import { Link } from "react-router-dom";
import {
Dialog,
DialogContent,
DialogDescription,
DialogHeader,
DialogTitle,
} from "@/components/ui/dialog";
interface CookiePreferences {
necessary: boolean;
analytics: boolean;
marketing: boolean;
}
const COOKIE_CONSENT_KEY = "cookie-consent";
const COOKIE_PREFERENCES_KEY = "cookie-preferences";
const CookieConsent = () => {
const [showBanner, setShowBanner] = useState(false);
const [showSettings, setShowSettings] = useState(false);
const [preferences, setPreferences] = useState<CookiePreferences>({
necessary: true, // Always required
analytics: false,
marketing: false,
});
useEffect(() => {
const consent = localStorage.getItem(COOKIE_CONSENT_KEY);
if (!consent) {
// Small delay to avoid flash on page load
const timer = setTimeout(() => setShowBanner(true), 1000);
return () => clearTimeout(timer);
} else {
const savedPreferences = localStorage.getItem(COOKIE_PREFERENCES_KEY);
if (savedPreferences) {
setPreferences(JSON.parse(savedPreferences));
}
}
}, []);
const handleAcceptAll = () => {
const allAccepted: CookiePreferences = {
necessary: true,
analytics: true,
marketing: true,
};
saveConsent(allAccepted);
};
const handleRejectAll = () => {
const onlyNecessary: CookiePreferences = {
necessary: true,
analytics: false,
marketing: false,
};
saveConsent(onlyNecessary);
};
const handleSavePreferences = () => {
saveConsent(preferences);
setShowSettings(false);
};
const saveConsent = (prefs: CookiePreferences) => {
localStorage.setItem(COOKIE_CONSENT_KEY, "true");
localStorage.setItem(COOKIE_PREFERENCES_KEY, JSON.stringify(prefs));
setPreferences(prefs);
setShowBanner(false);
// Dispatch custom event for analytics scripts to listen to
window.dispatchEvent(
new CustomEvent("cookie-consent-updated", { detail: prefs })
);
};
if (!showBanner) return null;
return (
<>
{/* Cookie Banner */}
<div className="fixed bottom-0 left-0 right-0 z-50 p-4 animate-fade-in">
<Card className="max-w-4xl mx-auto glass-card border-border/50 shadow-2xl">
<CardContent className="p-6">
<div className="flex flex-col md:flex-row items-start md:items-center gap-4">
<div className="flex items-start gap-3 flex-1">
<div className="p-2 rounded-lg bg-primary/10">
<Cookie className="w-6 h-6 text-primary" />
</div>
<div className="space-y-1">
<h3 className="font-semibold text-foreground">
We value your privacy
</h3>
<p className="text-sm text-muted-foreground">
We use cookies to enhance your browsing experience, serve
personalized content, and analyze our traffic. By clicking
"Accept All", you consent to our use of cookies.{" "}
<Link
to="/privacy"
className="text-primary hover:underline"
>
Read our Privacy Policy
</Link>
</p>
</div>
</div>
<div className="flex flex-wrap items-center gap-2 w-full md:w-auto">
<Button
variant="outline"
size="sm"
onClick={() => setShowSettings(true)}
className="gap-2"
>
<Settings className="w-4 h-4" />
Customize
</Button>
<Button variant="outline" size="sm" onClick={handleRejectAll}>
Reject All
</Button>
<Button size="sm" onClick={handleAcceptAll}>
Accept All
</Button>
</div>
</div>
</CardContent>
</Card>
</div>
{/* Cookie Settings Dialog */}
<Dialog open={showSettings} onOpenChange={setShowSettings}>
<DialogContent className="sm:max-w-lg">
<DialogHeader>
<DialogTitle className="flex items-center gap-2">
<Shield className="w-5 h-5 text-primary" />
Cookie Preferences
</DialogTitle>
<DialogDescription>
Manage your cookie preferences. You can enable or disable
different types of cookies below.
</DialogDescription>
</DialogHeader>
<div className="space-y-6 py-4">
{/* Necessary Cookies */}
<div className="flex items-start justify-between gap-4">
<div className="space-y-1">
<Label className="text-base font-medium">
Necessary Cookies
</Label>
<p className="text-sm text-muted-foreground">
Essential for the website to function properly. Cannot be
disabled.
</p>
</div>
<Switch checked={true} disabled />
</div>
{/* Analytics Cookies */}
<div className="flex items-start justify-between gap-4">
<div className="space-y-1">
<Label className="text-base font-medium">
Analytics Cookies
</Label>
<p className="text-sm text-muted-foreground">
Help us understand how visitors interact with our website to
improve user experience.
</p>
</div>
<Switch
checked={preferences.analytics}
onCheckedChange={(checked) =>
setPreferences((prev) => ({ ...prev, analytics: checked }))
}
/>
</div>
{/* Marketing Cookies */}
<div className="flex items-start justify-between gap-4">
<div className="space-y-1">
<Label className="text-base font-medium">
Marketing Cookies
</Label>
<p className="text-sm text-muted-foreground">
Used to track visitors across websites to display relevant
advertisements.
</p>
</div>
<Switch
checked={preferences.marketing}
onCheckedChange={(checked) =>
setPreferences((prev) => ({ ...prev, marketing: checked }))
}
/>
</div>
</div>
<div className="flex justify-end gap-2">
<Button variant="outline" onClick={handleRejectAll}>
Reject All
</Button>
<Button onClick={handleSavePreferences}>Save Preferences</Button>
</div>
</DialogContent>
</Dialog>
</>
);
};
export default CookieConsent;