@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.
- package/README.md +88 -14
- package/dist/components/breach-notification/BreachNotificationForm.d.ts +18 -0
- package/dist/components/breach-notification/BreachNotificationForm.d.ts.map +1 -0
- package/dist/components/consent/ConsentBanner.d.ts +30 -0
- package/dist/components/consent/ConsentBanner.d.ts.map +1 -0
- package/dist/components/consent/ConsentManager.d.ts +51 -0
- package/dist/components/consent/ConsentManager.d.ts.map +1 -0
- package/dist/components/consent/ConsentSettings.d.ts +15 -0
- package/dist/components/consent/ConsentSettings.d.ts.map +1 -0
- package/dist/components/consent/unstyled/UnstyledConsentBanner.d.ts +7 -0
- package/dist/components/consent/unstyled/UnstyledConsentBanner.d.ts.map +1 -0
- package/dist/components/consent/unstyled/UnstyledConsentSettings.d.ts +7 -0
- package/dist/components/consent/unstyled/UnstyledConsentSettings.d.ts.map +1 -0
- package/dist/components/consent/unstyled/UnstyledConsentToggle.d.ts +8 -0
- package/dist/components/consent/unstyled/UnstyledConsentToggle.d.ts.map +1 -0
- package/dist/components/consent/unstyled/index.d.ts +4 -0
- package/dist/components/consent/unstyled/index.d.ts.map +1 -0
- package/dist/components/data-subject-rights/DataSubjectRequestForm.d.ts +14 -0
- package/dist/components/data-subject-rights/DataSubjectRequestForm.d.ts.map +1 -0
- package/dist/components/docs/DocLayout.d.ts +9 -0
- package/dist/components/docs/DocLayout.d.ts.map +1 -0
- package/dist/components/docs/index.d.ts +2 -0
- package/dist/components/docs/index.d.ts.map +1 -0
- package/dist/components/dpia/DPIAQuestionnaire.d.ts +9 -0
- package/dist/components/dpia/DPIAQuestionnaire.d.ts.map +1 -0
- package/dist/components/privacy-policy/PolicyGenerator.d.ts +12 -0
- package/dist/components/privacy-policy/PolicyGenerator.d.ts.map +1 -0
- package/dist/components/privacy-policy/data.d.ts +8 -0
- package/dist/components/privacy-policy/data.d.ts.map +1 -0
- package/dist/components/privacy-policy/shared/CheckboxField.d.ts +13 -0
- package/dist/components/privacy-policy/shared/CheckboxField.d.ts.map +1 -0
- package/dist/components/privacy-policy/shared/CheckboxGroup.d.ts +13 -0
- package/dist/components/privacy-policy/shared/CheckboxGroup.d.ts.map +1 -0
- package/dist/components/privacy-policy/shared/FormField.d.ts +13 -0
- package/dist/components/privacy-policy/shared/FormField.d.ts.map +1 -0
- package/dist/components/privacy-policy/shared/StepIndicator.d.ts +8 -0
- package/dist/components/privacy-policy/shared/StepIndicator.d.ts.map +1 -0
- package/dist/components/privacy-policy/steps/CustomSectionsStep.d.ts +15 -0
- package/dist/components/privacy-policy/steps/CustomSectionsStep.d.ts.map +1 -0
- package/dist/components/privacy-policy/steps/DataCollectionStep.d.ts +20 -0
- package/dist/components/privacy-policy/steps/DataCollectionStep.d.ts.map +1 -0
- package/dist/components/privacy-policy/steps/DataSharingStep.d.ts +34 -0
- package/dist/components/privacy-policy/steps/DataSharingStep.d.ts.map +1 -0
- package/dist/components/privacy-policy/steps/OrganizationInfoStep.d.ts +17 -0
- package/dist/components/privacy-policy/steps/OrganizationInfoStep.d.ts.map +1 -0
- package/dist/components/privacy-policy/steps/PolicyPreviewStep.d.ts +30 -0
- package/dist/components/privacy-policy/steps/PolicyPreviewStep.d.ts.map +1 -0
- package/dist/components/ui/Badge.d.ts +10 -0
- package/dist/components/ui/Badge.d.ts.map +1 -0
- package/dist/components/ui/Button.d.ts +11 -0
- package/dist/components/ui/Button.d.ts.map +1 -0
- package/dist/components/ui/Card.d.ts +10 -0
- package/dist/components/ui/Card.d.ts.map +1 -0
- package/dist/components/ui/Checkbox.d.ts +8 -0
- package/dist/components/ui/Checkbox.d.ts.map +1 -0
- package/dist/components/ui/FormField.d.ts +11 -0
- package/dist/components/ui/FormField.d.ts.map +1 -0
- package/dist/components/ui/Input.d.ts +6 -0
- package/dist/components/ui/Input.d.ts.map +1 -0
- package/dist/components/ui/Select.d.ts +6 -0
- package/dist/components/ui/Select.d.ts.map +1 -0
- package/dist/components/ui/TextArea.d.ts +6 -0
- package/dist/components/ui/TextArea.d.ts.map +1 -0
- package/dist/components/ui/dialog.d.ts +18 -0
- package/dist/components/ui/dialog.d.ts.map +1 -0
- package/dist/components/ui/label.d.ts +5 -0
- package/dist/components/ui/label.d.ts.map +1 -0
- package/dist/components/ui/switch.d.ts +5 -0
- package/dist/components/ui/switch.d.ts.map +1 -0
- package/dist/components/ui/tabs.d.ts +8 -0
- package/dist/components/ui/tabs.d.ts.map +1 -0
- package/dist/contexts/ConsentContext.d.ts +35 -0
- package/dist/contexts/ConsentContext.d.ts.map +1 -0
- package/dist/contexts/GenericConsentContext.d.ts +11 -0
- package/dist/contexts/GenericConsentContext.d.ts.map +1 -0
- package/dist/hooks/useConsent.d.ts +12 -0
- package/dist/hooks/useConsent.d.ts.map +1 -0
- package/dist/hooks/useConsentActions.d.ts +12 -0
- package/dist/hooks/useConsentActions.d.ts.map +1 -0
- package/dist/hooks/useConsentManager.d.ts +14 -0
- package/dist/hooks/useConsentManager.d.ts.map +1 -0
- package/dist/hooks/useConsentState.d.ts +10 -0
- package/dist/hooks/useConsentState.d.ts.map +1 -0
- package/dist/index.d.mts +256 -0
- package/dist/index.d.ts +24 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +2 -0
- package/dist/index.mjs.map +1 -0
- package/dist/lib/consentService.d.ts +11 -0
- package/dist/lib/consentService.d.ts.map +1 -0
- package/dist/lib/dpiaQuestions.d.ts +3 -0
- package/dist/lib/dpiaQuestions.d.ts.map +1 -0
- package/dist/lib/requestService.d.ts +10 -0
- package/dist/lib/requestService.d.ts.map +1 -0
- package/dist/lib/utils.d.ts +3 -0
- package/dist/lib/utils.d.ts.map +1 -0
- package/dist/styles.css +38 -0
- package/dist/types/consent.d.ts +57 -0
- package/dist/types/consent.d.ts.map +1 -0
- package/dist/types/index.d.ts +91 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/unstyled.d.mts +22 -0
- package/dist/unstyled.d.ts +2 -0
- package/dist/unstyled.d.ts.map +1 -0
- package/dist/unstyled.js +2 -0
- package/dist/unstyled.js.map +1 -0
- package/dist/unstyled.mjs +2 -0
- package/dist/unstyled.mjs.map +1 -0
- package/package.json +33 -5
- package/CHANGELOG.md +0 -16
- package/CNAME +0 -1
- package/CONTRIBUTING.md +0 -87
- package/RELEASE-NOTES-v1.0.0.md +0 -140
- package/RELEASE-NOTES-v1.0.1.md +0 -69
- package/SECURITY.md +0 -21
- package/components.json +0 -21
- package/eslint.config.mjs +0 -16
- package/next-env.d.ts +0 -5
- package/next.config.js +0 -15
- package/next.config.ts +0 -62
- package/packages/ndpr-toolkit/README.md +0 -467
- package/packages/ndpr-toolkit/dist/components/breach/BreachNotificationManager.d.ts +0 -62
- package/packages/ndpr-toolkit/dist/components/breach/BreachReportForm.d.ts +0 -66
- package/packages/ndpr-toolkit/dist/components/breach/BreachRiskAssessment.d.ts +0 -50
- package/packages/ndpr-toolkit/dist/components/breach/RegulatoryReportGenerator.d.ts +0 -94
- package/packages/ndpr-toolkit/dist/components/consent/ConsentBanner.d.ts +0 -79
- package/packages/ndpr-toolkit/dist/components/consent/ConsentManager.d.ts +0 -73
- package/packages/ndpr-toolkit/dist/components/consent/ConsentStorage.d.ts +0 -41
- package/packages/ndpr-toolkit/dist/components/dpia/DPIAQuestionnaire.d.ts +0 -70
- package/packages/ndpr-toolkit/dist/components/dpia/DPIAReport.d.ts +0 -40
- package/packages/ndpr-toolkit/dist/components/dpia/StepIndicator.d.ts +0 -64
- package/packages/ndpr-toolkit/dist/components/dsr/DSRDashboard.d.ts +0 -58
- package/packages/ndpr-toolkit/dist/components/dsr/DSRRequestForm.d.ts +0 -74
- package/packages/ndpr-toolkit/dist/components/dsr/DSRTracker.d.ts +0 -56
- package/packages/ndpr-toolkit/dist/components/policy/PolicyExporter.d.ts +0 -65
- package/packages/ndpr-toolkit/dist/components/policy/PolicyGenerator.d.ts +0 -54
- package/packages/ndpr-toolkit/dist/components/policy/PolicyPreview.d.ts +0 -71
- package/packages/ndpr-toolkit/dist/hooks/useBreach.d.ts +0 -97
- package/packages/ndpr-toolkit/dist/hooks/useConsent.d.ts +0 -63
- package/packages/ndpr-toolkit/dist/hooks/useDPIA.d.ts +0 -92
- package/packages/ndpr-toolkit/dist/hooks/useDSR.d.ts +0 -72
- package/packages/ndpr-toolkit/dist/hooks/usePrivacyPolicy.d.ts +0 -87
- package/packages/ndpr-toolkit/dist/index.d.ts +0 -31
- package/packages/ndpr-toolkit/dist/index.esm.js +0 -2
- package/packages/ndpr-toolkit/dist/index.esm.js.map +0 -1
- package/packages/ndpr-toolkit/dist/index.js +0 -2
- package/packages/ndpr-toolkit/dist/index.js.map +0 -1
- package/packages/ndpr-toolkit/dist/setupTests.d.ts +0 -2
- package/packages/ndpr-toolkit/dist/types/breach.d.ts +0 -239
- package/packages/ndpr-toolkit/dist/types/consent.d.ts +0 -95
- package/packages/ndpr-toolkit/dist/types/dpia.d.ts +0 -196
- package/packages/ndpr-toolkit/dist/types/dsr.d.ts +0 -162
- package/packages/ndpr-toolkit/dist/types/privacy.d.ts +0 -204
- package/packages/ndpr-toolkit/dist/utils/breach.d.ts +0 -14
- package/packages/ndpr-toolkit/dist/utils/consent.d.ts +0 -10
- package/packages/ndpr-toolkit/dist/utils/dpia.d.ts +0 -12
- package/packages/ndpr-toolkit/dist/utils/dsr.d.ts +0 -11
- package/packages/ndpr-toolkit/dist/utils/privacy.d.ts +0 -12
- package/packages/ndpr-toolkit/package-lock.json +0 -8197
- package/packages/ndpr-toolkit/package.json +0 -71
- package/packages/ndpr-toolkit/rollup.config.js +0 -34
- package/packages/ndpr-toolkit/src/components/breach/BreachNotificationManager.tsx +0 -701
- package/packages/ndpr-toolkit/src/components/breach/BreachReportForm.tsx +0 -631
- package/packages/ndpr-toolkit/src/components/breach/BreachRiskAssessment.tsx +0 -569
- package/packages/ndpr-toolkit/src/components/breach/RegulatoryReportGenerator.tsx +0 -496
- package/packages/ndpr-toolkit/src/components/consent/ConsentBanner.tsx +0 -270
- package/packages/ndpr-toolkit/src/components/consent/ConsentManager.tsx +0 -217
- package/packages/ndpr-toolkit/src/components/consent/ConsentStorage.tsx +0 -206
- package/packages/ndpr-toolkit/src/components/dpia/DPIAQuestionnaire.tsx +0 -342
- package/packages/ndpr-toolkit/src/components/dpia/DPIAReport.tsx +0 -373
- package/packages/ndpr-toolkit/src/components/dpia/StepIndicator.tsx +0 -174
- package/packages/ndpr-toolkit/src/components/dsr/DSRDashboard.tsx +0 -717
- package/packages/ndpr-toolkit/src/components/dsr/DSRRequestForm.tsx +0 -476
- package/packages/ndpr-toolkit/src/components/dsr/DSRTracker.tsx +0 -620
- package/packages/ndpr-toolkit/src/components/policy/PolicyExporter.tsx +0 -541
- package/packages/ndpr-toolkit/src/components/policy/PolicyGenerator.tsx +0 -454
- package/packages/ndpr-toolkit/src/components/policy/PolicyPreview.tsx +0 -333
- package/packages/ndpr-toolkit/src/hooks/useBreach.ts +0 -409
- package/packages/ndpr-toolkit/src/hooks/useConsent.ts +0 -263
- package/packages/ndpr-toolkit/src/hooks/useDPIA.ts +0 -457
- package/packages/ndpr-toolkit/src/hooks/useDSR.ts +0 -236
- package/packages/ndpr-toolkit/src/hooks/usePrivacyPolicy.ts +0 -428
- package/packages/ndpr-toolkit/src/index.ts +0 -44
- package/packages/ndpr-toolkit/src/setupTests.ts +0 -5
- package/packages/ndpr-toolkit/src/types/breach.ts +0 -283
- package/packages/ndpr-toolkit/src/types/consent.ts +0 -111
- package/packages/ndpr-toolkit/src/types/dpia.ts +0 -236
- package/packages/ndpr-toolkit/src/types/dsr.ts +0 -192
- package/packages/ndpr-toolkit/src/types/index.ts +0 -42
- package/packages/ndpr-toolkit/src/types/privacy.ts +0 -246
- package/packages/ndpr-toolkit/src/utils/breach.ts +0 -122
- package/packages/ndpr-toolkit/src/utils/consent.ts +0 -51
- package/packages/ndpr-toolkit/src/utils/dpia.ts +0 -104
- package/packages/ndpr-toolkit/src/utils/dsr.ts +0 -77
- package/packages/ndpr-toolkit/src/utils/privacy.ts +0 -100
- package/packages/ndpr-toolkit/tsconfig.json +0 -23
- package/postcss.config.mjs +0 -5
- package/public/NDPR TOOLKIT.svg +0 -1
- package/public/favicon/android-chrome-192x192.png +0 -0
- package/public/favicon/android-chrome-512x512.png +0 -0
- package/public/favicon/apple-touch-icon.png +0 -0
- package/public/favicon/favicon-16x16.png +0 -0
- package/public/favicon/favicon-32x32.png +0 -0
- package/public/favicon/site.webmanifest +0 -1
- package/public/file.svg +0 -1
- package/public/globe.svg +0 -1
- package/public/ndpr-toolkit-logo.svg +0 -108
- package/public/next.svg +0 -1
- package/public/vercel.svg +0 -1
- package/public/window.svg +0 -1
- package/src/app/accessibility.css +0 -70
- package/src/app/favicon.ico +0 -0
- package/src/app/globals.css +0 -123
- package/src/app/layout.tsx +0 -37
- package/src/app/ndpr-demos/breach/page.tsx +0 -354
- package/src/app/ndpr-demos/consent/page.tsx +0 -366
- package/src/app/ndpr-demos/dpia/page.tsx +0 -495
- package/src/app/ndpr-demos/dsr/page.tsx +0 -280
- package/src/app/ndpr-demos/page.tsx +0 -73
- package/src/app/ndpr-demos/policy/page.tsx +0 -771
- package/src/app/page.tsx +0 -452
- package/src/components/ErrorBoundary.tsx +0 -90
- package/src/components/breach-notification/BreachNotificationForm.tsx +0 -479
- package/src/components/consent/ConsentBanner.tsx +0 -193
- package/src/components/data-subject-rights/DataSubjectRequestForm.tsx +0 -530
- package/src/components/dpia/DPIAQuestionnaire.tsx +0 -523
- package/src/components/privacy-policy/PolicyGenerator.tsx +0 -1062
- package/src/components/privacy-policy/data.ts +0 -98
- package/src/components/privacy-policy/shared/CheckboxField.tsx +0 -38
- package/src/components/privacy-policy/shared/CheckboxGroup.tsx +0 -85
- package/src/components/privacy-policy/shared/FormField.tsx +0 -79
- package/src/components/privacy-policy/shared/StepIndicator.tsx +0 -86
- package/src/components/privacy-policy/steps/CustomSectionsStep.tsx +0 -361
- package/src/components/privacy-policy/steps/DataCollectionStep.tsx +0 -231
- package/src/components/privacy-policy/steps/DataSharingStep.tsx +0 -418
- package/src/components/privacy-policy/steps/OrganizationInfoStep.tsx +0 -202
- package/src/components/privacy-policy/steps/PolicyPreviewStep.tsx +0 -226
- package/src/components/ui/Badge.tsx +0 -46
- package/src/components/ui/Button.tsx +0 -59
- package/src/components/ui/Card.tsx +0 -92
- package/src/components/ui/Checkbox.tsx +0 -57
- package/src/components/ui/FormField.tsx +0 -50
- package/src/components/ui/Input.tsx +0 -38
- package/src/components/ui/Loading.tsx +0 -201
- package/src/components/ui/Select.tsx +0 -42
- package/src/components/ui/TextArea.tsx +0 -38
- package/src/components/ui/label.tsx +0 -24
- package/src/components/ui/switch.tsx +0 -31
- package/src/components/ui/tabs.tsx +0 -66
- package/src/hooks/useConsent.ts +0 -70
- package/src/hooks/useLoadingState.ts +0 -85
- package/src/lib/consentService.ts +0 -144
- package/src/lib/dpiaQuestions.ts +0 -188
- package/src/lib/requestService.ts +0 -79
- package/src/lib/sanitize.ts +0 -108
- package/src/lib/storage.ts +0 -222
- package/src/lib/utils.ts +0 -6
- package/src/types/html-to-docx.d.ts +0 -30
- package/src/types/index.ts +0 -77
- package/tailwind.config.ts +0 -65
- package/tsconfig.json +0 -41
|
@@ -1,457 +0,0 @@
|
|
|
1
|
-
import { useState, useEffect } from 'react';
|
|
2
|
-
import { DPIAQuestion, DPIASection, DPIAResult, DPIARisk } from '../types/dpia';
|
|
3
|
-
import { assessDPIARisk } from '../utils/dpia';
|
|
4
|
-
|
|
5
|
-
interface UseDPIAOptions {
|
|
6
|
-
/**
|
|
7
|
-
* Sections of the DPIA questionnaire
|
|
8
|
-
*/
|
|
9
|
-
sections: DPIASection[];
|
|
10
|
-
|
|
11
|
-
/**
|
|
12
|
-
* Initial answers (if resuming a DPIA)
|
|
13
|
-
*/
|
|
14
|
-
initialAnswers?: Record<string, any>;
|
|
15
|
-
|
|
16
|
-
/**
|
|
17
|
-
* Storage key for DPIA data
|
|
18
|
-
* @default "ndpr_dpia_data"
|
|
19
|
-
*/
|
|
20
|
-
storageKey?: string;
|
|
21
|
-
|
|
22
|
-
/**
|
|
23
|
-
* Whether to use local storage to persist DPIA data
|
|
24
|
-
* @default true
|
|
25
|
-
*/
|
|
26
|
-
useLocalStorage?: boolean;
|
|
27
|
-
|
|
28
|
-
/**
|
|
29
|
-
* Callback function called when the DPIA is completed
|
|
30
|
-
*/
|
|
31
|
-
onComplete?: (result: DPIAResult) => void;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
interface UseDPIAReturn {
|
|
35
|
-
/**
|
|
36
|
-
* Current section index
|
|
37
|
-
*/
|
|
38
|
-
currentSectionIndex: number;
|
|
39
|
-
|
|
40
|
-
/**
|
|
41
|
-
* Current section
|
|
42
|
-
*/
|
|
43
|
-
currentSection: DPIASection | null;
|
|
44
|
-
|
|
45
|
-
/**
|
|
46
|
-
* All answers
|
|
47
|
-
*/
|
|
48
|
-
answers: Record<string, any>;
|
|
49
|
-
|
|
50
|
-
/**
|
|
51
|
-
* Update an answer
|
|
52
|
-
*/
|
|
53
|
-
updateAnswer: (questionId: string, value: any) => void;
|
|
54
|
-
|
|
55
|
-
/**
|
|
56
|
-
* Go to the next section
|
|
57
|
-
*/
|
|
58
|
-
nextSection: () => boolean;
|
|
59
|
-
|
|
60
|
-
/**
|
|
61
|
-
* Go to the previous section
|
|
62
|
-
*/
|
|
63
|
-
prevSection: () => boolean;
|
|
64
|
-
|
|
65
|
-
/**
|
|
66
|
-
* Go to a specific section
|
|
67
|
-
*/
|
|
68
|
-
goToSection: (index: number) => boolean;
|
|
69
|
-
|
|
70
|
-
/**
|
|
71
|
-
* Check if the current section is valid
|
|
72
|
-
*/
|
|
73
|
-
isCurrentSectionValid: () => boolean;
|
|
74
|
-
|
|
75
|
-
/**
|
|
76
|
-
* Get validation errors for the current section
|
|
77
|
-
*/
|
|
78
|
-
getCurrentSectionErrors: () => Record<string, string>;
|
|
79
|
-
|
|
80
|
-
/**
|
|
81
|
-
* Check if the DPIA is complete
|
|
82
|
-
*/
|
|
83
|
-
isComplete: () => boolean;
|
|
84
|
-
|
|
85
|
-
/**
|
|
86
|
-
* Complete the DPIA and generate a result
|
|
87
|
-
*/
|
|
88
|
-
completeDPIA: (assessorInfo: { name: string; role: string; email: string; }, title: string, processingDescription: string) => DPIAResult;
|
|
89
|
-
|
|
90
|
-
/**
|
|
91
|
-
* Get the visible questions for the current section
|
|
92
|
-
*/
|
|
93
|
-
getVisibleQuestions: () => DPIAQuestion[];
|
|
94
|
-
|
|
95
|
-
/**
|
|
96
|
-
* Reset the DPIA
|
|
97
|
-
*/
|
|
98
|
-
resetDPIA: () => void;
|
|
99
|
-
|
|
100
|
-
/**
|
|
101
|
-
* Progress percentage
|
|
102
|
-
*/
|
|
103
|
-
progress: number;
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
/**
|
|
107
|
-
* Hook for conducting Data Protection Impact Assessments in compliance with NDPR
|
|
108
|
-
*/
|
|
109
|
-
export function useDPIA({
|
|
110
|
-
sections,
|
|
111
|
-
initialAnswers = {},
|
|
112
|
-
storageKey = "ndpr_dpia_data",
|
|
113
|
-
useLocalStorage = true,
|
|
114
|
-
onComplete
|
|
115
|
-
}: UseDPIAOptions): UseDPIAReturn {
|
|
116
|
-
const [currentSectionIndex, setCurrentSectionIndex] = useState<number>(0);
|
|
117
|
-
const [answers, setAnswers] = useState<Record<string, any>>(initialAnswers);
|
|
118
|
-
|
|
119
|
-
// Load DPIA data from storage on mount
|
|
120
|
-
useEffect(() => {
|
|
121
|
-
if (useLocalStorage && typeof window !== 'undefined') {
|
|
122
|
-
try {
|
|
123
|
-
const savedData = localStorage.getItem(storageKey);
|
|
124
|
-
if (savedData) {
|
|
125
|
-
const { answers: savedAnswers, sectionIndex } = JSON.parse(savedData);
|
|
126
|
-
setAnswers(savedAnswers || {});
|
|
127
|
-
setCurrentSectionIndex(sectionIndex || 0);
|
|
128
|
-
}
|
|
129
|
-
} catch (error) {
|
|
130
|
-
console.error('Error loading DPIA data:', error);
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
}, [storageKey, useLocalStorage]);
|
|
134
|
-
|
|
135
|
-
// Save DPIA data to storage when it changes
|
|
136
|
-
useEffect(() => {
|
|
137
|
-
if (useLocalStorage && typeof window !== 'undefined') {
|
|
138
|
-
try {
|
|
139
|
-
localStorage.setItem(storageKey, JSON.stringify({
|
|
140
|
-
answers,
|
|
141
|
-
sectionIndex: currentSectionIndex
|
|
142
|
-
}));
|
|
143
|
-
} catch (error) {
|
|
144
|
-
console.error('Error saving DPIA data:', error);
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
}, [answers, currentSectionIndex, storageKey, useLocalStorage]);
|
|
148
|
-
|
|
149
|
-
// Get the current section
|
|
150
|
-
const currentSection = sections[currentSectionIndex] || null;
|
|
151
|
-
|
|
152
|
-
// Update an answer
|
|
153
|
-
const updateAnswer = (questionId: string, value: any) => {
|
|
154
|
-
setAnswers(prevAnswers => ({
|
|
155
|
-
...prevAnswers,
|
|
156
|
-
[questionId]: value
|
|
157
|
-
}));
|
|
158
|
-
};
|
|
159
|
-
|
|
160
|
-
// Check if a question should be shown based on its conditions
|
|
161
|
-
const shouldShowQuestion = (question: DPIAQuestion): boolean => {
|
|
162
|
-
if (!question.showWhen) {
|
|
163
|
-
return true;
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
return question.showWhen.every(condition => {
|
|
167
|
-
const answer = answers[condition.questionId];
|
|
168
|
-
|
|
169
|
-
switch (condition.operator) {
|
|
170
|
-
case 'equals':
|
|
171
|
-
return answer === condition.value;
|
|
172
|
-
case 'contains':
|
|
173
|
-
return Array.isArray(answer) ? answer.includes(condition.value) : false;
|
|
174
|
-
case 'greaterThan':
|
|
175
|
-
return typeof answer === 'number' ? answer > condition.value : false;
|
|
176
|
-
case 'lessThan':
|
|
177
|
-
return typeof answer === 'number' ? answer < condition.value : false;
|
|
178
|
-
default:
|
|
179
|
-
return true;
|
|
180
|
-
}
|
|
181
|
-
});
|
|
182
|
-
};
|
|
183
|
-
|
|
184
|
-
// Get the visible questions for the current section
|
|
185
|
-
const getVisibleQuestions = (): DPIAQuestion[] => {
|
|
186
|
-
if (!currentSection) {
|
|
187
|
-
return [];
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
return currentSection.questions.filter(shouldShowQuestion);
|
|
191
|
-
};
|
|
192
|
-
|
|
193
|
-
// Check if the current section is valid
|
|
194
|
-
const isCurrentSectionValid = (): boolean => {
|
|
195
|
-
if (!currentSection) {
|
|
196
|
-
return false;
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
const visibleQuestions = getVisibleQuestions();
|
|
200
|
-
|
|
201
|
-
return visibleQuestions.every(question => {
|
|
202
|
-
if (!question.required) {
|
|
203
|
-
return true;
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
const answer = answers[question.id];
|
|
207
|
-
|
|
208
|
-
if (answer === undefined || answer === null) {
|
|
209
|
-
return false;
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
if (typeof answer === 'string' && answer.trim() === '') {
|
|
213
|
-
return false;
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
if (Array.isArray(answer) && answer.length === 0) {
|
|
217
|
-
return false;
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
return true;
|
|
221
|
-
});
|
|
222
|
-
};
|
|
223
|
-
|
|
224
|
-
// Get validation errors for the current section
|
|
225
|
-
const getCurrentSectionErrors = (): Record<string, string> => {
|
|
226
|
-
const errors: Record<string, string> = {};
|
|
227
|
-
|
|
228
|
-
if (!currentSection) {
|
|
229
|
-
return errors;
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
const visibleQuestions = getVisibleQuestions();
|
|
233
|
-
|
|
234
|
-
visibleQuestions.forEach(question => {
|
|
235
|
-
if (!question.required) {
|
|
236
|
-
return;
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
const answer = answers[question.id];
|
|
240
|
-
|
|
241
|
-
if (answer === undefined || answer === null) {
|
|
242
|
-
errors[question.id] = 'This question is required';
|
|
243
|
-
} else if (typeof answer === 'string' && answer.trim() === '') {
|
|
244
|
-
errors[question.id] = 'This question is required';
|
|
245
|
-
} else if (Array.isArray(answer) && answer.length === 0) {
|
|
246
|
-
errors[question.id] = 'At least one option must be selected';
|
|
247
|
-
}
|
|
248
|
-
});
|
|
249
|
-
|
|
250
|
-
return errors;
|
|
251
|
-
};
|
|
252
|
-
|
|
253
|
-
// Go to the next section
|
|
254
|
-
const nextSection = (): boolean => {
|
|
255
|
-
if (!isCurrentSectionValid()) {
|
|
256
|
-
return false;
|
|
257
|
-
}
|
|
258
|
-
|
|
259
|
-
if (currentSectionIndex < sections.length - 1) {
|
|
260
|
-
setCurrentSectionIndex(prevIndex => prevIndex + 1);
|
|
261
|
-
return true;
|
|
262
|
-
}
|
|
263
|
-
|
|
264
|
-
return false;
|
|
265
|
-
};
|
|
266
|
-
|
|
267
|
-
// Go to the previous section
|
|
268
|
-
const prevSection = (): boolean => {
|
|
269
|
-
if (currentSectionIndex > 0) {
|
|
270
|
-
setCurrentSectionIndex(prevIndex => prevIndex - 1);
|
|
271
|
-
return true;
|
|
272
|
-
}
|
|
273
|
-
|
|
274
|
-
return false;
|
|
275
|
-
};
|
|
276
|
-
|
|
277
|
-
// Go to a specific section
|
|
278
|
-
const goToSection = (index: number): boolean => {
|
|
279
|
-
if (index >= 0 && index < sections.length) {
|
|
280
|
-
setCurrentSectionIndex(index);
|
|
281
|
-
return true;
|
|
282
|
-
}
|
|
283
|
-
|
|
284
|
-
return false;
|
|
285
|
-
};
|
|
286
|
-
|
|
287
|
-
// Check if the DPIA is complete
|
|
288
|
-
const isComplete = (): boolean => {
|
|
289
|
-
return sections.every((section, index) => {
|
|
290
|
-
// Temporarily set the current section to check ifit's valid
|
|
291
|
-
setCurrentSectionIndex(index);
|
|
292
|
-
const valid = isCurrentSectionValid();
|
|
293
|
-
// Restore the current section
|
|
294
|
-
setCurrentSectionIndex(currentSectionIndex);
|
|
295
|
-
return valid;
|
|
296
|
-
});
|
|
297
|
-
};
|
|
298
|
-
|
|
299
|
-
// Identify risks based on answers
|
|
300
|
-
const identifyRisks = (): DPIARisk[] => {
|
|
301
|
-
const risks: DPIARisk[] = [];
|
|
302
|
-
|
|
303
|
-
// Check each question for risk indicators
|
|
304
|
-
sections.forEach(section => {
|
|
305
|
-
section.questions.forEach(question => {
|
|
306
|
-
const answer = answers[question.id];
|
|
307
|
-
|
|
308
|
-
// Skip if no answer
|
|
309
|
-
if (answer === undefined || answer === null) {
|
|
310
|
-
return;
|
|
311
|
-
}
|
|
312
|
-
|
|
313
|
-
// Check if the question has a risk level
|
|
314
|
-
if (question.riskLevel) {
|
|
315
|
-
// For select/radio/checkbox questions, check if the selected option has a risk level
|
|
316
|
-
if (['select', 'radio', 'checkbox'].includes(question.type) && question.options) {
|
|
317
|
-
const selectedOptions = Array.isArray(answer) ? answer : [answer];
|
|
318
|
-
|
|
319
|
-
selectedOptions.forEach(selectedOption => {
|
|
320
|
-
const option = question.options?.find(opt => opt.value === selectedOption);
|
|
321
|
-
|
|
322
|
-
if (option?.riskLevel) {
|
|
323
|
-
const riskLevel = option.riskLevel;
|
|
324
|
-
const likelihood = riskLevel === 'low' ? 1 : riskLevel === 'medium' ? 3 : 5;
|
|
325
|
-
const impact = riskLevel === 'low' ? 1 : riskLevel === 'medium' ? 3 : 5;
|
|
326
|
-
|
|
327
|
-
risks.push({
|
|
328
|
-
id: `risk_${risks.length + 1}`,
|
|
329
|
-
description: `${question.text} - ${option.label}`,
|
|
330
|
-
likelihood,
|
|
331
|
-
impact,
|
|
332
|
-
score: likelihood * impact,
|
|
333
|
-
level: riskLevel,
|
|
334
|
-
mitigated: false,
|
|
335
|
-
relatedQuestionIds: [question.id]
|
|
336
|
-
});
|
|
337
|
-
}
|
|
338
|
-
});
|
|
339
|
-
} else {
|
|
340
|
-
// For other question types, use the question's risk level
|
|
341
|
-
const riskLevel = question.riskLevel;
|
|
342
|
-
const likelihood = riskLevel === 'low' ? 1 : riskLevel === 'medium' ? 3 : 5;
|
|
343
|
-
const impact = riskLevel === 'low' ? 1 : riskLevel === 'medium' ? 3 : 5;
|
|
344
|
-
|
|
345
|
-
risks.push({
|
|
346
|
-
id: `risk_${risks.length + 1}`,
|
|
347
|
-
description: question.text,
|
|
348
|
-
likelihood,
|
|
349
|
-
impact,
|
|
350
|
-
score: likelihood * impact,
|
|
351
|
-
level: riskLevel,
|
|
352
|
-
mitigated: false,
|
|
353
|
-
relatedQuestionIds: [question.id]
|
|
354
|
-
});
|
|
355
|
-
}
|
|
356
|
-
}
|
|
357
|
-
});
|
|
358
|
-
});
|
|
359
|
-
|
|
360
|
-
return risks;
|
|
361
|
-
};
|
|
362
|
-
|
|
363
|
-
// Complete the DPIA and generate a result
|
|
364
|
-
const completeDPIA = (
|
|
365
|
-
assessorInfo: { name: string; role: string; email: string; },
|
|
366
|
-
title: string,
|
|
367
|
-
processingDescription: string
|
|
368
|
-
): DPIAResult => {
|
|
369
|
-
const risks = identifyRisks();
|
|
370
|
-
|
|
371
|
-
const result: DPIAResult = {
|
|
372
|
-
id: `dpia_${Date.now()}`,
|
|
373
|
-
title,
|
|
374
|
-
processingDescription,
|
|
375
|
-
startedAt: Date.now(),
|
|
376
|
-
completedAt: Date.now(),
|
|
377
|
-
assessor: assessorInfo,
|
|
378
|
-
answers,
|
|
379
|
-
risks,
|
|
380
|
-
overallRiskLevel: 'low',
|
|
381
|
-
canProceed: true,
|
|
382
|
-
conclusion: '',
|
|
383
|
-
version: '1.0'
|
|
384
|
-
};
|
|
385
|
-
|
|
386
|
-
// Assess the risks
|
|
387
|
-
const assessment = assessDPIARisk(result);
|
|
388
|
-
|
|
389
|
-
result.overallRiskLevel = assessment.overallRiskLevel;
|
|
390
|
-
result.canProceed = assessment.canProceed;
|
|
391
|
-
result.conclusion = assessment.canProceed
|
|
392
|
-
? 'Based on the assessment, the processing can proceed with appropriate safeguards.'
|
|
393
|
-
: 'Based on the assessment, the processing should not proceed without further mitigation measures.';
|
|
394
|
-
result.recommendations = assessment.recommendations;
|
|
395
|
-
|
|
396
|
-
if (onComplete) {
|
|
397
|
-
onComplete(result);
|
|
398
|
-
}
|
|
399
|
-
|
|
400
|
-
return result;
|
|
401
|
-
};
|
|
402
|
-
|
|
403
|
-
// Reset the DPIA
|
|
404
|
-
const resetDPIA = () => {
|
|
405
|
-
setAnswers({});
|
|
406
|
-
setCurrentSectionIndex(0);
|
|
407
|
-
|
|
408
|
-
if (useLocalStorage && typeof window !== 'undefined') {
|
|
409
|
-
localStorage.removeItem(storageKey);
|
|
410
|
-
}
|
|
411
|
-
};
|
|
412
|
-
|
|
413
|
-
// Calculate progress percentage
|
|
414
|
-
const progress = (() => {
|
|
415
|
-
let answeredQuestions = 0;
|
|
416
|
-
let totalRequiredQuestions = 0;
|
|
417
|
-
|
|
418
|
-
sections.forEach(section => {
|
|
419
|
-
section.questions.forEach(question => {
|
|
420
|
-
if (question.required && shouldShowQuestion(question)) {
|
|
421
|
-
totalRequiredQuestions++;
|
|
422
|
-
|
|
423
|
-
const answer = answers[question.id];
|
|
424
|
-
if (
|
|
425
|
-
answer !== undefined &&
|
|
426
|
-
answer !== null &&
|
|
427
|
-
!(typeof answer === 'string' && answer.trim() === '') &&
|
|
428
|
-
!(Array.isArray(answer) && answer.length === 0)
|
|
429
|
-
) {
|
|
430
|
-
answeredQuestions++;
|
|
431
|
-
}
|
|
432
|
-
}
|
|
433
|
-
});
|
|
434
|
-
});
|
|
435
|
-
|
|
436
|
-
return totalRequiredQuestions > 0
|
|
437
|
-
? Math.round((answeredQuestions / totalRequiredQuestions) * 100)
|
|
438
|
-
: 0;
|
|
439
|
-
})();
|
|
440
|
-
|
|
441
|
-
return {
|
|
442
|
-
currentSectionIndex,
|
|
443
|
-
currentSection,
|
|
444
|
-
answers,
|
|
445
|
-
updateAnswer,
|
|
446
|
-
nextSection,
|
|
447
|
-
prevSection,
|
|
448
|
-
goToSection,
|
|
449
|
-
isCurrentSectionValid,
|
|
450
|
-
getCurrentSectionErrors,
|
|
451
|
-
isComplete,
|
|
452
|
-
completeDPIA,
|
|
453
|
-
getVisibleQuestions,
|
|
454
|
-
resetDPIA,
|
|
455
|
-
progress
|
|
456
|
-
};
|
|
457
|
-
}
|
|
@@ -1,236 +0,0 @@
|
|
|
1
|
-
import { useState, useEffect } from 'react';
|
|
2
|
-
import { DSRRequest, RequestStatus, RequestType } from '../types/dsr';
|
|
3
|
-
import { formatDSRRequest } from '../utils/dsr';
|
|
4
|
-
|
|
5
|
-
interface UseDSROptions {
|
|
6
|
-
/**
|
|
7
|
-
* Initial requests to load
|
|
8
|
-
*/
|
|
9
|
-
initialRequests?: DSRRequest[];
|
|
10
|
-
|
|
11
|
-
/**
|
|
12
|
-
* Available request types
|
|
13
|
-
*/
|
|
14
|
-
requestTypes: RequestType[];
|
|
15
|
-
|
|
16
|
-
/**
|
|
17
|
-
* Storage key for requests
|
|
18
|
-
* @default "ndpr_dsr_requests"
|
|
19
|
-
*/
|
|
20
|
-
storageKey?: string;
|
|
21
|
-
|
|
22
|
-
/**
|
|
23
|
-
* Whether to use local storage to persist requests
|
|
24
|
-
* @default true
|
|
25
|
-
*/
|
|
26
|
-
useLocalStorage?: boolean;
|
|
27
|
-
|
|
28
|
-
/**
|
|
29
|
-
* Callback function called when a request is submitted
|
|
30
|
-
*/
|
|
31
|
-
onSubmit?: (request: DSRRequest) => void;
|
|
32
|
-
|
|
33
|
-
/**
|
|
34
|
-
* Callback function called when a request is updated
|
|
35
|
-
*/
|
|
36
|
-
onUpdate?: (request: DSRRequest) => void;
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
interface UseDSRReturn {
|
|
40
|
-
/**
|
|
41
|
-
* All requests
|
|
42
|
-
*/
|
|
43
|
-
requests: DSRRequest[];
|
|
44
|
-
|
|
45
|
-
/**
|
|
46
|
-
* Submit a new request
|
|
47
|
-
*/
|
|
48
|
-
submitRequest: (requestData: Omit<DSRRequest, 'id' | 'status' | 'submittedAt' | 'updatedAt' | 'estimatedCompletionDate'>) => DSRRequest;
|
|
49
|
-
|
|
50
|
-
/**
|
|
51
|
-
* Update an existing request
|
|
52
|
-
*/
|
|
53
|
-
updateRequest: (id: string, updates: Partial<DSRRequest>) => DSRRequest | null;
|
|
54
|
-
|
|
55
|
-
/**
|
|
56
|
-
* Get a request by ID
|
|
57
|
-
*/
|
|
58
|
-
getRequest: (id: string) => DSRRequest | null;
|
|
59
|
-
|
|
60
|
-
/**
|
|
61
|
-
* Get requests by status
|
|
62
|
-
*/
|
|
63
|
-
getRequestsByStatus: (status: RequestStatus) => DSRRequest[];
|
|
64
|
-
|
|
65
|
-
/**
|
|
66
|
-
* Get requests by type
|
|
67
|
-
*/
|
|
68
|
-
getRequestsByType: (type: string) => DSRRequest[];
|
|
69
|
-
|
|
70
|
-
/**
|
|
71
|
-
* Get the request type definition by ID
|
|
72
|
-
*/
|
|
73
|
-
getRequestType: (typeId: string) => RequestType | undefined;
|
|
74
|
-
|
|
75
|
-
/**
|
|
76
|
-
* Format a request for display or submission
|
|
77
|
-
*/
|
|
78
|
-
formatRequest: (request: DSRRequest) => Record<string, any>;
|
|
79
|
-
|
|
80
|
-
/**
|
|
81
|
-
* Clear all requests
|
|
82
|
-
*/
|
|
83
|
-
clearRequests: () => void;
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
/**
|
|
87
|
-
* Hook for managing Data Subject Requests in compliance with NDPR
|
|
88
|
-
*/
|
|
89
|
-
export function useDSR({
|
|
90
|
-
initialRequests = [],
|
|
91
|
-
requestTypes,
|
|
92
|
-
storageKey = "ndpr_dsr_requests",
|
|
93
|
-
useLocalStorage = true,
|
|
94
|
-
onSubmit,
|
|
95
|
-
onUpdate
|
|
96
|
-
}: UseDSROptions): UseDSRReturn {
|
|
97
|
-
const [requests, setRequests] = useState<DSRRequest[]>(initialRequests);
|
|
98
|
-
|
|
99
|
-
// Load requests from storage on mount
|
|
100
|
-
useEffect(() => {
|
|
101
|
-
if (useLocalStorage && typeof window !== 'undefined') {
|
|
102
|
-
try {
|
|
103
|
-
const savedRequests = localStorage.getItem(storageKey);
|
|
104
|
-
if (savedRequests) {
|
|
105
|
-
setRequests(JSON.parse(savedRequests));
|
|
106
|
-
}
|
|
107
|
-
} catch (error) {
|
|
108
|
-
console.error('Error loading DSR requests:', error);
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
}, [storageKey, useLocalStorage]);
|
|
112
|
-
|
|
113
|
-
// Save requests to storage when they change
|
|
114
|
-
useEffect(() => {
|
|
115
|
-
if (useLocalStorage && typeof window !== 'undefined' && requests.length > 0) {
|
|
116
|
-
try {
|
|
117
|
-
localStorage.setItem(storageKey, JSON.stringify(requests));
|
|
118
|
-
} catch (error) {
|
|
119
|
-
console.error('Error saving DSR requests:', error);
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
}, [requests, storageKey, useLocalStorage]);
|
|
123
|
-
|
|
124
|
-
// Generate a unique ID
|
|
125
|
-
const generateId = (): string => {
|
|
126
|
-
return 'dsr_' + Date.now() + '_' + Math.random().toString(36).substr(2, 9);
|
|
127
|
-
};
|
|
128
|
-
|
|
129
|
-
// Submit a new request
|
|
130
|
-
const submitRequest = (requestData: Omit<DSRRequest, 'id' | 'status' | 'submittedAt' | 'updatedAt' | 'estimatedCompletionDate'>): DSRRequest => {
|
|
131
|
-
// Find the request type to get the estimated completion time
|
|
132
|
-
const requestType = requestTypes.find(type => type.id === requestData.type);
|
|
133
|
-
const estimatedCompletionDays = requestType?.estimatedCompletionTime || 30; // Default to 30 days
|
|
134
|
-
|
|
135
|
-
const now = Date.now();
|
|
136
|
-
const estimatedCompletionDate = now + (estimatedCompletionDays * 24 * 60 * 60 * 1000);
|
|
137
|
-
|
|
138
|
-
// Extract any properties we want to override from requestData
|
|
139
|
-
const { createdAt, ...restRequestData } = requestData as any;
|
|
140
|
-
|
|
141
|
-
const newRequest: DSRRequest = {
|
|
142
|
-
id: generateId(),
|
|
143
|
-
status: 'pending',
|
|
144
|
-
createdAt: now,
|
|
145
|
-
updatedAt: now,
|
|
146
|
-
dueDate: estimatedCompletionDate,
|
|
147
|
-
...restRequestData
|
|
148
|
-
};
|
|
149
|
-
|
|
150
|
-
setRequests(prevRequests => [...prevRequests, newRequest]);
|
|
151
|
-
|
|
152
|
-
if (onSubmit) {
|
|
153
|
-
onSubmit(newRequest);
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
return newRequest;
|
|
157
|
-
};
|
|
158
|
-
|
|
159
|
-
// Update an existing request
|
|
160
|
-
const updateRequest = (id: string, updates: Partial<DSRRequest>): DSRRequest | null => {
|
|
161
|
-
let updatedRequest: DSRRequest | null = null;
|
|
162
|
-
|
|
163
|
-
setRequests(prevRequests => {
|
|
164
|
-
const index = prevRequests.findIndex(request => request.id === id);
|
|
165
|
-
|
|
166
|
-
if (index === -1) {
|
|
167
|
-
return prevRequests;
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
const request = prevRequests[index];
|
|
171
|
-
updatedRequest = {
|
|
172
|
-
...request,
|
|
173
|
-
...updates,
|
|
174
|
-
updatedAt: Date.now()
|
|
175
|
-
};
|
|
176
|
-
|
|
177
|
-
const newRequests = [...prevRequests];
|
|
178
|
-
newRequests[index] = updatedRequest as DSRRequest;
|
|
179
|
-
|
|
180
|
-
return newRequests;
|
|
181
|
-
});
|
|
182
|
-
|
|
183
|
-
if (updatedRequest && onUpdate) {
|
|
184
|
-
onUpdate(updatedRequest);
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
return updatedRequest;
|
|
188
|
-
};
|
|
189
|
-
|
|
190
|
-
// Get a request by ID
|
|
191
|
-
const getRequest = (id: string): DSRRequest | null => {
|
|
192
|
-
return requests.find(request => request.id === id) || null;
|
|
193
|
-
};
|
|
194
|
-
|
|
195
|
-
// Get requests by status
|
|
196
|
-
const getRequestsByStatus = (status: RequestStatus): DSRRequest[] => {
|
|
197
|
-
return requests.filter(request => request.status === status);
|
|
198
|
-
};
|
|
199
|
-
|
|
200
|
-
// Get requests by type
|
|
201
|
-
const getRequestsByType = (type: string): DSRRequest[] => {
|
|
202
|
-
return requests.filter(request => request.type === type);
|
|
203
|
-
};
|
|
204
|
-
|
|
205
|
-
// Get the request type definition by ID
|
|
206
|
-
const getRequestType = (typeId: string): RequestType | undefined => {
|
|
207
|
-
return requestTypes.find(type => type.id === typeId);
|
|
208
|
-
};
|
|
209
|
-
|
|
210
|
-
// Format a request for display or submission
|
|
211
|
-
const formatRequest = (request: DSRRequest): Record<string, any> => {
|
|
212
|
-
const { formattedRequest } = formatDSRRequest(request);
|
|
213
|
-
return formattedRequest;
|
|
214
|
-
};
|
|
215
|
-
|
|
216
|
-
// Clear all requests
|
|
217
|
-
const clearRequests = () => {
|
|
218
|
-
setRequests([]);
|
|
219
|
-
|
|
220
|
-
if (useLocalStorage && typeof window !== 'undefined') {
|
|
221
|
-
localStorage.removeItem(storageKey);
|
|
222
|
-
}
|
|
223
|
-
};
|
|
224
|
-
|
|
225
|
-
return {
|
|
226
|
-
requests,
|
|
227
|
-
submitRequest,
|
|
228
|
-
updateRequest,
|
|
229
|
-
getRequest,
|
|
230
|
-
getRequestsByStatus,
|
|
231
|
-
getRequestsByType,
|
|
232
|
-
getRequestType,
|
|
233
|
-
formatRequest,
|
|
234
|
-
clearRequests
|
|
235
|
-
};
|
|
236
|
-
}
|