@tantainnovative/ndpr-toolkit 1.0.2 → 1.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/settings.local.json +20 -0
- package/.eslintrc.json +10 -0
- package/.github/workflows/ci.yml +36 -0
- package/.github/workflows/nextjs.yml +104 -0
- package/.husky/commit-msg +4 -0
- package/.husky/pre-commit +4 -0
- package/.lintstagedrc.js +4 -0
- package/.nvmrc +1 -0
- package/.versionrc +17 -0
- package/CHANGELOG.md +16 -0
- package/CLAUDE.md +90 -0
- package/CNAME +1 -0
- package/CONTRIBUTING.md +87 -0
- package/README.md +84 -447
- package/RELEASE-NOTES-v1.0.0.md +140 -0
- package/RELEASE-NOTES-v1.0.1.md +69 -0
- package/SECURITY.md +21 -0
- package/commitlint.config.js +36 -0
- package/components.json +21 -0
- package/eslint.config.mjs +16 -0
- package/jest.config.js +31 -0
- package/jest.setup.js +15 -0
- package/next.config.js +15 -0
- package/next.config.ts +62 -0
- package/package.json +70 -52
- package/packages/ndpr-toolkit/README.md +467 -0
- package/packages/ndpr-toolkit/jest.config.js +23 -0
- package/packages/ndpr-toolkit/package-lock.json +8197 -0
- package/packages/ndpr-toolkit/package.json +71 -0
- package/packages/ndpr-toolkit/rollup.config.js +34 -0
- package/packages/ndpr-toolkit/src/__tests__/components/consent/ConsentBanner.test.tsx +119 -0
- package/packages/ndpr-toolkit/src/__tests__/components/consent/ConsentManager.test.tsx +122 -0
- package/packages/ndpr-toolkit/src/__tests__/components/consent/ConsentStorage.test.tsx +270 -0
- package/packages/ndpr-toolkit/src/__tests__/components/dsr/DSRDashboard.test.tsx +199 -0
- package/packages/ndpr-toolkit/src/__tests__/components/dsr/DSRRequestForm.test.tsx +224 -0
- package/packages/ndpr-toolkit/src/__tests__/components/dsr/DSRTracker.test.tsx +104 -0
- package/packages/ndpr-toolkit/src/__tests__/hooks/useConsent.test.tsx +161 -0
- package/packages/ndpr-toolkit/src/__tests__/hooks/useDSR.test.tsx +330 -0
- package/packages/ndpr-toolkit/src/__tests__/utils/breach.test.ts +149 -0
- package/packages/ndpr-toolkit/src/__tests__/utils/consent.test.ts +88 -0
- package/packages/ndpr-toolkit/src/__tests__/utils/dpia.test.ts +160 -0
- package/packages/ndpr-toolkit/src/__tests__/utils/dsr.test.ts +110 -0
- package/packages/ndpr-toolkit/src/__tests__/utils/privacy.test.ts +97 -0
- package/packages/ndpr-toolkit/src/components/breach/BreachNotificationManager.tsx +701 -0
- package/packages/ndpr-toolkit/src/components/breach/BreachReportForm.tsx +631 -0
- package/packages/ndpr-toolkit/src/components/breach/BreachRiskAssessment.tsx +569 -0
- package/packages/ndpr-toolkit/src/components/breach/RegulatoryReportGenerator.tsx +496 -0
- package/packages/ndpr-toolkit/src/components/consent/ConsentBanner.tsx +270 -0
- package/packages/ndpr-toolkit/src/components/consent/ConsentManager.tsx +217 -0
- package/packages/ndpr-toolkit/src/components/consent/ConsentStorage.tsx +206 -0
- package/packages/ndpr-toolkit/src/components/dpia/DPIAQuestionnaire.tsx +342 -0
- package/packages/ndpr-toolkit/src/components/dpia/DPIAReport.tsx +373 -0
- package/packages/ndpr-toolkit/src/components/dpia/StepIndicator.tsx +174 -0
- package/packages/ndpr-toolkit/src/components/dsr/DSRDashboard.tsx +717 -0
- package/packages/ndpr-toolkit/src/components/dsr/DSRRequestForm.tsx +476 -0
- package/packages/ndpr-toolkit/src/components/dsr/DSRTracker.tsx +620 -0
- package/packages/ndpr-toolkit/src/components/policy/PolicyExporter.tsx +541 -0
- package/packages/ndpr-toolkit/src/components/policy/PolicyGenerator.tsx +454 -0
- package/packages/ndpr-toolkit/src/components/policy/PolicyPreview.tsx +333 -0
- package/packages/ndpr-toolkit/src/hooks/useBreach.ts +409 -0
- package/packages/ndpr-toolkit/src/hooks/useConsent.ts +263 -0
- package/packages/ndpr-toolkit/src/hooks/useDPIA.ts +457 -0
- package/packages/ndpr-toolkit/src/hooks/useDSR.ts +236 -0
- package/packages/ndpr-toolkit/src/hooks/usePrivacyPolicy.ts +428 -0
- package/{dist/index.d.ts → packages/ndpr-toolkit/src/index.ts} +13 -0
- package/packages/ndpr-toolkit/src/setupTests.ts +5 -0
- package/packages/ndpr-toolkit/src/types/breach.ts +283 -0
- package/packages/ndpr-toolkit/src/types/consent.ts +111 -0
- package/packages/ndpr-toolkit/src/types/dpia.ts +236 -0
- package/packages/ndpr-toolkit/src/types/dsr.ts +192 -0
- package/packages/ndpr-toolkit/src/types/index.ts +42 -0
- package/packages/ndpr-toolkit/src/types/privacy.ts +246 -0
- package/packages/ndpr-toolkit/src/utils/breach.ts +122 -0
- package/packages/ndpr-toolkit/src/utils/consent.ts +51 -0
- package/packages/ndpr-toolkit/src/utils/dpia.ts +104 -0
- package/packages/ndpr-toolkit/src/utils/dsr.ts +77 -0
- package/packages/ndpr-toolkit/src/utils/privacy.ts +100 -0
- package/packages/ndpr-toolkit/tsconfig.json +23 -0
- package/postcss.config.mjs +5 -0
- package/public/NDPR TOOLKIT.svg +1 -0
- package/public/favicon/android-chrome-192x192.png +0 -0
- package/public/favicon/android-chrome-512x512.png +0 -0
- package/public/favicon/apple-touch-icon.png +0 -0
- package/public/favicon/favicon-16x16.png +0 -0
- package/public/favicon/favicon-32x32.png +0 -0
- package/public/favicon/site.webmanifest +1 -0
- package/public/file.svg +1 -0
- package/public/globe.svg +1 -0
- package/public/ndpr-toolkit-logo.svg +108 -0
- package/public/next.svg +1 -0
- package/public/vercel.svg +1 -0
- package/public/window.svg +1 -0
- package/src/__tests__/example.test.ts +13 -0
- package/src/__tests__/requestService.test.ts +57 -0
- package/src/app/accessibility.css +70 -0
- package/src/app/docs/components/DocLayout.tsx +267 -0
- package/src/app/docs/components/breach-notification/page.tsx +797 -0
- package/src/app/docs/components/consent-management/page.tsx +576 -0
- package/src/app/docs/components/data-subject-rights/page.tsx +511 -0
- package/src/app/docs/components/dpia-questionnaire/layout.tsx +15 -0
- package/src/app/docs/components/dpia-questionnaire/metadata.ts +31 -0
- package/src/app/docs/components/dpia-questionnaire/page.tsx +666 -0
- package/src/app/docs/components/hooks/page.tsx +305 -0
- package/src/app/docs/components/page.tsx +84 -0
- package/src/app/docs/components/privacy-policy-generator/page.tsx +634 -0
- package/src/app/docs/guides/breach-notification-process/components/BestPractices.tsx +123 -0
- package/src/app/docs/guides/breach-notification-process/components/ImplementationSteps.tsx +328 -0
- package/src/app/docs/guides/breach-notification-process/components/Introduction.tsx +28 -0
- package/src/app/docs/guides/breach-notification-process/components/NotificationTimeline.tsx +91 -0
- package/src/app/docs/guides/breach-notification-process/components/Resources.tsx +118 -0
- package/src/app/docs/guides/breach-notification-process/page.tsx +39 -0
- package/src/app/docs/guides/conducting-dpia/page.tsx +593 -0
- package/src/app/docs/guides/data-subject-requests/page.tsx +666 -0
- package/src/app/docs/guides/managing-consent/page.tsx +738 -0
- package/src/app/docs/guides/ndpr-compliance-checklist/components/ComplianceChecklist.tsx +296 -0
- package/src/app/docs/guides/ndpr-compliance-checklist/components/ImplementationTools.tsx +145 -0
- package/src/app/docs/guides/ndpr-compliance-checklist/components/Introduction.tsx +33 -0
- package/src/app/docs/guides/ndpr-compliance-checklist/components/KeyRequirements.tsx +99 -0
- package/src/app/docs/guides/ndpr-compliance-checklist/components/Resources.tsx +159 -0
- package/src/app/docs/guides/ndpr-compliance-checklist/page.tsx +38 -0
- package/src/app/docs/guides/page.tsx +67 -0
- package/src/app/docs/layout.tsx +15 -0
- package/src/app/docs/metadata.ts +31 -0
- package/src/app/docs/page.tsx +572 -0
- package/src/app/favicon.ico +0 -0
- package/src/app/globals.css +123 -0
- package/src/app/layout.tsx +37 -0
- package/src/app/ndpr-demos/breach/page.tsx +354 -0
- package/src/app/ndpr-demos/consent/page.tsx +366 -0
- package/src/app/ndpr-demos/dpia/page.tsx +495 -0
- package/src/app/ndpr-demos/dsr/page.tsx +280 -0
- package/src/app/ndpr-demos/page.tsx +73 -0
- package/src/app/ndpr-demos/policy/page.tsx +771 -0
- package/src/app/page.tsx +452 -0
- package/src/components/ErrorBoundary.tsx +90 -0
- package/src/components/breach-notification/BreachNotificationForm.tsx +479 -0
- package/src/components/consent/ConsentBanner.tsx +159 -0
- package/src/components/data-subject-rights/DataSubjectRequestForm.tsx +419 -0
- package/src/components/docs/DocLayout.tsx +289 -0
- package/src/components/docs/index.ts +2 -0
- package/src/components/dpia/DPIAQuestionnaire.tsx +483 -0
- package/src/components/privacy-policy/PolicyGenerator.tsx +1062 -0
- package/src/components/privacy-policy/data.ts +98 -0
- package/src/components/privacy-policy/shared/CheckboxField.tsx +38 -0
- package/src/components/privacy-policy/shared/CheckboxGroup.tsx +85 -0
- package/src/components/privacy-policy/shared/FormField.tsx +79 -0
- package/src/components/privacy-policy/shared/StepIndicator.tsx +86 -0
- package/src/components/privacy-policy/steps/CustomSectionsStep.tsx +335 -0
- package/src/components/privacy-policy/steps/DataCollectionStep.tsx +231 -0
- package/src/components/privacy-policy/steps/DataSharingStep.tsx +418 -0
- package/src/components/privacy-policy/steps/OrganizationInfoStep.tsx +202 -0
- package/src/components/privacy-policy/steps/PolicyPreviewStep.tsx +172 -0
- package/src/components/ui/Badge.tsx +46 -0
- package/src/components/ui/Button.tsx +59 -0
- package/src/components/ui/Card.tsx +92 -0
- package/src/components/ui/Checkbox.tsx +57 -0
- package/src/components/ui/FormField.tsx +50 -0
- package/src/components/ui/Input.tsx +38 -0
- package/src/components/ui/Loading.tsx +201 -0
- package/src/components/ui/Select.tsx +42 -0
- package/src/components/ui/TextArea.tsx +38 -0
- package/src/components/ui/label.tsx +24 -0
- package/src/components/ui/switch.tsx +31 -0
- package/src/components/ui/tabs.tsx +66 -0
- package/src/hooks/useConsent.ts +64 -0
- package/src/hooks/useLoadingState.ts +85 -0
- package/src/lib/consentService.ts +137 -0
- package/src/lib/dpiaQuestions.ts +148 -0
- package/src/lib/requestService.ts +75 -0
- package/src/lib/sanitize.ts +108 -0
- package/src/lib/storage.ts +222 -0
- package/src/lib/utils.ts +6 -0
- package/src/types/html-to-docx.d.ts +30 -0
- package/src/types/index.ts +72 -0
- package/tailwind.config.ts +65 -0
- package/tsconfig.json +41 -0
- package/dist/components/breach/BreachNotificationManager.d.ts +0 -62
- package/dist/components/breach/BreachReportForm.d.ts +0 -66
- package/dist/components/breach/BreachRiskAssessment.d.ts +0 -50
- package/dist/components/breach/RegulatoryReportGenerator.d.ts +0 -94
- package/dist/components/consent/ConsentBanner.d.ts +0 -79
- package/dist/components/consent/ConsentManager.d.ts +0 -73
- package/dist/components/consent/ConsentStorage.d.ts +0 -41
- package/dist/components/dpia/DPIAQuestionnaire.d.ts +0 -70
- package/dist/components/dpia/DPIAReport.d.ts +0 -40
- package/dist/components/dpia/StepIndicator.d.ts +0 -64
- package/dist/components/dsr/DSRDashboard.d.ts +0 -58
- package/dist/components/dsr/DSRRequestForm.d.ts +0 -74
- package/dist/components/dsr/DSRTracker.d.ts +0 -56
- package/dist/components/policy/PolicyExporter.d.ts +0 -65
- package/dist/components/policy/PolicyGenerator.d.ts +0 -54
- package/dist/components/policy/PolicyPreview.d.ts +0 -71
- package/dist/hooks/useBreach.d.ts +0 -97
- package/dist/hooks/useConsent.d.ts +0 -63
- package/dist/hooks/useDPIA.d.ts +0 -92
- package/dist/hooks/useDSR.d.ts +0 -72
- package/dist/hooks/usePrivacyPolicy.d.ts +0 -87
- package/dist/index.esm.js +0 -2
- package/dist/index.esm.js.map +0 -1
- package/dist/index.js +0 -2
- package/dist/index.js.map +0 -1
- package/dist/setupTests.d.ts +0 -2
- package/dist/types/breach.d.ts +0 -239
- package/dist/types/consent.d.ts +0 -95
- package/dist/types/dpia.d.ts +0 -196
- package/dist/types/dsr.d.ts +0 -162
- package/dist/types/privacy.d.ts +0 -204
- package/dist/utils/breach.d.ts +0 -14
- package/dist/utils/consent.d.ts +0 -10
- package/dist/utils/dpia.d.ts +0 -12
- package/dist/utils/dsr.d.ts +0 -11
- package/dist/utils/privacy.d.ts +0 -12
|
@@ -0,0 +1,738 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import Link from 'next/link';
|
|
4
|
+
import { DocLayout } from '@/components/docs/DocLayout';
|
|
5
|
+
import { Button } from '@/components/ui/Button';
|
|
6
|
+
import { Card, CardContent } from '@/components/ui/Card';
|
|
7
|
+
|
|
8
|
+
export default function ManagingConsentGuide() {
|
|
9
|
+
return (
|
|
10
|
+
<DocLayout
|
|
11
|
+
title="Managing Consent"
|
|
12
|
+
description="Learn how to implement a complete consent management system with the NDPR Toolkit"
|
|
13
|
+
>
|
|
14
|
+
<div className="flex mb-6 space-x-2">
|
|
15
|
+
<Button asChild variant="outline" size="sm">
|
|
16
|
+
<Link href="/demo/consent">
|
|
17
|
+
View Consent Demo
|
|
18
|
+
</Link>
|
|
19
|
+
</Button>
|
|
20
|
+
<Button asChild variant="outline" size="sm">
|
|
21
|
+
<Link href="/docs/components/consent-management">
|
|
22
|
+
Consent Component Docs
|
|
23
|
+
</Link>
|
|
24
|
+
</Button>
|
|
25
|
+
</div>
|
|
26
|
+
|
|
27
|
+
<section id="introduction" className="mb-8">
|
|
28
|
+
<h2 className="text-2xl font-bold mb-4">Introduction</h2>
|
|
29
|
+
<p className="mb-4">
|
|
30
|
+
Consent is a cornerstone of data protection under the Nigeria Data Protection Regulation (NDPR).
|
|
31
|
+
Organizations must obtain valid consent before collecting, processing, or sharing personal data.
|
|
32
|
+
This guide will help you implement a comprehensive consent management system using the NDPR Toolkit.
|
|
33
|
+
</p>
|
|
34
|
+
<div className="bg-blue-50 dark:bg-blue-900/20 p-4 rounded-md">
|
|
35
|
+
<h4 className="text-blue-800 dark:text-blue-200 font-medium mb-2">NDPR Consent Requirements</h4>
|
|
36
|
+
<p className="text-blue-700 dark:text-blue-300 text-sm mb-0">
|
|
37
|
+
Under the NDPR, valid consent must be:
|
|
38
|
+
</p>
|
|
39
|
+
<ul className="list-disc pl-6 mt-2 text-blue-700 dark:text-blue-300 text-sm">
|
|
40
|
+
<li><strong>Freely given:</strong> Data subjects must have a genuine choice and control</li>
|
|
41
|
+
<li><strong>Specific:</strong> Consent must be granular for different types of processing</li>
|
|
42
|
+
<li><strong>Informed:</strong> Data subjects must understand what they're consenting to</li>
|
|
43
|
+
<li><strong>Unambiguous:</strong> Consent must be given through a clear affirmative action</li>
|
|
44
|
+
<li><strong>Withdrawable:</strong> Data subjects must be able to withdraw consent easily</li>
|
|
45
|
+
</ul>
|
|
46
|
+
</div>
|
|
47
|
+
</section>
|
|
48
|
+
|
|
49
|
+
<section id="consent-lifecycle" className="mb-8">
|
|
50
|
+
<h2 className="text-2xl font-bold mb-4">The Consent Lifecycle</h2>
|
|
51
|
+
<p className="mb-4">
|
|
52
|
+
A complete consent management system covers the entire lifecycle of consent, from collection to withdrawal.
|
|
53
|
+
The NDPR Toolkit provides components for each stage of this lifecycle:
|
|
54
|
+
</p>
|
|
55
|
+
|
|
56
|
+
<div className="relative border-l-2 border-blue-500 pl-8 pb-8 space-y-10">
|
|
57
|
+
<div className="relative">
|
|
58
|
+
<div className="absolute -left-10 mt-1.5 h-6 w-6 rounded-full bg-blue-500 flex items-center justify-center">
|
|
59
|
+
<span className="text-white font-bold text-sm">1</span>
|
|
60
|
+
</div>
|
|
61
|
+
<h3 className="text-xl font-bold">Consent Collection</h3>
|
|
62
|
+
<p className="text-gray-600 dark:text-gray-300 mt-2">
|
|
63
|
+
The first step is collecting consent from data subjects. This typically happens when users first visit your website
|
|
64
|
+
or when they sign up for your service. The NDPR Toolkit's ConsentBanner component is designed for this purpose.
|
|
65
|
+
</p>
|
|
66
|
+
<div className="mt-4 bg-gray-100 dark:bg-gray-800 p-4 rounded-md">
|
|
67
|
+
<h4 className="font-medium mb-2">Code Example</h4>
|
|
68
|
+
<div className="bg-gray-800 text-gray-200 p-4 rounded-md overflow-x-auto">
|
|
69
|
+
<pre><code>{`import { ConsentBanner } from '@tantainnovative/ndpr-toolkit';
|
|
70
|
+
|
|
71
|
+
function App() {
|
|
72
|
+
const consentOptions = [
|
|
73
|
+
{
|
|
74
|
+
id: 'necessary',
|
|
75
|
+
label: 'Necessary Cookies',
|
|
76
|
+
description: 'These cookies are essential for the website to function properly.',
|
|
77
|
+
required: true
|
|
78
|
+
},
|
|
79
|
+
{
|
|
80
|
+
id: 'analytics',
|
|
81
|
+
label: 'Analytics Cookies',
|
|
82
|
+
description: 'These cookies help us understand how visitors interact with our website.',
|
|
83
|
+
required: false
|
|
84
|
+
},
|
|
85
|
+
{
|
|
86
|
+
id: 'marketing',
|
|
87
|
+
label: 'Marketing Cookies',
|
|
88
|
+
description: 'These cookies are used to track visitors across websites to display relevant advertisements.',
|
|
89
|
+
required: false
|
|
90
|
+
}
|
|
91
|
+
];
|
|
92
|
+
|
|
93
|
+
const handleSaveConsent = (consents) => {
|
|
94
|
+
// Save consent preferences to your backend or local storage
|
|
95
|
+
console.log('Consent preferences:', consents);
|
|
96
|
+
|
|
97
|
+
// Example: Save to localStorage
|
|
98
|
+
localStorage.setItem('userConsents', JSON.stringify(consents));
|
|
99
|
+
|
|
100
|
+
// Example: Send to backend API
|
|
101
|
+
fetch('/api/consents', {
|
|
102
|
+
method: 'POST',
|
|
103
|
+
headers: {
|
|
104
|
+
'Content-Type': 'application/json',
|
|
105
|
+
},
|
|
106
|
+
body: JSON.stringify(consents),
|
|
107
|
+
});
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
return (
|
|
111
|
+
<div>
|
|
112
|
+
<ConsentBanner
|
|
113
|
+
options={consentOptions}
|
|
114
|
+
onSave={handleSaveConsent}
|
|
115
|
+
privacyPolicyUrl="/privacy-policy"
|
|
116
|
+
position="bottom"
|
|
117
|
+
showCloseButton={false}
|
|
118
|
+
/>
|
|
119
|
+
{/* Rest of your application */}
|
|
120
|
+
</div>
|
|
121
|
+
);
|
|
122
|
+
}`}</code></pre>
|
|
123
|
+
</div>
|
|
124
|
+
</div>
|
|
125
|
+
</div>
|
|
126
|
+
|
|
127
|
+
<div className="relative">
|
|
128
|
+
<div className="absolute -left-10 mt-1.5 h-6 w-6 rounded-full bg-blue-500 flex items-center justify-center">
|
|
129
|
+
<span className="text-white font-bold text-sm">2</span>
|
|
130
|
+
</div>
|
|
131
|
+
<h3 className="text-xl font-bold">Consent Storage</h3>
|
|
132
|
+
<p className="text-gray-600 dark:text-gray-300 mt-2">
|
|
133
|
+
Once collected, consent preferences must be securely stored and easily retrievable. The NDPR Toolkit provides
|
|
134
|
+
utilities for storing consent in various formats, including local storage, cookies, and server-side databases.
|
|
135
|
+
</p>
|
|
136
|
+
<div className="mt-4 bg-gray-100 dark:bg-gray-800 p-4 rounded-md">
|
|
137
|
+
<h4 className="font-medium mb-2">Code Example</h4>
|
|
138
|
+
<div className="bg-gray-800 text-gray-200 p-4 rounded-md overflow-x-auto">
|
|
139
|
+
<pre><code>{`import { ConsentStorage } from '@tantainnovative/ndpr-toolkit';
|
|
140
|
+
|
|
141
|
+
// Create a consent storage instance
|
|
142
|
+
const consentStorage = new ConsentStorage({
|
|
143
|
+
storageType: 'localStorage', // or 'cookie', 'indexedDB', 'api'
|
|
144
|
+
apiEndpoint: '/api/consents', // Only required for 'api' storage type
|
|
145
|
+
cookieOptions: { // Only required for 'cookie' storage type
|
|
146
|
+
domain: 'example.com',
|
|
147
|
+
secure: true,
|
|
148
|
+
sameSite: 'strict',
|
|
149
|
+
maxAge: 60 * 60 * 24 * 365 // 1 year in seconds
|
|
150
|
+
}
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
// Save consent
|
|
154
|
+
function saveConsent(userId, consents) {
|
|
155
|
+
return consentStorage.saveConsent(userId, consents);
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
// Retrieve consent
|
|
159
|
+
async function getConsent(userId) {
|
|
160
|
+
return await consentStorage.getConsent(userId);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
// Example usage
|
|
164
|
+
const userId = 'user123';
|
|
165
|
+
const consents = {
|
|
166
|
+
necessary: true,
|
|
167
|
+
analytics: true,
|
|
168
|
+
marketing: false,
|
|
169
|
+
timestamp: new Date().toISOString(),
|
|
170
|
+
version: '1.0'
|
|
171
|
+
};
|
|
172
|
+
|
|
173
|
+
saveConsent(userId, consents);
|
|
174
|
+
|
|
175
|
+
// Later, retrieve the consent
|
|
176
|
+
getConsent(userId).then(savedConsents => {
|
|
177
|
+
console.log('Retrieved consents:', savedConsents);
|
|
178
|
+
});`}</code></pre>
|
|
179
|
+
</div>
|
|
180
|
+
</div>
|
|
181
|
+
</div>
|
|
182
|
+
|
|
183
|
+
<div className="relative">
|
|
184
|
+
<div className="absolute -left-10 mt-1.5 h-6 w-6 rounded-full bg-blue-500 flex items-center justify-center">
|
|
185
|
+
<span className="text-white font-bold text-sm">3</span>
|
|
186
|
+
</div>
|
|
187
|
+
<h3 className="text-xl font-bold">Consent Verification</h3>
|
|
188
|
+
<p className="text-gray-600 dark:text-gray-300 mt-2">
|
|
189
|
+
Before processing personal data, you must verify that the user has given consent for the specific processing activity.
|
|
190
|
+
The NDPR Toolkit provides utilities for checking consent status.
|
|
191
|
+
</p>
|
|
192
|
+
<div className="mt-4 bg-gray-100 dark:bg-gray-800 p-4 rounded-md">
|
|
193
|
+
<h4 className="font-medium mb-2">Code Example</h4>
|
|
194
|
+
<div className="bg-gray-800 text-gray-200 p-4 rounded-md overflow-x-auto">
|
|
195
|
+
<pre><code>{`import { useConsent } from '@tantainnovative/ndpr-toolkit';
|
|
196
|
+
|
|
197
|
+
function AnalyticsComponent() {
|
|
198
|
+
const { hasConsent, isLoading } = useConsent('analytics');
|
|
199
|
+
|
|
200
|
+
useEffect(() => {
|
|
201
|
+
if (!isLoading && hasConsent) {
|
|
202
|
+
// Initialize analytics only if user has given consent
|
|
203
|
+
initializeAnalytics();
|
|
204
|
+
}
|
|
205
|
+
}, [hasConsent, isLoading]);
|
|
206
|
+
|
|
207
|
+
if (isLoading) {
|
|
208
|
+
return <div>Loading consent preferences...</div>;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
if (!hasConsent) {
|
|
212
|
+
return (
|
|
213
|
+
<div>
|
|
214
|
+
<p>Analytics are disabled based on your consent preferences.</p>
|
|
215
|
+
<button onClick={() => openConsentManager()}>
|
|
216
|
+
Update Preferences
|
|
217
|
+
</button>
|
|
218
|
+
</div>
|
|
219
|
+
);
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
return <div>Analytics are enabled and tracking your usage.</div>;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
function MarketingComponent() {
|
|
226
|
+
const { hasConsent, isLoading } = useConsent('marketing');
|
|
227
|
+
|
|
228
|
+
// Similar implementation for marketing features
|
|
229
|
+
}`}</code></pre>
|
|
230
|
+
</div>
|
|
231
|
+
</div>
|
|
232
|
+
</div>
|
|
233
|
+
|
|
234
|
+
<div className="relative">
|
|
235
|
+
<div className="absolute -left-10 mt-1.5 h-6 w-6 rounded-full bg-blue-500 flex items-center justify-center">
|
|
236
|
+
<span className="text-white font-bold text-sm">4</span>
|
|
237
|
+
</div>
|
|
238
|
+
<h3 className="text-xl font-bold">Consent Management</h3>
|
|
239
|
+
<p className="text-gray-600 dark:text-gray-300 mt-2">
|
|
240
|
+
Data subjects must be able to view and update their consent preferences at any time. The NDPR Toolkit's
|
|
241
|
+
ConsentManager component provides a user interface for managing consent preferences.
|
|
242
|
+
</p>
|
|
243
|
+
<div className="mt-4 bg-gray-100 dark:bg-gray-800 p-4 rounded-md">
|
|
244
|
+
<h4 className="font-medium mb-2">Code Example</h4>
|
|
245
|
+
<div className="bg-gray-800 text-gray-200 p-4 rounded-md overflow-x-auto">
|
|
246
|
+
<pre><code>{`import { ConsentManager } from '@tantainnovative/ndpr-toolkit';
|
|
247
|
+
|
|
248
|
+
function PrivacySettingsPage() {
|
|
249
|
+
const consentOptions = [
|
|
250
|
+
{
|
|
251
|
+
id: 'necessary',
|
|
252
|
+
label: 'Necessary Cookies',
|
|
253
|
+
description: 'These cookies are essential for the website to function properly.',
|
|
254
|
+
required: true
|
|
255
|
+
},
|
|
256
|
+
{
|
|
257
|
+
id: 'analytics',
|
|
258
|
+
label: 'Analytics Cookies',
|
|
259
|
+
description: 'These cookies help us understand how visitors interact with our website.',
|
|
260
|
+
required: false
|
|
261
|
+
},
|
|
262
|
+
{
|
|
263
|
+
id: 'marketing',
|
|
264
|
+
label: 'Marketing Cookies',
|
|
265
|
+
description: 'These cookies are used to track visitors across websites to display relevant advertisements.',
|
|
266
|
+
required: false
|
|
267
|
+
}
|
|
268
|
+
];
|
|
269
|
+
|
|
270
|
+
const handleSaveConsent = (consents) => {
|
|
271
|
+
// Save updated consent preferences
|
|
272
|
+
console.log('Updated consent preferences:', consents);
|
|
273
|
+
|
|
274
|
+
// Example: Save to localStorage
|
|
275
|
+
localStorage.setItem('userConsents', JSON.stringify(consents));
|
|
276
|
+
|
|
277
|
+
// Example: Send to backend API
|
|
278
|
+
fetch('/api/consents', {
|
|
279
|
+
method: 'POST',
|
|
280
|
+
headers: {
|
|
281
|
+
'Content-Type': 'application/json',
|
|
282
|
+
},
|
|
283
|
+
body: JSON.stringify(consents),
|
|
284
|
+
});
|
|
285
|
+
};
|
|
286
|
+
|
|
287
|
+
return (
|
|
288
|
+
<div>
|
|
289
|
+
<h1>Privacy Settings</h1>
|
|
290
|
+
<p>
|
|
291
|
+
Manage your consent preferences for how we use your data.
|
|
292
|
+
You can change these settings at any time.
|
|
293
|
+
</p>
|
|
294
|
+
|
|
295
|
+
<ConsentManager
|
|
296
|
+
options={consentOptions}
|
|
297
|
+
onSave={handleSaveConsent}
|
|
298
|
+
initialValues={JSON.parse(localStorage.getItem('userConsents') || '{}')}
|
|
299
|
+
/>
|
|
300
|
+
</div>
|
|
301
|
+
);
|
|
302
|
+
}`}</code></pre>
|
|
303
|
+
</div>
|
|
304
|
+
</div>
|
|
305
|
+
</div>
|
|
306
|
+
|
|
307
|
+
<div className="relative">
|
|
308
|
+
<div className="absolute -left-10 mt-1.5 h-6 w-6 rounded-full bg-blue-500 flex items-center justify-center">
|
|
309
|
+
<span className="text-white font-bold text-sm">5</span>
|
|
310
|
+
</div>
|
|
311
|
+
<h3 className="text-xl font-bold">Consent Records</h3>
|
|
312
|
+
<p className="text-gray-600 dark:text-gray-300 mt-2">
|
|
313
|
+
For compliance purposes, you must maintain records of consent, including when and how consent was given or withdrawn.
|
|
314
|
+
The NDPR Toolkit provides utilities for maintaining detailed consent records.
|
|
315
|
+
</p>
|
|
316
|
+
<div className="mt-4 bg-gray-100 dark:bg-gray-800 p-4 rounded-md">
|
|
317
|
+
<h4 className="font-medium mb-2">Code Example</h4>
|
|
318
|
+
<div className="bg-gray-800 text-gray-200 p-4 rounded-md overflow-x-auto">
|
|
319
|
+
<pre><code>{`import { ConsentRecorder } from '@tantainnovative/ndpr-toolkit';
|
|
320
|
+
|
|
321
|
+
// Create a consent recorder instance
|
|
322
|
+
const consentRecorder = new ConsentRecorder({
|
|
323
|
+
storageType: 'api',
|
|
324
|
+
apiEndpoint: '/api/consent-records'
|
|
325
|
+
});
|
|
326
|
+
|
|
327
|
+
// Record a consent event
|
|
328
|
+
function recordConsentEvent(userId, event) {
|
|
329
|
+
const consentEvent = {
|
|
330
|
+
userId,
|
|
331
|
+
eventType: event.type, // 'given', 'updated', 'withdrawn'
|
|
332
|
+
consents: event.consents,
|
|
333
|
+
timestamp: new Date().toISOString(),
|
|
334
|
+
source: event.source, // 'banner', 'settings', 'account-deletion', etc.
|
|
335
|
+
ipAddress: event.ipAddress,
|
|
336
|
+
userAgent: event.userAgent,
|
|
337
|
+
version: event.version
|
|
338
|
+
};
|
|
339
|
+
|
|
340
|
+
return consentRecorder.recordEvent(consentEvent);
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
// Example usage
|
|
344
|
+
const userId = 'user123';
|
|
345
|
+
const consentEvent = {
|
|
346
|
+
type: 'given',
|
|
347
|
+
consents: {
|
|
348
|
+
necessary: true,
|
|
349
|
+
analytics: true,
|
|
350
|
+
marketing: false
|
|
351
|
+
},
|
|
352
|
+
source: 'banner',
|
|
353
|
+
ipAddress: '192.168.1.1',
|
|
354
|
+
userAgent: 'Mozilla/5.0...',
|
|
355
|
+
version: '1.0'
|
|
356
|
+
};
|
|
357
|
+
|
|
358
|
+
recordConsentEvent(userId, consentEvent);
|
|
359
|
+
|
|
360
|
+
// Retrieve consent history for a user
|
|
361
|
+
consentRecorder.getEventHistory(userId).then(history => {
|
|
362
|
+
console.log('Consent history:', history);
|
|
363
|
+
});`}</code></pre>
|
|
364
|
+
</div>
|
|
365
|
+
</div>
|
|
366
|
+
</div>
|
|
367
|
+
|
|
368
|
+
<div className="relative">
|
|
369
|
+
<div className="absolute -left-10 mt-1.5 h-6 w-6 rounded-full bg-blue-500 flex items-center justify-center">
|
|
370
|
+
<span className="text-white font-bold text-sm">6</span>
|
|
371
|
+
</div>
|
|
372
|
+
<h3 className="text-xl font-bold">Consent Withdrawal</h3>
|
|
373
|
+
<p className="text-gray-600 dark:text-gray-300 mt-2">
|
|
374
|
+
Data subjects must be able to withdraw their consent as easily as they gave it. The NDPR Toolkit provides
|
|
375
|
+
components and utilities for handling consent withdrawal.
|
|
376
|
+
</p>
|
|
377
|
+
<div className="mt-4 bg-gray-100 dark:bg-gray-800 p-4 rounded-md">
|
|
378
|
+
<h4 className="font-medium mb-2">Implementation Tip</h4>
|
|
379
|
+
<p className="text-sm">
|
|
380
|
+
When a user withdraws consent, you must stop processing their data for the purposes they've withdrawn consent for.
|
|
381
|
+
This may include deleting data or disabling certain features. Make sure your application architecture supports
|
|
382
|
+
this granular control.
|
|
383
|
+
</p>
|
|
384
|
+
</div>
|
|
385
|
+
</div>
|
|
386
|
+
</div>
|
|
387
|
+
</section>
|
|
388
|
+
|
|
389
|
+
<section id="complete-implementation" className="mb-8">
|
|
390
|
+
<h2 className="text-2xl font-bold mb-4">Complete Implementation Example</h2>
|
|
391
|
+
<p className="mb-4">
|
|
392
|
+
Here's a complete example of how to implement a consent management system using the NDPR Toolkit:
|
|
393
|
+
</p>
|
|
394
|
+
<div className="bg-gray-800 text-gray-200 p-4 rounded-md overflow-x-auto">
|
|
395
|
+
<pre><code>{`import { useState, useEffect } from 'react';
|
|
396
|
+
import {
|
|
397
|
+
ConsentBanner,
|
|
398
|
+
ConsentManager,
|
|
399
|
+
ConsentStorage,
|
|
400
|
+
ConsentRecorder,
|
|
401
|
+
ConsentContext,
|
|
402
|
+
useConsent
|
|
403
|
+
} from '@tantainnovative/ndpr-toolkit';
|
|
404
|
+
|
|
405
|
+
// Define consent options
|
|
406
|
+
const consentOptions = [
|
|
407
|
+
{
|
|
408
|
+
id: 'necessary',
|
|
409
|
+
label: 'Necessary Cookies',
|
|
410
|
+
description: 'These cookies are essential for the website to function properly.',
|
|
411
|
+
required: true
|
|
412
|
+
},
|
|
413
|
+
{
|
|
414
|
+
id: 'analytics',
|
|
415
|
+
label: 'Analytics Cookies',
|
|
416
|
+
description: 'These cookies help us understand how visitors interact with our website.',
|
|
417
|
+
required: false
|
|
418
|
+
},
|
|
419
|
+
{
|
|
420
|
+
id: 'marketing',
|
|
421
|
+
label: 'Marketing Cookies',
|
|
422
|
+
description: 'These cookies are used to track visitors across websites to display relevant advertisements.',
|
|
423
|
+
required: false
|
|
424
|
+
},
|
|
425
|
+
{
|
|
426
|
+
id: 'personalization',
|
|
427
|
+
label: 'Personalization',
|
|
428
|
+
description: 'These cookies allow us to provide personalized content and recommendations.',
|
|
429
|
+
required: false
|
|
430
|
+
}
|
|
431
|
+
];
|
|
432
|
+
|
|
433
|
+
// Create storage and recorder instances
|
|
434
|
+
const consentStorage = new ConsentStorage({ storageType: 'localStorage' });
|
|
435
|
+
const consentRecorder = new ConsentRecorder({ storageType: 'api', apiEndpoint: '/api/consent-records' });
|
|
436
|
+
|
|
437
|
+
// Main application with consent management
|
|
438
|
+
function App() {
|
|
439
|
+
const [userId, setUserId] = useState(null);
|
|
440
|
+
const [showBanner, setShowBanner] = useState(false);
|
|
441
|
+
const [consents, setConsents] = useState(null);
|
|
442
|
+
|
|
443
|
+
useEffect(() => {
|
|
444
|
+
// Generate or retrieve user ID
|
|
445
|
+
const storedUserId = localStorage.getItem('userId');
|
|
446
|
+
if (storedUserId) {
|
|
447
|
+
setUserId(storedUserId);
|
|
448
|
+
} else {
|
|
449
|
+
const newUserId = \`user_\${Date.now()}\`;
|
|
450
|
+
localStorage.setItem('userId', newUserId);
|
|
451
|
+
setUserId(newUserId);
|
|
452
|
+
}
|
|
453
|
+
}, []);
|
|
454
|
+
|
|
455
|
+
useEffect(() => {
|
|
456
|
+
if (userId) {
|
|
457
|
+
// Check if user has already given consent
|
|
458
|
+
consentStorage.getConsent(userId).then(storedConsents => {
|
|
459
|
+
if (storedConsents) {
|
|
460
|
+
setConsents(storedConsents);
|
|
461
|
+
} else {
|
|
462
|
+
// No stored consents, show the banner
|
|
463
|
+
setShowBanner(true);
|
|
464
|
+
}
|
|
465
|
+
});
|
|
466
|
+
}
|
|
467
|
+
}, [userId]);
|
|
468
|
+
|
|
469
|
+
const handleSaveConsent = (newConsents) => {
|
|
470
|
+
// Save the consent preferences
|
|
471
|
+
setConsents(newConsents);
|
|
472
|
+
consentStorage.saveConsent(userId, newConsents);
|
|
473
|
+
|
|
474
|
+
// Record the consent event
|
|
475
|
+
const eventType = consents ? 'updated' : 'given';
|
|
476
|
+
consentRecorder.recordEvent({
|
|
477
|
+
userId,
|
|
478
|
+
eventType,
|
|
479
|
+
consents: newConsents,
|
|
480
|
+
timestamp: new Date().toISOString(),
|
|
481
|
+
source: eventType === 'given' ? 'banner' : 'settings',
|
|
482
|
+
userAgent: navigator.userAgent,
|
|
483
|
+
version: '1.0'
|
|
484
|
+
});
|
|
485
|
+
|
|
486
|
+
// Hide the banner ifit's showing
|
|
487
|
+
setShowBanner(false);
|
|
488
|
+
};
|
|
489
|
+
|
|
490
|
+
const openConsentManager = () => {
|
|
491
|
+
// Open a modal with the consent manager
|
|
492
|
+
setShowConsentManager(true);
|
|
493
|
+
};
|
|
494
|
+
|
|
495
|
+
const [showConsentManager, setShowConsentManager] = useState(false);
|
|
496
|
+
|
|
497
|
+
return (
|
|
498
|
+
<ConsentContext.Provider value={{ consents, openConsentManager }}>
|
|
499
|
+
<div className="app">
|
|
500
|
+
<header>
|
|
501
|
+
<h1>My NDPR-Compliant Website</h1>
|
|
502
|
+
<nav>
|
|
503
|
+
<ul>
|
|
504
|
+
<li><a href="/">Home</a></li>
|
|
505
|
+
<li><a href="/about">About</a></li>
|
|
506
|
+
<li><a href="/contact">Contact</a></li>
|
|
507
|
+
<li>
|
|
508
|
+
<button onClick={openConsentManager}>
|
|
509
|
+
Privacy Settings
|
|
510
|
+
</button>
|
|
511
|
+
</li>
|
|
512
|
+
</ul>
|
|
513
|
+
</nav>
|
|
514
|
+
</header>
|
|
515
|
+
|
|
516
|
+
<main>
|
|
517
|
+
{/* Main content of your application */}
|
|
518
|
+
<HomePage />
|
|
519
|
+
</main>
|
|
520
|
+
|
|
521
|
+
<footer>
|
|
522
|
+
<p>© 2023 My Company</p>
|
|
523
|
+
<button onClick={openConsentManager}>
|
|
524
|
+
Manage Cookie Preferences
|
|
525
|
+
</button>
|
|
526
|
+
</footer>
|
|
527
|
+
|
|
528
|
+
{/* Consent banner */}
|
|
529
|
+
{showBanner && (
|
|
530
|
+
<ConsentBanner
|
|
531
|
+
options={consentOptions}
|
|
532
|
+
onSave={handleSaveConsent}
|
|
533
|
+
privacyPolicyUrl="/privacy-policy"
|
|
534
|
+
position="bottom"
|
|
535
|
+
showCloseButton={false}
|
|
536
|
+
/>
|
|
537
|
+
)}
|
|
538
|
+
|
|
539
|
+
{/* Consent manager modal */}
|
|
540
|
+
{showConsentManager && (
|
|
541
|
+
<div className="modal">
|
|
542
|
+
<div className="modal-content">
|
|
543
|
+
<h2>Privacy Settings</h2>
|
|
544
|
+
<ConsentManager
|
|
545
|
+
options={consentOptions}
|
|
546
|
+
onSave={(newConsents) => {
|
|
547
|
+
handleSaveConsent(newConsents);
|
|
548
|
+
setShowConsentManager(false);
|
|
549
|
+
}}
|
|
550
|
+
initialValues={consents || {}}
|
|
551
|
+
onCancel={() => setShowConsentManager(false)}
|
|
552
|
+
/>
|
|
553
|
+
</div>
|
|
554
|
+
</div>
|
|
555
|
+
)}
|
|
556
|
+
</div>
|
|
557
|
+
</ConsentContext.Provider>
|
|
558
|
+
);
|
|
559
|
+
}
|
|
560
|
+
|
|
561
|
+
// Example component that uses consent
|
|
562
|
+
function HomePage() {
|
|
563
|
+
const { hasConsent: hasAnalyticsConsent } = useConsent('analytics');
|
|
564
|
+
const { hasConsent: hasMarketingConsent } = useConsent('marketing');
|
|
565
|
+
const { hasConsent: hasPersonalizationConsent } = useConsent('personalization');
|
|
566
|
+
const { openConsentManager } = useConsent();
|
|
567
|
+
|
|
568
|
+
useEffect(() => {
|
|
569
|
+
if (hasAnalyticsConsent) {
|
|
570
|
+
// Initialize analytics
|
|
571
|
+
console.log('Initializing analytics...');
|
|
572
|
+
}
|
|
573
|
+
}, [hasAnalyticsConsent]);
|
|
574
|
+
|
|
575
|
+
useEffect(() => {
|
|
576
|
+
if (hasMarketingConsent) {
|
|
577
|
+
// Initialize marketing tools
|
|
578
|
+
console.log('Initializing marketing tools...');
|
|
579
|
+
}
|
|
580
|
+
}, [hasMarketingConsent]);
|
|
581
|
+
|
|
582
|
+
return (
|
|
583
|
+
<div>
|
|
584
|
+
<h2>Welcome to our website</h2>
|
|
585
|
+
|
|
586
|
+
{hasPersonalizationConsent ? (
|
|
587
|
+
<div>
|
|
588
|
+
<h3>Personalized Content</h3>
|
|
589
|
+
<p>Here's some content tailored just for you!</p>
|
|
590
|
+
</div>
|
|
591
|
+
) : (
|
|
592
|
+
<div>
|
|
593
|
+
<h3>Standard Content</h3>
|
|
594
|
+
<p>
|
|
595
|
+
Enable personalization to see content tailored to your interests.
|
|
596
|
+
<button onClick={openConsentManager}>
|
|
597
|
+
Update Privacy Settings
|
|
598
|
+
</button>
|
|
599
|
+
</p>
|
|
600
|
+
</div>
|
|
601
|
+
)}
|
|
602
|
+
|
|
603
|
+
{/* More content... */}
|
|
604
|
+
</div>
|
|
605
|
+
);
|
|
606
|
+
}`}</code></pre>
|
|
607
|
+
</div>
|
|
608
|
+
</section>
|
|
609
|
+
|
|
610
|
+
<section id="best-practices" className="mb-8">
|
|
611
|
+
<h2 className="text-2xl font-bold mb-4">Best Practices</h2>
|
|
612
|
+
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
|
|
613
|
+
<Card>
|
|
614
|
+
<CardContent className="p-6">
|
|
615
|
+
<h3 className="font-bold text-lg mb-2">No Pre-checked Boxes</h3>
|
|
616
|
+
<p className="text-gray-600 dark:text-gray-300 text-sm">
|
|
617
|
+
Never use pre-checked boxes for optional consent options. The NDPR requires that consent be given through
|
|
618
|
+
a clear affirmative action, and pre-checked boxes do not meet this requirement.
|
|
619
|
+
</p>
|
|
620
|
+
</CardContent>
|
|
621
|
+
</Card>
|
|
622
|
+
|
|
623
|
+
<Card>
|
|
624
|
+
<CardContent className="p-6">
|
|
625
|
+
<h3 className="font-bold text-lg mb-2">Clear Language</h3>
|
|
626
|
+
<p className="text-gray-600 dark:text-gray-300 text-sm">
|
|
627
|
+
Use clear, plain language to explain what data you're collecting, why you're collecting it, and how it will be used.
|
|
628
|
+
Avoid legal jargon that may confuse users.
|
|
629
|
+
</p>
|
|
630
|
+
</CardContent>
|
|
631
|
+
</Card>
|
|
632
|
+
|
|
633
|
+
<Card>
|
|
634
|
+
<CardContent className="p-6">
|
|
635
|
+
<h3 className="font-bold text-lg mb-2">Granular Consent</h3>
|
|
636
|
+
<p className="text-gray-600 dark:text-gray-300 text-sm">
|
|
637
|
+
Provide granular consent options for different types of processing. don't bundle multiple purposes into a single
|
|
638
|
+
consent option. This allows users to consent to some types of processing but not others.
|
|
639
|
+
</p>
|
|
640
|
+
</CardContent>
|
|
641
|
+
</Card>
|
|
642
|
+
|
|
643
|
+
<Card>
|
|
644
|
+
<CardContent className="p-6">
|
|
645
|
+
<h3 className="font-bold text-lg mb-2">Easy Withdrawal</h3>
|
|
646
|
+
<p className="text-gray-600 dark:text-gray-300 text-sm">
|
|
647
|
+
Make it as easy to withdraw consent as it is to give it. Provide a clear, accessible way for users to
|
|
648
|
+
update their consent preferences at any time.
|
|
649
|
+
</p>
|
|
650
|
+
</CardContent>
|
|
651
|
+
</Card>
|
|
652
|
+
|
|
653
|
+
<Card>
|
|
654
|
+
<CardContent className="p-6">
|
|
655
|
+
<h3 className="font-bold text-lg mb-2">Record Keeping</h3>
|
|
656
|
+
<p className="text-gray-600 dark:text-gray-300 text-sm">
|
|
657
|
+
Maintain detailed records of consent, including when and how consent was given or withdrawn. This is essential
|
|
658
|
+
for demonstrating compliance with the NDPR.
|
|
659
|
+
</p>
|
|
660
|
+
</CardContent>
|
|
661
|
+
</Card>
|
|
662
|
+
|
|
663
|
+
<Card>
|
|
664
|
+
<CardContent className="p-6">
|
|
665
|
+
<h3 className="font-bold text-lg mb-2">Regular Review</h3>
|
|
666
|
+
<p className="text-gray-600 dark:text-gray-300 text-sm">
|
|
667
|
+
Regularly review and update your consent mechanisms to ensure they remain compliant with the NDPR and
|
|
668
|
+
effective for your users. Consider conducting user testing to ensure your consent mechanisms are clear and usable.
|
|
669
|
+
</p>
|
|
670
|
+
</CardContent>
|
|
671
|
+
</Card>
|
|
672
|
+
</div>
|
|
673
|
+
</section>
|
|
674
|
+
|
|
675
|
+
<section id="common-pitfalls" className="mb-8">
|
|
676
|
+
<h2 className="text-2xl font-bold mb-4">Common Pitfalls to Avoid</h2>
|
|
677
|
+
<ul className="list-disc pl-6 space-y-2">
|
|
678
|
+
<li>
|
|
679
|
+
<strong>Cookie Walls:</strong> Blocking access to your website unless users accept all cookies is generally not
|
|
680
|
+
considered valid consent under the NDPR, as it doesn't give users a genuine choice.
|
|
681
|
+
</li>
|
|
682
|
+
<li>
|
|
683
|
+
<strong>Bundling Consent:</strong> Requiring users to consent to multiple unrelated purposes as a package deal
|
|
684
|
+
is not compliant with the NDPR's requirement for specific consent.
|
|
685
|
+
</li>
|
|
686
|
+
<li>
|
|
687
|
+
<strong>Ignoring Consent:</strong> Loading tracking scripts or cookies before obtaining consent is a common
|
|
688
|
+
mistake that violates the NDPR's requirement for valid consent.
|
|
689
|
+
</li>
|
|
690
|
+
<li>
|
|
691
|
+
<strong>Unclear Language:</strong> Using vague or technical language that users may not understand undermines
|
|
692
|
+
the 'informed' aspect of valid consent.
|
|
693
|
+
</li>
|
|
694
|
+
<li>
|
|
695
|
+
<strong>Difficult Withdrawal:</strong> Making it difficult for users to withdraw consent, such as by hiding
|
|
696
|
+
the option in a complex settings menu, is not compliant with the NDPR's requirement for withdrawable consent.
|
|
697
|
+
</li>
|
|
698
|
+
<li>
|
|
699
|
+
<strong>Inadequate Records:</strong> Failing to maintain adequate records of consent can make it difficult to
|
|
700
|
+
demonstrate compliance with the NDPR's requirement for record-keeping.
|
|
701
|
+
</li>
|
|
702
|
+
</ul>
|
|
703
|
+
</section>
|
|
704
|
+
|
|
705
|
+
<section id="resources" className="mb-8">
|
|
706
|
+
<h2 className="text-2xl font-bold mb-4">Additional Resources</h2>
|
|
707
|
+
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
|
|
708
|
+
<Card>
|
|
709
|
+
<CardContent className="p-4">
|
|
710
|
+
<h3 className="font-medium text-gray-900 dark:text-white mb-2">NDPR Implementation Framework</h3>
|
|
711
|
+
<p className="text-gray-600 dark:text-gray-300 text-sm mb-3">
|
|
712
|
+
Official guidance on implementing the NDPR, including consent requirements.
|
|
713
|
+
</p>
|
|
714
|
+
<Button asChild variant="outline" size="sm">
|
|
715
|
+
<a href="https://nitda.gov.ng/wp-content/uploads/2020/01/NDPR-Implementation-Framework.pdf" target="_blank" rel="noopener noreferrer">
|
|
716
|
+
View Framework
|
|
717
|
+
</a>
|
|
718
|
+
</Button>
|
|
719
|
+
</CardContent>
|
|
720
|
+
</Card>
|
|
721
|
+
<Card>
|
|
722
|
+
<CardContent className="p-4">
|
|
723
|
+
<h3 className="font-medium text-gray-900 dark:text-white mb-2">Consent Component Documentation</h3>
|
|
724
|
+
<p className="text-gray-600 dark:text-gray-300 text-sm mb-3">
|
|
725
|
+
Technical documentation for the Consent Management components.
|
|
726
|
+
</p>
|
|
727
|
+
<Button asChild variant="outline" size="sm">
|
|
728
|
+
<Link href="/docs/components/consent-management">
|
|
729
|
+
View Documentation
|
|
730
|
+
</Link>
|
|
731
|
+
</Button>
|
|
732
|
+
</CardContent>
|
|
733
|
+
</Card>
|
|
734
|
+
</div>
|
|
735
|
+
</section>
|
|
736
|
+
</DocLayout>
|
|
737
|
+
);
|
|
738
|
+
}
|