@tantainnovative/ndpr-toolkit 1.0.5 → 1.0.7

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 (263) hide show
  1. package/README.md +88 -14
  2. package/dist/components/breach-notification/BreachNotificationForm.d.ts +18 -0
  3. package/dist/components/breach-notification/BreachNotificationForm.d.ts.map +1 -0
  4. package/dist/components/consent/ConsentBanner.d.ts +30 -0
  5. package/dist/components/consent/ConsentBanner.d.ts.map +1 -0
  6. package/dist/components/consent/ConsentManager.d.ts +51 -0
  7. package/dist/components/consent/ConsentManager.d.ts.map +1 -0
  8. package/dist/components/consent/ConsentSettings.d.ts +15 -0
  9. package/dist/components/consent/ConsentSettings.d.ts.map +1 -0
  10. package/dist/components/consent/unstyled/UnstyledConsentBanner.d.ts +7 -0
  11. package/dist/components/consent/unstyled/UnstyledConsentBanner.d.ts.map +1 -0
  12. package/dist/components/consent/unstyled/UnstyledConsentSettings.d.ts +7 -0
  13. package/dist/components/consent/unstyled/UnstyledConsentSettings.d.ts.map +1 -0
  14. package/dist/components/consent/unstyled/UnstyledConsentToggle.d.ts +8 -0
  15. package/dist/components/consent/unstyled/UnstyledConsentToggle.d.ts.map +1 -0
  16. package/dist/components/consent/unstyled/index.d.ts +4 -0
  17. package/dist/components/consent/unstyled/index.d.ts.map +1 -0
  18. package/dist/components/data-subject-rights/DataSubjectRequestForm.d.ts +14 -0
  19. package/dist/components/data-subject-rights/DataSubjectRequestForm.d.ts.map +1 -0
  20. package/dist/components/docs/DocLayout.d.ts +9 -0
  21. package/dist/components/docs/DocLayout.d.ts.map +1 -0
  22. package/dist/components/docs/index.d.ts +2 -0
  23. package/dist/components/docs/index.d.ts.map +1 -0
  24. package/dist/components/dpia/DPIAQuestionnaire.d.ts +9 -0
  25. package/dist/components/dpia/DPIAQuestionnaire.d.ts.map +1 -0
  26. package/dist/components/privacy-policy/PolicyGenerator.d.ts +12 -0
  27. package/dist/components/privacy-policy/PolicyGenerator.d.ts.map +1 -0
  28. package/dist/components/privacy-policy/data.d.ts +8 -0
  29. package/dist/components/privacy-policy/data.d.ts.map +1 -0
  30. package/dist/components/privacy-policy/shared/CheckboxField.d.ts +13 -0
  31. package/dist/components/privacy-policy/shared/CheckboxField.d.ts.map +1 -0
  32. package/dist/components/privacy-policy/shared/CheckboxGroup.d.ts +13 -0
  33. package/dist/components/privacy-policy/shared/CheckboxGroup.d.ts.map +1 -0
  34. package/dist/components/privacy-policy/shared/FormField.d.ts +13 -0
  35. package/dist/components/privacy-policy/shared/FormField.d.ts.map +1 -0
  36. package/dist/components/privacy-policy/shared/StepIndicator.d.ts +8 -0
  37. package/dist/components/privacy-policy/shared/StepIndicator.d.ts.map +1 -0
  38. package/dist/components/privacy-policy/steps/CustomSectionsStep.d.ts +15 -0
  39. package/dist/components/privacy-policy/steps/CustomSectionsStep.d.ts.map +1 -0
  40. package/dist/components/privacy-policy/steps/DataCollectionStep.d.ts +20 -0
  41. package/dist/components/privacy-policy/steps/DataCollectionStep.d.ts.map +1 -0
  42. package/dist/components/privacy-policy/steps/DataSharingStep.d.ts +34 -0
  43. package/dist/components/privacy-policy/steps/DataSharingStep.d.ts.map +1 -0
  44. package/dist/components/privacy-policy/steps/OrganizationInfoStep.d.ts +17 -0
  45. package/dist/components/privacy-policy/steps/OrganizationInfoStep.d.ts.map +1 -0
  46. package/dist/components/privacy-policy/steps/PolicyPreviewStep.d.ts +30 -0
  47. package/dist/components/privacy-policy/steps/PolicyPreviewStep.d.ts.map +1 -0
  48. package/dist/components/ui/Badge.d.ts +10 -0
  49. package/dist/components/ui/Badge.d.ts.map +1 -0
  50. package/dist/components/ui/Button.d.ts +11 -0
  51. package/dist/components/ui/Button.d.ts.map +1 -0
  52. package/dist/components/ui/Card.d.ts +10 -0
  53. package/dist/components/ui/Card.d.ts.map +1 -0
  54. package/dist/components/ui/Checkbox.d.ts +8 -0
  55. package/dist/components/ui/Checkbox.d.ts.map +1 -0
  56. package/dist/components/ui/FormField.d.ts +11 -0
  57. package/dist/components/ui/FormField.d.ts.map +1 -0
  58. package/dist/components/ui/Input.d.ts +6 -0
  59. package/dist/components/ui/Input.d.ts.map +1 -0
  60. package/dist/components/ui/Select.d.ts +6 -0
  61. package/dist/components/ui/Select.d.ts.map +1 -0
  62. package/dist/components/ui/TextArea.d.ts +6 -0
  63. package/dist/components/ui/TextArea.d.ts.map +1 -0
  64. package/dist/components/ui/dialog.d.ts +18 -0
  65. package/dist/components/ui/dialog.d.ts.map +1 -0
  66. package/dist/components/ui/label.d.ts +5 -0
  67. package/dist/components/ui/label.d.ts.map +1 -0
  68. package/dist/components/ui/switch.d.ts +5 -0
  69. package/dist/components/ui/switch.d.ts.map +1 -0
  70. package/dist/components/ui/tabs.d.ts +8 -0
  71. package/dist/components/ui/tabs.d.ts.map +1 -0
  72. package/dist/contexts/ConsentContext.d.ts +35 -0
  73. package/dist/contexts/ConsentContext.d.ts.map +1 -0
  74. package/dist/contexts/GenericConsentContext.d.ts +11 -0
  75. package/dist/contexts/GenericConsentContext.d.ts.map +1 -0
  76. package/dist/hooks/useConsent.d.ts +12 -0
  77. package/dist/hooks/useConsent.d.ts.map +1 -0
  78. package/dist/hooks/useConsentActions.d.ts +12 -0
  79. package/dist/hooks/useConsentActions.d.ts.map +1 -0
  80. package/dist/hooks/useConsentManager.d.ts +14 -0
  81. package/dist/hooks/useConsentManager.d.ts.map +1 -0
  82. package/dist/hooks/useConsentState.d.ts +10 -0
  83. package/dist/hooks/useConsentState.d.ts.map +1 -0
  84. package/dist/index.d.mts +256 -0
  85. package/dist/index.d.ts +24 -0
  86. package/dist/index.d.ts.map +1 -0
  87. package/dist/index.js +2 -0
  88. package/dist/index.js.map +1 -0
  89. package/dist/index.mjs +2 -0
  90. package/dist/index.mjs.map +1 -0
  91. package/dist/lib/consentService.d.ts +11 -0
  92. package/dist/lib/consentService.d.ts.map +1 -0
  93. package/dist/lib/dpiaQuestions.d.ts +3 -0
  94. package/dist/lib/dpiaQuestions.d.ts.map +1 -0
  95. package/dist/lib/requestService.d.ts +10 -0
  96. package/dist/lib/requestService.d.ts.map +1 -0
  97. package/dist/lib/utils.d.ts +3 -0
  98. package/dist/lib/utils.d.ts.map +1 -0
  99. package/dist/styles.css +38 -0
  100. package/dist/types/consent.d.ts +57 -0
  101. package/dist/types/consent.d.ts.map +1 -0
  102. package/dist/types/index.d.ts +91 -0
  103. package/dist/types/index.d.ts.map +1 -0
  104. package/dist/unstyled.d.mts +22 -0
  105. package/dist/unstyled.d.ts +2 -0
  106. package/dist/unstyled.d.ts.map +1 -0
  107. package/dist/unstyled.js +2 -0
  108. package/dist/unstyled.js.map +1 -0
  109. package/dist/unstyled.mjs +2 -0
  110. package/dist/unstyled.mjs.map +1 -0
  111. package/package.json +33 -5
  112. package/CHANGELOG.md +0 -16
  113. package/CNAME +0 -1
  114. package/CONTRIBUTING.md +0 -87
  115. package/RELEASE-NOTES-v1.0.0.md +0 -140
  116. package/RELEASE-NOTES-v1.0.1.md +0 -69
  117. package/SECURITY.md +0 -21
  118. package/components.json +0 -21
  119. package/eslint.config.mjs +0 -16
  120. package/next-env.d.ts +0 -5
  121. package/next.config.js +0 -15
  122. package/next.config.ts +0 -62
  123. package/packages/ndpr-toolkit/README.md +0 -467
  124. package/packages/ndpr-toolkit/dist/components/breach/BreachNotificationManager.d.ts +0 -62
  125. package/packages/ndpr-toolkit/dist/components/breach/BreachReportForm.d.ts +0 -66
  126. package/packages/ndpr-toolkit/dist/components/breach/BreachRiskAssessment.d.ts +0 -50
  127. package/packages/ndpr-toolkit/dist/components/breach/RegulatoryReportGenerator.d.ts +0 -94
  128. package/packages/ndpr-toolkit/dist/components/consent/ConsentBanner.d.ts +0 -79
  129. package/packages/ndpr-toolkit/dist/components/consent/ConsentManager.d.ts +0 -73
  130. package/packages/ndpr-toolkit/dist/components/consent/ConsentStorage.d.ts +0 -41
  131. package/packages/ndpr-toolkit/dist/components/dpia/DPIAQuestionnaire.d.ts +0 -70
  132. package/packages/ndpr-toolkit/dist/components/dpia/DPIAReport.d.ts +0 -40
  133. package/packages/ndpr-toolkit/dist/components/dpia/StepIndicator.d.ts +0 -64
  134. package/packages/ndpr-toolkit/dist/components/dsr/DSRDashboard.d.ts +0 -58
  135. package/packages/ndpr-toolkit/dist/components/dsr/DSRRequestForm.d.ts +0 -74
  136. package/packages/ndpr-toolkit/dist/components/dsr/DSRTracker.d.ts +0 -56
  137. package/packages/ndpr-toolkit/dist/components/policy/PolicyExporter.d.ts +0 -65
  138. package/packages/ndpr-toolkit/dist/components/policy/PolicyGenerator.d.ts +0 -54
  139. package/packages/ndpr-toolkit/dist/components/policy/PolicyPreview.d.ts +0 -71
  140. package/packages/ndpr-toolkit/dist/hooks/useBreach.d.ts +0 -97
  141. package/packages/ndpr-toolkit/dist/hooks/useConsent.d.ts +0 -63
  142. package/packages/ndpr-toolkit/dist/hooks/useDPIA.d.ts +0 -92
  143. package/packages/ndpr-toolkit/dist/hooks/useDSR.d.ts +0 -72
  144. package/packages/ndpr-toolkit/dist/hooks/usePrivacyPolicy.d.ts +0 -87
  145. package/packages/ndpr-toolkit/dist/index.d.ts +0 -31
  146. package/packages/ndpr-toolkit/dist/index.esm.js +0 -2
  147. package/packages/ndpr-toolkit/dist/index.esm.js.map +0 -1
  148. package/packages/ndpr-toolkit/dist/index.js +0 -2
  149. package/packages/ndpr-toolkit/dist/index.js.map +0 -1
  150. package/packages/ndpr-toolkit/dist/setupTests.d.ts +0 -2
  151. package/packages/ndpr-toolkit/dist/types/breach.d.ts +0 -239
  152. package/packages/ndpr-toolkit/dist/types/consent.d.ts +0 -95
  153. package/packages/ndpr-toolkit/dist/types/dpia.d.ts +0 -196
  154. package/packages/ndpr-toolkit/dist/types/dsr.d.ts +0 -162
  155. package/packages/ndpr-toolkit/dist/types/privacy.d.ts +0 -204
  156. package/packages/ndpr-toolkit/dist/utils/breach.d.ts +0 -14
  157. package/packages/ndpr-toolkit/dist/utils/consent.d.ts +0 -10
  158. package/packages/ndpr-toolkit/dist/utils/dpia.d.ts +0 -12
  159. package/packages/ndpr-toolkit/dist/utils/dsr.d.ts +0 -11
  160. package/packages/ndpr-toolkit/dist/utils/privacy.d.ts +0 -12
  161. package/packages/ndpr-toolkit/package-lock.json +0 -8197
  162. package/packages/ndpr-toolkit/package.json +0 -71
  163. package/packages/ndpr-toolkit/rollup.config.js +0 -34
  164. package/packages/ndpr-toolkit/src/components/breach/BreachNotificationManager.tsx +0 -701
  165. package/packages/ndpr-toolkit/src/components/breach/BreachReportForm.tsx +0 -631
  166. package/packages/ndpr-toolkit/src/components/breach/BreachRiskAssessment.tsx +0 -569
  167. package/packages/ndpr-toolkit/src/components/breach/RegulatoryReportGenerator.tsx +0 -496
  168. package/packages/ndpr-toolkit/src/components/consent/ConsentBanner.tsx +0 -270
  169. package/packages/ndpr-toolkit/src/components/consent/ConsentManager.tsx +0 -217
  170. package/packages/ndpr-toolkit/src/components/consent/ConsentStorage.tsx +0 -206
  171. package/packages/ndpr-toolkit/src/components/dpia/DPIAQuestionnaire.tsx +0 -342
  172. package/packages/ndpr-toolkit/src/components/dpia/DPIAReport.tsx +0 -373
  173. package/packages/ndpr-toolkit/src/components/dpia/StepIndicator.tsx +0 -174
  174. package/packages/ndpr-toolkit/src/components/dsr/DSRDashboard.tsx +0 -717
  175. package/packages/ndpr-toolkit/src/components/dsr/DSRRequestForm.tsx +0 -476
  176. package/packages/ndpr-toolkit/src/components/dsr/DSRTracker.tsx +0 -620
  177. package/packages/ndpr-toolkit/src/components/policy/PolicyExporter.tsx +0 -541
  178. package/packages/ndpr-toolkit/src/components/policy/PolicyGenerator.tsx +0 -454
  179. package/packages/ndpr-toolkit/src/components/policy/PolicyPreview.tsx +0 -333
  180. package/packages/ndpr-toolkit/src/hooks/useBreach.ts +0 -409
  181. package/packages/ndpr-toolkit/src/hooks/useConsent.ts +0 -263
  182. package/packages/ndpr-toolkit/src/hooks/useDPIA.ts +0 -457
  183. package/packages/ndpr-toolkit/src/hooks/useDSR.ts +0 -236
  184. package/packages/ndpr-toolkit/src/hooks/usePrivacyPolicy.ts +0 -428
  185. package/packages/ndpr-toolkit/src/index.ts +0 -44
  186. package/packages/ndpr-toolkit/src/setupTests.ts +0 -5
  187. package/packages/ndpr-toolkit/src/types/breach.ts +0 -283
  188. package/packages/ndpr-toolkit/src/types/consent.ts +0 -111
  189. package/packages/ndpr-toolkit/src/types/dpia.ts +0 -236
  190. package/packages/ndpr-toolkit/src/types/dsr.ts +0 -192
  191. package/packages/ndpr-toolkit/src/types/index.ts +0 -42
  192. package/packages/ndpr-toolkit/src/types/privacy.ts +0 -246
  193. package/packages/ndpr-toolkit/src/utils/breach.ts +0 -122
  194. package/packages/ndpr-toolkit/src/utils/consent.ts +0 -51
  195. package/packages/ndpr-toolkit/src/utils/dpia.ts +0 -104
  196. package/packages/ndpr-toolkit/src/utils/dsr.ts +0 -77
  197. package/packages/ndpr-toolkit/src/utils/privacy.ts +0 -100
  198. package/packages/ndpr-toolkit/tsconfig.json +0 -23
  199. package/postcss.config.mjs +0 -5
  200. package/public/NDPR TOOLKIT.svg +0 -1
  201. package/public/favicon/android-chrome-192x192.png +0 -0
  202. package/public/favicon/android-chrome-512x512.png +0 -0
  203. package/public/favicon/apple-touch-icon.png +0 -0
  204. package/public/favicon/favicon-16x16.png +0 -0
  205. package/public/favicon/favicon-32x32.png +0 -0
  206. package/public/favicon/site.webmanifest +0 -1
  207. package/public/file.svg +0 -1
  208. package/public/globe.svg +0 -1
  209. package/public/ndpr-toolkit-logo.svg +0 -108
  210. package/public/next.svg +0 -1
  211. package/public/vercel.svg +0 -1
  212. package/public/window.svg +0 -1
  213. package/src/app/accessibility.css +0 -70
  214. package/src/app/favicon.ico +0 -0
  215. package/src/app/globals.css +0 -123
  216. package/src/app/layout.tsx +0 -37
  217. package/src/app/ndpr-demos/breach/page.tsx +0 -354
  218. package/src/app/ndpr-demos/consent/page.tsx +0 -366
  219. package/src/app/ndpr-demos/dpia/page.tsx +0 -495
  220. package/src/app/ndpr-demos/dsr/page.tsx +0 -280
  221. package/src/app/ndpr-demos/page.tsx +0 -73
  222. package/src/app/ndpr-demos/policy/page.tsx +0 -771
  223. package/src/app/page.tsx +0 -452
  224. package/src/components/ErrorBoundary.tsx +0 -90
  225. package/src/components/breach-notification/BreachNotificationForm.tsx +0 -479
  226. package/src/components/consent/ConsentBanner.tsx +0 -193
  227. package/src/components/data-subject-rights/DataSubjectRequestForm.tsx +0 -530
  228. package/src/components/dpia/DPIAQuestionnaire.tsx +0 -523
  229. package/src/components/privacy-policy/PolicyGenerator.tsx +0 -1062
  230. package/src/components/privacy-policy/data.ts +0 -98
  231. package/src/components/privacy-policy/shared/CheckboxField.tsx +0 -38
  232. package/src/components/privacy-policy/shared/CheckboxGroup.tsx +0 -85
  233. package/src/components/privacy-policy/shared/FormField.tsx +0 -79
  234. package/src/components/privacy-policy/shared/StepIndicator.tsx +0 -86
  235. package/src/components/privacy-policy/steps/CustomSectionsStep.tsx +0 -361
  236. package/src/components/privacy-policy/steps/DataCollectionStep.tsx +0 -231
  237. package/src/components/privacy-policy/steps/DataSharingStep.tsx +0 -418
  238. package/src/components/privacy-policy/steps/OrganizationInfoStep.tsx +0 -202
  239. package/src/components/privacy-policy/steps/PolicyPreviewStep.tsx +0 -226
  240. package/src/components/ui/Badge.tsx +0 -46
  241. package/src/components/ui/Button.tsx +0 -59
  242. package/src/components/ui/Card.tsx +0 -92
  243. package/src/components/ui/Checkbox.tsx +0 -57
  244. package/src/components/ui/FormField.tsx +0 -50
  245. package/src/components/ui/Input.tsx +0 -38
  246. package/src/components/ui/Loading.tsx +0 -201
  247. package/src/components/ui/Select.tsx +0 -42
  248. package/src/components/ui/TextArea.tsx +0 -38
  249. package/src/components/ui/label.tsx +0 -24
  250. package/src/components/ui/switch.tsx +0 -31
  251. package/src/components/ui/tabs.tsx +0 -66
  252. package/src/hooks/useConsent.ts +0 -70
  253. package/src/hooks/useLoadingState.ts +0 -85
  254. package/src/lib/consentService.ts +0 -144
  255. package/src/lib/dpiaQuestions.ts +0 -188
  256. package/src/lib/requestService.ts +0 -79
  257. package/src/lib/sanitize.ts +0 -108
  258. package/src/lib/storage.ts +0 -222
  259. package/src/lib/utils.ts +0 -6
  260. package/src/types/html-to-docx.d.ts +0 -30
  261. package/src/types/index.ts +0 -77
  262. package/tailwind.config.ts +0 -65
  263. package/tsconfig.json +0 -41
