@tantainnovative/ndpr-toolkit 1.0.5 → 1.0.6

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 (159) hide show
  1. package/README.md +447 -84
  2. package/dist/index.esm.js +2 -0
  3. package/dist/index.esm.js.map +1 -0
  4. package/dist/index.js +2 -0
  5. package/dist/index.js.map +1 -0
  6. package/dist/types/index.d.ts +35 -0
  7. package/package.json +52 -70
  8. package/CHANGELOG.md +0 -16
  9. package/CNAME +0 -1
  10. package/CONTRIBUTING.md +0 -87
  11. package/RELEASE-NOTES-v1.0.0.md +0 -140
  12. package/RELEASE-NOTES-v1.0.1.md +0 -69
  13. package/SECURITY.md +0 -21
  14. package/components.json +0 -21
  15. package/eslint.config.mjs +0 -16
  16. package/next-env.d.ts +0 -5
  17. package/next.config.js +0 -15
  18. package/next.config.ts +0 -62
  19. package/packages/ndpr-toolkit/README.md +0 -467
  20. package/packages/ndpr-toolkit/dist/index.esm.js +0 -2
  21. package/packages/ndpr-toolkit/dist/index.esm.js.map +0 -1
  22. package/packages/ndpr-toolkit/dist/index.js +0 -2
  23. package/packages/ndpr-toolkit/dist/index.js.map +0 -1
  24. package/packages/ndpr-toolkit/package-lock.json +0 -8197
  25. package/packages/ndpr-toolkit/package.json +0 -71
  26. package/packages/ndpr-toolkit/rollup.config.js +0 -34
  27. package/packages/ndpr-toolkit/src/components/breach/BreachNotificationManager.tsx +0 -701
  28. package/packages/ndpr-toolkit/src/components/breach/BreachReportForm.tsx +0 -631
  29. package/packages/ndpr-toolkit/src/components/breach/BreachRiskAssessment.tsx +0 -569
  30. package/packages/ndpr-toolkit/src/components/breach/RegulatoryReportGenerator.tsx +0 -496
  31. package/packages/ndpr-toolkit/src/components/consent/ConsentBanner.tsx +0 -270
  32. package/packages/ndpr-toolkit/src/components/consent/ConsentManager.tsx +0 -217
  33. package/packages/ndpr-toolkit/src/components/consent/ConsentStorage.tsx +0 -206
  34. package/packages/ndpr-toolkit/src/components/dpia/DPIAQuestionnaire.tsx +0 -342
  35. package/packages/ndpr-toolkit/src/components/dpia/DPIAReport.tsx +0 -373
  36. package/packages/ndpr-toolkit/src/components/dpia/StepIndicator.tsx +0 -174
  37. package/packages/ndpr-toolkit/src/components/dsr/DSRDashboard.tsx +0 -717
  38. package/packages/ndpr-toolkit/src/components/dsr/DSRRequestForm.tsx +0 -476
  39. package/packages/ndpr-toolkit/src/components/dsr/DSRTracker.tsx +0 -620
  40. package/packages/ndpr-toolkit/src/components/policy/PolicyExporter.tsx +0 -541
  41. package/packages/ndpr-toolkit/src/components/policy/PolicyGenerator.tsx +0 -454
  42. package/packages/ndpr-toolkit/src/components/policy/PolicyPreview.tsx +0 -333
  43. package/packages/ndpr-toolkit/src/hooks/useBreach.ts +0 -409
  44. package/packages/ndpr-toolkit/src/hooks/useConsent.ts +0 -263
  45. package/packages/ndpr-toolkit/src/hooks/useDPIA.ts +0 -457
  46. package/packages/ndpr-toolkit/src/hooks/useDSR.ts +0 -236
  47. package/packages/ndpr-toolkit/src/hooks/usePrivacyPolicy.ts +0 -428
  48. package/packages/ndpr-toolkit/src/index.ts +0 -44
  49. package/packages/ndpr-toolkit/src/setupTests.ts +0 -5
  50. package/packages/ndpr-toolkit/src/types/breach.ts +0 -283
  51. package/packages/ndpr-toolkit/src/types/consent.ts +0 -111
  52. package/packages/ndpr-toolkit/src/types/dpia.ts +0 -236
  53. package/packages/ndpr-toolkit/src/types/dsr.ts +0 -192
  54. package/packages/ndpr-toolkit/src/types/index.ts +0 -42
  55. package/packages/ndpr-toolkit/src/types/privacy.ts +0 -246
  56. package/packages/ndpr-toolkit/src/utils/breach.ts +0 -122
  57. package/packages/ndpr-toolkit/src/utils/consent.ts +0 -51
  58. package/packages/ndpr-toolkit/src/utils/dpia.ts +0 -104
  59. package/packages/ndpr-toolkit/src/utils/dsr.ts +0 -77
  60. package/packages/ndpr-toolkit/src/utils/privacy.ts +0 -100
  61. package/packages/ndpr-toolkit/tsconfig.json +0 -23
  62. package/postcss.config.mjs +0 -5
  63. package/public/NDPR TOOLKIT.svg +0 -1
  64. package/public/favicon/android-chrome-192x192.png +0 -0
  65. package/public/favicon/android-chrome-512x512.png +0 -0
  66. package/public/favicon/apple-touch-icon.png +0 -0
  67. package/public/favicon/favicon-16x16.png +0 -0
  68. package/public/favicon/favicon-32x32.png +0 -0
  69. package/public/favicon/site.webmanifest +0 -1
  70. package/public/file.svg +0 -1
  71. package/public/globe.svg +0 -1
  72. package/public/ndpr-toolkit-logo.svg +0 -108
  73. package/public/next.svg +0 -1
  74. package/public/vercel.svg +0 -1
  75. package/public/window.svg +0 -1
  76. package/src/app/accessibility.css +0 -70
  77. package/src/app/favicon.ico +0 -0
  78. package/src/app/globals.css +0 -123
  79. package/src/app/layout.tsx +0 -37
  80. package/src/app/ndpr-demos/breach/page.tsx +0 -354
  81. package/src/app/ndpr-demos/consent/page.tsx +0 -366
  82. package/src/app/ndpr-demos/dpia/page.tsx +0 -495
  83. package/src/app/ndpr-demos/dsr/page.tsx +0 -280
  84. package/src/app/ndpr-demos/page.tsx +0 -73
  85. package/src/app/ndpr-demos/policy/page.tsx +0 -771
  86. package/src/app/page.tsx +0 -452
  87. package/src/components/ErrorBoundary.tsx +0 -90
  88. package/src/components/breach-notification/BreachNotificationForm.tsx +0 -479
  89. package/src/components/consent/ConsentBanner.tsx +0 -193
  90. package/src/components/data-subject-rights/DataSubjectRequestForm.tsx +0 -530
  91. package/src/components/dpia/DPIAQuestionnaire.tsx +0 -523
  92. package/src/components/privacy-policy/PolicyGenerator.tsx +0 -1062
  93. package/src/components/privacy-policy/data.ts +0 -98
  94. package/src/components/privacy-policy/shared/CheckboxField.tsx +0 -38
  95. package/src/components/privacy-policy/shared/CheckboxGroup.tsx +0 -85
  96. package/src/components/privacy-policy/shared/FormField.tsx +0 -79
  97. package/src/components/privacy-policy/shared/StepIndicator.tsx +0 -86
  98. package/src/components/privacy-policy/steps/CustomSectionsStep.tsx +0 -361
  99. package/src/components/privacy-policy/steps/DataCollectionStep.tsx +0 -231
  100. package/src/components/privacy-policy/steps/DataSharingStep.tsx +0 -418
  101. package/src/components/privacy-policy/steps/OrganizationInfoStep.tsx +0 -202
  102. package/src/components/privacy-policy/steps/PolicyPreviewStep.tsx +0 -226
  103. package/src/components/ui/Badge.tsx +0 -46
  104. package/src/components/ui/Button.tsx +0 -59
  105. package/src/components/ui/Card.tsx +0 -92
  106. package/src/components/ui/Checkbox.tsx +0 -57
  107. package/src/components/ui/FormField.tsx +0 -50
  108. package/src/components/ui/Input.tsx +0 -38
  109. package/src/components/ui/Loading.tsx +0 -201
  110. package/src/components/ui/Select.tsx +0 -42
  111. package/src/components/ui/TextArea.tsx +0 -38
  112. package/src/components/ui/label.tsx +0 -24
  113. package/src/components/ui/switch.tsx +0 -31
  114. package/src/components/ui/tabs.tsx +0 -66
  115. package/src/hooks/useConsent.ts +0 -70
  116. package/src/hooks/useLoadingState.ts +0 -85
  117. package/src/lib/consentService.ts +0 -144
  118. package/src/lib/dpiaQuestions.ts +0 -188
  119. package/src/lib/requestService.ts +0 -79
  120. package/src/lib/sanitize.ts +0 -108
  121. package/src/lib/storage.ts +0 -222
  122. package/src/lib/utils.ts +0 -6
  123. package/src/types/html-to-docx.d.ts +0 -30
  124. package/src/types/index.ts +0 -77
  125. package/tailwind.config.ts +0 -65
  126. package/tsconfig.json +0 -41
  127. /package/{packages/ndpr-toolkit/dist → dist}/components/breach/BreachNotificationManager.d.ts +0 -0
  128. /package/{packages/ndpr-toolkit/dist → dist}/components/breach/BreachReportForm.d.ts +0 -0
  129. /package/{packages/ndpr-toolkit/dist → dist}/components/breach/BreachRiskAssessment.d.ts +0 -0
  130. /package/{packages/ndpr-toolkit/dist → dist}/components/breach/RegulatoryReportGenerator.d.ts +0 -0
  131. /package/{packages/ndpr-toolkit/dist → dist}/components/consent/ConsentBanner.d.ts +0 -0
  132. /package/{packages/ndpr-toolkit/dist → dist}/components/consent/ConsentManager.d.ts +0 -0
  133. /package/{packages/ndpr-toolkit/dist → dist}/components/consent/ConsentStorage.d.ts +0 -0
  134. /package/{packages/ndpr-toolkit/dist → dist}/components/dpia/DPIAQuestionnaire.d.ts +0 -0
  135. /package/{packages/ndpr-toolkit/dist → dist}/components/dpia/DPIAReport.d.ts +0 -0
  136. /package/{packages/ndpr-toolkit/dist → dist}/components/dpia/StepIndicator.d.ts +0 -0
  137. /package/{packages/ndpr-toolkit/dist → dist}/components/dsr/DSRDashboard.d.ts +0 -0
  138. /package/{packages/ndpr-toolkit/dist → dist}/components/dsr/DSRRequestForm.d.ts +0 -0
  139. /package/{packages/ndpr-toolkit/dist → dist}/components/dsr/DSRTracker.d.ts +0 -0
  140. /package/{packages/ndpr-toolkit/dist → dist}/components/policy/PolicyExporter.d.ts +0 -0
  141. /package/{packages/ndpr-toolkit/dist → dist}/components/policy/PolicyGenerator.d.ts +0 -0
  142. /package/{packages/ndpr-toolkit/dist → dist}/components/policy/PolicyPreview.d.ts +0 -0
  143. /package/{packages/ndpr-toolkit/dist → dist}/hooks/useBreach.d.ts +0 -0
  144. /package/{packages/ndpr-toolkit/dist → dist}/hooks/useConsent.d.ts +0 -0
  145. /package/{packages/ndpr-toolkit/dist → dist}/hooks/useDPIA.d.ts +0 -0
  146. /package/{packages/ndpr-toolkit/dist → dist}/hooks/useDSR.d.ts +0 -0
  147. /package/{packages/ndpr-toolkit/dist → dist}/hooks/usePrivacyPolicy.d.ts +0 -0
  148. /package/{packages/ndpr-toolkit/dist → dist}/index.d.ts +0 -0
  149. /package/{packages/ndpr-toolkit/dist → dist}/setupTests.d.ts +0 -0
  150. /package/{packages/ndpr-toolkit/dist → dist}/types/breach.d.ts +0 -0
  151. /package/{packages/ndpr-toolkit/dist → dist}/types/consent.d.ts +0 -0
  152. /package/{packages/ndpr-toolkit/dist → dist}/types/dpia.d.ts +0 -0
  153. /package/{packages/ndpr-toolkit/dist → dist}/types/dsr.d.ts +0 -0
  154. /package/{packages/ndpr-toolkit/dist → dist}/types/privacy.d.ts +0 -0
  155. /package/{packages/ndpr-toolkit/dist → dist}/utils/breach.d.ts +0 -0
  156. /package/{packages/ndpr-toolkit/dist → dist}/utils/consent.d.ts +0 -0
  157. /package/{packages/ndpr-toolkit/dist → dist}/utils/dpia.d.ts +0 -0
  158. /package/{packages/ndpr-toolkit/dist → dist}/utils/dsr.d.ts +0 -0
  159. /package/{packages/ndpr-toolkit/dist → dist}/utils/privacy.d.ts +0 -0
