@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.
- package/next-env.d.ts +5 -0
- package/package.json +1 -1
- package/.claude/settings.local.json +0 -20
- package/.eslintrc.json +0 -10
- package/.github/workflows/ci.yml +0 -36
- package/.github/workflows/nextjs.yml +0 -104
- package/.husky/commit-msg +0 -4
- package/.husky/pre-commit +0 -4
- package/.lintstagedrc.js +0 -4
- package/.nvmrc +0 -1
- package/.versionrc +0 -17
- package/CLAUDE.md +0 -90
- package/commitlint.config.js +0 -36
- package/eslint.config.mjs +0 -16
- package/jest.config.js +0 -31
- package/jest.setup.js +0 -15
- package/next.config.js +0 -15
- package/next.config.ts +0 -62
- package/packages/ndpr-toolkit/README.md +0 -467
- package/packages/ndpr-toolkit/jest.config.js +0 -23
- 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/__tests__/components/consent/ConsentBanner.test.tsx +0 -119
- package/packages/ndpr-toolkit/src/__tests__/components/consent/ConsentManager.test.tsx +0 -122
- package/packages/ndpr-toolkit/src/__tests__/components/consent/ConsentStorage.test.tsx +0 -270
- package/packages/ndpr-toolkit/src/__tests__/components/dsr/DSRDashboard.test.tsx +0 -199
- package/packages/ndpr-toolkit/src/__tests__/components/dsr/DSRRequestForm.test.tsx +0 -224
- package/packages/ndpr-toolkit/src/__tests__/components/dsr/DSRTracker.test.tsx +0 -104
- package/packages/ndpr-toolkit/src/__tests__/hooks/useConsent.test.tsx +0 -161
- package/packages/ndpr-toolkit/src/__tests__/hooks/useDSR.test.tsx +0 -330
- package/packages/ndpr-toolkit/src/__tests__/utils/breach.test.ts +0 -149
- package/packages/ndpr-toolkit/src/__tests__/utils/consent.test.ts +0 -88
- package/packages/ndpr-toolkit/src/__tests__/utils/dpia.test.ts +0 -160
- package/packages/ndpr-toolkit/src/__tests__/utils/dsr.test.ts +0 -110
- package/packages/ndpr-toolkit/src/__tests__/utils/privacy.test.ts +0 -97
- 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/src/__tests__/example.test.ts +0 -13
- package/src/__tests__/requestService.test.ts +0 -57
- package/src/app/accessibility.css +0 -70
- package/src/app/docs/components/DocLayout.tsx +0 -267
- package/src/app/docs/components/breach-notification/page.tsx +0 -797
- package/src/app/docs/components/consent-management/page.tsx +0 -576
- package/src/app/docs/components/data-subject-rights/page.tsx +0 -511
- package/src/app/docs/components/dpia-questionnaire/layout.tsx +0 -15
- package/src/app/docs/components/dpia-questionnaire/metadata.ts +0 -31
- package/src/app/docs/components/dpia-questionnaire/page.tsx +0 -666
- package/src/app/docs/components/hooks/page.tsx +0 -305
- package/src/app/docs/components/page.tsx +0 -84
- package/src/app/docs/components/privacy-policy-generator/page.tsx +0 -634
- package/src/app/docs/guides/breach-notification-process/components/BestPractices.tsx +0 -123
- package/src/app/docs/guides/breach-notification-process/components/ImplementationSteps.tsx +0 -328
- package/src/app/docs/guides/breach-notification-process/components/Introduction.tsx +0 -28
- package/src/app/docs/guides/breach-notification-process/components/NotificationTimeline.tsx +0 -91
- package/src/app/docs/guides/breach-notification-process/components/Resources.tsx +0 -118
- package/src/app/docs/guides/breach-notification-process/page.tsx +0 -39
- package/src/app/docs/guides/conducting-dpia/page.tsx +0 -593
- package/src/app/docs/guides/data-subject-requests/page.tsx +0 -666
- package/src/app/docs/guides/managing-consent/page.tsx +0 -738
- package/src/app/docs/guides/ndpr-compliance-checklist/components/ComplianceChecklist.tsx +0 -296
- package/src/app/docs/guides/ndpr-compliance-checklist/components/ImplementationTools.tsx +0 -145
- package/src/app/docs/guides/ndpr-compliance-checklist/components/Introduction.tsx +0 -33
- package/src/app/docs/guides/ndpr-compliance-checklist/components/KeyRequirements.tsx +0 -99
- package/src/app/docs/guides/ndpr-compliance-checklist/components/Resources.tsx +0 -159
- package/src/app/docs/guides/ndpr-compliance-checklist/page.tsx +0 -38
- package/src/app/docs/guides/page.tsx +0 -67
- package/src/app/docs/layout.tsx +0 -15
- package/src/app/docs/metadata.ts +0 -31
- package/src/app/docs/page.tsx +0 -572
- 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 -159
- package/src/components/data-subject-rights/DataSubjectRequestForm.tsx +0 -419
- package/src/components/docs/DocLayout.tsx +0 -289
- package/src/components/docs/index.ts +0 -2
- package/src/components/dpia/DPIAQuestionnaire.tsx +0 -483
- 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 -335
- 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 -172
- 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 -64
- package/src/hooks/useLoadingState.ts +0 -85
- package/src/lib/consentService.ts +0 -137
- package/src/lib/dpiaQuestions.ts +0 -148
- package/src/lib/requestService.ts +0 -75
- 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 -72
- package/tailwind.config.ts +0 -65
- package/tsconfig.json +0 -41
|
@@ -1,104 +0,0 @@
|
|
|
1
|
-
import { DPIAResult, DPIARisk } from '../types/dpia';
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Assesses the risk level of a DPIA based on the identified risks
|
|
5
|
-
* @param dpiaResult The DPIA result containing risks to assess
|
|
6
|
-
* @returns Assessment result with overall risk level and recommendations
|
|
7
|
-
*/
|
|
8
|
-
export function assessDPIARisk(dpiaResult: DPIAResult): {
|
|
9
|
-
overallRiskLevel: 'low' | 'medium' | 'high' | 'critical';
|
|
10
|
-
requiresConsultation: boolean;
|
|
11
|
-
canProceed: boolean;
|
|
12
|
-
recommendations: string[];
|
|
13
|
-
} {
|
|
14
|
-
// Count risks by level
|
|
15
|
-
const riskCounts = {
|
|
16
|
-
low: 0,
|
|
17
|
-
medium: 0,
|
|
18
|
-
high: 0,
|
|
19
|
-
critical: 0
|
|
20
|
-
};
|
|
21
|
-
|
|
22
|
-
// Calculate the highest risk score
|
|
23
|
-
let highestRiskScore = 0;
|
|
24
|
-
|
|
25
|
-
// Track unmitigated high/critical risks
|
|
26
|
-
const unmitigatedHighRisks: DPIARisk[] = [];
|
|
27
|
-
|
|
28
|
-
// Analyze each risk
|
|
29
|
-
dpiaResult.risks.forEach(risk => {
|
|
30
|
-
// Count by level
|
|
31
|
-
riskCounts[risk.level]++;
|
|
32
|
-
|
|
33
|
-
// Track highest score
|
|
34
|
-
if (risk.score > highestRiskScore) {
|
|
35
|
-
highestRiskScore = risk.score;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
// Track unmitigated high/critical risks
|
|
39
|
-
if ((risk.level === 'high' || risk.level === 'critical') && !risk.mitigated) {
|
|
40
|
-
unmitigatedHighRisks.push(risk);
|
|
41
|
-
}
|
|
42
|
-
});
|
|
43
|
-
|
|
44
|
-
// Determine overall risk level
|
|
45
|
-
let overallRiskLevel: 'low' | 'medium' | 'high' | 'critical';
|
|
46
|
-
|
|
47
|
-
if (riskCounts.critical > 0) {
|
|
48
|
-
overallRiskLevel = 'critical';
|
|
49
|
-
} else if (riskCounts.high > 2 || (riskCounts.high > 0 && riskCounts.medium > 3)) {
|
|
50
|
-
overallRiskLevel = 'high';
|
|
51
|
-
} else if (riskCounts.high > 0 || riskCounts.medium > 1) {
|
|
52
|
-
overallRiskLevel = 'medium';
|
|
53
|
-
} else {
|
|
54
|
-
overallRiskLevel = 'low';
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
// Determine if NITDA consultation is required
|
|
58
|
-
// Under NDPR, consultation is required for high-risk processing
|
|
59
|
-
const requiresConsultation = overallRiskLevel === 'high' || overallRiskLevel === 'critical';
|
|
60
|
-
|
|
61
|
-
// Determine if processing can proceed
|
|
62
|
-
// Processing can proceed if all high/critical risks are mitigated
|
|
63
|
-
const canProceed = unmitigatedHighRisks.length === 0;
|
|
64
|
-
|
|
65
|
-
// Generate recommendations
|
|
66
|
-
const recommendations: string[] = [];
|
|
67
|
-
|
|
68
|
-
if (unmitigatedHighRisks.length > 0) {
|
|
69
|
-
recommendations.push(
|
|
70
|
-
`Mitigate the following high/critical risks before proceeding: ${
|
|
71
|
-
unmitigatedHighRisks.map(risk => risk.description).join(', ')
|
|
72
|
-
}`
|
|
73
|
-
);
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
if (requiresConsultation) {
|
|
77
|
-
recommendations.push(
|
|
78
|
-
'Consult with NITDA before proceeding with this processing activity, as required by NDPR for high-risk processing.'
|
|
79
|
-
);
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
if (riskCounts.medium > 0) {
|
|
83
|
-
recommendations.push(
|
|
84
|
-
'Implement additional safeguards to reduce medium-level risks where possible.'
|
|
85
|
-
);
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
if (overallRiskLevel !== 'low') {
|
|
89
|
-
recommendations.push(
|
|
90
|
-
'Schedule a review of this DPIA in 6 months to reassess risks and effectiveness of mitigation measures.'
|
|
91
|
-
);
|
|
92
|
-
} else {
|
|
93
|
-
recommendations.push(
|
|
94
|
-
'Schedule a review of this DPIA in 12 months as part of regular compliance activities.'
|
|
95
|
-
);
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
return {
|
|
99
|
-
overallRiskLevel,
|
|
100
|
-
requiresConsultation,
|
|
101
|
-
canProceed,
|
|
102
|
-
recommendations
|
|
103
|
-
};
|
|
104
|
-
}
|
|
@@ -1,77 +0,0 @@
|
|
|
1
|
-
import { DSRRequest } from '../types/dsr';
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Formats a DSR request for display or submission
|
|
5
|
-
* @param request The DSR request to format
|
|
6
|
-
* @returns Formatted request data
|
|
7
|
-
*/
|
|
8
|
-
export function formatDSRRequest(request: DSRRequest): {
|
|
9
|
-
formattedRequest: Record<string, any>;
|
|
10
|
-
isValid: boolean;
|
|
11
|
-
validationErrors: string[];
|
|
12
|
-
} {
|
|
13
|
-
const validationErrors: string[] = [];
|
|
14
|
-
|
|
15
|
-
// Validate required fields
|
|
16
|
-
if (!request.id) {
|
|
17
|
-
validationErrors.push('Request ID is required');
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
if (!request.type) {
|
|
21
|
-
validationErrors.push('Request type is required');
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
if (!request.status) {
|
|
25
|
-
validationErrors.push('Request status is required');
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
if (!request.createdAt) {
|
|
29
|
-
validationErrors.push('Creation timestamp is required');
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
if (!request.subject?.name) {
|
|
33
|
-
validationErrors.push('Data subject name is required');
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
if (!request.subject?.email) {
|
|
37
|
-
validationErrors.push('Data subject email is required');
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
// Format the request for display or submission
|
|
41
|
-
const formattedRequest = {
|
|
42
|
-
requestId: request.id,
|
|
43
|
-
requestType: request.type,
|
|
44
|
-
status: request.status,
|
|
45
|
-
createdDate: new Date(request.createdAt).toISOString(),
|
|
46
|
-
lastUpdated: request.updatedAt ? new Date(request.updatedAt).toISOString() : undefined,
|
|
47
|
-
dueDate: request.dueDate
|
|
48
|
-
? new Date(request.dueDate).toISOString()
|
|
49
|
-
: undefined,
|
|
50
|
-
dataSubject: {
|
|
51
|
-
name: request.subject.name,
|
|
52
|
-
email: request.subject.email,
|
|
53
|
-
phone: request.subject.phone || 'Not provided',
|
|
54
|
-
identifier: {
|
|
55
|
-
type: request.subject.identifierType || 'Not specified',
|
|
56
|
-
value: request.subject.identifierValue || 'Not provided'
|
|
57
|
-
}
|
|
58
|
-
},
|
|
59
|
-
additionalInformation: request.additionalInfo || {},
|
|
60
|
-
verificationStatus: request.verification
|
|
61
|
-
? `${request.verification.verified ? 'Verified' : 'Not verified'}${request.verification.method ? ` via ${request.verification.method}` : ''}`
|
|
62
|
-
: 'Pending verification',
|
|
63
|
-
attachments: request.attachments
|
|
64
|
-
? request.attachments.map(attachment => ({
|
|
65
|
-
name: attachment.name,
|
|
66
|
-
type: attachment.type,
|
|
67
|
-
addedOn: new Date(attachment.addedAt).toISOString()
|
|
68
|
-
}))
|
|
69
|
-
: []
|
|
70
|
-
};
|
|
71
|
-
|
|
72
|
-
return {
|
|
73
|
-
formattedRequest,
|
|
74
|
-
isValid: validationErrors.length === 0,
|
|
75
|
-
validationErrors
|
|
76
|
-
};
|
|
77
|
-
}
|
|
@@ -1,100 +0,0 @@
|
|
|
1
|
-
import { PolicySection, OrganizationInfo, PolicyVariable } from '../types/privacy';
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Generates policy text by replacing variables in a template with organization-specific values
|
|
5
|
-
* @param sectionsOrTemplate The policy sections or template string to generate text for
|
|
6
|
-
* @param organizationInfoOrVariables The organization information or variable map to use for replacement
|
|
7
|
-
* @returns The generated policy text or an object with the generated text and metadata
|
|
8
|
-
*/
|
|
9
|
-
export function generatePolicyText(
|
|
10
|
-
sectionsOrTemplate: PolicySection[] | string,
|
|
11
|
-
organizationInfoOrVariables: OrganizationInfo | Record<string, string>
|
|
12
|
-
): string | {
|
|
13
|
-
fullText: string;
|
|
14
|
-
sectionTexts: Record<string, string>;
|
|
15
|
-
missingVariables: string[];
|
|
16
|
-
} {
|
|
17
|
-
// Check if we're using the new API (template string and variable map)
|
|
18
|
-
if (typeof sectionsOrTemplate === 'string') {
|
|
19
|
-
const template = sectionsOrTemplate;
|
|
20
|
-
const variableMap = organizationInfoOrVariables as Record<string, string>;
|
|
21
|
-
|
|
22
|
-
// Replace variables in the template
|
|
23
|
-
let result = template;
|
|
24
|
-
const variableRegex = /\{\{([^}]+)\}\}/g;
|
|
25
|
-
let match;
|
|
26
|
-
|
|
27
|
-
// Find and replace all variables in the content
|
|
28
|
-
while ((match = variableRegex.exec(template)) !== null) {
|
|
29
|
-
const variable = match[1].trim();
|
|
30
|
-
const replacement = variableMap[variable] || '';
|
|
31
|
-
|
|
32
|
-
// Replace the variable in the content
|
|
33
|
-
result = result.replace(
|
|
34
|
-
new RegExp(`\\{\\{\\s*${variable}\\s*\\}\\}`, 'g'),
|
|
35
|
-
replacement
|
|
36
|
-
);
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
return result;
|
|
40
|
-
}
|
|
41
|
-
// Otherwise use the original API (sections array and organization info)
|
|
42
|
-
else {
|
|
43
|
-
const sections = sectionsOrTemplate;
|
|
44
|
-
const organizationInfo = organizationInfoOrVariables as OrganizationInfo;
|
|
45
|
-
const sectionTexts: Record<string, string> = {};
|
|
46
|
-
const missingVariables: string[] = [];
|
|
47
|
-
|
|
48
|
-
// Process each section
|
|
49
|
-
sections
|
|
50
|
-
.filter(section => section.included)
|
|
51
|
-
.sort((a, b) => (a.order || 0) - (b.order || 0))
|
|
52
|
-
.forEach(section => {
|
|
53
|
-
// Use template if available, otherwise fall back to custom/default content
|
|
54
|
-
let content = section.template || section.customContent || section.defaultContent || '';
|
|
55
|
-
|
|
56
|
-
// Replace variables in the content
|
|
57
|
-
const variableRegex = /\{\{([^}]+)\}\}/g;
|
|
58
|
-
let match;
|
|
59
|
-
|
|
60
|
-
// Find all variables in the content
|
|
61
|
-
const contentVariables: string[] = [];
|
|
62
|
-
while ((match = variableRegex.exec(content)) !== null) {
|
|
63
|
-
contentVariables.push(match[1].trim());
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
// Replace each variable with its value
|
|
67
|
-
contentVariables.forEach(variable => {
|
|
68
|
-
let replacement = '';
|
|
69
|
-
|
|
70
|
-
// Check if the variable exists in organizationInfo
|
|
71
|
-
if (variable in organizationInfo) {
|
|
72
|
-
replacement = organizationInfo[variable as keyof OrganizationInfo] as string || '';
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
// If replacement is empty, add to missing variables
|
|
76
|
-
if (!replacement) {
|
|
77
|
-
missingVariables.push(variable);
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
// Replace the variable in the content
|
|
81
|
-
content = content.replace(
|
|
82
|
-
new RegExp(`\\{\\{\\s*${variable}\\s*\\}\\}`, 'g'),
|
|
83
|
-
replacement
|
|
84
|
-
);
|
|
85
|
-
});
|
|
86
|
-
|
|
87
|
-
// Store the processed section text
|
|
88
|
-
sectionTexts[section.id] = content;
|
|
89
|
-
});
|
|
90
|
-
|
|
91
|
-
// Combine all sections into full text
|
|
92
|
-
const fullText = Object.values(sectionTexts).join('\n\n');
|
|
93
|
-
|
|
94
|
-
return {
|
|
95
|
-
fullText,
|
|
96
|
-
sectionTexts,
|
|
97
|
-
missingVariables: Array.from(new Set(missingVariables)) // Remove duplicates
|
|
98
|
-
};
|
|
99
|
-
}
|
|
100
|
-
}
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"compilerOptions": {
|
|
3
|
-
"target": "es5",
|
|
4
|
-
"lib": ["dom", "dom.iterable", "esnext"],
|
|
5
|
-
"allowJs": true,
|
|
6
|
-
"skipLibCheck": true,
|
|
7
|
-
"esModuleInterop": true,
|
|
8
|
-
"allowSyntheticDefaultImports": true,
|
|
9
|
-
"strict": true,
|
|
10
|
-
"forceConsistentCasingInFileNames": true,
|
|
11
|
-
"noFallthroughCasesInSwitch": true,
|
|
12
|
-
"module": "esnext",
|
|
13
|
-
"moduleResolution": "node",
|
|
14
|
-
"resolveJsonModule": true,
|
|
15
|
-
"isolatedModules": true,
|
|
16
|
-
"jsx": "react-jsx",
|
|
17
|
-
"declaration": true,
|
|
18
|
-
"declarationDir": "dist",
|
|
19
|
-
"outDir": "dist"
|
|
20
|
-
},
|
|
21
|
-
"include": ["src"],
|
|
22
|
-
"exclude": ["node_modules", "dist", "**/*.test.ts", "**/*.test.tsx"]
|
|
23
|
-
}
|
package/postcss.config.mjs
DELETED
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Example test file for NDPR-Toolkit
|
|
3
|
-
*
|
|
4
|
-
* This file demonstrates how to structure tests for the NDPR-Toolkit.
|
|
5
|
-
* Add your actual tests in this directory following a similar pattern.
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
describe('NDPR-Toolkit', () => {
|
|
9
|
-
test('example test setup', () => {
|
|
10
|
-
// This is just a placeholder test to demonstrate the test structure
|
|
11
|
-
expect(true).toBe(true);
|
|
12
|
-
});
|
|
13
|
-
});
|
|
@@ -1,57 +0,0 @@
|
|
|
1
|
-
import requestService from '@/lib/requestService';
|
|
2
|
-
|
|
3
|
-
describe('requestService', () => {
|
|
4
|
-
beforeEach(() => {
|
|
5
|
-
const localStorageMock = (() => {
|
|
6
|
-
let store: Record<string, string> = {};
|
|
7
|
-
return {
|
|
8
|
-
getItem: (key: string) => (key in store ? store[key] : null),
|
|
9
|
-
setItem: (key: string, value: string) => {
|
|
10
|
-
store[key] = value;
|
|
11
|
-
},
|
|
12
|
-
removeItem: (key: string) => {
|
|
13
|
-
delete store[key];
|
|
14
|
-
},
|
|
15
|
-
clear: () => {
|
|
16
|
-
store = {};
|
|
17
|
-
}
|
|
18
|
-
};
|
|
19
|
-
})();
|
|
20
|
-
|
|
21
|
-
Object.defineProperty(window, 'localStorage', {
|
|
22
|
-
value: localStorageMock,
|
|
23
|
-
writable: true,
|
|
24
|
-
});
|
|
25
|
-
requestService.clear();
|
|
26
|
-
});
|
|
27
|
-
|
|
28
|
-
test('creates and retrieves a request', () => {
|
|
29
|
-
const req = requestService.createRequest('access', 'John Doe', 'john@example.com', 'details', true);
|
|
30
|
-
const stored = requestService.getRequest(req.id);
|
|
31
|
-
expect(stored).not.toBeNull();
|
|
32
|
-
expect(stored?.requestType).toBe('access');
|
|
33
|
-
expect(stored?.status).toBe('pending');
|
|
34
|
-
});
|
|
35
|
-
|
|
36
|
-
test('updates request status', () => {
|
|
37
|
-
const req = requestService.createRequest('erasure', 'Jane', 'jane@example.com', 'erase', true);
|
|
38
|
-
const updated = requestService.updateStatus(req.id, 'completed');
|
|
39
|
-
expect(updated?.status).toBe('completed');
|
|
40
|
-
const stored = requestService.getRequest(req.id);
|
|
41
|
-
expect(stored?.status).toBe('completed');
|
|
42
|
-
});
|
|
43
|
-
|
|
44
|
-
test('retrieves all requests', () => {
|
|
45
|
-
requestService.createRequest('access', 'A', 'a@example.com', 'a', true);
|
|
46
|
-
requestService.createRequest('erasure', 'B', 'b@example.com', 'b', true);
|
|
47
|
-
const all = requestService.getAllRequests();
|
|
48
|
-
expect(all.length).toBe(2);
|
|
49
|
-
});
|
|
50
|
-
|
|
51
|
-
test('clears storage', () => {
|
|
52
|
-
requestService.createRequest('access', 'A', 'a@example.com', 'a', true);
|
|
53
|
-
requestService.clear();
|
|
54
|
-
const all = requestService.getAllRequests();
|
|
55
|
-
expect(all.length).toBe(0);
|
|
56
|
-
});
|
|
57
|
-
});
|
|
@@ -1,70 +0,0 @@
|
|
|
1
|
-
/* Accessibility-focused styles with improved color contrast */
|
|
2
|
-
|
|
3
|
-
/* Badge styles with WCAG AA compliant contrast ratios */
|
|
4
|
-
.badge-success {
|
|
5
|
-
@apply bg-green-700 text-white dark:bg-green-600 dark:text-white;
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
.badge-warning {
|
|
9
|
-
@apply bg-amber-700 text-white dark:bg-amber-600 dark:text-white;
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
.badge-error {
|
|
13
|
-
@apply bg-red-700 text-white dark:bg-red-600 dark:text-white;
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
.badge-info {
|
|
17
|
-
@apply bg-blue-700 text-white dark:bg-blue-600 dark:text-white;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
.badge-neutral {
|
|
21
|
-
@apply bg-gray-700 text-white dark:bg-gray-500 dark:text-white;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
/* Text colors with improved contrast */
|
|
25
|
-
.text-muted-accessible {
|
|
26
|
-
@apply text-gray-700 dark:text-gray-300;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
.text-secondary-accessible {
|
|
30
|
-
@apply text-gray-600 dark:text-gray-400;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
/* Focus indicators for better keyboard navigation */
|
|
34
|
-
.focus-visible-ring {
|
|
35
|
-
@apply focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:ring-blue-600 dark:focus-visible:ring-blue-400 focus-visible:ring-offset-background;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
/* High contrast mode support */
|
|
39
|
-
@media (prefers-contrast: high) {
|
|
40
|
-
.badge-success,
|
|
41
|
-
.badge-warning,
|
|
42
|
-
.badge-error,
|
|
43
|
-
.badge-info,
|
|
44
|
-
.badge-neutral {
|
|
45
|
-
@apply border-2 border-current;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
.text-muted-accessible {
|
|
49
|
-
@apply text-gray-900 dark:text-gray-100;
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
/* Ensure interactive elements have sufficient size */
|
|
54
|
-
.interactive-target {
|
|
55
|
-
@apply min-h-[44px] min-w-[44px];
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
/* Skip link for keyboard navigation */
|
|
59
|
-
.skip-link {
|
|
60
|
-
@apply sr-only focus:not-sr-only focus:absolute focus:top-4 focus:left-4 focus:z-50 focus:px-4 focus:py-2 focus:bg-blue-600 focus:text-white focus:rounded-md;
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
/* Aria live region styles */
|
|
64
|
-
.aria-live-polite {
|
|
65
|
-
@apply sr-only;
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
[role="alert"] {
|
|
69
|
-
@apply font-medium;
|
|
70
|
-
}
|