@tantainnovative/ndpr-toolkit 1.0.3 → 1.0.4

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 (156) hide show
  1. package/next-env.d.ts +5 -0
  2. package/package.json +1 -1
  3. package/.claude/settings.local.json +0 -20
  4. package/.eslintrc.json +0 -10
  5. package/.github/workflows/ci.yml +0 -36
  6. package/.github/workflows/nextjs.yml +0 -104
  7. package/.husky/commit-msg +0 -4
  8. package/.husky/pre-commit +0 -4
  9. package/.lintstagedrc.js +0 -4
  10. package/.nvmrc +0 -1
  11. package/.versionrc +0 -17
  12. package/CLAUDE.md +0 -90
  13. package/commitlint.config.js +0 -36
  14. package/eslint.config.mjs +0 -16
  15. package/jest.config.js +0 -31
  16. package/jest.setup.js +0 -15
  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/jest.config.js +0 -23
  21. package/packages/ndpr-toolkit/package-lock.json +0 -8197
  22. package/packages/ndpr-toolkit/package.json +0 -71
  23. package/packages/ndpr-toolkit/rollup.config.js +0 -34
  24. package/packages/ndpr-toolkit/src/__tests__/components/consent/ConsentBanner.test.tsx +0 -119
  25. package/packages/ndpr-toolkit/src/__tests__/components/consent/ConsentManager.test.tsx +0 -122
  26. package/packages/ndpr-toolkit/src/__tests__/components/consent/ConsentStorage.test.tsx +0 -270
  27. package/packages/ndpr-toolkit/src/__tests__/components/dsr/DSRDashboard.test.tsx +0 -199
  28. package/packages/ndpr-toolkit/src/__tests__/components/dsr/DSRRequestForm.test.tsx +0 -224
  29. package/packages/ndpr-toolkit/src/__tests__/components/dsr/DSRTracker.test.tsx +0 -104
  30. package/packages/ndpr-toolkit/src/__tests__/hooks/useConsent.test.tsx +0 -161
  31. package/packages/ndpr-toolkit/src/__tests__/hooks/useDSR.test.tsx +0 -330
  32. package/packages/ndpr-toolkit/src/__tests__/utils/breach.test.ts +0 -149
  33. package/packages/ndpr-toolkit/src/__tests__/utils/consent.test.ts +0 -88
  34. package/packages/ndpr-toolkit/src/__tests__/utils/dpia.test.ts +0 -160
  35. package/packages/ndpr-toolkit/src/__tests__/utils/dsr.test.ts +0 -110
  36. package/packages/ndpr-toolkit/src/__tests__/utils/privacy.test.ts +0 -97
  37. package/packages/ndpr-toolkit/src/components/breach/BreachNotificationManager.tsx +0 -701
  38. package/packages/ndpr-toolkit/src/components/breach/BreachReportForm.tsx +0 -631
  39. package/packages/ndpr-toolkit/src/components/breach/BreachRiskAssessment.tsx +0 -569
  40. package/packages/ndpr-toolkit/src/components/breach/RegulatoryReportGenerator.tsx +0 -496
  41. package/packages/ndpr-toolkit/src/components/consent/ConsentBanner.tsx +0 -270
  42. package/packages/ndpr-toolkit/src/components/consent/ConsentManager.tsx +0 -217
  43. package/packages/ndpr-toolkit/src/components/consent/ConsentStorage.tsx +0 -206
  44. package/packages/ndpr-toolkit/src/components/dpia/DPIAQuestionnaire.tsx +0 -342
  45. package/packages/ndpr-toolkit/src/components/dpia/DPIAReport.tsx +0 -373
  46. package/packages/ndpr-toolkit/src/components/dpia/StepIndicator.tsx +0 -174
  47. package/packages/ndpr-toolkit/src/components/dsr/DSRDashboard.tsx +0 -717
  48. package/packages/ndpr-toolkit/src/components/dsr/DSRRequestForm.tsx +0 -476
  49. package/packages/ndpr-toolkit/src/components/dsr/DSRTracker.tsx +0 -620
  50. package/packages/ndpr-toolkit/src/components/policy/PolicyExporter.tsx +0 -541
  51. package/packages/ndpr-toolkit/src/components/policy/PolicyGenerator.tsx +0 -454
  52. package/packages/ndpr-toolkit/src/components/policy/PolicyPreview.tsx +0 -333
  53. package/packages/ndpr-toolkit/src/hooks/useBreach.ts +0 -409
  54. package/packages/ndpr-toolkit/src/hooks/useConsent.ts +0 -263
  55. package/packages/ndpr-toolkit/src/hooks/useDPIA.ts +0 -457
  56. package/packages/ndpr-toolkit/src/hooks/useDSR.ts +0 -236
  57. package/packages/ndpr-toolkit/src/hooks/usePrivacyPolicy.ts +0 -428
  58. package/packages/ndpr-toolkit/src/index.ts +0 -44
  59. package/packages/ndpr-toolkit/src/setupTests.ts +0 -5
  60. package/packages/ndpr-toolkit/src/types/breach.ts +0 -283
  61. package/packages/ndpr-toolkit/src/types/consent.ts +0 -111
  62. package/packages/ndpr-toolkit/src/types/dpia.ts +0 -236
  63. package/packages/ndpr-toolkit/src/types/dsr.ts +0 -192
  64. package/packages/ndpr-toolkit/src/types/index.ts +0 -42
  65. package/packages/ndpr-toolkit/src/types/privacy.ts +0 -246
  66. package/packages/ndpr-toolkit/src/utils/breach.ts +0 -122
  67. package/packages/ndpr-toolkit/src/utils/consent.ts +0 -51
  68. package/packages/ndpr-toolkit/src/utils/dpia.ts +0 -104
  69. package/packages/ndpr-toolkit/src/utils/dsr.ts +0 -77
  70. package/packages/ndpr-toolkit/src/utils/privacy.ts +0 -100
  71. package/packages/ndpr-toolkit/tsconfig.json +0 -23
  72. package/postcss.config.mjs +0 -5
  73. package/src/__tests__/example.test.ts +0 -13
  74. package/src/__tests__/requestService.test.ts +0 -57
  75. package/src/app/accessibility.css +0 -70
  76. package/src/app/docs/components/DocLayout.tsx +0 -267
  77. package/src/app/docs/components/breach-notification/page.tsx +0 -797
  78. package/src/app/docs/components/consent-management/page.tsx +0 -576
  79. package/src/app/docs/components/data-subject-rights/page.tsx +0 -511
  80. package/src/app/docs/components/dpia-questionnaire/layout.tsx +0 -15
  81. package/src/app/docs/components/dpia-questionnaire/metadata.ts +0 -31
  82. package/src/app/docs/components/dpia-questionnaire/page.tsx +0 -666
  83. package/src/app/docs/components/hooks/page.tsx +0 -305
  84. package/src/app/docs/components/page.tsx +0 -84
  85. package/src/app/docs/components/privacy-policy-generator/page.tsx +0 -634
  86. package/src/app/docs/guides/breach-notification-process/components/BestPractices.tsx +0 -123
  87. package/src/app/docs/guides/breach-notification-process/components/ImplementationSteps.tsx +0 -328
  88. package/src/app/docs/guides/breach-notification-process/components/Introduction.tsx +0 -28
  89. package/src/app/docs/guides/breach-notification-process/components/NotificationTimeline.tsx +0 -91
  90. package/src/app/docs/guides/breach-notification-process/components/Resources.tsx +0 -118
  91. package/src/app/docs/guides/breach-notification-process/page.tsx +0 -39
  92. package/src/app/docs/guides/conducting-dpia/page.tsx +0 -593
  93. package/src/app/docs/guides/data-subject-requests/page.tsx +0 -666
  94. package/src/app/docs/guides/managing-consent/page.tsx +0 -738
  95. package/src/app/docs/guides/ndpr-compliance-checklist/components/ComplianceChecklist.tsx +0 -296
  96. package/src/app/docs/guides/ndpr-compliance-checklist/components/ImplementationTools.tsx +0 -145
  97. package/src/app/docs/guides/ndpr-compliance-checklist/components/Introduction.tsx +0 -33
  98. package/src/app/docs/guides/ndpr-compliance-checklist/components/KeyRequirements.tsx +0 -99
  99. package/src/app/docs/guides/ndpr-compliance-checklist/components/Resources.tsx +0 -159
  100. package/src/app/docs/guides/ndpr-compliance-checklist/page.tsx +0 -38
  101. package/src/app/docs/guides/page.tsx +0 -67
  102. package/src/app/docs/layout.tsx +0 -15
  103. package/src/app/docs/metadata.ts +0 -31
  104. package/src/app/docs/page.tsx +0 -572
  105. package/src/app/favicon.ico +0 -0
  106. package/src/app/globals.css +0 -123
  107. package/src/app/layout.tsx +0 -37
  108. package/src/app/ndpr-demos/breach/page.tsx +0 -354
  109. package/src/app/ndpr-demos/consent/page.tsx +0 -366
  110. package/src/app/ndpr-demos/dpia/page.tsx +0 -495
  111. package/src/app/ndpr-demos/dsr/page.tsx +0 -280
  112. package/src/app/ndpr-demos/page.tsx +0 -73
  113. package/src/app/ndpr-demos/policy/page.tsx +0 -771
  114. package/src/app/page.tsx +0 -452
  115. package/src/components/ErrorBoundary.tsx +0 -90
  116. package/src/components/breach-notification/BreachNotificationForm.tsx +0 -479
  117. package/src/components/consent/ConsentBanner.tsx +0 -159
  118. package/src/components/data-subject-rights/DataSubjectRequestForm.tsx +0 -419
  119. package/src/components/docs/DocLayout.tsx +0 -289
  120. package/src/components/docs/index.ts +0 -2
  121. package/src/components/dpia/DPIAQuestionnaire.tsx +0 -483
  122. package/src/components/privacy-policy/PolicyGenerator.tsx +0 -1062
  123. package/src/components/privacy-policy/data.ts +0 -98
  124. package/src/components/privacy-policy/shared/CheckboxField.tsx +0 -38
  125. package/src/components/privacy-policy/shared/CheckboxGroup.tsx +0 -85
  126. package/src/components/privacy-policy/shared/FormField.tsx +0 -79
  127. package/src/components/privacy-policy/shared/StepIndicator.tsx +0 -86
  128. package/src/components/privacy-policy/steps/CustomSectionsStep.tsx +0 -335
  129. package/src/components/privacy-policy/steps/DataCollectionStep.tsx +0 -231
  130. package/src/components/privacy-policy/steps/DataSharingStep.tsx +0 -418
  131. package/src/components/privacy-policy/steps/OrganizationInfoStep.tsx +0 -202
  132. package/src/components/privacy-policy/steps/PolicyPreviewStep.tsx +0 -172
  133. package/src/components/ui/Badge.tsx +0 -46
  134. package/src/components/ui/Button.tsx +0 -59
  135. package/src/components/ui/Card.tsx +0 -92
  136. package/src/components/ui/Checkbox.tsx +0 -57
  137. package/src/components/ui/FormField.tsx +0 -50
  138. package/src/components/ui/Input.tsx +0 -38
  139. package/src/components/ui/Loading.tsx +0 -201
  140. package/src/components/ui/Select.tsx +0 -42
  141. package/src/components/ui/TextArea.tsx +0 -38
  142. package/src/components/ui/label.tsx +0 -24
  143. package/src/components/ui/switch.tsx +0 -31
  144. package/src/components/ui/tabs.tsx +0 -66
  145. package/src/hooks/useConsent.ts +0 -64
  146. package/src/hooks/useLoadingState.ts +0 -85
  147. package/src/lib/consentService.ts +0 -137
  148. package/src/lib/dpiaQuestions.ts +0 -148
  149. package/src/lib/requestService.ts +0 -75
  150. package/src/lib/sanitize.ts +0 -108
  151. package/src/lib/storage.ts +0 -222
  152. package/src/lib/utils.ts +0 -6
  153. package/src/types/html-to-docx.d.ts +0 -30
  154. package/src/types/index.ts +0 -72
  155. package/tailwind.config.ts +0 -65
  156. package/tsconfig.json +0 -41
