feat: add CustomCookieBanner with matching Karcher square checkboxes and styling
This commit is contained in:
@@ -7,7 +7,6 @@ import {
|
|||||||
} from '@intecion/ipal-kit'
|
} from '@intecion/ipal-kit'
|
||||||
import {
|
import {
|
||||||
ConsentProvider,
|
ConsentProvider,
|
||||||
CookieBanner,
|
|
||||||
CookieButton,
|
CookieButton,
|
||||||
Analytics,
|
Analytics,
|
||||||
} from '@intecion/ipal-kit/client'
|
} from '@intecion/ipal-kit/client'
|
||||||
@@ -16,6 +15,7 @@ import { getCachedPayload, getConfiguredLocales } from '@/lib/content'
|
|||||||
import { getSettings } from '@/lib/payload'
|
import { getSettings } from '@/lib/payload'
|
||||||
import { Header, type NavItem } from '@/components/Header'
|
import { Header, type NavItem } from '@/components/Header'
|
||||||
import { Footer, type FooterNavItem } from '@/components/Footer'
|
import { Footer, type FooterNavItem } from '@/components/Footer'
|
||||||
|
import { CustomCookieBanner } from '@/components/CustomCookieBanner'
|
||||||
import '../styles.css'
|
import '../styles.css'
|
||||||
|
|
||||||
import type { Company, Navigation, Page } from '@/payload-types'
|
import type { Company, Navigation, Page } from '@/payload-types'
|
||||||
@@ -125,15 +125,7 @@ export default async function LocaleLayout({ children, params }: LayoutProps) {
|
|||||||
privacyHref={privacyHref}
|
privacyHref={privacyHref}
|
||||||
cookieHref={cookieHref}
|
cookieHref={cookieHref}
|
||||||
/>
|
/>
|
||||||
<CookieBanner
|
<CustomCookieBanner />
|
||||||
classNames={{
|
|
||||||
root: 'fixed bottom-0 inset-x-0 z-50 bg-[#1f1f1f] text-white p-6 border-t-4 border-[#FFED00] shadow-2xl',
|
|
||||||
primaryButton:
|
|
||||||
'bg-[#FFED00] hover:bg-[#fae100] text-[#1f1f1f] border-2 border-[#1f1f1f] px-6 py-2.5 text-xs font-black uppercase tracking-widest transition-all cursor-pointer shadow-xs',
|
|
||||||
secondaryButton:
|
|
||||||
'bg-[#2b2b2b] hover:bg-[#383838] text-white border border-[#444444] px-4 py-2.5 text-xs font-bold uppercase tracking-wider transition-colors cursor-pointer',
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
<CookieButton className="fixed bottom-4 left-4 z-40 bg-[#1f1f1f] hover:bg-[#FFED00] text-[#FFED00] hover:text-[#1f1f1f] border-2 border-[#FFED00] p-2.5 transition-all shadow-lg cursor-pointer" />
|
<CookieButton className="fixed bottom-4 left-4 z-40 bg-[#1f1f1f] hover:bg-[#FFED00] text-[#FFED00] hover:text-[#1f1f1f] border-2 border-[#FFED00] p-2.5 transition-all shadow-lg cursor-pointer" />
|
||||||
<Analytics {...analytics} />
|
<Analytics {...analytics} />
|
||||||
</ConsentProvider>
|
</ConsentProvider>
|
||||||
|
|||||||
@@ -0,0 +1,159 @@
|
|||||||
|
'use client'
|
||||||
|
|
||||||
|
import React, { useState, useEffect } from 'react'
|
||||||
|
import { Cookie, Check, ArrowRight } from 'lucide-react'
|
||||||
|
import { useConsentContext } from '@intecion/ipal-kit/client'
|
||||||
|
|
||||||
|
const CONSENT_CATEGORIES = ['necessary', 'analytics', 'marketing'] as const
|
||||||
|
type ConsentCat = (typeof CONSENT_CATEGORIES)[number]
|
||||||
|
|
||||||
|
export function CustomCookieBanner() {
|
||||||
|
const { acceptAll, decided, rejectAll, savePreferences, state, texts } = useConsentContext()
|
||||||
|
const [showSettings, setShowSettings] = useState(false)
|
||||||
|
const [choices, setChoices] = useState(state)
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setChoices(state)
|
||||||
|
}, [state])
|
||||||
|
|
||||||
|
if (decided) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
const toggle = (cat: ConsentCat) => {
|
||||||
|
if (cat === 'necessary') return
|
||||||
|
setChoices((prev) => ({
|
||||||
|
...prev,
|
||||||
|
[cat]: !prev[cat],
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
role="dialog"
|
||||||
|
aria-label="Cookie consent"
|
||||||
|
className="fixed bottom-0 inset-x-0 z-50 bg-[#1f1f1f] text-white p-6 border-t-4 border-[#FFED00] shadow-2xl"
|
||||||
|
>
|
||||||
|
<div className="container mx-auto max-w-4xl">
|
||||||
|
{!showSettings ? (
|
||||||
|
<div className="flex flex-col lg:flex-row lg:items-center justify-between gap-6">
|
||||||
|
<div className="flex items-start gap-4">
|
||||||
|
<div className="p-2 bg-[#FFED00] text-[#1f1f1f] shrink-0 border border-[#1f1f1f]">
|
||||||
|
<Cookie className="h-6 w-6" />
|
||||||
|
</div>
|
||||||
|
<div className="text-xs sm:text-sm text-[#e0e0e0] leading-relaxed">
|
||||||
|
<p>
|
||||||
|
{texts.message}{' '}
|
||||||
|
{texts.privacyLink && (
|
||||||
|
<a
|
||||||
|
href={texts.privacyLink.href}
|
||||||
|
className="text-[#FFED00] underline hover:no-underline font-bold"
|
||||||
|
>
|
||||||
|
{texts.privacyLink.label}
|
||||||
|
</a>
|
||||||
|
)}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="flex flex-wrap items-center gap-3 shrink-0">
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
onClick={() => setShowSettings(true)}
|
||||||
|
className="bg-[#2b2b2b] hover:bg-[#383838] text-white border border-[#444444] px-4 py-2.5 text-xs font-bold uppercase tracking-wider transition-colors cursor-pointer"
|
||||||
|
>
|
||||||
|
{texts.buttons.settings}
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
onClick={rejectAll}
|
||||||
|
className="bg-[#2b2b2b] hover:bg-[#383838] text-white border border-[#444444] px-4 py-2.5 text-xs font-bold uppercase tracking-wider transition-colors cursor-pointer"
|
||||||
|
>
|
||||||
|
{texts.buttons.reject}
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
onClick={acceptAll}
|
||||||
|
className="bg-[#FFED00] hover:bg-[#fae100] text-[#1f1f1f] border-2 border-[#1f1f1f] px-6 py-2.5 text-xs font-black uppercase tracking-widest transition-all cursor-pointer shadow-xs"
|
||||||
|
>
|
||||||
|
{texts.buttons.acceptAll}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<div className="space-y-6">
|
||||||
|
<div className="flex items-center gap-3 border-b border-[#333333] pb-4">
|
||||||
|
<div className="p-1.5 bg-[#FFED00] text-[#1f1f1f]">
|
||||||
|
<Cookie className="h-5 w-5" />
|
||||||
|
</div>
|
||||||
|
<h2 className="text-base font-black uppercase tracking-wider text-white">
|
||||||
|
{texts.settingsTitle}
|
||||||
|
</h2>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<ul className="space-y-4">
|
||||||
|
{CONSENT_CATEGORIES.map((cat) => {
|
||||||
|
const isChecked = cat === 'necessary' ? true : !!choices[cat]
|
||||||
|
const isDisabled = cat === 'necessary'
|
||||||
|
const catData = texts.categories[cat]
|
||||||
|
|
||||||
|
if (!catData) return null
|
||||||
|
|
||||||
|
return (
|
||||||
|
<li
|
||||||
|
key={cat}
|
||||||
|
onClick={() => !isDisabled && toggle(cat)}
|
||||||
|
className={`flex items-start justify-between gap-4 p-4 border border-[#333333] bg-[#262626] ${
|
||||||
|
!isDisabled ? 'cursor-pointer hover:border-[#FFED00]' : 'opacity-90'
|
||||||
|
} transition-colors`}
|
||||||
|
>
|
||||||
|
<div className="pr-4">
|
||||||
|
<div className="text-xs font-black uppercase tracking-wider text-[#FFED00]">
|
||||||
|
{catData.title}
|
||||||
|
</div>
|
||||||
|
<p className="text-xs text-[#a0a0a0] mt-1 leading-relaxed">
|
||||||
|
{catData.description}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Custom Kärcher Checkbox */}
|
||||||
|
<div className="relative flex items-center justify-center mt-0.5 shrink-0">
|
||||||
|
<div
|
||||||
|
className={`w-5 h-5 border-2 border-[#1f1f1f] transition-all flex items-center justify-center ${
|
||||||
|
isChecked ? 'bg-[#FFED00]' : 'bg-white'
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
<Check
|
||||||
|
className={`w-3.5 h-3.5 text-[#1f1f1f] stroke-[3] transition-opacity ${
|
||||||
|
isChecked ? 'opacity-100' : 'opacity-0'
|
||||||
|
}`}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
)
|
||||||
|
})}
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<div className="flex justify-end gap-3 pt-2">
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
onClick={() => setShowSettings(false)}
|
||||||
|
className="bg-[#2b2b2b] hover:bg-[#383838] text-white border border-[#444444] px-5 py-2.5 text-xs font-bold uppercase tracking-wider transition-colors cursor-pointer"
|
||||||
|
>
|
||||||
|
{texts.buttons.back}
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
onClick={() => savePreferences(choices)}
|
||||||
|
className="bg-[#FFED00] hover:bg-[#fae100] text-[#1f1f1f] border-2 border-[#1f1f1f] px-6 py-2.5 text-xs font-black uppercase tracking-widest transition-all cursor-pointer shadow-xs"
|
||||||
|
>
|
||||||
|
{texts.buttons.save}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user