@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,576 @@
1
+ 'use client';
2
+
3
+ import Link from 'next/link';
4
+ import { DocLayout } from '../DocLayout';
5
+ import { Button } from '@/components/ui/Button';
6
+ import { Card, CardContent } from '@/components/ui/Card';
7
+
8
+ export default function ConsentManagementDocs() {
9
+ return (
10
+ <DocLayout
11
+ title="Consent Management"
12
+ description="NDPR-compliant consent management system for handling user consent preferences"
13
+ >
14
+ <div className="flex mb-6 space-x-2">
15
+ <Button asChild variant="outline" size="sm">
16
+ <Link href="/gdrp-demos/consent">
17
+ View Demo
18
+ </Link>
19
+ </Button>
20
+ <Button asChild variant="outline" size="sm">
21
+ <a href="https://github.com/tantainnovative/ndpr-toolkit/tree/main/src/components/consent" target="_blank" rel="noopener noreferrer">
22
+ View Source
23
+ </a>
24
+ </Button>
25
+ </div>
26
+
27
+ <section id="overview" className="mb-8">
28
+ <h2 className="text-2xl font-bold mb-4">Overview</h2>
29
+ <p className="mb-4">
30
+ The Consent Management component provides a complete solution for collecting, storing, and managing user consent
31
+ in compliance with the Nigeria Data Protection Regulation (NDPR). It includes a customizable consent banner,
32
+ preference management interface, and consent storage system.
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, consent must be freely given, specific, informed, and unambiguous. The data subject must clearly
38
+ indicate acceptance through a statement or clear affirmative action. Pre-ticked boxes or silence do not constitute valid consent.
39
+ </p>
40
+ </div>
41
+ </section>
42
+
43
+ <section id="installation" className="mb-8">
44
+ <h2 className="text-2xl font-bold mb-4">Installation</h2>
45
+ <p className="mb-4">
46
+ Install the NDPR Toolkit package which includes the Consent Management components:
47
+ </p>
48
+ <div className="bg-gray-800 text-gray-200 p-4 rounded-md overflow-x-auto mb-4">
49
+ <pre><code>npm install @tantainnovative/ndpr-toolkit</code></pre>
50
+ </div>
51
+ <p>
52
+ Or if you&apos;re using yarn:
53
+ </p>
54
+ <div className="bg-gray-800 text-gray-200 p-4 rounded-md overflow-x-auto">
55
+ <pre><code>yarn add @tantainnovative/ndpr-toolkit</code></pre>
56
+ </div>
57
+ </section>
58
+
59
+ <section id="components" className="mb-8">
60
+ <h2 className="text-2xl font-bold mb-4">Components</h2>
61
+ <p className="mb-4">
62
+ The Consent Management system includes several components that work together:
63
+ </p>
64
+
65
+ <div className="space-y-6">
66
+ <div className="bg-white dark:bg-gray-800 p-6 rounded-lg shadow-sm border border-gray-200 dark:border-gray-700">
67
+ <h3 className="text-xl font-bold mb-2">ConsentBanner</h3>
68
+ <p className="text-gray-600 dark:text-gray-300 mb-4">
69
+ A cookie consent banner that appears at the bottom of the page when a user first visits your site. Fully customizable with support for multiple consent options.
70
+ </p>
71
+ <div className="bg-gray-800 text-gray-200 p-4 rounded-md overflow-x-auto">
72
+ <pre><code>{`import { ConsentBanner } from '@tantainnovative/ndpr-toolkit';
73
+
74
+ <ConsentBanner
75
+ options={[
76
+ {
77
+ id: 'necessary',
78
+ label: 'Necessary Cookies',
79
+ description: 'Essential cookies for the website to function.',
80
+ required: true
81
+ },
82
+ {
83
+ id: 'analytics',
84
+ label: 'Analytics Cookies',
85
+ description: 'Cookies that help us understand how you use our website.',
86
+ required: false
87
+ },
88
+ {
89
+ id: 'marketing',
90
+ label: 'Marketing Cookies',
91
+ description: 'Cookies used for marketing purposes.',
92
+ required: false
93
+ }
94
+ ]}
95
+ onSave={(consents) => console.log(consents)}
96
+ position="bottom"
97
+ showPreferences={true}
98
+ privacyPolicyUrl="/privacy-policy"
99
+ />`}</code></pre>
100
+ </div>
101
+ </div>
102
+
103
+ <div className="bg-white dark:bg-gray-800 p-6 rounded-lg shadow-sm border border-gray-200 dark:border-gray-700">
104
+ <h3 className="text-xl font-bold mb-2">ConsentPreferences</h3>
105
+ <p className="text-gray-600 dark:text-gray-300 mb-4">
106
+ A detailed interface for users to manage their consent preferences after the initial consent has been given.
107
+ </p>
108
+ <div className="bg-gray-800 text-gray-200 p-4 rounded-md overflow-x-auto">
109
+ <pre><code>{`import { ConsentPreferences } from '@tantainnovative/ndpr-toolkit';
110
+
111
+ <ConsentPreferences
112
+ options={consentOptions}
113
+ currentConsent={currentConsent}
114
+ onSave={handleSaveConsent}
115
+ onReset={handleResetConsent}
116
+ />`}</code></pre>
117
+ </div>
118
+ </div>
119
+
120
+ <div className="bg-white dark:bg-gray-800 p-6 rounded-lg shadow-sm border border-gray-200 dark:border-gray-700">
121
+ <h3 className="text-xl font-bold mb-2">ConsentManager</h3>
122
+ <p className="text-gray-600 dark:text-gray-300 mb-4">
123
+ A higher-order component that manages the consent state and provides methods for checking and updating consent. Works with the useConsent hook to provide a complete consent management solution.
124
+ </p>
125
+ <div className="bg-gray-800 text-gray-200 p-4 rounded-md overflow-x-auto">
126
+ <pre><code>{`import { ConsentManager, useConsent } from '@tantainnovative/ndpr-toolkit';
127
+
128
+ function App() {
129
+ return (
130
+ <ConsentManager
131
+ options={[
132
+ {
133
+ id: 'necessary',
134
+ label: 'Necessary Cookies',
135
+ description: 'Essential cookies for the website to function.',
136
+ required: true
137
+ },
138
+ {
139
+ id: 'analytics',
140
+ label: 'Analytics Cookies',
141
+ description: 'Cookies that help us understand how you use our website.',
142
+ required: false
143
+ }
144
+ ]}
145
+ storageKey="my-app-consent"
146
+ autoLoad={true}
147
+ autoSave={true}
148
+ >
149
+ <MyApp />
150
+ </ConsentManager>
151
+ );
152
+ }
153
+
154
+ function MyApp() {
155
+ const {
156
+ consents,
157
+ hasConsented,
158
+ updateConsent,
159
+ saveConsents,
160
+ resetConsents
161
+ } = useConsent();
162
+
163
+ // Check if user has given consent for analytics
164
+ if (hasConsented('analytics')) {
165
+ // Initialize analytics
166
+ }
167
+
168
+ return (
169
+ <div>
170
+ {/* Your app content */}
171
+ <button onClick={() => updateConsent('analytics', true)}>Enable Analytics</button>
172
+ </div>
173
+ );
174
+ }`}</code></pre>
175
+ </div>
176
+ </div>
177
+
178
+ <div className="bg-white dark:bg-gray-800 p-6 rounded-lg shadow-sm border border-gray-200 dark:border-gray-700">
179
+ <h3 className="text-xl font-bold mb-2">ConsentStorage</h3>
180
+ <p className="text-gray-600 dark:text-gray-300 mb-4">
181
+ A component for handling the storage and retrieval of consent settings. Supports both local storage and custom storage mechanisms.
182
+ </p>
183
+ <div className="bg-gray-800 text-gray-200 p-4 rounded-md overflow-x-auto">
184
+ <pre><code>{`import { ConsentStorage, ConsentSettings } from '@tantainnovative/ndpr-toolkit';
185
+ import { useState } from 'react';
186
+
187
+ function ConsentStorageExample() {
188
+ const [settings, setSettings] = useState<ConsentSettings>({
189
+ necessary: true,
190
+ analytics: false,
191
+ marketing: false,
192
+ lastUpdated: Date.now()
193
+ });
194
+
195
+ const handleLoad = (loadedSettings: ConsentSettings | null) => {
196
+ if (loadedSettings) {
197
+ setSettings(loadedSettings);
198
+ }
199
+ };
200
+
201
+ return (
202
+ <ConsentStorage
203
+ settings={settings}
204
+ storageOptions={{
205
+ key: 'my-app-consent',
206
+ storage: 'localStorage' // or 'sessionStorage' or 'cookie'
207
+ }}
208
+ onLoad={handleLoad}
209
+ onSave={(savedSettings) => console.log('Saved:', savedSettings)}
210
+ autoLoad={true}
211
+ autoSave={true}
212
+ >
213
+ {/* Render prop pattern */}
214
+ {({ loadSettings, saveSettings, clearSettings, loaded }) => (
215
+ <div>
216
+ <p>Consent settings loaded: {loaded ? 'Yes' : 'No'}</p>
217
+ <button onClick={() => saveSettings(settings)}>Save Settings</button>
218
+ <button onClick={() => clearSettings()}>Clear Settings</button>
219
+ </div>
220
+ )}
221
+ </ConsentStorage>
222
+ );
223
+ }`}</code></pre>
224
+ </div>
225
+ </div>
226
+ </div>
227
+ </section>
228
+
229
+ <section id="usage" className="mb-8">
230
+ <h2 className="text-2xl font-bold mb-4">Usage</h2>
231
+ <p className="mb-4">
232
+ Here&apos;s a complete example of how to implement the consent management system in your application:
233
+ </p>
234
+ <div className="bg-gray-800 text-gray-200 p-4 rounded-md overflow-x-auto">
235
+ <pre><code>{`import { useState, useEffect } from 'react';
236
+ import {
237
+ ConsentBanner,
238
+ ConsentPreferences,
239
+ ConsentManager,
240
+ ConsentStorage,
241
+ useConsent
242
+ } from '@tantainnovative/ndpr-toolkit';
243
+
244
+ // Define your consent options
245
+ const consentOptions = [
246
+ {
247
+ id: 'necessary',
248
+ label: 'Necessary Cookies',
249
+ description: 'Essential cookies for the website to function.',
250
+ required: true
251
+ },
252
+ {
253
+ id: 'analytics',
254
+ label: 'Analytics Cookies',
255
+ description: 'Cookies that help us understand how you use our website.',
256
+ required: false
257
+ },
258
+ {
259
+ id: 'marketing',
260
+ label: 'Marketing Cookies',
261
+ description: 'Cookies used for marketing purposes.',
262
+ required: false
263
+ }
264
+ ];
265
+
266
+ function App() {
267
+ const [showPreferences, setShowPreferences] = useState(false);
268
+
269
+ return (
270
+ <ConsentManager
271
+ options={consentOptions}
272
+ storageKey="my-app-consent"
273
+ >
274
+ <div>
275
+ {/* Your app content */}
276
+ <header>
277
+ <nav>
278
+ {/* ... */}
279
+ <button onClick={() => setShowPreferences(true)}>
280
+ Cookie Preferences
281
+ </button>
282
+ </nav>
283
+ </header>
284
+
285
+ <main>
286
+ {/* Your main content */}
287
+ </main>
288
+
289
+ {/* Cookie preferences modal */}
290
+ {showPreferences && (
291
+ <PreferencesModal
292
+ onClose={() => setShowPreferences(false)}
293
+ />
294
+ )}
295
+
296
+ {/* Consent banner */}
297
+ <ConsentBanner
298
+ options={consentOptions}
299
+ position="bottom"
300
+ privacyPolicyUrl="/privacy-policy"
301
+ />
302
+ </div>
303
+ </ConsentManager>
304
+ );
305
+ }
306
+
307
+ function PreferencesModal({ onClose }) {
308
+ const {
309
+ consents,
310
+ updateConsent,
311
+ saveConsents,
312
+ resetConsents
313
+ } = useConsent();
314
+
315
+ const handleSave = () => {
316
+ saveConsents();
317
+ onClose();
318
+ };
319
+
320
+ return (
321
+ <div className="modal">
322
+ <div className="modal-content">
323
+ <h2>Cookie Preferences</h2>
324
+ <ConsentPreferences
325
+ options={consentOptions}
326
+ currentConsent={consents}
327
+ onSave={handleSave}
328
+ onReset={resetConsents}
329
+ />
330
+ <button onClick={onClose}>Cancel</button>
331
+ </div>
332
+ </div>
333
+ );
334
+ }
335
+
336
+ // Example of using the useConsent hook to check consent
337
+ function AnalyticsComponent() {
338
+ const { hasConsented } = useConsent();
339
+
340
+ useEffect(() => {
341
+ if (hasConsented('analytics')) {
342
+ // Initialize analytics
343
+ console.log('Analytics initialized');
344
+ }
345
+ }, [hasConsented]);
346
+
347
+ return null;
348
+ }`}</code></pre>
349
+ </div>
350
+ </section>
351
+
352
+ <section id="api" className="mb-8">
353
+ <h2 className="text-2xl font-bold mb-4">API Reference</h2>
354
+
355
+ <h3 className="text-xl font-bold mt-8 mb-4">ConsentBanner Props</h3>
356
+ <div className="overflow-x-auto">
357
+ <table className="min-w-full divide-y divide-gray-200 dark:divide-gray-700">
358
+ <thead className="bg-gray-50 dark:bg-gray-800">
359
+ <tr>
360
+ <th scope="col" className="px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider">Prop</th>
361
+ <th scope="col" className="px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider">Type</th>
362
+ <th scope="col" className="px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider">Default</th>
363
+ <th scope="col" className="px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider">Description</th>
364
+ </tr>
365
+ </thead>
366
+ <tbody className="bg-white dark:bg-gray-900 divide-y divide-gray-200 dark:divide-gray-700">
367
+ <tr>
368
+ <td className="px-6 py-4 whitespace-nowrap text-sm font-medium text-gray-900 dark:text-white">options</td>
369
+ <td className="px-6 py-4 whitespace-nowrap text-sm text-gray-500 dark:text-gray-400">ConsentOption[]</td>
370
+ <td className="px-6 py-4 whitespace-nowrap text-sm text-gray-500 dark:text-gray-400">Required</td>
371
+ <td className="px-6 py-4 text-sm text-gray-500 dark:text-gray-400">Array of consent options to display</td>
372
+ </tr>
373
+ <tr>
374
+ <td className="px-6 py-4 whitespace-nowrap text-sm font-medium text-gray-900 dark:text-white">onSave</td>
375
+ <td className="px-6 py-4 whitespace-nowrap text-sm text-gray-500 dark:text-gray-400">{`({ consents: Record<string, boolean> }) => void`}</td>
376
+ <td className="px-6 py-4 whitespace-nowrap text-sm text-gray-500 dark:text-gray-400">Required</td>
377
+ <td className="px-6 py-4 text-sm text-gray-500 dark:text-gray-400">Callback function called when consent is saved</td>
378
+ </tr>
379
+ <tr>
380
+ <td className="px-6 py-4 whitespace-nowrap text-sm font-medium text-gray-900 dark:text-white">position</td>
381
+ <td className="px-6 py-4 whitespace-nowrap text-sm text-gray-500 dark:text-gray-400">&apos;top&apos; | &apos;bottom&apos;</td>
382
+ <td className="px-6 py-4 whitespace-nowrap text-sm text-gray-500 dark:text-gray-400">&apos;bottom&apos;</td>
383
+ <td className="px-6 py-4 text-sm text-gray-500 dark:text-gray-400">Position of the banner on the page</td>
384
+ </tr>
385
+ <tr>
386
+ <td className="px-6 py-4 whitespace-nowrap text-sm font-medium text-gray-900 dark:text-white">title</td>
387
+ <td className="px-6 py-4 whitespace-nowrap text-sm text-gray-500 dark:text-gray-400">string</td>
388
+ <td className="px-6 py-4 whitespace-nowrap text-sm text-gray-500 dark:text-gray-400">&apos;Cookie Consent&apos;</td>
389
+ <td className="px-6 py-4 text-sm text-gray-500 dark:text-gray-400">Title displayed on the banner</td>
390
+ </tr>
391
+ <tr>
392
+ <td className="px-6 py-4 whitespace-nowrap text-sm font-medium text-gray-900 dark:text-white">description</td>
393
+ <td className="px-6 py-4 whitespace-nowrap text-sm text-gray-500 dark:text-gray-400">string</td>
394
+ <td className="px-6 py-4 whitespace-nowrap text-sm text-gray-500 dark:text-gray-400">&apos;We use cookies...&apos;</td>
395
+ <td className="px-6 py-4 text-sm text-gray-500 dark:text-gray-400">Description text explaining the purpose of cookies</td>
396
+ </tr>
397
+ <tr>
398
+ <td className="px-6 py-4 whitespace-nowrap text-sm font-medium text-gray-900 dark:text-white">showPreferences</td>
399
+ <td className="px-6 py-4 whitespace-nowrap text-sm text-gray-500 dark:text-gray-400">boolean</td>
400
+ <td className="px-6 py-4 whitespace-nowrap text-sm text-gray-500 dark:text-gray-400">true</td>
401
+ <td className="px-6 py-4 text-sm text-gray-500 dark:text-gray-400">Whether to show the &quot;Preferences&quot; button</td>
402
+ </tr>
403
+ <tr>
404
+ <td className="px-6 py-4 whitespace-nowrap text-sm font-medium text-gray-900 dark:text-white">privacyPolicyUrl</td>
405
+ <td className="px-6 py-4 whitespace-nowrap text-sm text-gray-500 dark:text-gray-400">string</td>
406
+ <td className="px-6 py-4 whitespace-nowrap text-sm text-gray-500 dark:text-gray-400">undefined</td>
407
+ <td className="px-6 py-4 text-sm text-gray-500 dark:text-gray-400">URL to the privacy policy page</td>
408
+ </tr>
409
+ </tbody>
410
+ </table>
411
+ </div>
412
+
413
+ <h3 className="text-xl font-bold mt-8 mb-4">ConsentStorage Props</h3>
414
+ <div className="overflow-x-auto">
415
+ <table className="min-w-full divide-y divide-gray-200 dark:divide-gray-700">
416
+ <thead className="bg-gray-50 dark:bg-gray-800">
417
+ <tr>
418
+ <th scope="col" className="px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider">Prop</th>
419
+ <th scope="col" className="px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider">Type</th>
420
+ <th scope="col" className="px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider">Default</th>
421
+ <th scope="col" className="px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider">Description</th>
422
+ </tr>
423
+ </thead>
424
+ <tbody className="bg-white dark:bg-gray-900 divide-y divide-gray-200 dark:divide-gray-700">
425
+ <tr>
426
+ <td className="px-6 py-4 whitespace-nowrap text-sm font-medium text-gray-900 dark:text-white">settings</td>
427
+ <td className="px-6 py-4 whitespace-nowrap text-sm text-gray-500 dark:text-gray-400">ConsentSettings</td>
428
+ <td className="px-6 py-4 whitespace-nowrap text-sm text-gray-500 dark:text-gray-400">Required</td>
429
+ <td className="px-6 py-4 text-sm text-gray-500 dark:text-gray-400">Current consent settings to store</td>
430
+ </tr>
431
+ <tr>
432
+ <td className="px-6 py-4 whitespace-nowrap text-sm font-medium text-gray-900 dark:text-white">storageOptions</td>
433
+ <td className="px-6 py-4 whitespace-nowrap text-sm text-gray-500 dark:text-gray-400">ConsentStorageOptions</td>
434
+ <td className="px-6 py-4 whitespace-nowrap text-sm text-gray-500 dark:text-gray-400">{`{ storageKey: 'ndpr_consent', storageType: 'localStorage' }`}</td>
435
+ <td className="px-6 py-4 text-sm text-gray-500 dark:text-gray-400">Options for storage mechanism</td>
436
+ </tr>
437
+ <tr>
438
+ <td className="px-6 py-4 whitespace-nowrap text-sm font-medium text-gray-900 dark:text-white">onLoad</td>
439
+ <td className="px-6 py-4 whitespace-nowrap text-sm text-gray-500 dark:text-gray-400">{`(settings: ConsentSettings | null) => void`}</td>
440
+ <td className="px-6 py-4 whitespace-nowrap text-sm text-gray-500 dark:text-gray-400">undefined</td>
441
+ <td className="px-6 py-4 text-sm text-gray-500 dark:text-gray-400">Callback when settings are loaded</td>
442
+ </tr>
443
+ <tr>
444
+ <td className="px-6 py-4 whitespace-nowrap text-sm font-medium text-gray-900 dark:text-white">onSave</td>
445
+ <td className="px-6 py-4 whitespace-nowrap text-sm text-gray-500 dark:text-gray-400">{`(settings: ConsentSettings) => void`}</td>
446
+ <td className="px-6 py-4 whitespace-nowrap text-sm text-gray-500 dark:text-gray-400">undefined</td>
447
+ <td className="px-6 py-4 text-sm text-gray-500 dark:text-gray-400">Callback when settings are saved</td>
448
+ </tr>
449
+ <tr>
450
+ <td className="px-6 py-4 whitespace-nowrap text-sm font-medium text-gray-900 dark:text-white">autoLoad</td>
451
+ <td className="px-6 py-4 whitespace-nowrap text-sm text-gray-500 dark:text-gray-400">boolean</td>
452
+ <td className="px-6 py-4 whitespace-nowrap text-sm text-gray-500 dark:text-gray-400">true</td>
453
+ <td className="px-6 py-4 text-sm text-gray-500 dark:text-gray-400">Whether to load settings on mount</td>
454
+ </tr>
455
+ <tr>
456
+ <td className="px-6 py-4 whitespace-nowrap text-sm font-medium text-gray-900 dark:text-white">autoSave</td>
457
+ <td className="px-6 py-4 whitespace-nowrap text-sm text-gray-500 dark:text-gray-400">boolean</td>
458
+ <td className="px-6 py-4 whitespace-nowrap text-sm text-gray-500 dark:text-gray-400">true</td>
459
+ <td className="px-6 py-4 text-sm text-gray-500 dark:text-gray-400">Whether to save settings automatically</td>
460
+ </tr>
461
+ <tr>
462
+ <td className="px-6 py-4 whitespace-nowrap text-sm font-medium text-gray-900 dark:text-white">children</td>
463
+ <td className="px-6 py-4 whitespace-nowrap text-sm text-gray-500 dark:text-gray-400">ReactNode | Function</td>
464
+ <td className="px-6 py-4 whitespace-nowrap text-sm text-gray-500 dark:text-gray-400">undefined</td>
465
+ <td className="px-6 py-4 text-sm text-gray-500 dark:text-gray-400">React nodes or render prop function</td>
466
+ </tr>
467
+ </tbody>
468
+ </table>
469
+ </div>
470
+
471
+ <h3 className="text-xl font-bold mt-8 mb-4">ConsentOption Type</h3>
472
+ <div className="bg-gray-800 text-gray-200 p-4 rounded-md overflow-x-auto">
473
+ <pre><code>{`type ConsentOption = {
474
+ id: string;
475
+ label: string;
476
+ description: string;
477
+ required?: boolean;
478
+ };`}</code></pre>
479
+ </div>
480
+
481
+ <h3 className="text-xl font-bold mt-8 mb-4">ConsentSettings Type</h3>
482
+ <div className="bg-gray-800 text-gray-200 p-4 rounded-md overflow-x-auto">
483
+ <pre><code>{`type ConsentSettings = {
484
+ [key: string]: boolean;
485
+ lastUpdated: number;
486
+ };`}</code></pre>
487
+ </div>
488
+
489
+ <h3 className="text-xl font-bold mt-8 mb-4">ConsentStorageOptions Type</h3>
490
+ <div className="bg-gray-800 text-gray-200 p-4 rounded-md overflow-x-auto">
491
+ <pre><code>{`type ConsentStorageOptions = {
492
+ key: string;
493
+ storage: 'localStorage' | 'sessionStorage' | 'cookie';
494
+ cookieOptions?: {
495
+ path?: string;
496
+ domain?: string;
497
+ secure?: boolean;
498
+ sameSite?: 'strict' | 'lax' | 'none';
499
+ maxAge?: number;
500
+ };
501
+ };`}</code></pre>
502
+ </div>
503
+ </section>
504
+
505
+ <section id="best-practices" className="mb-8">
506
+ <h2 className="text-2xl font-bold mb-4">Best Practices</h2>
507
+ <ul className="list-disc pl-6 space-y-2">
508
+ <li>
509
+ <strong>Clear Language:</strong> Use clear, plain language to explain what each type of cookie does and why you&apos;re collecting the data.
510
+ </li>
511
+ <li>
512
+ <strong>No Pre-selected Options:</strong> Don&apos;t pre-select non-essential cookies. The NDPR requires that consent is freely given and pre-selected checkboxes don&apos;t constitute valid consent.
513
+ </li>
514
+ <li>
515
+ <strong>Easy Access to Preferences:</strong> Make it easy for users to access and update their consent preferences at any time.
516
+ </li>
517
+ <li>
518
+ <strong>Consent Records:</strong> Keep records of when and how consent was obtained. The ConsentManager component automatically tracks consent history.
519
+ </li>
520
+ <li>
521
+ <strong>Respect User Choices:</strong> Only activate cookies and tracking technologies when the user has given explicit consent for them.
522
+ </li>
523
+ </ul>
524
+ </section>
525
+
526
+ <section id="accessibility" className="mb-8">
527
+ <h2 className="text-2xl font-bold mb-4">Accessibility</h2>
528
+ <p className="mb-4">
529
+ The Consent Management components are built with accessibility in mind:
530
+ </p>
531
+ <ul className="list-disc pl-6 space-y-2">
532
+ <li>All form elements have proper labels and ARIA attributes</li>
533
+ <li>Focus states are clearly visible</li>
534
+ <li>Color contrast meets WCAG 2.1 AA standards</li>
535
+ <li>Keyboard navigation is fully supported</li>
536
+ <li>The banner is announced to screen readers when it appears</li>
537
+ </ul>
538
+ </section>
539
+
540
+ <section id="help-resources" className="mb-8">
541
+ <h2 className="text-2xl font-bold mb-4">Need Help?</h2>
542
+ <p className="mb-4">
543
+ If you have questions about implementing the Consent Management system or need assistance with NDPR compliance, check out these resources:
544
+ </p>
545
+ <div className="grid grid-cols-1 md:grid-cols-2 gap-4">
546
+ <Card>
547
+ <CardContent className="p-4">
548
+ <h3 className="font-medium text-gray-900 dark:text-white mb-2">GitHub Issues</h3>
549
+ <p className="text-gray-600 dark:text-gray-300 text-sm mb-3">
550
+ Report bugs or request features on our GitHub repository.
551
+ </p>
552
+ <Button asChild variant="outline" size="sm">
553
+ <a href="https://github.com/tantainnovative/ndpr-toolkit/issues" target="_blank" rel="noopener noreferrer">
554
+ View Issues
555
+ </a>
556
+ </Button>
557
+ </CardContent>
558
+ </Card>
559
+ <Card>
560
+ <CardContent className="p-4">
561
+ <h3 className="font-medium text-gray-900 dark:text-white mb-2">NDPR Resources</h3>
562
+ <p className="text-gray-600 dark:text-gray-300 text-sm mb-3">
563
+ Learn more about NDPR compliance requirements.
564
+ </p>
565
+ <Button asChild variant="outline" size="sm">
566
+ <a href="https://nitda.gov.ng/wp-content/uploads/2020/01/NDPR-Implementation-Framework.pdf" target="_blank" rel="noopener noreferrer">
567
+ NDPR Framework
568
+ </a>
569
+ </Button>
570
+ </CardContent>
571
+ </Card>
572
+ </div>
573
+ </section>
574
+ </DocLayout>
575
+ );
576
+ }