feat(cookie-consent): add GDPR cookie consent banner - #209
Conversation
- ConsentContext with localStorage persistence, DNT/GPC auto-deny - CookieConsentBanner with Accept All / Decline All, framer-motion animation - PostHogProvider gated behind analytics consent (deferred init) - AppShell component extracted for consent-aware provider wiring - useConsent hook in dedicated hooks/ file (react-refresh compliant) - Footer 'Cookie Preferences' link to reopen consent - Privacy policy updated to reflect consent banner - i18n keys in en/fr/ar (including RTL Arabic support) - 21 tests across ConsentContext, CookieConsentBanner, Footer
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (6)
🚧 Files skipped from review as they are similar to previous changes (4)
📝 WalkthroughWalkthroughIntroduces persisted analytics consent with privacy-signal handling, an animated localized consent banner, footer preference reset, consent-aware app composition, and deferred PostHog initialization. ChangesConsent-gated analytics
Estimated code review effort: 4 (Complex) | ~45 minutes Sequence Diagram(s)sequenceDiagram
participant ConsentProvider
participant AppShell
participant PostHogProvider
participant PostHog
ConsentProvider->>AppShell: isAnalyticsAllowed
AppShell->>PostHogProvider: analytics prop
PostHogProvider->>PostHog: initialize or toggle capture
Possibly related PRs
Suggested labels: 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Warning There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure. 🔧 Checkov (3.3.8)src/i18n/locales/ar/translation.jsonTraceback (most recent call last): 🔧 ESLint
ESLint install failed: dependency version conflict. Check your lock file or package.json. Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 5
🧹 Nitpick comments (1)
src/components/Footer.test.jsx (1)
84-89: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winTest the reset action, not just its label.
Seed stored consent, click the button, and assert the stored decision is cleared and the consent state is reopened. The current test would pass if the button lost its
onClickhandler.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/components/Footer.test.jsx` around lines 84 - 89, Update the “renders cookie preferences button” test to seed stored consent, click the cookie preferences button, and assert the stored consent decision is cleared and the consent state is reopened. Retain the existing label assertion while verifying the button’s reset behavior rather than only its presence.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/components/Footer.jsx`:
- Around line 317-325: Update resetConsent in the consent provider so reopening
preferences re-evaluates the active DNT/GPC privacy signal before allowing
consent changes. If the signal is active, keep analytics denied and prevent the
reopened banner from enabling acceptance; otherwise preserve the existing reset
behavior.
In `@src/contexts/ConsentContext.jsx`:
- Around line 84-100: Update ConsentContext initialization to evaluate
hasPrivacySignal() synchronously before honoring stored consent; when active,
force analytics denial, persist it with writeConsent, and hide the banner even
if stored consent allows analytics. Update resetConsent to preserve this forced
denial and prevent reopening a banner that would allow re-enabling analytics
while the signal remains active. Add regressions covering both initial load with
stored approval and resetConsent under an active DNT/GPC signal.
In `@src/contexts/ConsentContext.test.jsx`:
- Around line 78-96: Isolate the “auto-denies when Global Privacy Control is
set” test by resetting navigator.doNotTrack to a non-active value such as '0'
before rendering useConsent, or by restoring navigator properties between tests.
Ensure the assertion exercises the globalPrivacyControl branch rather than the
preceding DNT state.
In `@src/i18n/locales/ar/translation.json`:
- Line 1029: Update the Arabic consent message in the locale entry keyed by
“message” to explicitly state that cookies are used for analytics or optional
analytics tracking, while preserving the existing acceptance/rejection wording
and Arabic localization.
In `@src/providers/PostHogProvider.jsx`:
- Around line 17-22: Update PostHogProvider’s useEffect to apply the configured
consent flow on every analytics transition, opting in when consent is granted
and calling opt_out_capturing (or using opt_out_capturing_by_default) when it is
declined or reset. Preserve existing DNT and PostHog configuration behavior, and
add coverage for accept-to-decline and accept-to-reset transitions.
---
Nitpick comments:
In `@src/components/Footer.test.jsx`:
- Around line 84-89: Update the “renders cookie preferences button” test to seed
stored consent, click the cookie preferences button, and assert the stored
consent decision is cleared and the consent state is reopened. Retain the
existing label assertion while verifying the button’s reset behavior rather than
only its presence.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: dbb995f9-2f64-434a-810c-c735051856cf
📒 Files selected for processing (14)
src/AppShell.jsxsrc/components/CookieConsentBanner.jsxsrc/components/CookieConsentBanner.test.jsxsrc/components/Footer.jsxsrc/components/Footer.test.jsxsrc/content/legal/privacy.en.jssrc/contexts/ConsentContext.jsxsrc/contexts/ConsentContext.test.jsxsrc/hooks/useConsent.jssrc/i18n/locales/ar/translation.jsonsrc/i18n/locales/en/translation.jsonsrc/i18n/locales/fr/translation.jsonsrc/main.jsxsrc/providers/PostHogProvider.jsx
…utside provider Footer uses useConsent() for the Cookie Preferences link. When other components/pages render Footer without ConsentProvider (e.g. in tests), the hook now returns safe defaults (analytics denied, no banner) instead of throwing. This fixes ProComingSoonPage.test.jsx and any other test that renders a page containing Footer.
Preview for Bayan Flow Staging ready!
Preview alias |
Codecov Report❌ Patch coverage is
📢 Thoughts on this report? Let us know! |
- ConsentContext: DNT/GPC now overrides stored consent on init and resetConsent - PostHogProvider: opt in/out on consent transitions, not just init on grant - ConsentContext tests: isolate GPC test from DNT, add DNT-overrides-stored and resetConsent-persists-denial tests - Arabic locale: clarify analytics purpose in consent message - Footer test: verify reset clears stored consent
Contribution workflow
develop: This PR targetsdevelop, notmain.Description
Adds a GDPR-compliant cookie consent banner that gates PostHog analytics behind explicit user consent. Users can Accept All or Decline analytics tracking. Consent is persisted in localStorage and can be revoked via a "Cookie Preferences" link in the footer. DNT and Global Privacy Control signals auto-deny without showing the banner.
Type of Change
Related Issues
N/A
Changes Made
ConsentContextwith localStorage persistence, DNT/GPC auto-deny, and grant/deny/reset actionsCookieConsentBannercomponent with Accept All / Decline All buttons, framer-motion animation, dark mode glass morphism, and RTL supportPostHogProviderto acceptanalyticsprop and deferinitPostHog()until consent is grantedAppShellcomponent frommain.jsxfor consent-aware provider wiringuseConsenthook in dedicatedhooks/file for react-refresh complianceFooterthat callsresetConsent()to reopen the bannerAlgorithm Details (if applicable)
N/A
Testing
pnpm test:run)Test Results
Screenshots/GIFs
Code Quality
pnpm lint) - 0 errors, 2 pre-existing warningsPerformance Impact
Accessibility
Breaking Changes
Checklist
Additional Notes
src/contexts/ConsentContext.jsxmanages consent state,src/hooks/useConsent.jsexposes the hookReviewer Guidelines:
Summary by CodeRabbit
New Features
Documentation