From 273b687e24b60cd8c786f757418a2b0e80e32023 Mon Sep 17 00:00:00 2001 From: GlenFonceca Date: Thu, 16 Oct 2025 21:49:42 +0530 Subject: [PATCH] feat: add cookie consent banner component for react --- .../cookie-consent-banner/CookieConsent.jsx | 476 ++++++++++++++++++ .../react/cookie-consent-banner/README.md | 198 ++++++++ .../cookie-consent-banner/component.json | 70 +++ 3 files changed, 744 insertions(+) create mode 100644 components/modal/react/cookie-consent-banner/CookieConsent.jsx create mode 100644 components/modal/react/cookie-consent-banner/README.md create mode 100644 components/modal/react/cookie-consent-banner/component.json diff --git a/components/modal/react/cookie-consent-banner/CookieConsent.jsx b/components/modal/react/cookie-consent-banner/CookieConsent.jsx new file mode 100644 index 0000000..4e2567e --- /dev/null +++ b/components/modal/react/cookie-consent-banner/CookieConsent.jsx @@ -0,0 +1,476 @@ +import React, { useState, useEffect } from 'react' +import {LuCookie, LuX, LuChevronDown, LuChevronUp } from "react-icons/lu"; + +// Custom Hook for Cookie Consent Management +const useCookieConsent = (cookieName = 'user_cookie_consent', expiryDays = 365) => { + const [consent, setConsent] = useState(null) + const [showBanner, setShowBanner] = useState(false) + + // Get consent from cookie + const getConsent = () => { + if (typeof document === 'undefined') return null + + const cookies = document.cookie.split(';') + for (let cookie of cookies) { + const [name, value] = cookie.trim().split('=') + if (name === cookieName) { + try { + return JSON.parse(decodeURIComponent(value)) + } catch (e) { + return null + } + } + } + return null + } + + // Save consent to cookie + const saveConsent = (consentData) => { + if (typeof document === 'undefined') return + + const consentString = JSON.stringify(consentData) + const expiryDate = new Date() + expiryDate.setDate(expiryDate.getDate() + expiryDays) + + document.cookie = `${cookieName}=${encodeURIComponent(consentString)}; expires=${expiryDate.toUTCString()}; path=/; SameSite=Lax` + setConsent(consentData) + setShowBanner(false) + } + + // Accept all cookies + const acceptAll = () => { + const consentData = { + essential: true, + analytics: true, + marketing: true, + preferences: true, + timestamp: new Date().toISOString() + } + saveConsent(consentData) + return consentData + } + + // Reject all cookies + const rejectAll = () => { + const consentData = { + essential: true, + analytics: false, + marketing: false, + preferences: false, + timestamp: new Date().toISOString() + } + saveConsent(consentData) + return consentData + } + + // Save custom preferences + const savePreferences = (preferences) => { + const consentData = { + essential: true, + analytics: preferences.analytics || false, + marketing: preferences.marketing || false, + preferences: preferences.preferences || false, + timestamp: new Date().toISOString() + } + saveConsent(consentData) + return consentData + } + + // Withdraw consent + const withdrawConsent = () => { + if (typeof document === 'undefined') return + + document.cookie = `${cookieName}=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;` + setConsent(null) + setShowBanner(true) + } + + // Check for existing consent on mount + useEffect(() => { + const existingConsent = getConsent() + if (existingConsent) { + setConsent(existingConsent) + setShowBanner(false) + } else { + setShowBanner(true) + } + }, []) + + return { + consent, + showBanner, + acceptAll, + rejectAll, + savePreferences, + withdrawConsent + } +} + +// Cookie Preferences Modal Component +const CookiePreferences = ({ isOpen, onClose, onSave, currentPreferences }) => { + const [preferences, setPreferences] = useState({ + analytics: false, + marketing: false, + preferences: false + }) + + const [expandedCategories, setExpandedCategories] = useState({}) + + useEffect(() => { + if (currentPreferences) { + setPreferences({ + analytics: currentPreferences.analytics || false, + marketing: currentPreferences.marketing || false, + preferences: currentPreferences.preferences || false + }) + } + }, [currentPreferences]) + + const toggleCategory = (category) => { + setExpandedCategories(prev => ({ + ...prev, + [category]: !prev[category] + })) + } + + const handleSave = () => { + onSave(preferences) + } + + if (!isOpen) return null + + const categories = [ + { + id: 'essential', + title: 'Essential Cookies', + description: 'Required for the website to function properly. Cannot be disabled.', + required: true, + cookies: [ + { name: 'user_cookie_consent', duration: '1 year', purpose: 'Stores user cookie preferences' } + ] + }, + { + id: 'analytics', + title: 'Analytics Cookies', + description: 'Help us understand how visitors interact with our website by collecting and reporting information anonymously.', + required: false, + cookies: [ + { name: '_ga', duration: '2 years', purpose: 'Google Analytics - distinguishes users' }, + { name: '_gid', duration: '24 hours', purpose: 'Google Analytics - distinguishes users' } + ] + }, + { + id: 'marketing', + title: 'Marketing Cookies', + description: 'Used to deliver personalized advertisements relevant to you and your interests.', + required: false, + cookies: [ + { name: '_fbp', duration: '3 months', purpose: 'Facebook Pixel - tracks conversions' }, + { name: 'IDE', duration: '1 year', purpose: 'Google Ads - advertising tracking' } + ] + }, + { + id: 'preferences', + title: 'Preference Cookies', + description: 'Remember your settings and preferences for a better experience.', + required: false, + cookies: [ + { name: 'theme', duration: '1 year', purpose: 'Stores user theme preference' }, + { name: 'language', duration: '1 year', purpose: 'Stores user language preference' } + ] + } + ] + + return ( + <> + {/* Backdrop */} +