@@ -1,409 +0,0 @@
1
- import { useState, useEffect } from 'react';
2
- import { BreachReport, BreachCategory, RiskAssessment, NotificationRequirement, RegulatoryNotification } from '../types/breach';
3
- import { calculateBreachSeverity } from '../utils/breach';
4
-
5
- interface UseBreachOptions {
6
- /**
7
- * Available breach categories
8
- */
9
- categories: BreachCategory[];
10
-
11
- /**
12
- * Initial breach reports
13
- */
14
- initialReports?: BreachReport[];
15
-
16
- /**
17
- * Storage key for breach data
18
- * @default "ndpr_breach_data"
19
- */
20
- storageKey?: string;
21
-
22
- /**
23
- * Whether to use local storage to persist breach data
24
- * @default true
25
- */
26
- useLocalStorage?: boolean;
27
-
28
- /**
29
- * Callback function called when a breach is reported
30
- */
31
- onReport?: (report: BreachReport) => void;
32
-
33
- /**
34
- * Callback function called when a risk assessment is completed
35
- */
36
- onAssessment?: (assessment: RiskAssessment) => void;
37
-
38
- /**
39
- * Callback function called when a notification is sent
40
- */
41
- onNotification?: (notification: RegulatoryNotification) => void;
42
- }
43
-
44
- interface UseBreachReturn {
45
- /**
46
- * All breach reports
47
- */
48
- reports: BreachReport[];
49
-
50
- /**
51
- * All risk assessments
52
- */
53
- assessments: RiskAssessment[];
54
-
55
- /**
56
- * All regulatory notifications
57
- */
58
- notifications: RegulatoryNotification[];
59
-
60
- /**
61
- * Submit a new breach report
62
- */
63
- reportBreach: (reportData: Omit<BreachReport, 'id' | 'reportedAt'>) => BreachReport;
64
-
65
- /**
66
- * Update an existing breach report
67
- */
68
- updateReport: (id: string, updates: Partial<BreachReport>) => BreachReport | null;
69
-
70
- /**
71
- * Get a breach report by ID
72
- */
73
- getReport: (id: string) => BreachReport | null;
74
-
75
- /**
76
- * Conduct a risk assessment for a breach
77
- */
78
- assessRisk: (breachId: string, assessmentData: Omit<RiskAssessment, 'id' | 'breachId' | 'assessedAt'>) => RiskAssessment;
79
-
80
- /**
81
- * Get a risk assessment for a breach
82
- */
83
- getAssessment: (breachId: string) => RiskAssessment | null;
84
-
85
- /**
86
- * Calculate notification requirements based on a risk assessment
87
- */
88
- calculateNotificationRequirements: (breachId: string) => NotificationRequirement | null;
89
-
90
- /**
91
- * Send a regulatory notification
92
- */
93
- sendNotification: (breachId: string, notificationData: Omit<RegulatoryNotification, 'id' | 'breachId' | 'sentAt'>) => RegulatoryNotification;
94
-
95
- /**
96
- * Get a regulatory notification for a breach
97
- */
98
- getNotification: (breachId: string) => RegulatoryNotification | null;
99
-
100
- /**
101
- * Get breaches that require notification within the next X hours
102
- */
103
- getBreachesRequiringNotification: (hoursThreshold?: number) => Array<{
104
- report: BreachReport;
105
- assessment: RiskAssessment;
106
- requirements: NotificationRequirement;
107
- hoursRemaining: number;
108
- }>;
109
-
110
- /**
111
- * Clear all breach data
112
- */
113
- clearBreachData: () => void;
114
- }
115
-
116
- /**
117
- * Hook for managing data breach notifications in compliance with NDPR
118
- */
119
- export function useBreach({
120
- categories,
121
- initialReports = [],
122
- storageKey = "ndpr_breach_data",
123
- useLocalStorage = true,
124
- onReport,
125
- onAssessment,
126
- onNotification
127
- }: UseBreachOptions): UseBreachReturn {
128
- const [reports, setReports] = useState<BreachReport[]>(initialReports);
129
- const [assessments, setAssessments] = useState<RiskAssessment[]>([]);
130
- const [notifications, setNotifications] = useState<RegulatoryNotification[]>([]);
131
-
132
- // Load breach data from storage on mount
133
- useEffect(() => {
134
- if (useLocalStorage && typeof window !== 'undefined') {
135
- try {
136
- const savedData = localStorage.getItem(storageKey);
137
- if (savedData) {
138
- const { reports, assessments, notifications } = JSON.parse(savedData);
139
- setReports(reports || []);
140
- setAssessments(assessments || []);
141
- setNotifications(notifications || []);
142
- }
143
- } catch (error) {
144
- console.error('Error loading breach data:', error);
145
- }
146
- }
147
- }, [storageKey, useLocalStorage]);
148
-
149
- // Save breach data to storage when it changes
150
- useEffect(() => {
151
- if (useLocalStorage && typeof window !== 'undefined') {
152
- try {
153
- localStorage.setItem(storageKey, JSON.stringify({
154
- reports,
155
- assessments,
156
- notifications
157
- }));
158
- } catch (error) {
159
- console.error('Error saving breach data:', error);
160
- }
161
- }
162
- }, [reports, assessments, notifications, storageKey, useLocalStorage]);
163
-
164
- // Generate a unique ID
165
- const generateId = (prefix: string): string => {
166
- return `${prefix}_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
167
- };
168
-
169
- // Submit a new breach report
170
- const reportBreach = (reportData: Omit<BreachReport, 'id' | 'reportedAt'>): BreachReport => {
171
- const newReport: BreachReport = {
172
- id: generateId('breach'),
173
- reportedAt: Date.now(),
174
- ...reportData
175
- };
176
-
177
- setReports(prevReports => [...prevReports, newReport]);
178
-
179
- if (onReport) {
180
- onReport(newReport);
181
- }
182
-
183
- return newReport;
184
- };
185
-
186
- // Update an existing breach report
187
- const updateReport = (id: string, updates: Partial<BreachReport>): BreachReport | null => {
188
- let updatedReport: BreachReport | null = null;
189
-
190
- setReports(prevReports => {
191
- const index = prevReports.findIndex(report => report.id === id);
192
-
193
- if (index === -1) {
194
- return prevReports;
195
- }
196
-
197
- const report = prevReports[index];
198
- updatedReport = {
199
- ...report,
200
- ...updates
201
- };
202
-
203
- const newReports = [...prevReports];
204
- newReports[index] = updatedReport as BreachReport;
205
-
206
- return newReports;
207
- });
208
-
209
- return updatedReport;
210
- };
211
-
212
- // Get a breach report by ID
213
- const getReport = (id: string): BreachReport | null => {
214
- return reports.find(report => report.id === id) || null;
215
- };
216
-
217
- // Conduct a risk assessment for a breach
218
- const assessRisk = (breachId: string, assessmentData: Omit<RiskAssessment, 'id' | 'breachId' | 'assessedAt'>): RiskAssessment => {
219
- // Check if an assessment already exists for this breach
220
- const existingAssessment = assessments.find(assessment => assessment.breachId === breachId);
221
-
222
- if (existingAssessment) {
223
- // Update the existing assessment
224
- const updatedAssessment: RiskAssessment = {
225
- ...existingAssessment,
226
- ...assessmentData,
227
- assessedAt: Date.now()
228
- };
229
-
230
- setAssessments(prevAssessments =>
231
- prevAssessments.map(assessment =>
232
- assessment.id === existingAssessment.id ? updatedAssessment : assessment
233
- )
234
- );
235
-
236
- if (onAssessment) {
237
- onAssessment(updatedAssessment);
238
- }
239
-
240
- return updatedAssessment;
241
- } else {
242
- // Create a new assessment
243
- const newAssessment: RiskAssessment = {
244
- id: generateId('assessment'),
245
- breachId,
246
- assessedAt: Date.now(),
247
- ...assessmentData
248
- };
249
-
250
- setAssessments(prevAssessments => [...prevAssessments, newAssessment]);
251
-
252
- if (onAssessment) {
253
- onAssessment(newAssessment);
254
- }
255
-
256
- return newAssessment;
257
- }
258
- };
259
-
260
- // Get a risk assessment for a breach
261
- const getAssessment = (breachId: string): RiskAssessment | null => {
262
- return assessments.find(assessment => assessment.breachId === breachId) || null;
263
- };
264
-
265
- // Calculate notification requirements based on a risk assessment
266
- const calculateNotificationRequirements = (breachId: string): NotificationRequirement | null => {
267
- const report = getReport(breachId);
268
- const assessment = getAssessment(breachId);
269
-
270
- if (!report) {
271
- return null;
272
- }
273
-
274
- const { severityLevel, notificationRequired, timeframeHours, justification } = calculateBreachSeverity(report, assessment || undefined);
275
-
276
- // Calculate the deadline (72 hours from discovery under NDPR)
277
- const deadline = report.discoveredAt + (timeframeHours * 60 * 60 * 1000);
278
-
279
- return {
280
- nitdaNotificationRequired: notificationRequired,
281
- nitdaNotificationDeadline: deadline,
282
- dataSubjectNotificationRequired: severityLevel === 'high' || severityLevel === 'critical',
283
- justification
284
- };
285
- };
286
-
287
- // Send a regulatory notification
288
- const sendNotification = (breachId: string, notificationData: Omit<RegulatoryNotification, 'id' | 'breachId' | 'sentAt'>): RegulatoryNotification => {
289
- // Check if a notification already exists for this breach
290
- const existingNotification = notifications.find(notification => notification.breachId === breachId);
291
-
292
- if (existingNotification) {
293
- // Update the existing notification
294
- const updatedNotification: RegulatoryNotification = {
295
- ...existingNotification,
296
- ...notificationData,
297
- sentAt: Date.now()
298
- };
299
-
300
- setNotifications(prevNotifications =>
301
- prevNotifications.map(notification =>
302
- notification.id === existingNotification.id ? updatedNotification : notification
303
- )
304
- );
305
-
306
- if (onNotification) {
307
- onNotification(updatedNotification);
308
- }
309
-
310
- return updatedNotification;
311
- } else {
312
- // Create a new notification
313
- const newNotification: RegulatoryNotification = {
314
- id: generateId('notification'),
315
- breachId,
316
- sentAt: Date.now(),
317
- ...notificationData
318
- };
319
-
320
- setNotifications(prevNotifications => [...prevNotifications, newNotification]);
321
-
322
- if (onNotification) {
323
- onNotification(newNotification);
324
- }
325
-
326
- return newNotification;
327
- }
328
- };
329
-
330
- // Get a regulatory notification for a breach
331
- const getNotification = (breachId: string): RegulatoryNotification | null => {
332
- return notifications.find(notification => notification.breachId === breachId) || null;
333
- };
334
-
335
- // Get breaches that require notification within the next X hours
336
- const getBreachesRequiringNotification = (hoursThreshold = 24): Array<{
337
- report: BreachReport;
338
- assessment: RiskAssessment;
339
- requirements: NotificationRequirement;
340
- hoursRemaining: number;
341
- }> => {
342
- const now = Date.now();
343
- const result: Array<{
344
- report: BreachReport;
345
- assessment: RiskAssessment;
346
- requirements: NotificationRequirement;
347
- hoursRemaining: number;
348
- }> = [];
349
-
350
- reports.forEach(report => {
351
- // Skip if a notification has already been sent
352
- if (notifications.some(notification => notification.breachId === report.id)) {
353
- return;
354
- }
355
-
356
- const assessment = getAssessment(report.id);
357
- if (!assessment) {
358
- return;
359
- }
360
-
361
- const requirements = calculateNotificationRequirements(report.id);
362
- if (!requirements || !requirements.nitdaNotificationRequired) {
363
- return;
364
- }
365
-
366
- const timeRemaining = requirements.nitdaNotificationDeadline - now;
367
- const hoursRemaining = timeRemaining / (60 * 60 * 1000);
368
-
369
- if (hoursRemaining <= hoursThreshold) {
370
- result.push({
371
- report,
372
- assessment,
373
- requirements,
374
- hoursRemaining
375
- });
376
- }
377
- });
378
-
379
- // Sort by hours remaining (ascending)
380
- return result.sort((a, b) => a.hoursRemaining - b.hoursRemaining);
381
- };
382
-
383
- // Clear all breach data
384
- const clearBreachData = () => {
385
- setReports([]);
386
- setAssessments([]);
387
- setNotifications([]);
388
-
389
- if (useLocalStorage && typeof window !== 'undefined') {
390
- localStorage.removeItem(storageKey);
391
- }
392
- };
393
-
394
- return {
395
- reports,
396
- assessments,
397
- notifications,
398
- reportBreach,
399
- updateReport,
400
- getReport,
401
- assessRisk,
402
- getAssessment,
403
- calculateNotificationRequirements,
404
- sendNotification,
405
- getNotification,
406
- getBreachesRequiringNotification,
407
- clearBreachData
408
- };
409
- }
@@ -1,263 +0,0 @@
1
- import { useState, useEffect } from 'react';
2
- import { ConsentOption, ConsentSettings, ConsentStorageOptions } from '../types/consent';
3
- import { validateConsent } from '../utils/consent';
4
-
5
- interface UseConsentOptions {
6
- /**
7
- * Consent options to present to the user
8
- */
9
- options: ConsentOption[];
10
-
11
- /**
12
- * Storage options for consent settings
13
- */
14
- storageOptions?: ConsentStorageOptions;
15
-
16
- /**
17
- * Version of the consent form
18
- * @default "1.0"
19
- */
20
- version?: string;
21
-
22
- /**
23
- * Callback function called when consent settings change
24
- */
25
- onChange?: (settings: ConsentSettings) => void;
26
- }
27
-
28
- interface UseConsentReturn {
29
- /**
30
- * Current consent settings
31
- */
32
- settings: ConsentSettings | null;
33
-
34
- /**
35
- * Whether consent has been given for a specific option
36
- */
37
- hasConsent: (optionId: string) => boolean;
38
-
39
- /**
40
- * Update consent settings
41
- */
42
- updateConsent: (consents: Record<string, boolean>) => void;
43
-
44
- /**
45
- * Accept all consent options
46
- */
47
- acceptAll: () => void;
48
-
49
- /**
50
- * Reject all non-required consent options
51
- */
52
- rejectAll: () => void;
53
-
54
- /**
55
- * Whether the consent banner should be shown
56
- */
57
- shouldShowBanner: boolean;
58
-
59
- /**
60
- * Whether consent settings are valid
61
- */
62
- isValid: boolean;
63
-
64
- /**
65
- * Validation errors (if any)
66
- */
67
- validationErrors: string[];
68
-
69
- /**
70
- * Reset consent settings (clear from storage)
71
- */
72
- resetConsent: () => void;
73
- }
74
-
75
- /**
76
- * Hook for managing user consent in compliance with NDPR
77
- */
78
- export function useConsent({
79
- options,
80
- storageOptions = {},
81
- version = "1.0",
82
- onChange
83
- }: UseConsentOptions): UseConsentReturn {
84
- const {
85
- storageKey = "ndpr_consent",
86
- storageType = "localStorage"
87
- } = storageOptions;
88
-
89
- const [settings, setSettings] = useState<ConsentSettings | null>(null);
90
- const [shouldShowBanner, setShouldShowBanner] = useState<boolean>(true);
91
- const [isValid, setIsValid] = useState<boolean>(false);
92
- const [validationErrors, setValidationErrors] = useState<string[]>([]);
93
-
94
- // Load consent settings from storage on mount
95
- useEffect(() => {
96
- let savedSettings: ConsentSettings | null = null;
97
-
98
- try {
99
- if (storageType === 'localStorage' && typeof window !== 'undefined') {
100
- const savedData = localStorage.getItem(storageKey);
101
- if (savedData) {
102
- savedSettings = JSON.parse(savedData);
103
- }
104
- } else if (storageType === 'sessionStorage' && typeof window !== 'undefined') {
105
- const savedData = sessionStorage.getItem(storageKey);
106
- if (savedData) {
107
- savedSettings = JSON.parse(savedData);
108
- }
109
- } else if (storageType === 'cookie' && typeof document !== 'undefined') {
110
- const cookies = document.cookie.split(';');
111
- const consentCookie = cookies.find(cookie => cookie.trim().startsWith(`${storageKey}=`));
112
- if (consentCookie) {
113
- const cookieValue = consentCookie.split('=')[1];
114
- savedSettings = JSON.parse(decodeURIComponent(cookieValue));
115
- }
116
- }
117
- } catch (error) {
118
- console.error('Error loading consent settings:', error);
119
- }
120
-
121
- if (savedSettings) {
122
- setSettings(savedSettings);
123
-
124
- // Validate the saved settings
125
- const { valid, errors } = validateConsent(savedSettings);
126
- setIsValid(valid);
127
- setValidationErrors(errors);
128
-
129
- // Only hide banner if settings are valid and for the current version
130
- setShouldShowBanner(!(valid && savedSettings.version === version));
131
- } else {
132
- setShouldShowBanner(true);
133
- }
134
- }, [storageKey, storageType, version]);
135
-
136
- // Save settings to storage
137
- const saveSettings = (newSettings: ConsentSettings) => {
138
- try {
139
- const settingsString = JSON.stringify(newSettings);
140
-
141
- if (storageType === 'localStorage' && typeof window !== 'undefined') {
142
- localStorage.setItem(storageKey, settingsString);
143
- } else if (storageType === 'sessionStorage' && typeof window !== 'undefined') {
144
- sessionStorage.setItem(storageKey, settingsString);
145
- } else if (storageType === 'cookie' && typeof document !== 'undefined') {
146
- const { cookieOptions = {} } = storageOptions;
147
- const {
148
- domain,
149
- path = '/',
150
- expires = 365,
151
- secure = true,
152
- sameSite = 'Lax'
153
- } = cookieOptions;
154
-
155
- const expiryDate = new Date();
156
- expiryDate.setDate(expiryDate.getDate() + expires);
157
-
158
- let cookieString = `${storageKey}=${encodeURIComponent(settingsString)}; path=${path}; expires=${expiryDate.toUTCString()}`;
159
-
160
- if (domain) {
161
- cookieString += `; domain=${domain}`;
162
- }
163
-
164
- if (secure) {
165
- cookieString += '; secure';
166
- }
167
-
168
- cookieString += `; samesite=${sameSite}`;
169
-
170
- document.cookie = cookieString;
171
- }
172
-
173
- // Validate the new settings
174
- const { valid, errors } = validateConsent(newSettings);
175
- setIsValid(valid);
176
- setValidationErrors(errors);
177
-
178
- // Call onChange callback if provided
179
- if (onChange) {
180
- onChange(newSettings);
181
- }
182
- } catch (error) {
183
- console.error('Error saving consent settings:', error);
184
- }
185
- };
186
-
187
- // Update consent settings
188
- const updateConsent = (consents: Record<string, boolean>) => {
189
- const newSettings: ConsentSettings = {
190
- consents,
191
- timestamp: Date.now(),
192
- version,
193
- method: 'explicit',
194
- hasInteracted: true
195
- };
196
-
197
- setSettings(newSettings);
198
- saveSettings(newSettings);
199
- setShouldShowBanner(false);
200
- };
201
-
202
- // Accept all consent options
203
- const acceptAll = () => {
204
- const allConsents: Record<string, boolean> = {};
205
- options.forEach(option => {
206
- allConsents[option.id] = true;
207
- });
208
-
209
- updateConsent(allConsents);
210
- };
211
-
212
- // Reject all non-required consent options
213
- const rejectAll = () => {
214
- const rejectedConsents: Record<string, boolean> = {};
215
- options.forEach(option => {
216
- rejectedConsents[option.id] = option.required || false;
217
- });
218
-
219
- updateConsent(rejectedConsents);
220
- };
221
-
222
- // Check if consent has been given for a specific option
223
- const hasConsent = (optionId: string): boolean => {
224
- return !!settings?.consents[optionId];
225
- };
226
-
227
- // Reset consent settings
228
- const resetConsent = () => {
229
- if (storageType === 'localStorage' && typeof window !== 'undefined') {
230
- localStorage.removeItem(storageKey);
231
- } else if (storageType === 'sessionStorage' && typeof window !== 'undefined') {
232
- sessionStorage.removeItem(storageKey);
233
- } else if (storageType === 'cookie' && typeof document !== 'undefined') {
234
- const { cookieOptions = {} } = storageOptions;
235
- const { domain, path = '/' } = cookieOptions;
236
-
237
- let cookieString = `${storageKey}=; path=${path}; expires=Thu, 01 Jan 1970 00:00:00 GMT`;
238
-
239
- if (domain) {
240
- cookieString += `; domain=${domain}`;
241
- }
242
-
243
- document.cookie = cookieString;
244
- }
245
-
246
- setSettings(null);
247
- setShouldShowBanner(true);
248
- setIsValid(false);
249
- setValidationErrors([]);
250
- };
251
-
252
- return {
253
- settings,
254
- hasConsent,
255
- updateConsent,
256
- acceptAll,
257
- rejectAll,
258
- shouldShowBanner,
259
- isValid,
260
- validationErrors,
261
- resetConsent
262
- };
263
- }