@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.
Files changed (212) hide show
  1. package/.claude/settings.local.json +20 -0
  2. package/.eslintrc.json +10 -0
  3. package/.github/workflows/ci.yml +36 -0
  4. package/.github/workflows/nextjs.yml +104 -0
  5. package/.husky/commit-msg +4 -0
  6. package/.husky/pre-commit +4 -0
  7. package/.lintstagedrc.js +4 -0
  8. package/.nvmrc +1 -0
  9. package/.versionrc +17 -0
  10. package/CHANGELOG.md +16 -0
  11. package/CLAUDE.md +90 -0
  12. package/CNAME +1 -0
  13. package/CONTRIBUTING.md +87 -0
  14. package/README.md +84 -447
  15. package/RELEASE-NOTES-v1.0.0.md +140 -0
  16. package/RELEASE-NOTES-v1.0.1.md +69 -0
  17. package/SECURITY.md +21 -0
  18. package/commitlint.config.js +36 -0
  19. package/components.json +21 -0
  20. package/eslint.config.mjs +16 -0
  21. package/jest.config.js +31 -0
  22. package/jest.setup.js +15 -0
  23. package/next.config.js +15 -0
  24. package/next.config.ts +62 -0
  25. package/package.json +70 -52
  26. package/packages/ndpr-toolkit/README.md +467 -0
  27. package/packages/ndpr-toolkit/jest.config.js +23 -0
  28. package/packages/ndpr-toolkit/package-lock.json +8197 -0
  29. package/packages/ndpr-toolkit/package.json +71 -0
  30. package/packages/ndpr-toolkit/rollup.config.js +34 -0
  31. package/packages/ndpr-toolkit/src/__tests__/components/consent/ConsentBanner.test.tsx +119 -0
  32. package/packages/ndpr-toolkit/src/__tests__/components/consent/ConsentManager.test.tsx +122 -0
  33. package/packages/ndpr-toolkit/src/__tests__/components/consent/ConsentStorage.test.tsx +270 -0
  34. package/packages/ndpr-toolkit/src/__tests__/components/dsr/DSRDashboard.test.tsx +199 -0
  35. package/packages/ndpr-toolkit/src/__tests__/components/dsr/DSRRequestForm.test.tsx +224 -0
  36. package/packages/ndpr-toolkit/src/__tests__/components/dsr/DSRTracker.test.tsx +104 -0
  37. package/packages/ndpr-toolkit/src/__tests__/hooks/useConsent.test.tsx +161 -0
  38. package/packages/ndpr-toolkit/src/__tests__/hooks/useDSR.test.tsx +330 -0
  39. package/packages/ndpr-toolkit/src/__tests__/utils/breach.test.ts +149 -0
  40. package/packages/ndpr-toolkit/src/__tests__/utils/consent.test.ts +88 -0
  41. package/packages/ndpr-toolkit/src/__tests__/utils/dpia.test.ts +160 -0
  42. package/packages/ndpr-toolkit/src/__tests__/utils/dsr.test.ts +110 -0
  43. package/packages/ndpr-toolkit/src/__tests__/utils/privacy.test.ts +97 -0
  44. package/packages/ndpr-toolkit/src/components/breach/BreachNotificationManager.tsx +701 -0
  45. package/packages/ndpr-toolkit/src/components/breach/BreachReportForm.tsx +631 -0
  46. package/packages/ndpr-toolkit/src/components/breach/BreachRiskAssessment.tsx +569 -0
  47. package/packages/ndpr-toolkit/src/components/breach/RegulatoryReportGenerator.tsx +496 -0
  48. package/packages/ndpr-toolkit/src/components/consent/ConsentBanner.tsx +270 -0
  49. package/packages/ndpr-toolkit/src/components/consent/ConsentManager.tsx +217 -0
  50. package/packages/ndpr-toolkit/src/components/consent/ConsentStorage.tsx +206 -0
  51. package/packages/ndpr-toolkit/src/components/dpia/DPIAQuestionnaire.tsx +342 -0
  52. package/packages/ndpr-toolkit/src/components/dpia/DPIAReport.tsx +373 -0
  53. package/packages/ndpr-toolkit/src/components/dpia/StepIndicator.tsx +174 -0
  54. package/packages/ndpr-toolkit/src/components/dsr/DSRDashboard.tsx +717 -0
  55. package/packages/ndpr-toolkit/src/components/dsr/DSRRequestForm.tsx +476 -0
  56. package/packages/ndpr-toolkit/src/components/dsr/DSRTracker.tsx +620 -0
  57. package/packages/ndpr-toolkit/src/components/policy/PolicyExporter.tsx +541 -0
  58. package/packages/ndpr-toolkit/src/components/policy/PolicyGenerator.tsx +454 -0
  59. package/packages/ndpr-toolkit/src/components/policy/PolicyPreview.tsx +333 -0
  60. package/packages/ndpr-toolkit/src/hooks/useBreach.ts +409 -0
  61. package/packages/ndpr-toolkit/src/hooks/useConsent.ts +263 -0
  62. package/packages/ndpr-toolkit/src/hooks/useDPIA.ts +457 -0
  63. package/packages/ndpr-toolkit/src/hooks/useDSR.ts +236 -0
  64. package/packages/ndpr-toolkit/src/hooks/usePrivacyPolicy.ts +428 -0
  65. package/{dist/index.d.ts → packages/ndpr-toolkit/src/index.ts} +13 -0
  66. package/packages/ndpr-toolkit/src/setupTests.ts +5 -0
  67. package/packages/ndpr-toolkit/src/types/breach.ts +283 -0
  68. package/packages/ndpr-toolkit/src/types/consent.ts +111 -0
  69. package/packages/ndpr-toolkit/src/types/dpia.ts +236 -0
  70. package/packages/ndpr-toolkit/src/types/dsr.ts +192 -0
  71. package/packages/ndpr-toolkit/src/types/index.ts +42 -0
  72. package/packages/ndpr-toolkit/src/types/privacy.ts +246 -0
  73. package/packages/ndpr-toolkit/src/utils/breach.ts +122 -0
  74. package/packages/ndpr-toolkit/src/utils/consent.ts +51 -0
  75. package/packages/ndpr-toolkit/src/utils/dpia.ts +104 -0
  76. package/packages/ndpr-toolkit/src/utils/dsr.ts +77 -0
  77. package/packages/ndpr-toolkit/src/utils/privacy.ts +100 -0
  78. package/packages/ndpr-toolkit/tsconfig.json +23 -0
  79. package/postcss.config.mjs +5 -0
  80. package/public/NDPR TOOLKIT.svg +1 -0
  81. package/public/favicon/android-chrome-192x192.png +0 -0
  82. package/public/favicon/android-chrome-512x512.png +0 -0
  83. package/public/favicon/apple-touch-icon.png +0 -0
  84. package/public/favicon/favicon-16x16.png +0 -0
  85. package/public/favicon/favicon-32x32.png +0 -0
  86. package/public/favicon/site.webmanifest +1 -0
  87. package/public/file.svg +1 -0
  88. package/public/globe.svg +1 -0
  89. package/public/ndpr-toolkit-logo.svg +108 -0
  90. package/public/next.svg +1 -0
  91. package/public/vercel.svg +1 -0
  92. package/public/window.svg +1 -0
  93. package/src/__tests__/example.test.ts +13 -0
  94. package/src/__tests__/requestService.test.ts +57 -0
  95. package/src/app/accessibility.css +70 -0
  96. package/src/app/docs/components/DocLayout.tsx +267 -0
  97. package/src/app/docs/components/breach-notification/page.tsx +797 -0
  98. package/src/app/docs/components/consent-management/page.tsx +576 -0
  99. package/src/app/docs/components/data-subject-rights/page.tsx +511 -0
  100. package/src/app/docs/components/dpia-questionnaire/layout.tsx +15 -0
  101. package/src/app/docs/components/dpia-questionnaire/metadata.ts +31 -0
  102. package/src/app/docs/components/dpia-questionnaire/page.tsx +666 -0
  103. package/src/app/docs/components/hooks/page.tsx +305 -0
  104. package/src/app/docs/components/page.tsx +84 -0
  105. package/src/app/docs/components/privacy-policy-generator/page.tsx +634 -0
  106. package/src/app/docs/guides/breach-notification-process/components/BestPractices.tsx +123 -0
  107. package/src/app/docs/guides/breach-notification-process/components/ImplementationSteps.tsx +328 -0
  108. package/src/app/docs/guides/breach-notification-process/components/Introduction.tsx +28 -0
  109. package/src/app/docs/guides/breach-notification-process/components/NotificationTimeline.tsx +91 -0
  110. package/src/app/docs/guides/breach-notification-process/components/Resources.tsx +118 -0
  111. package/src/app/docs/guides/breach-notification-process/page.tsx +39 -0
  112. package/src/app/docs/guides/conducting-dpia/page.tsx +593 -0
  113. package/src/app/docs/guides/data-subject-requests/page.tsx +666 -0
  114. package/src/app/docs/guides/managing-consent/page.tsx +738 -0
  115. package/src/app/docs/guides/ndpr-compliance-checklist/components/ComplianceChecklist.tsx +296 -0
  116. package/src/app/docs/guides/ndpr-compliance-checklist/components/ImplementationTools.tsx +145 -0
  117. package/src/app/docs/guides/ndpr-compliance-checklist/components/Introduction.tsx +33 -0
  118. package/src/app/docs/guides/ndpr-compliance-checklist/components/KeyRequirements.tsx +99 -0
  119. package/src/app/docs/guides/ndpr-compliance-checklist/components/Resources.tsx +159 -0
  120. package/src/app/docs/guides/ndpr-compliance-checklist/page.tsx +38 -0
  121. package/src/app/docs/guides/page.tsx +67 -0
  122. package/src/app/docs/layout.tsx +15 -0
  123. package/src/app/docs/metadata.ts +31 -0
  124. package/src/app/docs/page.tsx +572 -0
  125. package/src/app/favicon.ico +0 -0
  126. package/src/app/globals.css +123 -0
  127. package/src/app/layout.tsx +37 -0
  128. package/src/app/ndpr-demos/breach/page.tsx +354 -0
  129. package/src/app/ndpr-demos/consent/page.tsx +366 -0
  130. package/src/app/ndpr-demos/dpia/page.tsx +495 -0
  131. package/src/app/ndpr-demos/dsr/page.tsx +280 -0
  132. package/src/app/ndpr-demos/page.tsx +73 -0
  133. package/src/app/ndpr-demos/policy/page.tsx +771 -0
  134. package/src/app/page.tsx +452 -0
  135. package/src/components/ErrorBoundary.tsx +90 -0
  136. package/src/components/breach-notification/BreachNotificationForm.tsx +479 -0
  137. package/src/components/consent/ConsentBanner.tsx +159 -0
  138. package/src/components/data-subject-rights/DataSubjectRequestForm.tsx +419 -0
  139. package/src/components/docs/DocLayout.tsx +289 -0
  140. package/src/components/docs/index.ts +2 -0
  141. package/src/components/dpia/DPIAQuestionnaire.tsx +483 -0
  142. package/src/components/privacy-policy/PolicyGenerator.tsx +1062 -0
  143. package/src/components/privacy-policy/data.ts +98 -0
  144. package/src/components/privacy-policy/shared/CheckboxField.tsx +38 -0
  145. package/src/components/privacy-policy/shared/CheckboxGroup.tsx +85 -0
  146. package/src/components/privacy-policy/shared/FormField.tsx +79 -0
  147. package/src/components/privacy-policy/shared/StepIndicator.tsx +86 -0
  148. package/src/components/privacy-policy/steps/CustomSectionsStep.tsx +335 -0
  149. package/src/components/privacy-policy/steps/DataCollectionStep.tsx +231 -0
  150. package/src/components/privacy-policy/steps/DataSharingStep.tsx +418 -0
  151. package/src/components/privacy-policy/steps/OrganizationInfoStep.tsx +202 -0
  152. package/src/components/privacy-policy/steps/PolicyPreviewStep.tsx +172 -0
  153. package/src/components/ui/Badge.tsx +46 -0
  154. package/src/components/ui/Button.tsx +59 -0
  155. package/src/components/ui/Card.tsx +92 -0
  156. package/src/components/ui/Checkbox.tsx +57 -0
  157. package/src/components/ui/FormField.tsx +50 -0
  158. package/src/components/ui/Input.tsx +38 -0
  159. package/src/components/ui/Loading.tsx +201 -0
  160. package/src/components/ui/Select.tsx +42 -0
  161. package/src/components/ui/TextArea.tsx +38 -0
  162. package/src/components/ui/label.tsx +24 -0
  163. package/src/components/ui/switch.tsx +31 -0
  164. package/src/components/ui/tabs.tsx +66 -0
  165. package/src/hooks/useConsent.ts +64 -0
  166. package/src/hooks/useLoadingState.ts +85 -0
  167. package/src/lib/consentService.ts +137 -0
  168. package/src/lib/dpiaQuestions.ts +148 -0
  169. package/src/lib/requestService.ts +75 -0
  170. package/src/lib/sanitize.ts +108 -0
  171. package/src/lib/storage.ts +222 -0
  172. package/src/lib/utils.ts +6 -0
  173. package/src/types/html-to-docx.d.ts +30 -0
  174. package/src/types/index.ts +72 -0
  175. package/tailwind.config.ts +65 -0
  176. package/tsconfig.json +41 -0
  177. package/dist/components/breach/BreachNotificationManager.d.ts +0 -62
  178. package/dist/components/breach/BreachReportForm.d.ts +0 -66
  179. package/dist/components/breach/BreachRiskAssessment.d.ts +0 -50
  180. package/dist/components/breach/RegulatoryReportGenerator.d.ts +0 -94
  181. package/dist/components/consent/ConsentBanner.d.ts +0 -79
  182. package/dist/components/consent/ConsentManager.d.ts +0 -73
  183. package/dist/components/consent/ConsentStorage.d.ts +0 -41
  184. package/dist/components/dpia/DPIAQuestionnaire.d.ts +0 -70
  185. package/dist/components/dpia/DPIAReport.d.ts +0 -40
  186. package/dist/components/dpia/StepIndicator.d.ts +0 -64
  187. package/dist/components/dsr/DSRDashboard.d.ts +0 -58
  188. package/dist/components/dsr/DSRRequestForm.d.ts +0 -74
  189. package/dist/components/dsr/DSRTracker.d.ts +0 -56
  190. package/dist/components/policy/PolicyExporter.d.ts +0 -65
  191. package/dist/components/policy/PolicyGenerator.d.ts +0 -54
  192. package/dist/components/policy/PolicyPreview.d.ts +0 -71
  193. package/dist/hooks/useBreach.d.ts +0 -97
  194. package/dist/hooks/useConsent.d.ts +0 -63
  195. package/dist/hooks/useDPIA.d.ts +0 -92
  196. package/dist/hooks/useDSR.d.ts +0 -72
  197. package/dist/hooks/usePrivacyPolicy.d.ts +0 -87
  198. package/dist/index.esm.js +0 -2
  199. package/dist/index.esm.js.map +0 -1
  200. package/dist/index.js +0 -2
  201. package/dist/index.js.map +0 -1
  202. package/dist/setupTests.d.ts +0 -2
  203. package/dist/types/breach.d.ts +0 -239
  204. package/dist/types/consent.d.ts +0 -95
  205. package/dist/types/dpia.d.ts +0 -196
  206. package/dist/types/dsr.d.ts +0 -162
  207. package/dist/types/privacy.d.ts +0 -204
  208. package/dist/utils/breach.d.ts +0 -14
  209. package/dist/utils/consent.d.ts +0 -10
  210. package/dist/utils/dpia.d.ts +0 -12
  211. package/dist/utils/dsr.d.ts +0 -11
  212. 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&apos;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&apos;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&apos;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&apos;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&apos;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&apos;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&apos;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&apos;re collecting, why you&apos;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&apos;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&apos;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&apos;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&apos;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 &apos;informed&apos; 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&apos;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&apos;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
+ }