@@ -1,270 +0,0 @@
1
- import React, { useState, useEffect } from 'react';
2
- import { ConsentOption, ConsentSettings } from '../../types/consent';
3
-
4
- export interface ConsentBannerProps {
5
- /**
6
- * Array of consent options to display
7
- */
8
- options: ConsentOption[];
9
-
10
- /**
11
- * Callback function called when user saves their consent choices
12
- */
13
- onSave: (settings: ConsentSettings) => void;
14
-
15
- /**
16
- * Title displayed on the banner
17
- * @default "We Value Your Privacy"
18
- */
19
- title?: string;
20
-
21
- /**
22
- * Description text displayed on the banner
23
- * @default "We use cookies and similar technologies to provide our services and enhance your experience."
24
- */
25
- description?: string;
26
-
27
- /**
28
- * Text for the accept all button
29
- * @default "Accept All"
30
- */
31
- acceptAllButtonText?: string;
32
-
33
- /**
34
- * Text for the reject all button
35
- * @default "Reject All"
36
- */
37
- rejectAllButtonText?: string;
38
-
39
- /**
40
- * Text for the customize button
41
- * @default "Customize"
42
- */
43
- customizeButtonText?: string;
44
-
45
- /**
46
- * Text for the save button
47
- * @default "Save Preferences"
48
- */
49
- saveButtonText?: string;
50
-
51
- /**
52
- * Position of the banner
53
- * @default "bottom"
54
- */
55
- position?: 'top' | 'bottom' | 'center';
56
-
57
- /**
58
- * Version of the consent form
59
- * @default "1.0"
60
- */
61
- version?: string;
62
-
63
- /**
64
- * Whether to show the banner
65
- * If not provided, the banner will be shown if no consent has been saved
66
- */
67
- show?: boolean;
68
-
69
- /**
70
- * Storage key for consent settings
71
- * @default "ndpr_consent"
72
- */
73
- storageKey?: string;
74
-
75
- /**
76
- * Custom CSS class for the banner
77
- */
78
- className?: string;
79
-
80
- /**
81
- * Custom CSS class for the buttons
82
- */
83
- buttonClassName?: string;
84
-
85
- /**
86
- * Custom CSS class for the primary button
87
- */
88
- primaryButtonClassName?: string;
89
-
90
- /**
91
- * Custom CSS class for the secondary button
92
- */
93
- secondaryButtonClassName?: string;
94
- }
95
-
96
- export const ConsentBanner: React.FC<ConsentBannerProps> = ({
97
- options,
98
- onSave,
99
- title = "We Value Your Privacy",
100
- description = "We use cookies and similar technologies to provide our services and enhance your experience.",
101
- acceptAllButtonText = "Accept All",
102
- rejectAllButtonText = "Reject All",
103
- customizeButtonText = "Customize",
104
- saveButtonText = "Save Preferences",
105
- position = "bottom",
106
- version = "1.0",
107
- show,
108
- storageKey = "ndpr_consent",
109
- className = "",
110
- buttonClassName = "",
111
- primaryButtonClassName = "",
112
- secondaryButtonClassName = ""
113
- }) => {
114
- const [isOpen, setIsOpen] = useState<boolean>(false);
115
- const [showCustomize, setShowCustomize] = useState<boolean>(false);
116
- const [consents, setConsents] = useState<Record<string, boolean>>({});
117
-
118
- // Initialize consents from options
119
- useEffect(() => {
120
- const initialConsents: Record<string, boolean> = {};
121
- options.forEach(option => {
122
- initialConsents[option.id] = option.defaultValue || false;
123
- });
124
- setConsents(initialConsents);
125
-
126
- // Check if consent is already saved
127
- if (show === undefined) {
128
- const savedConsent = localStorage.getItem(storageKey);
129
- setIsOpen(!savedConsent);
130
- } else {
131
- setIsOpen(show);
132
- }
133
- }, [options, show, storageKey]);
134
-
135
- const handleAcceptAll = () => {
136
- const allConsents: Record<string, boolean> = {};
137
- options.forEach(option => {
138
- allConsents[option.id] = true;
139
- });
140
- saveConsent(allConsents);
141
- };
142
-
143
- const handleRejectAll = () => {
144
- const rejectedConsents: Record<string, boolean> = {};
145
- options.forEach(option => {
146
- rejectedConsents[option.id] = option.required || false;
147
- });
148
- saveConsent(rejectedConsents);
149
- };
150
-
151
- const handleToggleConsent = (id: string, value: boolean) => {
152
- setConsents(prev => ({
153
- ...prev,
154
- [id]: value
155
- }));
156
- };
157
-
158
- const handleSavePreferences = () => {
159
- saveConsent(consents);
160
- };
161
-
162
- const saveConsent = (consentValues: Record<string, boolean>) => {
163
- const settings: ConsentSettings = {
164
- consents: consentValues,
165
- timestamp: Date.now(),
166
- version,
167
- method: showCustomize ? 'customize' : 'banner',
168
- hasInteracted: true
169
- };
170
-
171
- // Save to localStorage
172
- localStorage.setItem(storageKey, JSON.stringify(settings));
173
-
174
- // Call onSave callback
175
- onSave(settings);
176
-
177
- // Close the banner
178
- setIsOpen(false);
179
- setShowCustomize(false);
180
- };
181
-
182
- if (!isOpen) {
183
- return null;
184
- }
185
-
186
- const positionClass =
187
- position === 'top' ? 'top-0 left-0 right-0' :
188
- position === 'center' ? 'top-1/2 left-1/2 transform -translate-x-1/2 -translate-y-1/2 max-w-lg' :
189
- 'bottom-0 left-0 right-0';
190
-
191
- return (
192
- <div
193
- className={`fixed z-50 bg-white dark:bg-gray-800 shadow-lg p-4 border border-gray-200 dark:border-gray-700 ${positionClass} ${className}`}
194
- role="dialog"
195
- aria-labelledby="consent-banner-title"
196
- >
197
- <div className="max-w-6xl mx-auto">
198
- <h2 id="consent-banner-title" className="text-lg font-bold mb-2">{title}</h2>
199
- <p className="mb-4">{description}</p>
200
-
201
- {showCustomize ? (
202
- <div className="mb-4">
203
- <div className="space-y-3">
204
- {options.map(option => (
205
- <div key={option.id} className="flex items-start">
206
- <div className="flex items-center h-5">
207
- <input
208
- id={`consent-${option.id}`}
209
- type="checkbox"
210
- checked={consents[option.id] || false}
211
- onChange={e => handleToggleConsent(option.id, e.target.checked)}
212
- disabled={option.required}
213
- className="h-4 w-4 rounded border-gray-300 text-blue-600 focus:ring-blue-500"
214
- />
215
- </div>
216
- <div className="ml-3 text-sm">
217
- <label htmlFor={`consent-${option.id}`} className="font-medium">
218
- {option.label} {option.required && <span className="text-red-500">*</span>}
219
- </label>
220
- <p className="text-gray-500 dark:text-gray-400">{option.description}</p>
221
- </div>
222
- </div>
223
- ))}
224
- </div>
225
-
226
- <div className="mt-4 flex flex-wrap gap-2">
227
- <button
228
- onClick={handleSavePreferences}
229
- className={`px-4 py-2 bg-blue-600 text-white rounded hover:bg-blue-700 ${buttonClassName} ${primaryButtonClassName}`}
230
- >
231
- {saveButtonText}
232
- </button>
233
- <button
234
- onClick={() => setShowCustomize(false)}
235
- className={`px-4 py-2 bg-gray-200 text-gray-800 dark:bg-gray-700 dark:text-white rounded hover:bg-gray-300 dark:hover:bg-gray-600 ${buttonClassName} ${secondaryButtonClassName}`}
236
- >
237
- Back
238
- </button>
239
- </div>
240
- </div>
241
- ) : (
242
- <div className="flex flex-wrap gap-2">
243
- <button
244
- onClick={handleAcceptAll}
245
- className={`px-4 py-2 bg-blue-600 text-white rounded hover:bg-blue-700 ${buttonClassName} ${primaryButtonClassName}`}
246
- >
247
- {acceptAllButtonText}
248
- </button>
249
- <button
250
- onClick={handleRejectAll}
251
- className={`px-4 py-2 bg-gray-200 text-gray-800 dark:bg-gray-700 dark:text-white rounded hover:bg-gray-300 dark:hover:bg-gray-600 ${buttonClassName} ${secondaryButtonClassName}`}
252
- >
253
- {rejectAllButtonText}
254
- </button>
255
- <button
256
- onClick={() => setShowCustomize(true)}
257
- className={`px-4 py-2 bg-transparent text-gray-800 dark:text-white hover:underline ${buttonClassName}`}
258
- >
259
- {customizeButtonText}
260
- </button>
261
- </div>
262
- )}
263
-
264
- <div className="mt-2 text-xs text-gray-500 dark:text-gray-400">
265
- By clicking "Accept All", you agree to the use of ALL cookies. Visit our Cookie Policy to learn more.
266
- </div>
267
- </div>
268
- </div>
269
- );
270
- };
@@ -1,217 +0,0 @@
1
- import React, { useState, useEffect } from 'react';
2
- import { ConsentOption, ConsentSettings } from '../../types/consent';
3
-
4
- export interface ConsentManagerProps {
5
- /**
6
- * Array of consent options to display
7
- */
8
- options: ConsentOption[];
9
-
10
- /**
11
- * Current consent settings
12
- */
13
- settings?: ConsentSettings;
14
-
15
- /**
16
- * Callback function called when user saves their consent choices
17
- */
18
- onSave: (settings: ConsentSettings) => void;
19
-
20
- /**
21
- * Title displayed in the manager
22
- * @default "Manage Your Privacy Settings"
23
- */
24
- title?: string;
25
-
26
- /**
27
- * Description text displayed in the manager
28
- * @default "Update your consent preferences at any time. Required cookies cannot be disabled as they are necessary for the website to function."
29
- */
30
- description?: string;
31
-
32
- /**
33
- * Text for the save button
34
- * @default "Save Preferences"
35
- */
36
- saveButtonText?: string;
37
-
38
- /**
39
- * Text for the reset button
40
- * @default "Reset to Defaults"
41
- */
42
- resetButtonText?: string;
43
-
44
- /**
45
- * Version of the consent form
46
- * @default "1.0"
47
- */
48
- version?: string;
49
-
50
- /**
51
- * Custom CSS class for the manager
52
- */
53
- className?: string;
54
-
55
- /**
56
- * Custom CSS class for the buttons
57
- */
58
- buttonClassName?: string;
59
-
60
- /**
61
- * Custom CSS class for the primary button
62
- */
63
- primaryButtonClassName?: string;
64
-
65
- /**
66
- * Custom CSS class for the secondary button
67
- */
68
- secondaryButtonClassName?: string;
69
-
70
- /**
71
- * Whether to show a success message after saving
72
- * @default true
73
- */
74
- showSuccessMessage?: boolean;
75
-
76
- /**
77
- * Success message to display after saving
78
- * @default "Your preferences have been saved."
79
- */
80
- successMessage?: string;
81
-
82
- /**
83
- * Duration to show the success message (in milliseconds)
84
- * @default 3000
85
- */
86
- successMessageDuration?: number;
87
- }
88
-
89
- export const ConsentManager: React.FC<ConsentManagerProps> = ({
90
- options,
91
- settings,
92
- onSave,
93
- title = "Manage Your Privacy Settings",
94
- description = "Update your consent preferences at any time. Required cookies cannot be disabled as they are necessary for the website to function.",
95
- saveButtonText = "Save Preferences",
96
- resetButtonText = "Reset to Defaults",
97
- version = "1.0",
98
- className = "",
99
- buttonClassName = "",
100
- primaryButtonClassName = "",
101
- secondaryButtonClassName = "",
102
- showSuccessMessage = true,
103
- successMessage = "Your preferences have been saved.",
104
- successMessageDuration = 3000
105
- }) => {
106
- const [consents, setConsents] = useState<Record<string, boolean>>({});
107
- const [showSuccess, setShowSuccess] = useState<boolean>(false);
108
-
109
- // Initialize consents from settings or options
110
- useEffect(() => {
111
- if (settings && settings.consents) {
112
- setConsents(settings.consents);
113
- } else {
114
- const initialConsents: Record<string, boolean> = {};
115
- options.forEach(option => {
116
- initialConsents[option.id] = option.defaultValue || false;
117
- });
118
- setConsents(initialConsents);
119
- }
120
- }, [options, settings]);
121
-
122
- const handleToggleConsent = (id: string, value: boolean) => {
123
- setConsents(prev => ({
124
- ...prev,
125
- [id]: value
126
- }));
127
- };
128
-
129
- const handleSave = () => {
130
- const newSettings: ConsentSettings = {
131
- consents,
132
- timestamp: Date.now(),
133
- version,
134
- method: 'manager',
135
- hasInteracted: true
136
- };
137
-
138
- onSave(newSettings);
139
-
140
- if (showSuccessMessage) {
141
- setShowSuccess(true);
142
- setTimeout(() => {
143
- setShowSuccess(false);
144
- }, successMessageDuration);
145
- }
146
- };
147
-
148
- const handleReset = () => {
149
- const defaultConsents: Record<string, boolean> = {};
150
- options.forEach(option => {
151
- defaultConsents[option.id] = option.defaultValue || false;
152
- });
153
- setConsents(defaultConsents);
154
- };
155
-
156
- return (
157
- <div className={`bg-white dark:bg-gray-800 rounded-lg shadow-md p-6 ${className}`}>
158
- <h2 className="text-xl font-bold mb-2">{title}</h2>
159
- <p className="mb-6 text-gray-600 dark:text-gray-300">{description}</p>
160
-
161
- <div className="space-y-6">
162
- {options.map(option => (
163
- <div key={option.id} className="border-b border-gray-200 dark:border-gray-700 pb-4 last:border-0">
164
- <div className="flex items-start justify-between">
165
- <div>
166
- <h3 className="font-medium text-gray-900 dark:text-white">{option.label}</h3>
167
- <p className="text-sm text-gray-500 dark:text-gray-400 mt-1">{option.description}</p>
168
- </div>
169
- <div className="ml-4 flex-shrink-0">
170
- <label className="relative inline-flex items-center cursor-pointer">
171
- <input
172
- type="checkbox"
173
- className="sr-only peer"
174
- checked={consents[option.id] || false}
175
- onChange={e => handleToggleConsent(option.id, e.target.checked)}
176
- disabled={option.required}
177
- />
178
- <div className={`w-11 h-6 bg-gray-200 peer-focus:outline-none peer-focus:ring-4 peer-focus:ring-blue-300 dark:peer-focus:ring-blue-800 rounded-full peer dark:bg-gray-700 peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-5 after:w-5 after:transition-all dark:border-gray-600 peer-checked:bg-blue-600 ${option.required ? 'opacity-60' : ''}`}></div>
179
- <span className="ml-3 text-sm font-medium text-gray-900 dark:text-gray-300">
180
- {consents[option.id] ? 'Enabled' : 'Disabled'}
181
- {option.required && <span className="text-xs text-red-500 ml-1">(Required)</span>}
182
- </span>
183
- </label>
184
- </div>
185
- </div>
186
- </div>
187
- ))}
188
- </div>
189
-
190
- {showSuccess && (
191
- <div className="mt-4 p-3 bg-green-50 dark:bg-green-900/20 text-green-800 dark:text-green-200 rounded-md">
192
- {successMessage}
193
- </div>
194
- )}
195
-
196
- <div className="mt-6 flex flex-wrap gap-3">
197
- <button
198
- onClick={handleSave}
199
- className={`px-4 py-2 bg-blue-600 text-white rounded hover:bg-blue-700 ${buttonClassName} ${primaryButtonClassName}`}
200
- >
201
- {saveButtonText}
202
- </button>
203
- <button
204
- onClick={handleReset}
205
- className={`px-4 py-2 bg-gray-200 text-gray-800 dark:bg-gray-700 dark:text-white rounded hover:bg-gray-300 dark:hover:bg-gray-600 ${buttonClassName} ${secondaryButtonClassName}`}
206
- >
207
- {resetButtonText}
208
- </button>
209
- </div>
210
-
211
- <div className="mt-4 text-xs text-gray-500 dark:text-gray-400">
212
- <p>Last updated: {settings ? new Date(settings.timestamp).toLocaleString() : 'Never'}</p>
213
- <p>Version: {version}</p>
214
- </div>
215
- </div>
216
- );
217
- };
@@ -1,206 +0,0 @@
1
- import React, { useState, useEffect } from 'react';
2
- import { ConsentSettings, ConsentStorageOptions } from '../../types/consent';
3
-
4
- export interface ConsentStorageProps {
5
- /**
6
- * Current consent settings
7
- */
8
- settings: ConsentSettings;
9
-
10
- /**
11
- * Storage options for consent settings
12
- */
13
- storageOptions?: ConsentStorageOptions;
14
-
15
- /**
16
- * Callback function called when settings are loaded from storage
17
- */
18
- onLoad?: (settings: ConsentSettings | null) => void;
19
-
20
- /**
21
- * Callback function called when settings are saved to storage
22
- */
23
- onSave?: (settings: ConsentSettings) => void;
24
-
25
- /**
26
- * Whether to automatically save settings to storage
27
- * @default true
28
- */
29
- autoSave?: boolean;
30
-
31
- /**
32
- * Whether to automatically load settings from storage on mount
33
- * @default true
34
- */
35
- autoLoad?: boolean;
36
-
37
- /**
38
- * Children to render
39
- * Can be either React nodes or a render prop function that receives storage methods
40
- */
41
- children?: React.ReactNode | ((props: {
42
- loadSettings: () => ConsentSettings | null;
43
- saveSettings: (settings: ConsentSettings) => void;
44
- clearSettings: () => void;
45
- loaded: boolean;
46
- }) => React.ReactNode);
47
- }
48
-
49
- export const ConsentStorage = ({
50
- settings,
51
- storageOptions = {},
52
- onLoad,
53
- onSave,
54
- autoSave = true,
55
- autoLoad = true,
56
- children
57
- }: ConsentStorageProps): React.ReactElement | null => {
58
- const {
59
- storageKey = "ndpr_consent",
60
- storageType = "localStorage",
61
- cookieOptions = {}
62
- } = storageOptions;
63
-
64
- const [loaded, setLoaded] = useState<boolean>(false);
65
-
66
- // Load consent settings from storage on mount
67
- useEffect(() => {
68
- if (autoLoad && !loaded) {
69
- loadSettings();
70
- }
71
- }, [autoLoad, loaded]);
72
-
73
- // Save consent settings to storage when they change
74
- useEffect(() => {
75
- if (autoSave && loaded) {
76
- saveSettings(settings);
77
- }
78
- }, [settings, autoSave, loaded]);
79
-
80
- // Load settings from storage
81
- const loadSettings = (): ConsentSettings | null => {
82
- let loadedSettings: ConsentSettings | null = null;
83
-
84
- try {
85
- if (storageType === 'localStorage' && typeof window !== 'undefined') {
86
- const savedData = localStorage.getItem(storageKey);
87
- if (savedData) {
88
- loadedSettings = JSON.parse(savedData);
89
- }
90
- } else if (storageType === 'sessionStorage' && typeof window !== 'undefined') {
91
- const savedData = sessionStorage.getItem(storageKey);
92
- if (savedData) {
93
- loadedSettings = JSON.parse(savedData);
94
- }
95
- } else if (storageType === 'cookie' && typeof document !== 'undefined') {
96
- const cookies = document.cookie.split(';');
97
- const consentCookie = cookies.find(cookie => cookie.trim().startsWith(`${storageKey}=`));
98
- if (consentCookie) {
99
- const cookieValue = consentCookie.split('=')[1];
100
- loadedSettings = JSON.parse(decodeURIComponent(cookieValue));
101
- }
102
- }
103
-
104
- setLoaded(true);
105
-
106
- if (onLoad) {
107
- onLoad(loadedSettings);
108
- }
109
- } catch (error) {
110
- console.error('Error loading consent settings:', error);
111
- setLoaded(true);
112
-
113
- if (onLoad) {
114
- onLoad(null);
115
- }
116
- }
117
-
118
- return loadedSettings;
119
- };
120
-
121
- // Save settings to storage
122
- const saveSettings = (settingsToSave: ConsentSettings): boolean => {
123
- try {
124
- const settingsString = JSON.stringify(settingsToSave);
125
-
126
- if (storageType === 'localStorage' && typeof window !== 'undefined') {
127
- localStorage.setItem(storageKey, settingsString);
128
- } else if (storageType === 'sessionStorage' && typeof window !== 'undefined') {
129
- sessionStorage.setItem(storageKey, settingsString);
130
- } else if (storageType === 'cookie' && typeof document !== 'undefined') {
131
- const {
132
- domain,
133
- path = '/',
134
- expires = 365,
135
- secure = true,
136
- sameSite = 'Lax'
137
- } = cookieOptions;
138
-
139
- const expiryDate = new Date();
140
- expiryDate.setDate(expiryDate.getDate() + expires);
141
-
142
- let cookieString = `${storageKey}=${encodeURIComponent(settingsString)}; path=${path}; expires=${expiryDate.toUTCString()}`;
143
-
144
- if (domain) {
145
- cookieString += `; domain=${domain}`;
146
- }
147
-
148
- if (secure) {
149
- cookieString += '; secure';
150
- }
151
-
152
- cookieString += `; samesite=${sameSite}`;
153
-
154
- document.cookie = cookieString;
155
- }
156
-
157
- if (onSave) {
158
- onSave(settingsToSave);
159
- }
160
-
161
- return true;
162
- } catch (error) {
163
- console.error('Error saving consent settings:', error);
164
- return false;
165
- }
166
- };
167
-
168
- // Clear settings from storage
169
- const clearSettings = (): boolean => {
170
- try {
171
- if (storageType === 'localStorage' && typeof window !== 'undefined') {
172
- localStorage.removeItem(storageKey);
173
- } else if (storageType === 'sessionStorage' && typeof window !== 'undefined') {
174
- sessionStorage.removeItem(storageKey);
175
- } else if (storageType === 'cookie' && typeof document !== 'undefined') {
176
- const { domain, path = '/' } = cookieOptions;
177
-
178
- let cookieString = `${storageKey}=; path=${path}; expires=Thu, 01 Jan 1970 00:00:00 GMT`;
179
-
180
- if (domain) {
181
- cookieString += `; domain=${domain}`;
182
- }
183
-
184
- document.cookie = cookieString;
185
- }
186
-
187
- return true;
188
- } catch (error) {
189
- console.error('Error clearing consent settings:', error);
190
- return false;
191
- }
192
- };
193
-
194
- // If children is a function, call it with the storage methods
195
- if (typeof children === 'function') {
196
- return <>{children({
197
- loadSettings,
198
- saveSettings,
199
- clearSettings,
200
- loaded
201
- })}</>;
202
- }
203
-
204
- // Otherwise, just render the children
205
- return <>{children}</>;
206
- };