@@ -1,523 +0,0 @@
1
- "use client";
2
-
3
- import { useState, useEffect } from "react";
4
- import { RiskAssessmentQuestion } from "@/types";
5
- import { Button } from "@/components/ui/Button";
6
- import { Input } from "@/components/ui/Input";
7
- import { TextArea } from "@/components/ui/TextArea";
8
- import { FormField } from "@/components/ui/FormField";
9
- import { Card, CardHeader, CardTitle, CardContent } from "@/components/ui/Card";
10
- import { Badge } from "@/components/ui/Badge";
11
-
12
- interface DPIAQuestionnaireProps {
13
- questions: RiskAssessmentQuestion[];
14
- onSubmit: (answers: Record<string, number>, projectName: string) => void;
15
- className?: string;
16
- }
17
-
18
- export default function DPIAQuestionnaire({
19
- questions,
20
- onSubmit,
21
- className = "",
22
- }: DPIAQuestionnaireProps) {
23
- const [projectName, setProjectName] = useState("");
24
- const [projectDescription, setProjectDescription] = useState("");
25
- const [dataController, setDataController] = useState("");
26
- const [assessmentDate, setAssessmentDate] = useState(
27
- new Date().toISOString().split("T")[0],
28
- );
29
- const [answers, setAnswers] = useState<Record<string, number>>({});
30
- const [currentStep, setCurrentStep] = useState(0);
31
- const [errors, setErrors] = useState<Record<string, string>>({});
32
- const [progress, setProgress] = useState(0);
33
-
34
- // Since DPIAQuestion doesn't have a category, we'll create a single category
35
- const categories: Record<string, RiskAssessmentQuestion[]> = {
36
- "Assessment Questions": questions,
37
- };
38
-
39
- const categoryNames = Object.keys(categories);
40
-
41
- const handleAnswerChange = (questionId: string, value: number | string) => {
42
- setAnswers((prev) => ({
43
- ...prev,
44
- [questionId]: typeof value === "string" ? parseInt(value, 10) : value,
45
- }));
46
-
47
- // Clear error when question is answered
48
- if (errors[questionId]) {
49
- setErrors((prev) => {
50
- const newErrors = { ...prev };
51
- delete newErrors[questionId];
52
- return newErrors;
53
- });
54
- }
55
- };
56
-
57
- // Render different input types based on question type
58
- const renderQuestionInput = (question: RiskAssessmentQuestion) => {
59
- switch (question.type) {
60
- case "text":
61
- return (
62
- <Input
63
- id={question.id}
64
- value={answers[question.id] || ""}
65
- onChange={(e) => handleAnswerChange(question.id, e.target.value)}
66
- placeholder={question.guidance}
67
- className="w-full"
68
- />
69
- );
70
-
71
- case "textarea":
72
- return (
73
- <TextArea
74
- id={question.id}
75
- value={answers[question.id] || ""}
76
- onChange={(e) => handleAnswerChange(question.id, e.target.value)}
77
- placeholder={question.guidance}
78
- rows={4}
79
- className="w-full"
80
- />
81
- );
82
-
83
- case "select":
84
- return (
85
- <select
86
- id={question.id}
87
- value={answers[question.id] || ""}
88
- onChange={(e) => handleAnswerChange(question.id, e.target.value)}
89
- className="w-full p-2 border border-gray-300 rounded-md focus:ring-2 focus:ring-blue-500 focus:border-blue-500"
90
- >
91
- <option value="">Select an option</option>
92
- {question.options?.map((option) => (
93
- <option key={option.value} value={option.value}>
94
- {option.label}
95
- </option>
96
- ))}
97
- </select>
98
- );
99
-
100
- case "radio":
101
- return question.options?.map((option) => (
102
- <div
103
- key={option.value}
104
- className={`p-3 border rounded-md cursor-pointer transition-colors ${
105
- answers[question.id] === parseInt(option.value)
106
- ? "border-blue-500 bg-blue-50 dark:bg-blue-900/30 dark:border-blue-400"
107
- : "border-gray-200 dark:border-gray-700 hover:bg-gray-50 dark:hover:bg-gray-800"
108
- }`}
109
- onClick={() => handleAnswerChange(question.id, option.value)}
110
- >
111
- <div className="flex items-center justify-between">
112
- <div className="flex items-center">
113
- <input
114
- id={`${question.id}-${option.value}`}
115
- name={question.id}
116
- type="radio"
117
- value={option.value}
118
- checked={answers[question.id] === parseInt(option.value)}
119
- onChange={() => handleAnswerChange(question.id, option.value)}
120
- className="h-4 w-4 border-gray-300 text-blue-600 focus:ring-blue-500"
121
- />
122
- <label
123
- htmlFor={`${question.id}-${option.value}`}
124
- className="ml-3 block text-sm text-gray-700 dark:text-gray-300 cursor-pointer"
125
- >
126
- {option.label}
127
- </label>
128
- </div>
129
- {option.riskLevel &&
130
- getRiskLevelIndicator(parseInt(option.value))}
131
- </div>
132
- </div>
133
- ));
134
-
135
- case "checkbox":
136
- return question.options?.map((option) => (
137
- <div key={option.value} className="flex items-center">
138
- <input
139
- id={`${question.id}-${option.value}`}
140
- type="checkbox"
141
- value={option.value}
142
- checked={answers[question.id]?.toString().includes(option.value)}
143
- onChange={(e) => {
144
- const currentValues =
145
- answers[question.id]?.toString().split(",").filter(Boolean) ||
146
- [];
147
- if (e.target.checked) {
148
- currentValues.push(option.value);
149
- } else {
150
- const index = currentValues.indexOf(option.value);
151
- if (index > -1) currentValues.splice(index, 1);
152
- }
153
- handleAnswerChange(question.id, currentValues.join(","));
154
- }}
155
- className="h-4 w-4 border-gray-300 text-blue-600 focus:ring-blue-500 rounded"
156
- />
157
- <label
158
- htmlFor={`${question.id}-${option.value}`}
159
- className="ml-3 block text-sm text-gray-700 dark:text-gray-300"
160
- >
161
- {option.label}
162
- </label>
163
- </div>
164
- ));
165
-
166
- case "scale":
167
- return (
168
- <div className="space-y-2">
169
- <input
170
- type="range"
171
- id={question.id}
172
- min={question.minValue || 1}
173
- max={question.maxValue || 5}
174
- value={answers[question.id] || question.minValue || 1}
175
- onChange={(e) => handleAnswerChange(question.id, e.target.value)}
176
- className="w-full"
177
- />
178
- <div className="flex justify-between text-sm text-gray-600">
179
- {question.scaleLabels ? (
180
- Object.entries(question.scaleLabels).map(([value, label]) => (
181
- <span key={value}>{label}</span>
182
- ))
183
- ) : (
184
- <>
185
- <span>{question.minValue || 1}</span>
186
- <span>{question.maxValue || 5}</span>
187
- </>
188
- )}
189
- </div>
190
- </div>
191
- );
192
-
193
- default:
194
- return (
195
- <p className="text-gray-500">
196
- Unsupported question type: {question.type}
197
- </p>
198
- );
199
- }
200
- };
201
-
202
- // Calculate overall progress
203
- useEffect(() => {
204
- const totalQuestions = questions.length;
205
- const answeredQuestions = Object.keys(answers).length;
206
- const projectInfoComplete = projectName.trim() !== "" ? 1 : 0;
207
-
208
- // Calculate progress percentage (project info counts as one question)
209
- const calculatedProgress = Math.round(
210
- ((answeredQuestions + projectInfoComplete) / (totalQuestions + 1)) * 100,
211
- );
212
- setProgress(calculatedProgress);
213
- }, [answers, projectName, questions.length]);
214
-
215
- const validateStep = (step: number) => {
216
- const newErrors: Record<string, string> = {};
217
-
218
- if (step === 0) {
219
- if (!projectName.trim()) {
220
- newErrors.projectName = "Project name is required";
221
- }
222
- // Description and data controller are optional, so no validation needed
223
- } else {
224
- const category = categoryNames[step - 1];
225
- const categoryQuestions = categories[category];
226
-
227
- categoryQuestions.forEach((question) => {
228
- if (answers[question.id] === undefined) {
229
- newErrors[question.id] = "Please select an answer for this question";
230
- }
231
- });
232
- }
233
-
234
- setErrors(newErrors);
235
- return Object.keys(newErrors).length === 0;
236
- };
237
-
238
- const handleNext = () => {
239
- if (validateStep(currentStep)) {
240
- setCurrentStep((prev) => prev + 1);
241
- }
242
- };
243
-
244
- const handleBack = () => {
245
- setCurrentStep((prev) => prev - 1);
246
- };
247
-
248
- const handleSubmit = () => {
249
- if (validateStep(currentStep)) {
250
- // Submit with just the answers and project name as per interface definition
251
- onSubmit(answers, projectName);
252
- }
253
- };
254
-
255
- const renderStepContent = () => {
256
- if (currentStep === 0) {
257
- return (
258
- <div className="space-y-6">
259
- <h3 className="text-lg font-medium text-gray-900 dark:text-white">
260
- Project Information
261
- </h3>
262
-
263
- <div className="bg-blue-50 dark:bg-blue-900/20 p-4 rounded-md mb-6">
264
- <p className="text-sm text-blue-800 dark:text-blue-200">
265
- This Data Protection Impact Assessment (DPIA) will help you
266
- identify and minimize data protection risks in your project.
267
- Please provide accurate information to receive the most relevant
268
- recommendations.
269
- </p>
270
- </div>
271
-
272
- <FormField
273
- id="projectName"
274
- label="Project Name"
275
- required
276
- error={errors.projectName}
277
- >
278
- <Input
279
- id="projectName"
280
- value={projectName}
281
- onChange={(e) => setProjectName(e.target.value)}
282
- placeholder="Enter the name of your project or data processing activity"
283
- />
284
- </FormField>
285
-
286
- <FormField
287
- id="projectDescription"
288
- label="Project Description"
289
- description="Briefly describe the purpose and scope of your project"
290
- >
291
- <TextArea
292
- id="projectDescription"
293
- value={projectDescription}
294
- onChange={(e) => setProjectDescription(e.target.value)}
295
- rows={3}
296
- placeholder="Briefly describe the purpose and scope of your project"
297
- />
298
- </FormField>
299
-
300
- <FormField
301
- id="dataController"
302
- label="Data Controller"
303
- description="Organization responsible for the data"
304
- >
305
- <Input
306
- id="dataController"
307
- value={dataController}
308
- onChange={(e) => setDataController(e.target.value)}
309
- placeholder="Name of the organization responsible for the data"
310
- />
311
- </FormField>
312
-
313
- <FormField id="assessmentDate" label="Assessment Date">
314
- <Input
315
- type="date"
316
- id="assessmentDate"
317
- value={assessmentDate}
318
- onChange={(e) => setAssessmentDate(e.target.value)}
319
- />
320
- </FormField>
321
- </div>
322
- );
323
- }
324
-
325
- const category = categoryNames[currentStep - 1];
326
- const categoryQuestions = categories[category];
327
-
328
- return (
329
- <div className="space-y-6">
330
- <div className="flex items-center space-x-2">
331
- <div className="w-8 h-8 rounded-full bg-blue-100 dark:bg-blue-900 flex items-center justify-center">
332
- <span className="text-blue-600 dark:text-blue-300 font-medium">
333
- {currentStep}
334
- </span>
335
- </div>
336
- <h3 className="text-lg font-medium text-gray-900 dark:text-white">
337
- {category}
338
- </h3>
339
- </div>
340
-
341
- <div className="bg-gray-50 dark:bg-gray-800 p-4 rounded-md mb-4">
342
- <p className="text-sm text-gray-600 dark:text-gray-400">
343
- {getCategoryDescription(category)}
344
- </p>
345
- </div>
346
-
347
- {categoryQuestions.map((question, index) => (
348
- <div
349
- key={question.id}
350
- className="p-4 border border-gray-200 dark:border-gray-700 rounded-lg space-y-4"
351
- >
352
- <div className="flex items-start">
353
- <div className="flex-shrink-0 w-6 h-6 rounded-full bg-blue-100 dark:bg-blue-900 flex items-center justify-center mr-3 mt-0.5">
354
- <span className="text-blue-600 dark:text-blue-300 text-xs font-medium">
355
- {index + 1}
356
- </span>
357
- </div>
358
- <label className="block text-sm font-medium text-gray-800 dark:text-gray-200">
359
- {question.text}
360
- </label>
361
- </div>
362
-
363
- <div className="ml-9 space-y-2">
364
- {renderQuestionInput(question)}
365
- </div>
366
-
367
- {errors[question.id] && (
368
- <p className="ml-9 text-sm text-red-600 dark:text-red-400">
369
- {errors[question.id]}
370
- </p>
371
- )}
372
- </div>
373
- ))}
374
- </div>
375
- );
376
- };
377
-
378
- // Helper function to get category descriptions
379
- const getCategoryDescription = (category: string): string => {
380
- switch (category) {
381
- case "Data Collection":
382
- return "These questions help assess the risks associated with the types of personal data you collect and the sources of that data.";
383
- case "Data Processing":
384
- return "These questions evaluate how you use, analyze, and transform the personal data within your project.";
385
- case "Data Sharing":
386
- return "These questions examine the risks of sharing personal data with third parties or transferring it across borders.";
387
- case "Security Measures":
388
- return "These questions assess the safeguards you have in place to protect personal data from unauthorized access or breaches.";
389
- case "Data Subject Rights":
390
- return "These questions evaluate how well your project supports individuals in exercising their rights over their personal data.";
391
- default:
392
- return "Please answer the following questions about your project.";
393
- }
394
- };
395
-
396
- // Helper function to display risk level indicators
397
- const getRiskLevelIndicator = (value: number) => {
398
- const variants: Record<
399
- number,
400
- "success" | "warning" | "danger" | "primary"
401
- > = {
402
- 1: "success",
403
- 2: "warning",
404
- 3: "danger",
405
- 4: "danger",
406
- };
407
-
408
- const labels = {
409
- 1: "Low Risk",
410
- 2: "Medium Risk",
411
- 3: "High Risk",
412
- 4: "Very High Risk",
413
- };
414
-
415
- return (
416
- <div className="flex items-center ml-auto pl-2">
417
- <Badge variant={variants[value as keyof typeof variants]}>
418
- {labels[value as keyof typeof labels]}
419
- </Badge>
420
- </div>
421
- );
422
- };
423
-
424
- const totalSteps = categoryNames.length + 1; // +1 for the project info step
425
-
426
- return (
427
- <Card className={className}>
428
- <CardHeader>
429
- <CardTitle>Data Protection Impact Assessment</CardTitle>
430
- <p className="text-sm text-gray-500 dark:text-gray-400">
431
- Assess the data protection risks of your project with our DPIA tool.
432
- </p>
433
- </CardHeader>
434
-
435
- <CardContent>
436
- <div className="mb-6">
437
- <div className="flex items-center justify-between mb-2">
438
- <div className="text-sm text-gray-500 dark:text-gray-400">
439
- Step {currentStep + 1} of {totalSteps}
440
- </div>
441
- <div className="text-sm font-medium text-gray-900 dark:text-white">
442
- {currentStep === 0
443
- ? "Project Information"
444
- : categoryNames[currentStep - 1]}
445
- </div>
446
- </div>
447
- <div className="h-2 w-full bg-gray-200 dark:bg-gray-700 rounded-full overflow-hidden">
448
- <div
449
- className="h-2 bg-blue-600 rounded-full transition-all duration-300 ease-in-out"
450
- style={{ width: `${((currentStep + 1) / totalSteps) * 100}%` }}
451
- />
452
- </div>
453
- <div className="flex justify-between mt-2">
454
- <div className="text-xs text-gray-500 dark:text-gray-400">
455
- Overall completion: {progress}%
456
- </div>
457
- {currentStep > 0 && currentStep < totalSteps && (
458
- <div className="text-xs text-gray-500 dark:text-gray-400">
459
- {
460
- categories[categoryNames[currentStep - 1]].filter(
461
- (q) => answers[q.id] !== undefined,
462
- ).length
463
- }{" "}
464
- of {categories[categoryNames[currentStep - 1]].length} questions
465
- answered
466
- </div>
467
- )}
468
- </div>
469
- </div>
470
-
471
- <div className="mb-6">{renderStepContent()}</div>
472
-
473
- <div className="flex justify-between pt-4 border-t border-gray-200 dark:border-gray-700">
474
- {currentStep > 0 ? (
475
- <Button type="button" onClick={handleBack} variant="outline">
476
- <svg
477
- className="w-5 h-5 mr-1"
478
- fill="none"
479
- stroke="currentColor"
480
- viewBox="0 0 24 24"
481
- xmlns="http://www.w3.org/2000/svg"
482
- >
483
- <path
484
- strokeLinecap="round"
485
- strokeLinejoin="round"
486
- strokeWidth={2}
487
- d="M15 19l-7-7 7-7"
488
- />
489
- </svg>
490
- Back
491
- </Button>
492
- ) : (
493
- <div>{/* Empty div to maintain layout */}</div>
494
- )}
495
-
496
- {currentStep < totalSteps - 1 ? (
497
- <Button type="button" onClick={handleNext} variant="default">
498
- Next
499
- <svg
500
- className="w-5 h-5 ml-1"
501
- fill="none"
502
- stroke="currentColor"
503
- viewBox="0 0 24 24"
504
- xmlns="http://www.w3.org/2000/svg"
505
- >
506
- <path
507
- strokeLinecap="round"
508
- strokeLinejoin="round"
509
- strokeWidth={2}
510
- d="M9 5l7 7-7 7"
511
- />
512
- </svg>
513
- </Button>
514
- ) : (
515
- <Button type="button" onClick={handleSubmit} variant="default">
516
- Submit Assessment
517
- </Button>
518
- )}
519
- </div>
520
- </CardContent>
521
- </Card>
522
- );
523
- }