@tantainnovative/ndpr-toolkit 1.0.3 → 1.0.5
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/packages/ndpr-toolkit/dist/components/breach/BreachNotificationManager.d.ts +62 -0
- package/packages/ndpr-toolkit/dist/components/breach/BreachReportForm.d.ts +66 -0
- package/packages/ndpr-toolkit/dist/components/breach/BreachRiskAssessment.d.ts +50 -0
- package/packages/ndpr-toolkit/dist/components/breach/RegulatoryReportGenerator.d.ts +94 -0
- package/packages/ndpr-toolkit/dist/components/consent/ConsentBanner.d.ts +79 -0
- package/packages/ndpr-toolkit/dist/components/consent/ConsentManager.d.ts +73 -0
- package/packages/ndpr-toolkit/dist/components/consent/ConsentStorage.d.ts +41 -0
- package/packages/ndpr-toolkit/dist/components/dpia/DPIAQuestionnaire.d.ts +70 -0
- package/packages/ndpr-toolkit/dist/components/dpia/DPIAReport.d.ts +40 -0
- package/packages/ndpr-toolkit/dist/components/dpia/StepIndicator.d.ts +64 -0
- package/packages/ndpr-toolkit/dist/components/dsr/DSRDashboard.d.ts +58 -0
- package/packages/ndpr-toolkit/dist/components/dsr/DSRRequestForm.d.ts +74 -0
- package/packages/ndpr-toolkit/dist/components/dsr/DSRTracker.d.ts +56 -0
- package/packages/ndpr-toolkit/dist/components/policy/PolicyExporter.d.ts +65 -0
- package/packages/ndpr-toolkit/dist/components/policy/PolicyGenerator.d.ts +54 -0
- package/packages/ndpr-toolkit/dist/components/policy/PolicyPreview.d.ts +71 -0
- package/packages/ndpr-toolkit/dist/hooks/useBreach.d.ts +97 -0
- package/packages/ndpr-toolkit/dist/hooks/useConsent.d.ts +63 -0
- package/packages/ndpr-toolkit/dist/hooks/useDPIA.d.ts +92 -0
- package/packages/ndpr-toolkit/dist/hooks/useDSR.d.ts +72 -0
- package/packages/ndpr-toolkit/dist/hooks/usePrivacyPolicy.d.ts +87 -0
- package/packages/ndpr-toolkit/dist/index.d.ts +31 -0
- package/packages/ndpr-toolkit/dist/index.esm.js +2 -0
- package/packages/ndpr-toolkit/dist/index.esm.js.map +1 -0
- package/packages/ndpr-toolkit/dist/index.js +2 -0
- package/packages/ndpr-toolkit/dist/index.js.map +1 -0
- package/packages/ndpr-toolkit/dist/setupTests.d.ts +2 -0
- package/packages/ndpr-toolkit/dist/types/breach.d.ts +239 -0
- package/packages/ndpr-toolkit/dist/types/consent.d.ts +95 -0
- package/packages/ndpr-toolkit/dist/types/dpia.d.ts +196 -0
- package/packages/ndpr-toolkit/dist/types/dsr.d.ts +162 -0
- package/packages/ndpr-toolkit/dist/types/privacy.d.ts +204 -0
- package/packages/ndpr-toolkit/dist/utils/breach.d.ts +14 -0
- package/packages/ndpr-toolkit/dist/utils/consent.d.ts +10 -0
- package/packages/ndpr-toolkit/dist/utils/dpia.d.ts +12 -0
- package/packages/ndpr-toolkit/dist/utils/dsr.d.ts +11 -0
- package/packages/ndpr-toolkit/dist/utils/privacy.d.ts +12 -0
- package/src/components/consent/ConsentBanner.tsx +82 -48
- package/src/components/data-subject-rights/DataSubjectRequestForm.tsx +240 -129
- package/src/components/dpia/DPIAQuestionnaire.tsx +162 -122
- package/src/components/privacy-policy/PolicyGenerator.tsx +5 -5
- package/src/components/privacy-policy/steps/CustomSectionsStep.tsx +103 -77
- package/src/components/privacy-policy/steps/PolicyPreviewStep.tsx +117 -63
- package/src/hooks/useConsent.ts +16 -10
- package/src/lib/consentService.ts +44 -37
- package/src/lib/dpiaQuestions.ts +139 -99
- package/src/lib/requestService.ts +21 -17
- package/src/types/index.ts +13 -8
- 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/jest.config.js +0 -31
- package/jest.setup.js +0 -15
- package/packages/ndpr-toolkit/jest.config.js +0 -23
- 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/src/__tests__/example.test.ts +0 -13
- package/src/__tests__/requestService.test.ts +0 -57
- 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/components/docs/DocLayout.tsx +0 -289
- package/src/components/docs/index.ts +0 -2
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Represents a section in a privacy policy
|
|
3
|
+
*/
|
|
4
|
+
export interface PolicySection {
|
|
5
|
+
/**
|
|
6
|
+
* Unique identifier for the section
|
|
7
|
+
*/
|
|
8
|
+
id: string;
|
|
9
|
+
/**
|
|
10
|
+
* Title of the section
|
|
11
|
+
*/
|
|
12
|
+
title: string;
|
|
13
|
+
/**
|
|
14
|
+
* Description of the section
|
|
15
|
+
*/
|
|
16
|
+
description?: string;
|
|
17
|
+
/**
|
|
18
|
+
* Order of the section in the policy
|
|
19
|
+
*/
|
|
20
|
+
order?: number;
|
|
21
|
+
/**
|
|
22
|
+
* Whether the section is required by NDPR
|
|
23
|
+
*/
|
|
24
|
+
required: boolean;
|
|
25
|
+
/**
|
|
26
|
+
* Template text for the section
|
|
27
|
+
*/
|
|
28
|
+
template: string;
|
|
29
|
+
/**
|
|
30
|
+
* Default content for the section (legacy field)
|
|
31
|
+
* @deprecated Use template instead
|
|
32
|
+
*/
|
|
33
|
+
defaultContent?: string;
|
|
34
|
+
/**
|
|
35
|
+
* Custom content for the section (overrides default content)
|
|
36
|
+
* @deprecated Use template instead
|
|
37
|
+
*/
|
|
38
|
+
customContent?: string;
|
|
39
|
+
/**
|
|
40
|
+
* Whether the section is included in the policy
|
|
41
|
+
*/
|
|
42
|
+
included: boolean;
|
|
43
|
+
/**
|
|
44
|
+
* Variables that can be used in the section content
|
|
45
|
+
*/
|
|
46
|
+
variables?: string[];
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Represents a privacy policy template
|
|
50
|
+
*/
|
|
51
|
+
export interface PolicyTemplate {
|
|
52
|
+
/**
|
|
53
|
+
* Unique identifier for the template
|
|
54
|
+
*/
|
|
55
|
+
id: string;
|
|
56
|
+
/**
|
|
57
|
+
* Name of the template
|
|
58
|
+
*/
|
|
59
|
+
name: string;
|
|
60
|
+
/**
|
|
61
|
+
* Description of the template
|
|
62
|
+
*/
|
|
63
|
+
description: string;
|
|
64
|
+
/**
|
|
65
|
+
* Type of organization the template is designed for
|
|
66
|
+
*/
|
|
67
|
+
organizationType: 'business' | 'nonprofit' | 'government' | 'educational';
|
|
68
|
+
/**
|
|
69
|
+
* Sections included in the template
|
|
70
|
+
*/
|
|
71
|
+
sections: PolicySection[];
|
|
72
|
+
/**
|
|
73
|
+
* Variables used across the template
|
|
74
|
+
*/
|
|
75
|
+
variables: Record<string, {
|
|
76
|
+
name: string;
|
|
77
|
+
description: string;
|
|
78
|
+
required: boolean;
|
|
79
|
+
defaultValue?: string;
|
|
80
|
+
}>;
|
|
81
|
+
/**
|
|
82
|
+
* Version of the template
|
|
83
|
+
*/
|
|
84
|
+
version: string;
|
|
85
|
+
/**
|
|
86
|
+
* Last updated date of the template
|
|
87
|
+
*/
|
|
88
|
+
lastUpdated: number;
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Represents organization information for a privacy policy
|
|
92
|
+
*/
|
|
93
|
+
export interface OrganizationInfo {
|
|
94
|
+
/**
|
|
95
|
+
* Name of the organization
|
|
96
|
+
*/
|
|
97
|
+
name: string;
|
|
98
|
+
/**
|
|
99
|
+
* Website URL of the organization
|
|
100
|
+
*/
|
|
101
|
+
website: string;
|
|
102
|
+
/**
|
|
103
|
+
* Contact email for privacy inquiries
|
|
104
|
+
*/
|
|
105
|
+
privacyEmail: string;
|
|
106
|
+
/**
|
|
107
|
+
* Physical address of the organization
|
|
108
|
+
*/
|
|
109
|
+
address?: string;
|
|
110
|
+
/**
|
|
111
|
+
* Phone number for privacy inquiries
|
|
112
|
+
*/
|
|
113
|
+
privacyPhone?: string;
|
|
114
|
+
/**
|
|
115
|
+
* Name of the Data Protection Officer (if applicable)
|
|
116
|
+
*/
|
|
117
|
+
dpoName?: string;
|
|
118
|
+
/**
|
|
119
|
+
* Email of the Data Protection Officer (if applicable)
|
|
120
|
+
*/
|
|
121
|
+
dpoEmail?: string;
|
|
122
|
+
/**
|
|
123
|
+
* Industry or sector of the organization
|
|
124
|
+
*/
|
|
125
|
+
industry?: string;
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Represents a variable in a privacy policy
|
|
129
|
+
*/
|
|
130
|
+
export interface PolicyVariable {
|
|
131
|
+
/**
|
|
132
|
+
* Unique identifier for the variable
|
|
133
|
+
*/
|
|
134
|
+
id: string;
|
|
135
|
+
/**
|
|
136
|
+
* Name of the variable as it appears in the template
|
|
137
|
+
*/
|
|
138
|
+
name: string;
|
|
139
|
+
/**
|
|
140
|
+
* Description of the variable
|
|
141
|
+
*/
|
|
142
|
+
description: string;
|
|
143
|
+
/**
|
|
144
|
+
* Default value for the variable
|
|
145
|
+
*/
|
|
146
|
+
defaultValue?: string;
|
|
147
|
+
/**
|
|
148
|
+
* Current value of the variable
|
|
149
|
+
*/
|
|
150
|
+
value: string;
|
|
151
|
+
/**
|
|
152
|
+
* Type of input for the variable
|
|
153
|
+
*/
|
|
154
|
+
inputType: 'text' | 'textarea' | 'email' | 'url' | 'date' | 'select';
|
|
155
|
+
/**
|
|
156
|
+
* Options for select inputs
|
|
157
|
+
*/
|
|
158
|
+
options?: string[];
|
|
159
|
+
/**
|
|
160
|
+
* Whether the variable is required
|
|
161
|
+
*/
|
|
162
|
+
required: boolean;
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* Represents a generated privacy policy
|
|
166
|
+
*/
|
|
167
|
+
export interface PrivacyPolicy {
|
|
168
|
+
/**
|
|
169
|
+
* Unique identifier for the policy
|
|
170
|
+
*/
|
|
171
|
+
id: string;
|
|
172
|
+
/**
|
|
173
|
+
* Title of the policy
|
|
174
|
+
*/
|
|
175
|
+
title: string;
|
|
176
|
+
/**
|
|
177
|
+
* Template used to generate the policy
|
|
178
|
+
*/
|
|
179
|
+
templateId: string;
|
|
180
|
+
/**
|
|
181
|
+
* Organization information
|
|
182
|
+
*/
|
|
183
|
+
organizationInfo: OrganizationInfo;
|
|
184
|
+
/**
|
|
185
|
+
* Sections of the policy
|
|
186
|
+
*/
|
|
187
|
+
sections: PolicySection[];
|
|
188
|
+
/**
|
|
189
|
+
* Values for the variables used in the policy
|
|
190
|
+
*/
|
|
191
|
+
variableValues: Record<string, string>;
|
|
192
|
+
/**
|
|
193
|
+
* Effective date of the policy
|
|
194
|
+
*/
|
|
195
|
+
effectiveDate: number;
|
|
196
|
+
/**
|
|
197
|
+
* Last updated date of the policy
|
|
198
|
+
*/
|
|
199
|
+
lastUpdated: number;
|
|
200
|
+
/**
|
|
201
|
+
* Version of the policy
|
|
202
|
+
*/
|
|
203
|
+
version: string;
|
|
204
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { BreachReport, RiskAssessment } from '../types/breach';
|
|
2
|
+
/**
|
|
3
|
+
* Calculates the severity of a data breach based on various factors
|
|
4
|
+
* @param report The breach report
|
|
5
|
+
* @param assessment The risk assessment (if available)
|
|
6
|
+
* @returns The calculated severity and notification requirements
|
|
7
|
+
*/
|
|
8
|
+
export declare function calculateBreachSeverity(report: BreachReport, assessment?: RiskAssessment): {
|
|
9
|
+
severityLevel: 'low' | 'medium' | 'high' | 'critical';
|
|
10
|
+
notificationRequired: boolean;
|
|
11
|
+
urgentNotificationRequired: boolean;
|
|
12
|
+
timeframeHours: number;
|
|
13
|
+
justification: string;
|
|
14
|
+
};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { ConsentSettings } from '../types/consent';
|
|
2
|
+
/**
|
|
3
|
+
* Validates consent settings to ensure they meet NDPR requirements
|
|
4
|
+
* @param settings The consent settings to validate
|
|
5
|
+
* @returns An object containing validation result and any error messages
|
|
6
|
+
*/
|
|
7
|
+
export declare function validateConsent(settings: ConsentSettings): {
|
|
8
|
+
valid: boolean;
|
|
9
|
+
errors: string[];
|
|
10
|
+
};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { DPIAResult } from '../types/dpia';
|
|
2
|
+
/**
|
|
3
|
+
* Assesses the risk level of a DPIA based on the identified risks
|
|
4
|
+
* @param dpiaResult The DPIA result containing risks to assess
|
|
5
|
+
* @returns Assessment result with overall risk level and recommendations
|
|
6
|
+
*/
|
|
7
|
+
export declare function assessDPIARisk(dpiaResult: DPIAResult): {
|
|
8
|
+
overallRiskLevel: 'low' | 'medium' | 'high' | 'critical';
|
|
9
|
+
requiresConsultation: boolean;
|
|
10
|
+
canProceed: boolean;
|
|
11
|
+
recommendations: string[];
|
|
12
|
+
};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { DSRRequest } from '../types/dsr';
|
|
2
|
+
/**
|
|
3
|
+
* Formats a DSR request for display or submission
|
|
4
|
+
* @param request The DSR request to format
|
|
5
|
+
* @returns Formatted request data
|
|
6
|
+
*/
|
|
7
|
+
export declare function formatDSRRequest(request: DSRRequest): {
|
|
8
|
+
formattedRequest: Record<string, any>;
|
|
9
|
+
isValid: boolean;
|
|
10
|
+
validationErrors: string[];
|
|
11
|
+
};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { PolicySection, OrganizationInfo } from '../types/privacy';
|
|
2
|
+
/**
|
|
3
|
+
* Generates policy text by replacing variables in a template with organization-specific values
|
|
4
|
+
* @param sectionsOrTemplate The policy sections or template string to generate text for
|
|
5
|
+
* @param organizationInfoOrVariables The organization information or variable map to use for replacement
|
|
6
|
+
* @returns The generated policy text or an object with the generated text and metadata
|
|
7
|
+
*/
|
|
8
|
+
export declare function generatePolicyText(sectionsOrTemplate: PolicySection[] | string, organizationInfoOrVariables: OrganizationInfo | Record<string, string>): string | {
|
|
9
|
+
fullText: string;
|
|
10
|
+
sectionTexts: Record<string, string>;
|
|
11
|
+
missingVariables: string[];
|
|
12
|
+
};
|
|
@@ -1,11 +1,18 @@
|
|
|
1
|
-
|
|
1
|
+
"use client";
|
|
2
2
|
|
|
3
|
-
import { useState } from
|
|
4
|
-
import { ConsentOption } from
|
|
5
|
-
import { Button } from
|
|
6
|
-
import { Checkbox } from
|
|
7
|
-
import {
|
|
8
|
-
|
|
3
|
+
import { useState } from "react";
|
|
4
|
+
import { ConsentOption } from "@/types";
|
|
5
|
+
import { Button } from "@/components/ui/Button";
|
|
6
|
+
import { Checkbox } from "@/components/ui/Checkbox";
|
|
7
|
+
import {
|
|
8
|
+
Card,
|
|
9
|
+
CardContent,
|
|
10
|
+
CardFooter,
|
|
11
|
+
CardHeader,
|
|
12
|
+
CardTitle,
|
|
13
|
+
CardDescription,
|
|
14
|
+
} from "@/components/ui/Card";
|
|
15
|
+
import { Badge } from "@/components/ui/Badge";
|
|
9
16
|
|
|
10
17
|
interface ConsentBannerProps {
|
|
11
18
|
title?: string;
|
|
@@ -18,36 +25,42 @@ interface ConsentBannerProps {
|
|
|
18
25
|
}
|
|
19
26
|
|
|
20
27
|
export default function ConsentBanner({
|
|
21
|
-
title =
|
|
22
|
-
description =
|
|
23
|
-
privacyPolicyUrl =
|
|
28
|
+
title = "Privacy Preferences",
|
|
29
|
+
description = "We use cookies and similar technologies to provide certain features, enhance the user experience and deliver content that is relevant to your interests.",
|
|
30
|
+
privacyPolicyUrl = "/privacy-policy",
|
|
24
31
|
options,
|
|
25
32
|
onSave,
|
|
26
|
-
className =
|
|
33
|
+
className = "",
|
|
27
34
|
}: ConsentBannerProps) {
|
|
28
35
|
const [consents, setConsents] = useState<Record<string, boolean>>(
|
|
29
|
-
options.reduce(
|
|
30
|
-
acc
|
|
31
|
-
|
|
32
|
-
|
|
36
|
+
options.reduce(
|
|
37
|
+
(acc, option) => {
|
|
38
|
+
acc[option.id] = option.defaultValue ?? false;
|
|
39
|
+
return acc;
|
|
40
|
+
},
|
|
41
|
+
{} as Record<string, boolean>,
|
|
42
|
+
),
|
|
33
43
|
);
|
|
34
44
|
|
|
35
45
|
const handleToggle = (id: string) => {
|
|
36
|
-
const option = options.find(opt => opt.id === id);
|
|
46
|
+
const option = options.find((opt) => opt.id === id);
|
|
37
47
|
if (option?.required) return;
|
|
38
|
-
|
|
39
|
-
setConsents(prev => ({
|
|
48
|
+
|
|
49
|
+
setConsents((prev) => ({
|
|
40
50
|
...prev,
|
|
41
|
-
[id]: !prev[id]
|
|
51
|
+
[id]: !prev[id],
|
|
42
52
|
}));
|
|
43
53
|
};
|
|
44
54
|
|
|
45
55
|
const handleAcceptAll = () => {
|
|
46
|
-
const allConsents = options.reduce(
|
|
47
|
-
acc
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
56
|
+
const allConsents = options.reduce(
|
|
57
|
+
(acc, option) => {
|
|
58
|
+
acc[option.id] = true;
|
|
59
|
+
return acc;
|
|
60
|
+
},
|
|
61
|
+
{} as Record<string, boolean>,
|
|
62
|
+
);
|
|
63
|
+
|
|
51
64
|
setConsents(allConsents);
|
|
52
65
|
onSave(allConsents);
|
|
53
66
|
};
|
|
@@ -57,17 +70,22 @@ export default function ConsentBanner({
|
|
|
57
70
|
};
|
|
58
71
|
|
|
59
72
|
const handleRejectAll = () => {
|
|
60
|
-
const rejectedConsents = options.reduce(
|
|
61
|
-
acc
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
73
|
+
const rejectedConsents = options.reduce(
|
|
74
|
+
(acc, option) => {
|
|
75
|
+
acc[option.id] = option.required ? true : false;
|
|
76
|
+
return acc;
|
|
77
|
+
},
|
|
78
|
+
{} as Record<string, boolean>,
|
|
79
|
+
);
|
|
80
|
+
|
|
65
81
|
setConsents(rejectedConsents);
|
|
66
82
|
onSave(rejectedConsents);
|
|
67
83
|
};
|
|
68
84
|
|
|
69
85
|
return (
|
|
70
|
-
<div
|
|
86
|
+
<div
|
|
87
|
+
className={`fixed inset-0 z-50 flex items-end sm:items-center justify-center p-4 bg-black/50 ${className}`}
|
|
88
|
+
>
|
|
71
89
|
<Card className="w-full max-w-3xl max-h-[90vh] overflow-auto shadow-xl animate-in fade-in slide-in-from-bottom-5 duration-300">
|
|
72
90
|
<CardHeader className="border-b border-gray-200 dark:border-gray-700">
|
|
73
91
|
<div className="flex items-center justify-between">
|
|
@@ -75,25 +93,38 @@ export default function ConsentBanner({
|
|
|
75
93
|
<CardTitle className="text-xl">{title}</CardTitle>
|
|
76
94
|
<CardDescription className="mt-2">{description}</CardDescription>
|
|
77
95
|
</div>
|
|
78
|
-
<Badge variant="primary" className="hidden sm:flex">
|
|
96
|
+
<Badge variant="primary" className="hidden sm:flex">
|
|
97
|
+
Privacy Settings
|
|
98
|
+
</Badge>
|
|
79
99
|
</div>
|
|
80
|
-
<a
|
|
81
|
-
href={privacyPolicyUrl}
|
|
100
|
+
<a
|
|
101
|
+
href={privacyPolicyUrl}
|
|
82
102
|
className="text-sm text-blue-600 dark:text-blue-400 hover:underline mt-2 inline-flex items-center"
|
|
83
103
|
>
|
|
84
|
-
<svg
|
|
85
|
-
|
|
104
|
+
<svg
|
|
105
|
+
className="w-4 h-4 mr-1"
|
|
106
|
+
fill="none"
|
|
107
|
+
stroke="currentColor"
|
|
108
|
+
viewBox="0 0 24 24"
|
|
109
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
110
|
+
>
|
|
111
|
+
<path
|
|
112
|
+
strokeLinecap="round"
|
|
113
|
+
strokeLinejoin="round"
|
|
114
|
+
strokeWidth={2}
|
|
115
|
+
d="M13.828 10.172a4 4 0 00-5.656 0l-4 4a4 4 0 105.656 5.656l1.102-1.101m-.758-4.899a4 4 0 005.656 0l4-4a4 4 0 00-5.656-5.656l-1.1 1.1"
|
|
116
|
+
/>
|
|
86
117
|
</svg>
|
|
87
118
|
View our Privacy Policy
|
|
88
119
|
</a>
|
|
89
120
|
</CardHeader>
|
|
90
|
-
|
|
121
|
+
|
|
91
122
|
<CardContent className="space-y-4 p-6">
|
|
92
123
|
<div className="grid gap-4">
|
|
93
124
|
{options.map((option) => (
|
|
94
|
-
<div
|
|
95
|
-
key={option.id}
|
|
96
|
-
className={`p-4 rounded-lg border ${consents[option.id] ?
|
|
125
|
+
<div
|
|
126
|
+
key={option.id}
|
|
127
|
+
className={`p-4 rounded-lg border ${consents[option.id] ? "border-blue-200 bg-blue-50 dark:border-blue-800 dark:bg-blue-900/20" : "border-gray-200 dark:border-gray-700"} transition-colors duration-200`}
|
|
97
128
|
>
|
|
98
129
|
<div className="flex items-start">
|
|
99
130
|
<div className="flex-1">
|
|
@@ -102,7 +133,9 @@ export default function ConsentBanner({
|
|
|
102
133
|
{option.label}
|
|
103
134
|
</h3>
|
|
104
135
|
{option.required && (
|
|
105
|
-
<Badge variant="secondary" className="ml-2 text-xs">
|
|
136
|
+
<Badge variant="secondary" className="ml-2 text-xs">
|
|
137
|
+
Required
|
|
138
|
+
</Badge>
|
|
106
139
|
)}
|
|
107
140
|
</div>
|
|
108
141
|
<p className="mt-1 text-sm text-gray-500 dark:text-gray-400">
|
|
@@ -122,30 +155,31 @@ export default function ConsentBanner({
|
|
|
122
155
|
))}
|
|
123
156
|
</div>
|
|
124
157
|
</CardContent>
|
|
125
|
-
|
|
158
|
+
|
|
126
159
|
<CardFooter className="flex flex-col sm:flex-row sm:justify-between border-t border-gray-200 dark:border-gray-700 p-6 bg-gray-50 dark:bg-gray-800">
|
|
127
160
|
<div className="mb-4 sm:mb-0">
|
|
128
161
|
<p className="text-xs text-gray-500 dark:text-gray-400">
|
|
129
|
-
You can change your preferences at any time by visiting your
|
|
162
|
+
You can change your preferences at any time by visiting your
|
|
163
|
+
account settings.
|
|
130
164
|
</p>
|
|
131
165
|
</div>
|
|
132
166
|
<div className="flex flex-col sm:flex-row space-y-2 sm:space-y-0 sm:space-x-2">
|
|
133
|
-
<Button
|
|
134
|
-
variant="outline"
|
|
167
|
+
<Button
|
|
168
|
+
variant="outline"
|
|
135
169
|
onClick={handleRejectAll}
|
|
136
170
|
className="sm:order-1"
|
|
137
171
|
>
|
|
138
172
|
Reject All
|
|
139
173
|
</Button>
|
|
140
|
-
<Button
|
|
141
|
-
variant="secondary"
|
|
174
|
+
<Button
|
|
175
|
+
variant="secondary"
|
|
142
176
|
onClick={handleSave}
|
|
143
177
|
className="sm:order-2"
|
|
144
178
|
>
|
|
145
179
|
Save Preferences
|
|
146
180
|
</Button>
|
|
147
|
-
<Button
|
|
148
|
-
variant="default"
|
|
181
|
+
<Button
|
|
182
|
+
variant="default"
|
|
149
183
|
onClick={handleAcceptAll}
|
|
150
184
|
className="sm:order-3"
|
|
151
185
|
>
|