Cookie Consent — Site Público Abracaf
O site público da Abracaf tem seu próprio banner de consentimento de cookies, separado do componente do MakerKit (@kit/ui/cookie-banner). A lógica de consentimento foi extraída para um hook reutilizável, useCookieConsent.
O banner do MakerKit é genérico (Dialog, cores bg-background, i18n via Trans, semântica accepted/rejected). O da Abracaf usa o design system próprio, links de Política/Termos e a semântica de LGPD accepted / essential. Avaliou-se substituir um pelo outro; concluiu-se que o do MakerKit não era melhor para este caso (seria regressão visual e de semântica). Em vez disso, portou-se a parte boa do MakerKit — um hook reutilizável — para dentro do componente da Abracaf.
Estrutura de arquivos
apps/web/app/[locale]/(extranet_public)/abracaf/
├── _components/
│ └── cookie-banner.tsx # 'use client' — UI do banner (visual + links)
└── _hooks/
└── use-cookie-consent.ts # 'use client' — estado e persistência do consentimento
O CookieBanner é montado uma vez no abracaf/layout.tsx, junto com ScrollToTopButton.
Hook useCookieConsent
import { useCookieConsent } from '../_hooks/use-cookie-consent';
const { status, hydrated, accept, reject, clear } = useCookieConsent();
API
| Campo | Tipo | Descrição |
|---|---|---|
status | 'accepted' | 'essential' | 'unknown' | Decisão atual do usuário |
hydrated | boolean | true após o valor ser lido do localStorage no cliente |
accept() | () => void | Grava 'accepted' (aceita todos os cookies) |
reject() | () => void | Grava 'essential' (somente essenciais) |
clear() | () => void | Reseta para 'unknown' (remove do storage) |
Semântica dos status
| Status | Significado |
|---|---|
accepted | Usuário aceitou todos os cookies |
essential | Usuário optou por somente os essenciais (botão "Somente essenciais") |
unknown | Ainda não decidiu — o banner deve aparecer |
A chave de localStorage é abracaf_cookie_consent.
A flag hydrated
O hook começa sempre como status: 'unknown' no servidor e na primeira render do cliente, e só lê o localStorage dentro de um useEffect (marcando hydrated = true). Isso evita mismatch de hidratação — o HTML do servidor nunca diverge da primeira render do cliente.
Por isso o banner só deve renderizar quando já hidratou e o usuário não decidiu:
export function CookieBanner() {
const { status, hydrated, accept, reject } = useCookieConsent();
if (!hydrated || status !== 'unknown') return null;
// ...UI do banner
}
O hook do MakerKit lê o localStorage no useState inicial, o que pode divergir do HTML do servidor. A versão da Abracaf usa a flag hydrated justamente para não ter esse risco.
Gating de analytics (futuro)
Hoje nem o banner da Abracaf nem o do MakerKit bloqueiam scripts de fato — ambos apenas registram a preferência. O hook foi desenhado para permitir esse gating quando necessário:
const { status } = useCookieConsent();
useEffect(() => {
if (status === 'accepted') {
// inicializar analytics / scripts dependentes de cookies
}
}, [status]);
Esse é o principal ganho de ter extraído a lógica para um hook reutilizável: qualquer parte do site pode ler a decisão do usuário sem reimplementar a persistência.