@tantainnovative/ndpr-toolkit 1.0.1 → 1.0.3
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/.claude/settings.local.json +20 -0
- package/.eslintrc.json +10 -0
- package/.github/workflows/ci.yml +36 -0
- package/.github/workflows/nextjs.yml +104 -0
- package/.husky/commit-msg +4 -0
- package/.husky/pre-commit +4 -0
- package/.lintstagedrc.js +4 -0
- package/.nvmrc +1 -0
- package/.versionrc +17 -0
- package/CHANGELOG.md +16 -0
- package/CLAUDE.md +90 -0
- package/CNAME +1 -0
- package/CONTRIBUTING.md +87 -0
- package/README.md +84 -431
- package/RELEASE-NOTES-v1.0.0.md +140 -0
- package/RELEASE-NOTES-v1.0.1.md +69 -0
- package/SECURITY.md +21 -0
- package/commitlint.config.js +36 -0
- package/components.json +21 -0
- package/eslint.config.mjs +16 -0
- package/jest.config.js +31 -0
- package/jest.setup.js +15 -0
- package/next.config.js +15 -0
- package/next.config.ts +62 -0
- package/package.json +70 -52
- package/packages/ndpr-toolkit/README.md +467 -0
- package/packages/ndpr-toolkit/jest.config.js +23 -0
- package/packages/ndpr-toolkit/package-lock.json +8197 -0
- package/packages/ndpr-toolkit/package.json +71 -0
- package/packages/ndpr-toolkit/rollup.config.js +34 -0
- package/packages/ndpr-toolkit/src/__tests__/components/consent/ConsentBanner.test.tsx +119 -0
- package/packages/ndpr-toolkit/src/__tests__/components/consent/ConsentManager.test.tsx +122 -0
- package/packages/ndpr-toolkit/src/__tests__/components/consent/ConsentStorage.test.tsx +270 -0
- package/packages/ndpr-toolkit/src/__tests__/components/dsr/DSRDashboard.test.tsx +199 -0
- package/packages/ndpr-toolkit/src/__tests__/components/dsr/DSRRequestForm.test.tsx +224 -0
- package/packages/ndpr-toolkit/src/__tests__/components/dsr/DSRTracker.test.tsx +104 -0
- package/packages/ndpr-toolkit/src/__tests__/hooks/useConsent.test.tsx +161 -0
- package/packages/ndpr-toolkit/src/__tests__/hooks/useDSR.test.tsx +330 -0
- package/packages/ndpr-toolkit/src/__tests__/utils/breach.test.ts +149 -0
- package/packages/ndpr-toolkit/src/__tests__/utils/consent.test.ts +88 -0
- package/packages/ndpr-toolkit/src/__tests__/utils/dpia.test.ts +160 -0
- package/packages/ndpr-toolkit/src/__tests__/utils/dsr.test.ts +110 -0
- package/packages/ndpr-toolkit/src/__tests__/utils/privacy.test.ts +97 -0
- package/packages/ndpr-toolkit/src/components/breach/BreachNotificationManager.tsx +701 -0
- package/packages/ndpr-toolkit/src/components/breach/BreachReportForm.tsx +631 -0
- package/packages/ndpr-toolkit/src/components/breach/BreachRiskAssessment.tsx +569 -0
- package/packages/ndpr-toolkit/src/components/breach/RegulatoryReportGenerator.tsx +496 -0
- package/packages/ndpr-toolkit/src/components/consent/ConsentBanner.tsx +270 -0
- package/packages/ndpr-toolkit/src/components/consent/ConsentManager.tsx +217 -0
- package/packages/ndpr-toolkit/src/components/consent/ConsentStorage.tsx +206 -0
- package/packages/ndpr-toolkit/src/components/dpia/DPIAQuestionnaire.tsx +342 -0
- package/packages/ndpr-toolkit/src/components/dpia/DPIAReport.tsx +373 -0
- package/packages/ndpr-toolkit/src/components/dpia/StepIndicator.tsx +174 -0
- package/packages/ndpr-toolkit/src/components/dsr/DSRDashboard.tsx +717 -0
- package/packages/ndpr-toolkit/src/components/dsr/DSRRequestForm.tsx +476 -0
- package/packages/ndpr-toolkit/src/components/dsr/DSRTracker.tsx +620 -0
- package/packages/ndpr-toolkit/src/components/policy/PolicyExporter.tsx +541 -0
- package/packages/ndpr-toolkit/src/components/policy/PolicyGenerator.tsx +454 -0
- package/packages/ndpr-toolkit/src/components/policy/PolicyPreview.tsx +333 -0
- package/packages/ndpr-toolkit/src/hooks/useBreach.ts +409 -0
- package/packages/ndpr-toolkit/src/hooks/useConsent.ts +263 -0
- package/packages/ndpr-toolkit/src/hooks/useDPIA.ts +457 -0
- package/packages/ndpr-toolkit/src/hooks/useDSR.ts +236 -0
- package/packages/ndpr-toolkit/src/hooks/usePrivacyPolicy.ts +428 -0
- package/{dist/index.d.ts → packages/ndpr-toolkit/src/index.ts} +14 -1
- package/packages/ndpr-toolkit/src/setupTests.ts +5 -0
- package/packages/ndpr-toolkit/src/types/breach.ts +283 -0
- package/packages/ndpr-toolkit/src/types/consent.ts +111 -0
- package/packages/ndpr-toolkit/src/types/dpia.ts +236 -0
- package/packages/ndpr-toolkit/src/types/dsr.ts +192 -0
- package/packages/ndpr-toolkit/src/types/index.ts +42 -0
- package/packages/ndpr-toolkit/src/types/privacy.ts +246 -0
- package/packages/ndpr-toolkit/src/utils/breach.ts +122 -0
- package/packages/ndpr-toolkit/src/utils/consent.ts +51 -0
- package/packages/ndpr-toolkit/src/utils/dpia.ts +104 -0
- package/packages/ndpr-toolkit/src/utils/dsr.ts +77 -0
- package/packages/ndpr-toolkit/src/utils/privacy.ts +100 -0
- package/packages/ndpr-toolkit/tsconfig.json +23 -0
- package/postcss.config.mjs +5 -0
- package/public/NDPR TOOLKIT.svg +1 -0
- 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 +1 -0
- package/public/file.svg +1 -0
- package/public/globe.svg +1 -0
- package/public/ndpr-toolkit-logo.svg +108 -0
- package/public/next.svg +1 -0
- package/public/vercel.svg +1 -0
- package/public/window.svg +1 -0
- package/src/__tests__/example.test.ts +13 -0
- package/src/__tests__/requestService.test.ts +57 -0
- package/src/app/accessibility.css +70 -0
- package/src/app/docs/components/DocLayout.tsx +267 -0
- package/src/app/docs/components/breach-notification/page.tsx +797 -0
- package/src/app/docs/components/consent-management/page.tsx +576 -0
- package/src/app/docs/components/data-subject-rights/page.tsx +511 -0
- package/src/app/docs/components/dpia-questionnaire/layout.tsx +15 -0
- package/src/app/docs/components/dpia-questionnaire/metadata.ts +31 -0
- package/src/app/docs/components/dpia-questionnaire/page.tsx +666 -0
- package/src/app/docs/components/hooks/page.tsx +305 -0
- package/src/app/docs/components/page.tsx +84 -0
- package/src/app/docs/components/privacy-policy-generator/page.tsx +634 -0
- package/src/app/docs/guides/breach-notification-process/components/BestPractices.tsx +123 -0
- package/src/app/docs/guides/breach-notification-process/components/ImplementationSteps.tsx +328 -0
- package/src/app/docs/guides/breach-notification-process/components/Introduction.tsx +28 -0
- package/src/app/docs/guides/breach-notification-process/components/NotificationTimeline.tsx +91 -0
- package/src/app/docs/guides/breach-notification-process/components/Resources.tsx +118 -0
- package/src/app/docs/guides/breach-notification-process/page.tsx +39 -0
- package/src/app/docs/guides/conducting-dpia/page.tsx +593 -0
- package/src/app/docs/guides/data-subject-requests/page.tsx +666 -0
- package/src/app/docs/guides/managing-consent/page.tsx +738 -0
- package/src/app/docs/guides/ndpr-compliance-checklist/components/ComplianceChecklist.tsx +296 -0
- package/src/app/docs/guides/ndpr-compliance-checklist/components/ImplementationTools.tsx +145 -0
- package/src/app/docs/guides/ndpr-compliance-checklist/components/Introduction.tsx +33 -0
- package/src/app/docs/guides/ndpr-compliance-checklist/components/KeyRequirements.tsx +99 -0
- package/src/app/docs/guides/ndpr-compliance-checklist/components/Resources.tsx +159 -0
- package/src/app/docs/guides/ndpr-compliance-checklist/page.tsx +38 -0
- package/src/app/docs/guides/page.tsx +67 -0
- package/src/app/docs/layout.tsx +15 -0
- package/src/app/docs/metadata.ts +31 -0
- package/src/app/docs/page.tsx +572 -0
- package/src/app/favicon.ico +0 -0
- package/src/app/globals.css +123 -0
- package/src/app/layout.tsx +37 -0
- package/src/app/ndpr-demos/breach/page.tsx +354 -0
- package/src/app/ndpr-demos/consent/page.tsx +366 -0
- package/src/app/ndpr-demos/dpia/page.tsx +495 -0
- package/src/app/ndpr-demos/dsr/page.tsx +280 -0
- package/src/app/ndpr-demos/page.tsx +73 -0
- package/src/app/ndpr-demos/policy/page.tsx +771 -0
- package/src/app/page.tsx +452 -0
- package/src/components/ErrorBoundary.tsx +90 -0
- package/src/components/breach-notification/BreachNotificationForm.tsx +479 -0
- package/src/components/consent/ConsentBanner.tsx +159 -0
- package/src/components/data-subject-rights/DataSubjectRequestForm.tsx +419 -0
- package/src/components/docs/DocLayout.tsx +289 -0
- package/src/components/docs/index.ts +2 -0
- package/src/components/dpia/DPIAQuestionnaire.tsx +483 -0
- package/src/components/privacy-policy/PolicyGenerator.tsx +1062 -0
- package/src/components/privacy-policy/data.ts +98 -0
- package/src/components/privacy-policy/shared/CheckboxField.tsx +38 -0
- package/src/components/privacy-policy/shared/CheckboxGroup.tsx +85 -0
- package/src/components/privacy-policy/shared/FormField.tsx +79 -0
- package/src/components/privacy-policy/shared/StepIndicator.tsx +86 -0
- package/src/components/privacy-policy/steps/CustomSectionsStep.tsx +335 -0
- package/src/components/privacy-policy/steps/DataCollectionStep.tsx +231 -0
- package/src/components/privacy-policy/steps/DataSharingStep.tsx +418 -0
- package/src/components/privacy-policy/steps/OrganizationInfoStep.tsx +202 -0
- package/src/components/privacy-policy/steps/PolicyPreviewStep.tsx +172 -0
- package/src/components/ui/Badge.tsx +46 -0
- package/src/components/ui/Button.tsx +59 -0
- package/src/components/ui/Card.tsx +92 -0
- package/src/components/ui/Checkbox.tsx +57 -0
- package/src/components/ui/FormField.tsx +50 -0
- package/src/components/ui/Input.tsx +38 -0
- package/src/components/ui/Loading.tsx +201 -0
- package/src/components/ui/Select.tsx +42 -0
- package/src/components/ui/TextArea.tsx +38 -0
- package/src/components/ui/label.tsx +24 -0
- package/src/components/ui/switch.tsx +31 -0
- package/src/components/ui/tabs.tsx +66 -0
- package/src/hooks/useConsent.ts +64 -0
- package/src/hooks/useLoadingState.ts +85 -0
- package/src/lib/consentService.ts +137 -0
- package/src/lib/dpiaQuestions.ts +148 -0
- package/src/lib/requestService.ts +75 -0
- package/src/lib/sanitize.ts +108 -0
- package/src/lib/storage.ts +222 -0
- package/src/lib/utils.ts +6 -0
- package/src/types/html-to-docx.d.ts +30 -0
- package/src/types/index.ts +72 -0
- package/tailwind.config.ts +65 -0
- package/tsconfig.json +41 -0
- package/dist/components/breach/BreachNotificationManager.d.ts +0 -62
- package/dist/components/breach/BreachReportForm.d.ts +0 -66
- package/dist/components/breach/BreachRiskAssessment.d.ts +0 -50
- package/dist/components/breach/RegulatoryReportGenerator.d.ts +0 -94
- package/dist/components/consent/ConsentBanner.d.ts +0 -79
- package/dist/components/consent/ConsentManager.d.ts +0 -73
- package/dist/components/consent/ConsentStorage.d.ts +0 -41
- package/dist/components/dpia/DPIAQuestionnaire.d.ts +0 -70
- package/dist/components/dpia/DPIAReport.d.ts +0 -40
- package/dist/components/dpia/StepIndicator.d.ts +0 -64
- package/dist/components/dsr/DSRDashboard.d.ts +0 -58
- package/dist/components/dsr/DSRRequestForm.d.ts +0 -74
- package/dist/components/dsr/DSRTracker.d.ts +0 -56
- package/dist/components/policy/PolicyExporter.d.ts +0 -65
- package/dist/components/policy/PolicyGenerator.d.ts +0 -54
- package/dist/components/policy/PolicyPreview.d.ts +0 -71
- package/dist/hooks/useBreach.d.ts +0 -97
- package/dist/hooks/useConsent.d.ts +0 -63
- package/dist/hooks/useDPIA.d.ts +0 -92
- package/dist/hooks/useDSR.d.ts +0 -72
- package/dist/hooks/usePrivacyPolicy.d.ts +0 -87
- package/dist/index.esm.js +0 -2
- package/dist/index.esm.js.map +0 -1
- package/dist/index.js +0 -2
- package/dist/index.js.map +0 -1
- package/dist/setupTests.d.ts +0 -2
- package/dist/types/breach.d.ts +0 -239
- package/dist/types/consent.d.ts +0 -95
- package/dist/types/dpia.d.ts +0 -196
- package/dist/types/dsr.d.ts +0 -162
- package/dist/types/privacy.d.ts +0 -204
- package/dist/utils/breach.d.ts +0 -14
- package/dist/utils/consent.d.ts +0 -10
- package/dist/utils/dpia.d.ts +0 -12
- package/dist/utils/dsr.d.ts +0 -11
- package/dist/utils/privacy.d.ts +0 -12
|
@@ -0,0 +1,771 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import React, { useState } from "react";
|
|
4
|
+
import Link from "next/link";
|
|
5
|
+
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
|
|
6
|
+
import {
|
|
7
|
+
Card,
|
|
8
|
+
CardContent,
|
|
9
|
+
CardDescription,
|
|
10
|
+
CardHeader,
|
|
11
|
+
CardTitle,
|
|
12
|
+
} from "@/components/ui/Card";
|
|
13
|
+
import {
|
|
14
|
+
PolicyGenerator,
|
|
15
|
+
PolicyPreview,
|
|
16
|
+
PolicyExporter,
|
|
17
|
+
PolicySection,
|
|
18
|
+
PolicyVariable,
|
|
19
|
+
} from "@tantainnovative/ndpr-toolkit";
|
|
20
|
+
import type { PolicyTemplate } from "@tantainnovative/ndpr-toolkit";
|
|
21
|
+
|
|
22
|
+
export default function PolicyDemoPage() {
|
|
23
|
+
const [activeTab, setActiveTab] = useState<string>("generator");
|
|
24
|
+
// Initialize with empty objects/arrays to prevent undefined errors
|
|
25
|
+
const [policyData, setPolicyData] = useState<Record<string, unknown>>({});
|
|
26
|
+
const [generatedPolicy, setGeneratedPolicy] = useState<PolicySection[]>([]);
|
|
27
|
+
const [policyVariables, setPolicyVariables] = useState<PolicyVariable[]>([]);
|
|
28
|
+
|
|
29
|
+
// Helper: process conditional {{#if …}}…{{else}}…{{/if}} blocks
|
|
30
|
+
const processConditionalBlocks = (
|
|
31
|
+
content: string,
|
|
32
|
+
data: Record<string, unknown>,
|
|
33
|
+
): string => {
|
|
34
|
+
if (!content || typeof content !== "string") return "";
|
|
35
|
+
if (!data || typeof data !== "object") data = {};
|
|
36
|
+
|
|
37
|
+
try {
|
|
38
|
+
// First pass: Process nested if blocks from innermost to outermost
|
|
39
|
+
let processedContent = content;
|
|
40
|
+
let lastContent = "";
|
|
41
|
+
|
|
42
|
+
// Keep processing until no more changes are made (handles nested conditionals)
|
|
43
|
+
while (processedContent !== lastContent) {
|
|
44
|
+
lastContent = processedContent;
|
|
45
|
+
const ifRegex =
|
|
46
|
+
/\{\{#if ([^}]+)\}\}([\s\S]*?)(?:\{\{else\}\}([\s\S]*?))?\{\{\/if\}\}/g;
|
|
47
|
+
|
|
48
|
+
processedContent = processedContent.replace(
|
|
49
|
+
ifRegex,
|
|
50
|
+
(_match, variable, ifContent, elseContent = "") => {
|
|
51
|
+
if (!variable || typeof variable !== "string") return elseContent;
|
|
52
|
+
|
|
53
|
+
// Handle complex conditions with AND/OR operators
|
|
54
|
+
if (variable.includes("&&") || variable.includes("||")) {
|
|
55
|
+
try {
|
|
56
|
+
// Create a safe evaluation context with data variables
|
|
57
|
+
const evalContext = { ...data };
|
|
58
|
+
// Replace operators with JavaScript operators
|
|
59
|
+
const jsCondition = variable
|
|
60
|
+
.replace(/\s*&&\s*/g, " && ")
|
|
61
|
+
.replace(/\s*\|\|\s*/g, " || ");
|
|
62
|
+
|
|
63
|
+
// Safely evaluate the condition
|
|
64
|
+
const result = Object.keys(evalContext).some(
|
|
65
|
+
(key) => jsCondition.includes(key) && evalContext[key],
|
|
66
|
+
);
|
|
67
|
+
|
|
68
|
+
return result ? ifContent : elseContent;
|
|
69
|
+
} catch (error) {
|
|
70
|
+
console.error("Error evaluating complex condition:", error);
|
|
71
|
+
return elseContent;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// Handle simple conditions
|
|
76
|
+
let value = data[variable];
|
|
77
|
+
if (value === "true") value = true;
|
|
78
|
+
if (value === "false") value = false;
|
|
79
|
+
if (Array.isArray(value) && value.length === 0) value = false;
|
|
80
|
+
if (value === "" || value === undefined || value === null)
|
|
81
|
+
value = false;
|
|
82
|
+
|
|
83
|
+
return value ? ifContent : elseContent;
|
|
84
|
+
},
|
|
85
|
+
);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// Second pass: Clean up any empty lines and extra whitespace
|
|
89
|
+
return processedContent
|
|
90
|
+
.replace(/\n{3,}/g, "\n\n") // Replace multiple newlines with double newlines
|
|
91
|
+
.replace(/\s+\n/g, "\n") // Remove trailing whitespace
|
|
92
|
+
.trim();
|
|
93
|
+
} catch (error) {
|
|
94
|
+
console.error("Error processing conditional blocks:", error);
|
|
95
|
+
return content; // Return original content if tHere's an error
|
|
96
|
+
}
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
// Build the exportable markdown/HTML content
|
|
100
|
+
const generateFormattedContent = (): string => {
|
|
101
|
+
try {
|
|
102
|
+
if (
|
|
103
|
+
!generatedPolicy ||
|
|
104
|
+
!Array.isArray(generatedPolicy) ||
|
|
105
|
+
generatedPolicy.length === 0
|
|
106
|
+
) {
|
|
107
|
+
return "# No policy content generated yet\n\nPlease use the generator to create your policy.";
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// Get current date in a professional format
|
|
111
|
+
const formattedDate = new Date().toLocaleDateString("en-US", {
|
|
112
|
+
year: "numeric",
|
|
113
|
+
month: "long",
|
|
114
|
+
day: "numeric",
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
// Create a professional header with proper spacing and formatting
|
|
118
|
+
const policyTitle = `# ${policyData?.organizationName || "Your Organization"} Privacy Policy\n\n`;
|
|
119
|
+
const lastUpdated = `*Last Updated: ${formattedDate}*\n\n`;
|
|
120
|
+
const complianceNotice = `*This privacy policy is designed to comply with the Nigeria Data Protection Regulation (NDPR) and has been prepared by ${policyData?.organizationName || "Your Organization"}.*\n\n`;
|
|
121
|
+
|
|
122
|
+
// Add a professional table of contents
|
|
123
|
+
let tableOfContents = "## Table of Contents\n\n";
|
|
124
|
+
const includedSections = generatedPolicy.filter(
|
|
125
|
+
(section) => section && section.included !== false,
|
|
126
|
+
);
|
|
127
|
+
|
|
128
|
+
includedSections.forEach((section, index) => {
|
|
129
|
+
if (section && section.title) {
|
|
130
|
+
tableOfContents += `${index + 1}. [${section.title}](#${section.id})\n`;
|
|
131
|
+
}
|
|
132
|
+
});
|
|
133
|
+
tableOfContents += "\n";
|
|
134
|
+
|
|
135
|
+
// Process each section with careful error handling and enhanced formatting
|
|
136
|
+
const sectionsContent = includedSections
|
|
137
|
+
.map((section, sectionIndex) => {
|
|
138
|
+
try {
|
|
139
|
+
if (
|
|
140
|
+
!section ||
|
|
141
|
+
!section.template ||
|
|
142
|
+
typeof section.template !== "string"
|
|
143
|
+
) {
|
|
144
|
+
return "";
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
let processed = section.template;
|
|
148
|
+
const sectionVars = section.variables || [];
|
|
149
|
+
|
|
150
|
+
// Process all variables for this section
|
|
151
|
+
if (Array.isArray(sectionVars)) {
|
|
152
|
+
sectionVars.forEach((varName) => {
|
|
153
|
+
if (typeof varName !== "string") return;
|
|
154
|
+
|
|
155
|
+
let val: unknown = policyData?.[varName] ?? "";
|
|
156
|
+
|
|
157
|
+
// Format array values as professional bullet points
|
|
158
|
+
if (Array.isArray(val) && val.length > 0) {
|
|
159
|
+
val = val.map((item, i) => `${i + 1}. ${item}`).join("\n\n");
|
|
160
|
+
} else if (Array.isArray(val)) {
|
|
161
|
+
val = "Not specified";
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
// Handle special formatting for dates
|
|
165
|
+
if (
|
|
166
|
+
varName.toLowerCase().includes("date") &&
|
|
167
|
+
typeof val === "string"
|
|
168
|
+
) {
|
|
169
|
+
try {
|
|
170
|
+
const date = new Date(val);
|
|
171
|
+
if (!isNaN(date.getTime())) {
|
|
172
|
+
val = date.toLocaleDateString("en-US", {
|
|
173
|
+
year: "numeric",
|
|
174
|
+
month: "long",
|
|
175
|
+
day: "numeric",
|
|
176
|
+
});
|
|
177
|
+
}
|
|
178
|
+
} catch {
|
|
179
|
+
// Keep original value if date parsing fails
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
try {
|
|
184
|
+
// Replace both triple and double braces for HTML/plain text
|
|
185
|
+
const valStr = String(val);
|
|
186
|
+
processed = processed
|
|
187
|
+
.replace(
|
|
188
|
+
new RegExp(`\\{\\{\\{${varName}\\}\\}\\}`, "g"),
|
|
189
|
+
valStr,
|
|
190
|
+
)
|
|
191
|
+
.replace(new RegExp(`\\{\\{${varName}\\}\\}`, "g"), valStr);
|
|
192
|
+
} catch (regexError) {
|
|
193
|
+
console.error("Error replacing variables:", regexError);
|
|
194
|
+
}
|
|
195
|
+
});
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
// Process conditional blocks with enhanced error handling
|
|
199
|
+
try {
|
|
200
|
+
processed = processConditionalBlocks(processed, policyData || {});
|
|
201
|
+
} catch (condError) {
|
|
202
|
+
console.error("Error processing conditional blocks:", condError);
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
// Add section number for better organization
|
|
206
|
+
return `## ${sectionIndex + 1}. ${section.title || "Untitled Section"} {#${section.id}}\n\n${processed}`;
|
|
207
|
+
} catch (sectionError) {
|
|
208
|
+
console.error("Error processing section:", sectionError);
|
|
209
|
+
return "";
|
|
210
|
+
}
|
|
211
|
+
})
|
|
212
|
+
.filter(Boolean)
|
|
213
|
+
.join("\n\n");
|
|
214
|
+
|
|
215
|
+
// Add a professional footer
|
|
216
|
+
const footer = `\n\n---\n\n*This privacy policy was last updated on ${formattedDate}. If you have any questions about this policy, please contact ${policyData?.dpoName || "our Data Protection Officer"} at ${policyData?.dpoEmail || policyData?.contactEmail || "our contact email"}.*\n\n© ${new Date().getFullYear()} ${policyData?.organizationName || "Your Organization"}. All rights reserved.`;
|
|
217
|
+
|
|
218
|
+
return (
|
|
219
|
+
policyTitle +
|
|
220
|
+
lastUpdated +
|
|
221
|
+
complianceNotice +
|
|
222
|
+
tableOfContents +
|
|
223
|
+
sectionsContent +
|
|
224
|
+
footer
|
|
225
|
+
);
|
|
226
|
+
} catch (error) {
|
|
227
|
+
console.error("Error generating formatted content:", error);
|
|
228
|
+
return "# Error Generating Policy\n\nThere was an error generating your policy content. Please try again.";
|
|
229
|
+
}
|
|
230
|
+
};
|
|
231
|
+
|
|
232
|
+
// Called when PolicyGenerator emits data
|
|
233
|
+
const handleGeneratePolicy = (data: Record<string, unknown>) => {
|
|
234
|
+
try {
|
|
235
|
+
console.log("Policy generator data received:", data);
|
|
236
|
+
|
|
237
|
+
// Validate sections
|
|
238
|
+
const sections = Array.isArray(data?.sections) ? data.sections : [];
|
|
239
|
+
// Validate variables
|
|
240
|
+
const variables = Array.isArray(data?.variables) ? data.variables : [];
|
|
241
|
+
// Validate values
|
|
242
|
+
const values =
|
|
243
|
+
data?.values && typeof data.values === "object" ? data.values : {};
|
|
244
|
+
|
|
245
|
+
// Update state with validated data
|
|
246
|
+
setGeneratedPolicy(sections);
|
|
247
|
+
setPolicyVariables(variables);
|
|
248
|
+
setPolicyData(values as Record<string, unknown>);
|
|
249
|
+
|
|
250
|
+
// Only navigate if we have valid sections
|
|
251
|
+
if (sections.length > 0) {
|
|
252
|
+
setActiveTab("display");
|
|
253
|
+
} else {
|
|
254
|
+
console.warn("No policy sections were generated");
|
|
255
|
+
}
|
|
256
|
+
} catch (error) {
|
|
257
|
+
console.error("Error handling policy generation:", error);
|
|
258
|
+
// Initialize with empty arrays to prevent mapping errors
|
|
259
|
+
setGeneratedPolicy([]);
|
|
260
|
+
setPolicyVariables([]);
|
|
261
|
+
setPolicyData({});
|
|
262
|
+
}
|
|
263
|
+
};
|
|
264
|
+
|
|
265
|
+
// Handle policy edits - we'll need to implement this differently since PolicyPreview doesn't support direct section updates
|
|
266
|
+
const handlePolicyEdit = () => {
|
|
267
|
+
console.log("Policy edit requested");
|
|
268
|
+
// In a real implementation, you might want to switch back to the generator tab or open an edit modal
|
|
269
|
+
setActiveTab("generator");
|
|
270
|
+
};
|
|
271
|
+
|
|
272
|
+
// Your NDPR template definition
|
|
273
|
+
const policyTemplate: PolicyTemplate = {
|
|
274
|
+
id: "ndpr-policy",
|
|
275
|
+
name: "NDPR Compliant Privacy Policy",
|
|
276
|
+
description: "A comprehensive privacy policy template compliant with NDPR",
|
|
277
|
+
organizationType: "business",
|
|
278
|
+
version: "1.0",
|
|
279
|
+
lastUpdated: Date.now(), // Using timestamp as required by the PolicyTemplate type
|
|
280
|
+
variables: {
|
|
281
|
+
organizationName: {
|
|
282
|
+
name: "Organization Name",
|
|
283
|
+
description: "The name of your organization",
|
|
284
|
+
required: true,
|
|
285
|
+
defaultValue: "Your Company",
|
|
286
|
+
},
|
|
287
|
+
website: {
|
|
288
|
+
name: "Website URL",
|
|
289
|
+
description: "Your organization's website",
|
|
290
|
+
required: true,
|
|
291
|
+
defaultValue: "https://example.com",
|
|
292
|
+
},
|
|
293
|
+
contactEmail: {
|
|
294
|
+
name: "Contact Email",
|
|
295
|
+
description: "Email for privacy inquiries",
|
|
296
|
+
required: true,
|
|
297
|
+
defaultValue: "privacy@example.com",
|
|
298
|
+
},
|
|
299
|
+
address: {
|
|
300
|
+
name: "Business Address",
|
|
301
|
+
description: "Physical address of your organization",
|
|
302
|
+
required: true,
|
|
303
|
+
defaultValue: "123 Business Street, Lagos, Nigeria",
|
|
304
|
+
},
|
|
305
|
+
phone: {
|
|
306
|
+
name: "Contact Phone",
|
|
307
|
+
description: "Phone number for privacy inquiries",
|
|
308
|
+
required: true,
|
|
309
|
+
defaultValue: "+234 123 456 7890",
|
|
310
|
+
},
|
|
311
|
+
dpoName: {
|
|
312
|
+
name: "Data Protection Officer Name",
|
|
313
|
+
description: "Name of your Data Protection Officer",
|
|
314
|
+
required: true,
|
|
315
|
+
defaultValue: "John Doe",
|
|
316
|
+
},
|
|
317
|
+
dpoEmail: {
|
|
318
|
+
name: "DPO Email",
|
|
319
|
+
description: "Email of your Data Protection Officer",
|
|
320
|
+
required: true,
|
|
321
|
+
defaultValue: "dpo@example.com",
|
|
322
|
+
},
|
|
323
|
+
industry: {
|
|
324
|
+
name: "Industry",
|
|
325
|
+
description: "Your organization's industry or sector",
|
|
326
|
+
required: true,
|
|
327
|
+
defaultValue: "Technology",
|
|
328
|
+
},
|
|
329
|
+
effectiveDate: {
|
|
330
|
+
name: "Effective Date",
|
|
331
|
+
description: "When this privacy policy becomes effective",
|
|
332
|
+
required: true,
|
|
333
|
+
defaultValue: new Date().toLocaleDateString(),
|
|
334
|
+
},
|
|
335
|
+
},
|
|
336
|
+
sections: [
|
|
337
|
+
{
|
|
338
|
+
id: "introduction",
|
|
339
|
+
title: "Introduction",
|
|
340
|
+
required: true,
|
|
341
|
+
description:
|
|
342
|
+
"Introduce your organization and the purpose of the policy",
|
|
343
|
+
template: `## Introduction
|
|
344
|
+
|
|
345
|
+
{{organizationName}} ("we", "us", or "our") is committed to protecting your personal data and respecting your privacy. This Privacy Policy explains how we collect, use, disclose, and safeguard your information when you interact with our services, website, and applications.
|
|
346
|
+
|
|
347
|
+
This policy is compliant with the Nigeria Data Protection Regulation (NDPR) 2019 and applies to all personal data processed by us. By using our services, you consent to the data practices described in this Privacy Policy.
|
|
348
|
+
|
|
349
|
+
### About Us
|
|
350
|
+
|
|
351
|
+
{{organizationName}} is a {{organizationType}} organization registered in Nigeria with its principal place of business at {{address}}. We can be contacted at:
|
|
352
|
+
|
|
353
|
+
- Email: {{contactEmail}}
|
|
354
|
+
- Phone: {{phone}}
|
|
355
|
+
- Address: {{address}}
|
|
356
|
+
|
|
357
|
+
### Data Protection Officer
|
|
358
|
+
|
|
359
|
+
We have appointed a Data Protection Officer ("DPO") who is responsible for overseeing questions regarding this Privacy Policy. If you have any questions about this Privacy Policy, including any requests to exercise your legal rights, please contact our DPO using the details below:
|
|
360
|
+
|
|
361
|
+
- Name: {{dpoName}}
|
|
362
|
+
- Email: {{dpoEmail}}
|
|
363
|
+
- Address: {{address}}
|
|
364
|
+
|
|
365
|
+
### Effective Date
|
|
366
|
+
|
|
367
|
+
This Privacy Policy is effective as of {{effectiveDate}} and will remain in effect except with respect to any changes in its provisions in the future, which will be in effect immediately after being posted on this page.`,
|
|
368
|
+
included: true,
|
|
369
|
+
variables: [
|
|
370
|
+
"organizationName",
|
|
371
|
+
"organizationType",
|
|
372
|
+
"address",
|
|
373
|
+
"contactEmail",
|
|
374
|
+
"phone",
|
|
375
|
+
"dpoName",
|
|
376
|
+
"dpoEmail",
|
|
377
|
+
"effectiveDate",
|
|
378
|
+
],
|
|
379
|
+
},
|
|
380
|
+
{
|
|
381
|
+
id: "definitions",
|
|
382
|
+
title: "Definitions",
|
|
383
|
+
required: true,
|
|
384
|
+
description: "Define key terms used throughout the policy",
|
|
385
|
+
template: `## Key Definitions
|
|
386
|
+
|
|
387
|
+
To help you understand this Privacy Policy, here are definitions of key terms used throughout:
|
|
388
|
+
|
|
389
|
+
- **Personal Data**: Any information relating to an identified or identifiable natural person ('data subject'); an identifiable natural person is one who can be identified, directly or indirectly, in particular by reference to an identifier such as a name, an identification number, location data, an online identifier or to one or more factors specific to the physical, physiological, genetic, mental, economic, cultural or social identity of that natural person.
|
|
390
|
+
|
|
391
|
+
- **Data Subject**: A natural person who is the subject of Personal Data, i.e., the individual to whom the Personal Data relates.
|
|
392
|
+
|
|
393
|
+
- **Processing**: Any operation or set of operations which is performed on Personal Data or on sets of Personal Data, whether or not by automated means, such as collection, recording, organization, structuring, storage, adaptation or alteration, retrieval, consultation, use, disclosure by transmission, dissemination or otherwise making available, alignment or combination, restriction, erasure or destruction.
|
|
394
|
+
|
|
395
|
+
- **Data Controller**: The natural or legal person, public authority, agency or other body which, alone or jointly with others, determines the purposes and means of the processing of Personal Data. For the purposes of this Privacy Policy, {{organizationName}} is the Data Controller.
|
|
396
|
+
|
|
397
|
+
- **Data Processor**: A natural or legal person, public authority, agency or other body which processes Personal Data on behalf of the Data Controller.
|
|
398
|
+
|
|
399
|
+
- **Consent**: Any freely given, specific, informed and unambiguous indication of the Data Subject's wishes by which he or she, by a statement or by a clear affirmative action, signifies agreement to the processing of Personal Data relating to him or her.
|
|
400
|
+
|
|
401
|
+
- **Data Breach**: A breach of security leading to the accidental or unlawful destruction, loss, alteration, unauthorized disclosure of, or access to, Personal Data transmitted, stored or otherwise processed.
|
|
402
|
+
|
|
403
|
+
- **NDPR**: The Nigeria Data Protection Regulation 2019, issued by the National Information Technology Development Agency (NITDA).
|
|
404
|
+
|
|
405
|
+
- **NITDA**: The National Information Technology Development Agency, the regulatory body responsible for enforcing the NDPR in Nigeria.
|
|
406
|
+
|
|
407
|
+
- **Special Categories of Personal Data**: Personal Data revealing racial or ethnic origin, political opinions, religious or philosophical beliefs, trade union membership, genetic data, biometric data, data concerning health, or data concerning a natural person's sex life or sexual orientation.`,
|
|
408
|
+
included: true,
|
|
409
|
+
variables: ["organizationName"],
|
|
410
|
+
},
|
|
411
|
+
{
|
|
412
|
+
id: "dataCollection",
|
|
413
|
+
title: "Data Collection",
|
|
414
|
+
required: true,
|
|
415
|
+
description:
|
|
416
|
+
"Explain what personal data you collect and how you collect it",
|
|
417
|
+
template: `## Personal Data We Collect
|
|
418
|
+
|
|
419
|
+
### Categories of Personal Data We Collect
|
|
420
|
+
|
|
421
|
+
{{#if collectsPersonalData}}
|
|
422
|
+
We collect and process various categories of personal data for the purposes set out in this Privacy Policy. These categories include:
|
|
423
|
+
|
|
424
|
+
{{{dataTypes}}}
|
|
425
|
+
{{else}}
|
|
426
|
+
We do not collect personal data beyond what is necessary for basic website functionality.
|
|
427
|
+
{{/if}}
|
|
428
|
+
|
|
429
|
+
### How We Collect Personal Data
|
|
430
|
+
|
|
431
|
+
We collect personal data through various methods, including:
|
|
432
|
+
|
|
433
|
+
1. **Direct Interactions**: When you provide your personal data by filling in forms, creating an account, subscribing to our services, requesting marketing materials, participating in surveys, or corresponding with us.
|
|
434
|
+
|
|
435
|
+
2. **Automated Technologies**: As you interact with our {{website}}, we automatically collect Technical Data about your equipment, browsing actions, and patterns using cookies, server logs, and other similar technologies.
|
|
436
|
+
|
|
437
|
+
3. **Third Parties or Publicly Available Sources**: We may receive personal data about you from various third parties and public sources, such as analytics providers, advertising networks, search information providers, data brokers, or publicly available databases.
|
|
438
|
+
|
|
439
|
+
### Cookies and Similar Technologies
|
|
440
|
+
|
|
441
|
+
{{#if usesCookies}}
|
|
442
|
+
We use cookies and similar tracking technologies to track activity on our services and to hold certain information. The types of cookies we use include:
|
|
443
|
+
|
|
444
|
+
{{{cookieTypes}}}
|
|
445
|
+
|
|
446
|
+
You can instruct your browser to refuse all cookies or to indicate when a cookie is being sent. However, if you do not accept cookies, you may not be able to use some portions of our services.
|
|
447
|
+
{{else}}
|
|
448
|
+
We do not use cookies or similar tracking technologies on our website.
|
|
449
|
+
{{/if}}
|
|
450
|
+
|
|
451
|
+
### Children's Privacy
|
|
452
|
+
|
|
453
|
+
{{#if collectsChildrenData}}
|
|
454
|
+
We may collect data from children under 13 with verifiable parental consent. Parents can review, delete, or refuse further collection of their child's personal data by contacting us using the details provided in this Privacy Policy.
|
|
455
|
+
{{else}}
|
|
456
|
+
Our services are not intended for children under the age of 13, and we do not knowingly collect personal data from children under 13. If we learn we have collected or received personal data from a child under 13 without verification of parental consent, we will delete that information.
|
|
457
|
+
{{/if}}`,
|
|
458
|
+
included: true,
|
|
459
|
+
variables: [
|
|
460
|
+
"collectsPersonalData",
|
|
461
|
+
"dataTypes",
|
|
462
|
+
"website",
|
|
463
|
+
"usesCookies",
|
|
464
|
+
"cookieTypes",
|
|
465
|
+
"collectsChildrenData",
|
|
466
|
+
],
|
|
467
|
+
},
|
|
468
|
+
{
|
|
469
|
+
id: "dataUse",
|
|
470
|
+
title: "Use of Personal Data",
|
|
471
|
+
required: true,
|
|
472
|
+
description: "Explain how you use the personal data you collect",
|
|
473
|
+
template: `## How We Use Your Personal Data
|
|
474
|
+
|
|
475
|
+
### Purposes for Processing Your Personal Data
|
|
476
|
+
|
|
477
|
+
{{#if collectsPersonalData}}
|
|
478
|
+
We will only use your personal data when the law allows us and for legitimate purposes. We process your personal data for the following purposes:
|
|
479
|
+
|
|
480
|
+
{{{dataPurposes}}}
|
|
481
|
+
{{else}}
|
|
482
|
+
We do not collect or process personal data beyond what is necessary for basic website functionality.
|
|
483
|
+
{{/if}}
|
|
484
|
+
|
|
485
|
+
### Automated Decision-Making and Profiling
|
|
486
|
+
|
|
487
|
+
We may use automated decision-making processes, including profiling, to analyze your personal data and make decisions that may have a significant effect on you. These processes may be used for purposes such as:
|
|
488
|
+
|
|
489
|
+
- Determining your eligibility for certain products or services
|
|
490
|
+
- Personalizing your experience and the content we show you
|
|
491
|
+
- Detecting fraudulent or suspicious activity
|
|
492
|
+
|
|
493
|
+
You have the right not to be subject to a decision based solely on automated processing, including profiling, which produces legal effects concerning you or similarly significantly affects you, except where:
|
|
494
|
+
|
|
495
|
+
- It is necessary for entering into or performing a contract between you and us
|
|
496
|
+
- It is authorized by applicable law
|
|
497
|
+
- It is based on your explicit consent
|
|
498
|
+
|
|
499
|
+
### Change of Purpose
|
|
500
|
+
|
|
501
|
+
We will only use your personal data for the purposes for which we collected it, unless we reasonably consider that we need to use it for another reason and that reason is compatible with the original purpose. If we need to use your personal data for an unrelated purpose, we will notify you and explain the legal basis which allows us to do so.
|
|
502
|
+
|
|
503
|
+
Please note that we may process your personal data without your knowledge or consent, in compliance with the above rules, where this is required or permitted by law.`,
|
|
504
|
+
included: true,
|
|
505
|
+
variables: ["collectsPersonalData", "dataPurposes"],
|
|
506
|
+
},
|
|
507
|
+
{
|
|
508
|
+
id: "legalBasis",
|
|
509
|
+
title: "Legal Basis for Processing",
|
|
510
|
+
required: true,
|
|
511
|
+
description: "Explain the legal basis for processing personal data",
|
|
512
|
+
template: `## Legal Basis for Processing Personal Data
|
|
513
|
+
|
|
514
|
+
Under the Nigeria Data Protection Regulation (NDPR), we must have a valid legal basis for processing your personal data. We rely on the following legal bases for processing your personal data:
|
|
515
|
+
|
|
516
|
+
{{#if legalBases}}
|
|
517
|
+
{{{legalBases}}}
|
|
518
|
+
{{else}}
|
|
519
|
+
### Consent
|
|
520
|
+
|
|
521
|
+
We process certain personal data based on your consent. This means you have given us specific, informed, and unambiguous consent to process your personal data for particular purposes. For example, when you opt-in to receive marketing communications or agree to the use of certain cookies on our website.
|
|
522
|
+
|
|
523
|
+
You have the right to withdraw your consent at any time by contacting us using the details provided in this Privacy Policy or by using the opt-out mechanisms we provide (such as unsubscribe links in our marketing emails).
|
|
524
|
+
|
|
525
|
+
### Contractual Necessity
|
|
526
|
+
|
|
527
|
+
We process personal data when it is necessary for the performance of a contract to which you are a party or to take steps at your request before entering into such a contract. For example, when you purchase our products or services, we need to process your personal data to fulfill your order, provide customer support, and manage your account.
|
|
528
|
+
|
|
529
|
+
### Legal Obligation
|
|
530
|
+
|
|
531
|
+
We process personal data when it is necessary for compliance with a legal obligation to which we are subject. For example, we may need to process your personal data to comply with tax laws, regulatory requirements, or court orders.
|
|
532
|
+
|
|
533
|
+
### Legitimate Interests
|
|
534
|
+
|
|
535
|
+
We process personal data when it is necessary for the purposes of the legitimate interests pursued by us or by a third party, except where such interests are overridden by your interests or fundamental rights and freedoms which require protection of personal data.
|
|
536
|
+
{{/if}}
|
|
537
|
+
|
|
538
|
+
### Special Categories of Personal Data
|
|
539
|
+
|
|
540
|
+
For special categories of personal data (such as data revealing racial or ethnic origin, political opinions, religious beliefs, health data, or biometric data), we will generally process such data only with your explicit consent, unless the processing is necessary for one of the other legal bases specifically permitted under the NDPR.
|
|
541
|
+
- For the establishment, exercise, or defense of legal claims
|
|
542
|
+
- For reasons of substantial public interest, on the basis of Nigerian law
|
|
543
|
+
- For preventive or occupational medicine, medical diagnosis, or the provision of health or social care`,
|
|
544
|
+
included: true,
|
|
545
|
+
variables: ["legalBases"],
|
|
546
|
+
},
|
|
547
|
+
{
|
|
548
|
+
id: "dataSharing",
|
|
549
|
+
title: "Data Sharing",
|
|
550
|
+
required: true,
|
|
551
|
+
description: "Explain how you share personal data with third parties",
|
|
552
|
+
template: `## Data Sharing
|
|
553
|
+
|
|
554
|
+
### Third-Party Disclosures
|
|
555
|
+
|
|
556
|
+
{{#if collectsPersonalData}}
|
|
557
|
+
We may share your personal data with the following categories of third parties:
|
|
558
|
+
|
|
559
|
+
{{{dataRecipients}}}
|
|
560
|
+
{{else}}
|
|
561
|
+
We do not share personal data with third parties beyond what is necessary for basic website functionality.
|
|
562
|
+
{{/if}}
|
|
563
|
+
|
|
564
|
+
### Safeguards for Third-Party Transfers
|
|
565
|
+
|
|
566
|
+
We require all third parties to respect the security of your personal data and to treat it in accordance with the law. We do not allow our third-party service providers to use your personal data for their own purposes and only permit them to process your personal data for specified purposes and in accordance with our instructions.
|
|
567
|
+
|
|
568
|
+
### International Transfers
|
|
569
|
+
|
|
570
|
+
{{#if transfersDataInternationally}}
|
|
571
|
+
We may transfer your personal data to countries outside Nigeria. When we do, we ensure a similar degree of protection is afforded to your personal data by ensuring at least one of the following safeguards is implemented:
|
|
572
|
+
|
|
573
|
+
- We will only transfer your personal data to countries that have been deemed to provide an adequate level of protection for personal data.
|
|
574
|
+
- Where we use certain service providers, we may use specific contracts approved for use in Nigeria which give personal data the same protection it has in Nigeria.
|
|
575
|
+
- Where we transfer data to the United States or other regions, we may use specific certification mechanisms or obtain your consent for the transfer.
|
|
576
|
+
|
|
577
|
+
Please contact us if you want further information on the specific mechanism used by us when transferring your personal data out of Nigeria.
|
|
578
|
+
{{/if}}`,
|
|
579
|
+
included: true,
|
|
580
|
+
variables: [
|
|
581
|
+
"collectsPersonalData",
|
|
582
|
+
"dataRecipients",
|
|
583
|
+
"transfersDataInternationally",
|
|
584
|
+
],
|
|
585
|
+
},
|
|
586
|
+
{
|
|
587
|
+
id: "dataRetention",
|
|
588
|
+
title: "Data Retention",
|
|
589
|
+
required: true,
|
|
590
|
+
description: "Explain how long you retain personal data",
|
|
591
|
+
template: `## Data Retention
|
|
592
|
+
### How Long We Keep Your Personal Data
|
|
593
|
+
|
|
594
|
+
{{#if collectsPersonalData}}
|
|
595
|
+
We will only retain your personal data for as long as necessary to fulfill the purposes we collected it for, including for the purposes of satisfying any legal, accounting, or reporting requirements.
|
|
596
|
+
|
|
597
|
+
Our standard retention period for personal data is: {{dataRetentionPeriod}}
|
|
598
|
+
|
|
599
|
+
To determine the appropriate retention period for personal data, we consider the amount, nature, and sensitivity of the personal data, the potential risk of harm from unauthorized use or disclosure of your personal data, the purposes for which we process your personal data and whether we can achieve those purposes through other means, and the applicable legal requirements.
|
|
600
|
+
{{else}}
|
|
601
|
+
We do not retain personal data beyond what is necessary for basic website functionality.
|
|
602
|
+
{{/if}}
|
|
603
|
+
|
|
604
|
+
### Data Deletion
|
|
605
|
+
|
|
606
|
+
When your personal data is no longer required for the purposes for which it was collected, we will delete or anonymize it. If this is not possible (for example, because your personal data has been stored in backup archives), then we will securely store your personal data and isolate it from any further processing until deletion is possible.
|
|
607
|
+
|
|
608
|
+
### Data Minimization
|
|
609
|
+
|
|
610
|
+
We practice data minimization, which means we only collect and process the personal data that is necessary for the purposes for which it is collected. We regularly review our data collection practices to ensure we are not collecting more data than necessary.`,
|
|
611
|
+
included: true,
|
|
612
|
+
variables: ["collectsPersonalData", "dataRetentionPeriod"],
|
|
613
|
+
},
|
|
614
|
+
],
|
|
615
|
+
};
|
|
616
|
+
|
|
617
|
+
return (
|
|
618
|
+
<div className="container mx-auto p-6">
|
|
619
|
+
<Tabs value={activeTab} onValueChange={setActiveTab}>
|
|
620
|
+
<TabsList>
|
|
621
|
+
<TabsTrigger value="generator">Generator</TabsTrigger>
|
|
622
|
+
<TabsTrigger value="display">Preview</TabsTrigger>
|
|
623
|
+
<TabsTrigger value="audit">Audit & Export</TabsTrigger>
|
|
624
|
+
</TabsList>
|
|
625
|
+
|
|
626
|
+
{/* Generator */}
|
|
627
|
+
<TabsContent value="generator" className="mt-6">
|
|
628
|
+
<Card>
|
|
629
|
+
<CardHeader>
|
|
630
|
+
<CardTitle>Privacy Policy Generator</CardTitle>
|
|
631
|
+
<CardDescription>
|
|
632
|
+
Configure your organization and generate an NDPR‐compliant
|
|
633
|
+
policy.
|
|
634
|
+
</CardDescription>
|
|
635
|
+
</CardHeader>
|
|
636
|
+
<CardContent>
|
|
637
|
+
<PolicyGenerator
|
|
638
|
+
sections={policyTemplate.sections}
|
|
639
|
+
variables={Object.entries(policyTemplate.variables).map(
|
|
640
|
+
([key, value]) => ({
|
|
641
|
+
id: key,
|
|
642
|
+
name: value.name,
|
|
643
|
+
description: value.description,
|
|
644
|
+
required: value.required,
|
|
645
|
+
defaultValue: value.defaultValue,
|
|
646
|
+
value: value.defaultValue || "",
|
|
647
|
+
inputType: "text", // Default to text input type
|
|
648
|
+
}),
|
|
649
|
+
)}
|
|
650
|
+
onGenerate={handleGeneratePolicy}
|
|
651
|
+
title="NDPR Privacy Policy Generator"
|
|
652
|
+
description="Generate an NDPR-compliant privacy policy for your organization."
|
|
653
|
+
buttonClassName="bg-blue-600 hover:bg-blue-700 text-white"
|
|
654
|
+
/>
|
|
655
|
+
</CardContent>
|
|
656
|
+
</Card>
|
|
657
|
+
</TabsContent>
|
|
658
|
+
|
|
659
|
+
{/* Preview */}
|
|
660
|
+
<TabsContent value="display" className="mt-6">
|
|
661
|
+
<Card>
|
|
662
|
+
<CardHeader>
|
|
663
|
+
<CardTitle>Policy Preview</CardTitle>
|
|
664
|
+
<CardDescription>
|
|
665
|
+
Review and edit your generated policy before exporting.
|
|
666
|
+
</CardDescription>
|
|
667
|
+
</CardHeader>
|
|
668
|
+
<CardContent>
|
|
669
|
+
{generatedPolicy && generatedPolicy.length > 0 ? (
|
|
670
|
+
<PolicyPreview
|
|
671
|
+
content={generateFormattedContent()}
|
|
672
|
+
sections={generatedPolicy}
|
|
673
|
+
variables={policyVariables || []}
|
|
674
|
+
onEdit={handlePolicyEdit}
|
|
675
|
+
organizationName={String(
|
|
676
|
+
policyData?.organizationName || "Your Organization",
|
|
677
|
+
)}
|
|
678
|
+
lastUpdated={new Date()}
|
|
679
|
+
showTableOfContents={true}
|
|
680
|
+
showMetadata={true}
|
|
681
|
+
title="Enterprise Privacy Policy"
|
|
682
|
+
description="NDPR-compliant privacy policy ready for implementation"
|
|
683
|
+
buttonClassName="bg-blue-600 hover:bg-blue-700 text-white"
|
|
684
|
+
/>
|
|
685
|
+
) : (
|
|
686
|
+
<div className="p-8 text-center">
|
|
687
|
+
<p className="text-gray-500">
|
|
688
|
+
No policy has been generated yet. Please use the Generator
|
|
689
|
+
tab first.
|
|
690
|
+
</p>
|
|
691
|
+
</div>
|
|
692
|
+
)}
|
|
693
|
+
</CardContent>
|
|
694
|
+
</Card>
|
|
695
|
+
{policyData && policyData.contactEmail ? (
|
|
696
|
+
<div className="mt-6 text-sm text-gray-500">
|
|
697
|
+
Questions? Contact{" "}
|
|
698
|
+
<a href={`mailto:${String(policyData.contactEmail)}`}>
|
|
699
|
+
{String(policyData.contactEmail)}
|
|
700
|
+
</a>
|
|
701
|
+
</div>
|
|
702
|
+
) : null}
|
|
703
|
+
</TabsContent>
|
|
704
|
+
|
|
705
|
+
{/* Audit & Export */}
|
|
706
|
+
<TabsContent value="audit" className="mt-6">
|
|
707
|
+
<Card>
|
|
708
|
+
<CardHeader>
|
|
709
|
+
<CardTitle>Audit & Export</CardTitle>
|
|
710
|
+
<CardDescription>
|
|
711
|
+
Check compliance and export in multiple formats.
|
|
712
|
+
</CardDescription>
|
|
713
|
+
</CardHeader>
|
|
714
|
+
<CardContent>
|
|
715
|
+
{generatedPolicy && generatedPolicy.length > 0 ? (
|
|
716
|
+
<PolicyExporter
|
|
717
|
+
content={generateFormattedContent()}
|
|
718
|
+
title={`${String(policyData?.organizationName || "Your Org")} Privacy Policy`}
|
|
719
|
+
organizationName={String(
|
|
720
|
+
policyData?.organizationName || "Your Org",
|
|
721
|
+
)}
|
|
722
|
+
lastUpdated={new Date()}
|
|
723
|
+
componentTitle="Export Privacy Policy"
|
|
724
|
+
description="Download in PDF, HTML, or Markdown."
|
|
725
|
+
buttonClassName="bg-blue-600 hover:bg-blue-700 text-white"
|
|
726
|
+
showExportHistory
|
|
727
|
+
includeComplianceNotice
|
|
728
|
+
/>
|
|
729
|
+
) : (
|
|
730
|
+
<div className="p-8 text-center">
|
|
731
|
+
<p className="text-gray-500">
|
|
732
|
+
No policy has been generated yet. Please use the Generator
|
|
733
|
+
tab first.
|
|
734
|
+
</p>
|
|
735
|
+
</div>
|
|
736
|
+
)}
|
|
737
|
+
</CardContent>
|
|
738
|
+
</Card>
|
|
739
|
+
</TabsContent>
|
|
740
|
+
</Tabs>
|
|
741
|
+
|
|
742
|
+
{/* Implementation Notes */}
|
|
743
|
+
<div className="mt-10 p-4 bg-gray-100 rounded-lg">
|
|
744
|
+
<h2 className="text-xl font-semibold mb-2">Implementation Notes</h2>
|
|
745
|
+
<ul className="list-disc pl-5 space-y-1">
|
|
746
|
+
<li>
|
|
747
|
+
<code>PolicyGenerator</code>: Build your policy based on the
|
|
748
|
+
template.
|
|
749
|
+
</li>
|
|
750
|
+
<li>
|
|
751
|
+
<code>PolicyPreview</code>: Live‐edit the generated sections.
|
|
752
|
+
</li>
|
|
753
|
+
<li>
|
|
754
|
+
<code>PolicyExporter</code>: Audit compliance and export final
|
|
755
|
+
documents.
|
|
756
|
+
</li>
|
|
757
|
+
</ul>
|
|
758
|
+
<p className="mt-4">
|
|
759
|
+
For full docs, visit{" "}
|
|
760
|
+
<Link
|
|
761
|
+
href="/docs/components/privacy-policy-generator"
|
|
762
|
+
className="text-blue-600 hover:underline"
|
|
763
|
+
>
|
|
764
|
+
Privacy Policy Generator documentation
|
|
765
|
+
</Link>
|
|
766
|
+
.
|
|
767
|
+
</p>
|
|
768
|
+
</div>
|
|
769
|
+
</div>
|
|
770
|
+
);
|
|
771
|
+
}
|