@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,476 +0,0 @@
1
- import React, { useState } from 'react';
2
- import { RequestType } from '../../types/dsr';
3
-
4
- export interface DSRRequestFormProps {
5
- /**
6
- * Array of request types that can be submitted
7
- */
8
- requestTypes: RequestType[];
9
-
10
- /**
11
- * Callback function called when form is submitted
12
- */
13
- onSubmit: (formData: any) => void;
14
-
15
- /**
16
- * Title displayed on the form
17
- * @default "Submit a Data Subject Request"
18
- */
19
- title?: string;
20
-
21
- /**
22
- * Description text displayed on the form
23
- * @default "Use this form to exercise your rights under the Nigeria Data Protection Regulation (NDPR)."
24
- */
25
- description?: string;
26
-
27
- /**
28
- * Text for the submit button
29
- * @default "Submit Request"
30
- */
31
- submitButtonText?: string;
32
-
33
- /**
34
- * Custom CSS class for the form
35
- */
36
- className?: string;
37
-
38
- /**
39
- * Custom CSS class for the submit button
40
- */
41
- buttonClassName?: string;
42
-
43
- /**
44
- * Whether to show a confirmation message after submission
45
- * @default true
46
- */
47
- showConfirmation?: boolean;
48
-
49
- /**
50
- * Confirmation message to display after submission
51
- * @default "Your request has been submitted successfully. You will receive a confirmation email shortly."
52
- */
53
- confirmationMessage?: string;
54
-
55
- /**
56
- * Whether to require identity verification
57
- * @default true
58
- */
59
- requireIdentityVerification?: boolean;
60
-
61
- /**
62
- * Types of identifiers accepted for verification
63
- * @default ["email", "account", "customer_id"]
64
- */
65
- identifierTypes?: Array<{
66
- id: string;
67
- label: string;
68
- }>;
69
-
70
- /**
71
- * Whether to collect additional contact information
72
- * @default true
73
- */
74
- collectAdditionalContact?: boolean;
75
-
76
- /**
77
- * Custom labels for form fields
78
- */
79
- labels?: {
80
- name?: string;
81
- email?: string;
82
- requestType?: string;
83
- description?: string;
84
- submit?: string;
85
- };
86
- }
87
-
88
- export const DSRRequestForm: React.FC<DSRRequestFormProps> = ({
89
- requestTypes,
90
- onSubmit,
91
- title = "Submit a Data Subject Request",
92
- description = "Use this form to exercise your rights under the Nigeria Data Protection Regulation (NDPR).",
93
- submitButtonText = "Submit Request",
94
- className = "",
95
- buttonClassName = "",
96
- showConfirmation = true,
97
- confirmationMessage = "Your request has been submitted successfully. You will receive a confirmation email shortly.",
98
- requireIdentityVerification = true,
99
- identifierTypes = [
100
- { id: "email", label: "Email Address" },
101
- { id: "account", label: "Account Number" },
102
- { id: "customer_id", label: "Customer ID" }
103
- ],
104
- collectAdditionalContact = true,
105
- labels = {}
106
- }) => {
107
- const [selectedRequestType, setSelectedRequestType] = useState<string>("");
108
- const [fullName, setFullName] = useState<string>("");
109
- const [email, setEmail] = useState<string>("");
110
- const [phone, setPhone] = useState<string>("");
111
- const [identifierType, setIdentifierType] = useState<string>(identifierTypes[0]?.id || "");
112
- const [identifierValue, setIdentifierValue] = useState<string>("");
113
- const [additionalInfo, setAdditionalInfo] = useState<Record<string, any>>({});
114
- const [isSubmitted, setIsSubmitted] = useState<boolean>(false);
115
- const [errors, setErrors] = useState<Record<string, string>>({});
116
-
117
- const selectedType = requestTypes.find(type => type.id === selectedRequestType);
118
-
119
- const handleRequestTypeChange = (e: React.ChangeEvent<HTMLSelectElement>) => {
120
- setSelectedRequestType(e.target.value);
121
- setAdditionalInfo({});
122
- };
123
-
124
- const handleAdditionalInfoChange = (id: string, value: any) => {
125
- setAdditionalInfo(prev => ({
126
- ...prev,
127
- [id]: value
128
- }));
129
- };
130
-
131
- const validateForm = () => {
132
- const newErrors: Record<string, string> = {};
133
-
134
- if (!fullName.trim()) {
135
- newErrors.fullName = "Full name is required";
136
- }
137
-
138
- if (!email.trim()) {
139
- newErrors.email = "Email is required";
140
- } else if (!/\S+@\S+\.\S+/.test(email)) {
141
- newErrors.email = "Email is invalid";
142
- }
143
-
144
- if (!selectedRequestType) {
145
- newErrors.requestType = "Please select a request type";
146
- }
147
-
148
- if (requireIdentityVerification && !identifierValue.trim()) {
149
- newErrors.identifierValue = "Identifier value is required";
150
- }
151
-
152
- // Validate additional fields if required
153
- if (selectedType?.requiresAdditionalInfo && selectedType.additionalFields) {
154
- selectedType.additionalFields.forEach(field => {
155
- if (field.required && !additionalInfo[field.id]) {
156
- newErrors[`additional_${field.id}`] = `${field.label} is required`;
157
- }
158
- });
159
- }
160
-
161
- setErrors(newErrors);
162
- return Object.keys(newErrors).length === 0;
163
- };
164
-
165
- const handleSubmit = (e: React.FormEvent) => {
166
- e.preventDefault();
167
-
168
- if (!validateForm()) {
169
- return;
170
- }
171
-
172
- const formData = {
173
- requestType: selectedRequestType,
174
- dataSubject: {
175
- fullName,
176
- email,
177
- phone: phone || undefined,
178
- identifierType,
179
- identifierValue
180
- },
181
- additionalInfo: Object.keys(additionalInfo).length > 0 ? additionalInfo : undefined,
182
- submittedAt: Date.now()
183
- };
184
-
185
- onSubmit(formData);
186
-
187
- if (showConfirmation) {
188
- setIsSubmitted(true);
189
- }
190
- };
191
-
192
- if (isSubmitted) {
193
- return (
194
- <div className={`p-4 bg-green-50 dark:bg-green-900/20 rounded-md ${className}`}>
195
- <h2 className="text-lg font-bold text-green-800 dark:text-green-200 mb-2">Request Submitted</h2>
196
- <p className="text-green-700 dark:text-green-300">{confirmationMessage}</p>
197
- <button
198
- onClick={() => setIsSubmitted(false)}
199
- className={`mt-4 px-4 py-2 bg-green-600 text-white rounded hover:bg-green-700 ${buttonClassName}`}
200
- >
201
- Submit Another Request
202
- </button>
203
- </div>
204
- );
205
- }
206
-
207
- return (
208
- <div className={`bg-white dark:bg-gray-800 p-6 rounded-lg shadow-md ${className}`}>
209
- <h2 className="text-xl font-bold mb-2">{title}</h2>
210
- <p className="mb-6 text-gray-600 dark:text-gray-300">{description}</p>
211
-
212
- <form onSubmit={handleSubmit}>
213
- <div className="space-y-4">
214
- {/* Personal Information */}
215
- <div>
216
- <h3 className="text-lg font-semibold mb-3">Personal Information</h3>
217
- <div className="grid grid-cols-1 gap-4 md:grid-cols-2">
218
- <div>
219
- <label htmlFor="fullName" className="block text-sm font-medium mb-1">
220
- {labels.name || "Full Name"} <span className="text-red-500">*</span>
221
- </label>
222
- <input
223
- type="text"
224
- id="fullName"
225
- value={fullName}
226
- onChange={e => setFullName(e.target.value)}
227
- className="w-full px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500"
228
- required
229
- />
230
- {errors.fullName && <p className="mt-1 text-sm text-red-500">{errors.fullName}</p>}
231
- </div>
232
-
233
- <div>
234
- <label htmlFor="email" className="block text-sm font-medium mb-1">
235
- {labels.email || "Email Address"} <span className="text-red-500">*</span>
236
- </label>
237
- <input
238
- type="email"
239
- id="email"
240
- value={email}
241
- onChange={e => setEmail(e.target.value)}
242
- className="w-full px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500"
243
- required
244
- />
245
- {errors.email && <p className="mt-1 text-sm text-red-500">{errors.email}</p>}
246
- </div>
247
-
248
- {collectAdditionalContact && (
249
- <div>
250
- <label htmlFor="phone" className="block text-sm font-medium mb-1">
251
- Phone Number (Optional)
252
- </label>
253
- <input
254
- type="tel"
255
- id="phone"
256
- value={phone}
257
- onChange={e => setPhone(e.target.value)}
258
- className="w-full px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500"
259
- />
260
- </div>
261
- )}
262
- </div>
263
- </div>
264
-
265
- {/* Request Type */}
266
- <div>
267
- <h3 className="text-lg font-semibold mb-3">Request Details</h3>
268
- <div className="mb-4">
269
- <label htmlFor="requestType" className="block text-sm font-medium mb-1">
270
- {labels.requestType || "Request Type"} <span className="text-red-500">*</span>
271
- </label>
272
- <select
273
- id="requestType"
274
- value={selectedRequestType}
275
- onChange={handleRequestTypeChange}
276
- className="w-full px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500"
277
- required
278
- >
279
- <option value="">Select a request type</option>
280
- {requestTypes.map(type => (
281
- <option key={type.id} value={type.id}>
282
- {type.name}
283
- </option>
284
- ))}
285
- </select>
286
- {errors.requestType && <p className="mt-1 text-sm text-red-500">{errors.requestType}</p>}
287
- </div>
288
-
289
- {selectedType && (
290
- <div className="mb-4 p-3 bg-gray-50 dark:bg-gray-700 rounded-md">
291
- <p className="text-sm text-gray-600 dark:text-gray-300 mb-2">{selectedType.description}</p>
292
- <p className="text-sm text-gray-500 dark:text-gray-400">
293
- Estimated completion time: {selectedType.estimatedCompletionTime} {selectedType.estimatedCompletionTime === 1 ? 'day' : 'days'}
294
- </p>
295
- </div>
296
- )}
297
-
298
- <div className="mb-4">
299
- <label htmlFor="requestDescription" className="block text-sm font-medium mb-1">
300
- {labels.description || "Additional Information"}
301
- </label>
302
- <textarea
303
- id="requestDescription"
304
- className="w-full px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500"
305
- rows={4}
306
- placeholder="Please provide any additional details that might help us process your request"
307
- />
308
- </div>
309
- </div>
310
-
311
- {/* Identity Verification */}
312
- {requireIdentityVerification && (
313
- <div>
314
- <h3 className="text-lg font-semibold mb-3">Identity Verification</h3>
315
- <p className="text-sm text-gray-600 dark:text-gray-300 mb-3">
316
- To protect your privacy, we need to verify your identity before processing your request.
317
- </p>
318
-
319
- <div className="grid grid-cols-1 gap-4 md:grid-cols-2">
320
- <div>
321
- <label htmlFor="identifierType" className="block text-sm font-medium mb-1">
322
- Identifier Type <span className="text-red-500">*</span>
323
- </label>
324
- <select
325
- id="identifierType"
326
- value={identifierType}
327
- onChange={e => setIdentifierType(e.target.value)}
328
- className="w-full px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500"
329
- required
330
- >
331
- {identifierTypes.map(type => (
332
- <option key={type.id} value={type.id}>
333
- {type.label}
334
- </option>
335
- ))}
336
- </select>
337
- </div>
338
-
339
- <div>
340
- <label htmlFor="identifierValue" className="block text-sm font-medium mb-1">
341
- Identifier Value <span className="text-red-500">*</span>
342
- </label>
343
- <input
344
- type="text"
345
- id="identifierValue"
346
- value={identifierValue}
347
- onChange={e => setIdentifierValue(e.target.value)}
348
- className="w-full px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500"
349
- required
350
- />
351
- {errors.identifierValue && <p className="mt-1 text-sm text-red-500">{errors.identifierValue}</p>}
352
- </div>
353
- </div>
354
- </div>
355
- )}
356
-
357
- {/* Additional Information */}
358
- {selectedType?.requiresAdditionalInfo && selectedType.additionalFields && selectedType.additionalFields.length > 0 && (
359
- <div>
360
- <h3 className="text-lg font-semibold mb-3">Additional Information</h3>
361
- <div className="space-y-4">
362
- {selectedType.additionalFields.map(field => (
363
- <div key={field.id}>
364
- <label htmlFor={field.id} className="block text-sm font-medium mb-1">
365
- {field.label} {field.required && <span className="text-red-500">*</span>}
366
- </label>
367
-
368
- {field.type === 'text' && (
369
- <input
370
- type="text"
371
- id={field.id}
372
- value={additionalInfo[field.id] || ''}
373
- onChange={e => handleAdditionalInfoChange(field.id, e.target.value)}
374
- placeholder={field.placeholder}
375
- className="w-full px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500"
376
- required={field.required}
377
- />
378
- )}
379
-
380
- {field.type === 'textarea' && (
381
- <textarea
382
- id={field.id}
383
- value={additionalInfo[field.id] || ''}
384
- onChange={e => handleAdditionalInfoChange(field.id, e.target.value)}
385
- placeholder={field.placeholder}
386
- className="w-full px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500"
387
- rows={4}
388
- required={field.required}
389
- />
390
- )}
391
-
392
- {field.type === 'select' && field.options && (
393
- <select
394
- id={field.id}
395
- value={additionalInfo[field.id] || ''}
396
- onChange={e => handleAdditionalInfoChange(field.id, e.target.value)}
397
- className="w-full px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500"
398
- required={field.required}
399
- >
400
- <option value="">{field.placeholder || 'Select an option'}</option>
401
- {field.options.map(option => (
402
- <option key={option} value={option}>
403
- {option}
404
- </option>
405
- ))}
406
- </select>
407
- )}
408
-
409
- {field.type === 'checkbox' && (
410
- <div className="flex items-start">
411
- <div className="flex items-center h-5">
412
- <input
413
- type="checkbox"
414
- id={field.id}
415
- checked={!!additionalInfo[field.id]}
416
- onChange={e => handleAdditionalInfoChange(field.id, e.target.checked)}
417
- className="h-4 w-4 rounded border-gray-300 text-blue-600 focus:ring-blue-500"
418
- required={field.required}
419
- />
420
- </div>
421
- <div className="ml-3 text-sm">
422
- <label htmlFor={field.id} className="text-gray-700 dark:text-gray-300">
423
- {field.placeholder || field.label}
424
- </label>
425
- </div>
426
- </div>
427
- )}
428
-
429
- {field.type === 'file' && (
430
- <input
431
- type="file"
432
- id={field.id}
433
- onChange={e => {
434
- const file = e.target.files?.[0];
435
- if (file) {
436
- handleAdditionalInfoChange(field.id, file);
437
- }
438
- }}
439
- className="w-full px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500"
440
- required={field.required}
441
- />
442
- )}
443
-
444
- {errors[`additional_${field.id}`] && (
445
- <p className="mt-1 text-sm text-red-500">{errors[`additional_${field.id}`]}</p>
446
- )}
447
- </div>
448
- ))}
449
- </div>
450
- </div>
451
- )}
452
-
453
- {/* Privacy Notice */}
454
- <div className="mt-6 p-4 bg-gray-50 dark:bg-gray-700 rounded-md">
455
- <h3 className="text-sm font-semibold mb-2">Privacy Notice</h3>
456
- <p className="text-xs text-gray-600 dark:text-gray-300">
457
- The information you provide in this form will be used solely for the purpose of processing your data subject request.
458
- We will retain this information for as long as necessary to fulfill your request and to comply with our legal obligations.
459
- For more information, please refer to our Privacy Policy.
460
- </p>
461
- </div>
462
-
463
- {/* Submit Button */}
464
- <div className="mt-6">
465
- <button
466
- type="submit"
467
- className={`px-6 py-3 bg-blue-600 text-white rounded-md hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 ${buttonClassName}`}
468
- >
469
- {labels.submit || submitButtonText}
470
- </button>
471
- </div>
472
- </div>
473
- </form>
474
- </div>
475
- );
476
- };