@tantainnovative/ndpr-toolkit 1.0.2 → 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.
Files changed (212) hide show
  1. package/.claude/settings.local.json +20 -0
  2. package/.eslintrc.json +10 -0
  3. package/.github/workflows/ci.yml +36 -0
  4. package/.github/workflows/nextjs.yml +104 -0
  5. package/.husky/commit-msg +4 -0
  6. package/.husky/pre-commit +4 -0
  7. package/.lintstagedrc.js +4 -0
  8. package/.nvmrc +1 -0
  9. package/.versionrc +17 -0
  10. package/CHANGELOG.md +16 -0
  11. package/CLAUDE.md +90 -0
  12. package/CNAME +1 -0
  13. package/CONTRIBUTING.md +87 -0
  14. package/README.md +84 -447
  15. package/RELEASE-NOTES-v1.0.0.md +140 -0
  16. package/RELEASE-NOTES-v1.0.1.md +69 -0
  17. package/SECURITY.md +21 -0
  18. package/commitlint.config.js +36 -0
  19. package/components.json +21 -0
  20. package/eslint.config.mjs +16 -0
  21. package/jest.config.js +31 -0
  22. package/jest.setup.js +15 -0
  23. package/next.config.js +15 -0
  24. package/next.config.ts +62 -0
  25. package/package.json +70 -52
  26. package/packages/ndpr-toolkit/README.md +467 -0
  27. package/packages/ndpr-toolkit/jest.config.js +23 -0
  28. package/packages/ndpr-toolkit/package-lock.json +8197 -0
  29. package/packages/ndpr-toolkit/package.json +71 -0
  30. package/packages/ndpr-toolkit/rollup.config.js +34 -0
  31. package/packages/ndpr-toolkit/src/__tests__/components/consent/ConsentBanner.test.tsx +119 -0
  32. package/packages/ndpr-toolkit/src/__tests__/components/consent/ConsentManager.test.tsx +122 -0
  33. package/packages/ndpr-toolkit/src/__tests__/components/consent/ConsentStorage.test.tsx +270 -0
  34. package/packages/ndpr-toolkit/src/__tests__/components/dsr/DSRDashboard.test.tsx +199 -0
  35. package/packages/ndpr-toolkit/src/__tests__/components/dsr/DSRRequestForm.test.tsx +224 -0
  36. package/packages/ndpr-toolkit/src/__tests__/components/dsr/DSRTracker.test.tsx +104 -0
  37. package/packages/ndpr-toolkit/src/__tests__/hooks/useConsent.test.tsx +161 -0
  38. package/packages/ndpr-toolkit/src/__tests__/hooks/useDSR.test.tsx +330 -0
  39. package/packages/ndpr-toolkit/src/__tests__/utils/breach.test.ts +149 -0
  40. package/packages/ndpr-toolkit/src/__tests__/utils/consent.test.ts +88 -0
  41. package/packages/ndpr-toolkit/src/__tests__/utils/dpia.test.ts +160 -0
  42. package/packages/ndpr-toolkit/src/__tests__/utils/dsr.test.ts +110 -0
  43. package/packages/ndpr-toolkit/src/__tests__/utils/privacy.test.ts +97 -0
  44. package/packages/ndpr-toolkit/src/components/breach/BreachNotificationManager.tsx +701 -0
  45. package/packages/ndpr-toolkit/src/components/breach/BreachReportForm.tsx +631 -0
  46. package/packages/ndpr-toolkit/src/components/breach/BreachRiskAssessment.tsx +569 -0
  47. package/packages/ndpr-toolkit/src/components/breach/RegulatoryReportGenerator.tsx +496 -0
  48. package/packages/ndpr-toolkit/src/components/consent/ConsentBanner.tsx +270 -0
  49. package/packages/ndpr-toolkit/src/components/consent/ConsentManager.tsx +217 -0
  50. package/packages/ndpr-toolkit/src/components/consent/ConsentStorage.tsx +206 -0
  51. package/packages/ndpr-toolkit/src/components/dpia/DPIAQuestionnaire.tsx +342 -0
  52. package/packages/ndpr-toolkit/src/components/dpia/DPIAReport.tsx +373 -0
  53. package/packages/ndpr-toolkit/src/components/dpia/StepIndicator.tsx +174 -0
  54. package/packages/ndpr-toolkit/src/components/dsr/DSRDashboard.tsx +717 -0
  55. package/packages/ndpr-toolkit/src/components/dsr/DSRRequestForm.tsx +476 -0
  56. package/packages/ndpr-toolkit/src/components/dsr/DSRTracker.tsx +620 -0
  57. package/packages/ndpr-toolkit/src/components/policy/PolicyExporter.tsx +541 -0
  58. package/packages/ndpr-toolkit/src/components/policy/PolicyGenerator.tsx +454 -0
  59. package/packages/ndpr-toolkit/src/components/policy/PolicyPreview.tsx +333 -0
  60. package/packages/ndpr-toolkit/src/hooks/useBreach.ts +409 -0
  61. package/packages/ndpr-toolkit/src/hooks/useConsent.ts +263 -0
  62. package/packages/ndpr-toolkit/src/hooks/useDPIA.ts +457 -0
  63. package/packages/ndpr-toolkit/src/hooks/useDSR.ts +236 -0
  64. package/packages/ndpr-toolkit/src/hooks/usePrivacyPolicy.ts +428 -0
  65. package/{dist/index.d.ts → packages/ndpr-toolkit/src/index.ts} +13 -0
  66. package/packages/ndpr-toolkit/src/setupTests.ts +5 -0
  67. package/packages/ndpr-toolkit/src/types/breach.ts +283 -0
  68. package/packages/ndpr-toolkit/src/types/consent.ts +111 -0
  69. package/packages/ndpr-toolkit/src/types/dpia.ts +236 -0
  70. package/packages/ndpr-toolkit/src/types/dsr.ts +192 -0
  71. package/packages/ndpr-toolkit/src/types/index.ts +42 -0
  72. package/packages/ndpr-toolkit/src/types/privacy.ts +246 -0
  73. package/packages/ndpr-toolkit/src/utils/breach.ts +122 -0
  74. package/packages/ndpr-toolkit/src/utils/consent.ts +51 -0
  75. package/packages/ndpr-toolkit/src/utils/dpia.ts +104 -0
  76. package/packages/ndpr-toolkit/src/utils/dsr.ts +77 -0
  77. package/packages/ndpr-toolkit/src/utils/privacy.ts +100 -0
  78. package/packages/ndpr-toolkit/tsconfig.json +23 -0
  79. package/postcss.config.mjs +5 -0
  80. package/public/NDPR TOOLKIT.svg +1 -0
  81. package/public/favicon/android-chrome-192x192.png +0 -0
  82. package/public/favicon/android-chrome-512x512.png +0 -0
  83. package/public/favicon/apple-touch-icon.png +0 -0
  84. package/public/favicon/favicon-16x16.png +0 -0
  85. package/public/favicon/favicon-32x32.png +0 -0
  86. package/public/favicon/site.webmanifest +1 -0
  87. package/public/file.svg +1 -0
  88. package/public/globe.svg +1 -0
  89. package/public/ndpr-toolkit-logo.svg +108 -0
  90. package/public/next.svg +1 -0
  91. package/public/vercel.svg +1 -0
  92. package/public/window.svg +1 -0
  93. package/src/__tests__/example.test.ts +13 -0
  94. package/src/__tests__/requestService.test.ts +57 -0
  95. package/src/app/accessibility.css +70 -0
  96. package/src/app/docs/components/DocLayout.tsx +267 -0
  97. package/src/app/docs/components/breach-notification/page.tsx +797 -0
  98. package/src/app/docs/components/consent-management/page.tsx +576 -0
  99. package/src/app/docs/components/data-subject-rights/page.tsx +511 -0
  100. package/src/app/docs/components/dpia-questionnaire/layout.tsx +15 -0
  101. package/src/app/docs/components/dpia-questionnaire/metadata.ts +31 -0
  102. package/src/app/docs/components/dpia-questionnaire/page.tsx +666 -0
  103. package/src/app/docs/components/hooks/page.tsx +305 -0
  104. package/src/app/docs/components/page.tsx +84 -0
  105. package/src/app/docs/components/privacy-policy-generator/page.tsx +634 -0
  106. package/src/app/docs/guides/breach-notification-process/components/BestPractices.tsx +123 -0
  107. package/src/app/docs/guides/breach-notification-process/components/ImplementationSteps.tsx +328 -0
  108. package/src/app/docs/guides/breach-notification-process/components/Introduction.tsx +28 -0
  109. package/src/app/docs/guides/breach-notification-process/components/NotificationTimeline.tsx +91 -0
  110. package/src/app/docs/guides/breach-notification-process/components/Resources.tsx +118 -0
  111. package/src/app/docs/guides/breach-notification-process/page.tsx +39 -0
  112. package/src/app/docs/guides/conducting-dpia/page.tsx +593 -0
  113. package/src/app/docs/guides/data-subject-requests/page.tsx +666 -0
  114. package/src/app/docs/guides/managing-consent/page.tsx +738 -0
  115. package/src/app/docs/guides/ndpr-compliance-checklist/components/ComplianceChecklist.tsx +296 -0
  116. package/src/app/docs/guides/ndpr-compliance-checklist/components/ImplementationTools.tsx +145 -0
  117. package/src/app/docs/guides/ndpr-compliance-checklist/components/Introduction.tsx +33 -0
  118. package/src/app/docs/guides/ndpr-compliance-checklist/components/KeyRequirements.tsx +99 -0
  119. package/src/app/docs/guides/ndpr-compliance-checklist/components/Resources.tsx +159 -0
  120. package/src/app/docs/guides/ndpr-compliance-checklist/page.tsx +38 -0
  121. package/src/app/docs/guides/page.tsx +67 -0
  122. package/src/app/docs/layout.tsx +15 -0
  123. package/src/app/docs/metadata.ts +31 -0
  124. package/src/app/docs/page.tsx +572 -0
  125. package/src/app/favicon.ico +0 -0
  126. package/src/app/globals.css +123 -0
  127. package/src/app/layout.tsx +37 -0
  128. package/src/app/ndpr-demos/breach/page.tsx +354 -0
  129. package/src/app/ndpr-demos/consent/page.tsx +366 -0
  130. package/src/app/ndpr-demos/dpia/page.tsx +495 -0
  131. package/src/app/ndpr-demos/dsr/page.tsx +280 -0
  132. package/src/app/ndpr-demos/page.tsx +73 -0
  133. package/src/app/ndpr-demos/policy/page.tsx +771 -0
  134. package/src/app/page.tsx +452 -0
  135. package/src/components/ErrorBoundary.tsx +90 -0
  136. package/src/components/breach-notification/BreachNotificationForm.tsx +479 -0
  137. package/src/components/consent/ConsentBanner.tsx +159 -0
  138. package/src/components/data-subject-rights/DataSubjectRequestForm.tsx +419 -0
  139. package/src/components/docs/DocLayout.tsx +289 -0
  140. package/src/components/docs/index.ts +2 -0
  141. package/src/components/dpia/DPIAQuestionnaire.tsx +483 -0
  142. package/src/components/privacy-policy/PolicyGenerator.tsx +1062 -0
  143. package/src/components/privacy-policy/data.ts +98 -0
  144. package/src/components/privacy-policy/shared/CheckboxField.tsx +38 -0
  145. package/src/components/privacy-policy/shared/CheckboxGroup.tsx +85 -0
  146. package/src/components/privacy-policy/shared/FormField.tsx +79 -0
  147. package/src/components/privacy-policy/shared/StepIndicator.tsx +86 -0
  148. package/src/components/privacy-policy/steps/CustomSectionsStep.tsx +335 -0
  149. package/src/components/privacy-policy/steps/DataCollectionStep.tsx +231 -0
  150. package/src/components/privacy-policy/steps/DataSharingStep.tsx +418 -0
  151. package/src/components/privacy-policy/steps/OrganizationInfoStep.tsx +202 -0
  152. package/src/components/privacy-policy/steps/PolicyPreviewStep.tsx +172 -0
  153. package/src/components/ui/Badge.tsx +46 -0
  154. package/src/components/ui/Button.tsx +59 -0
  155. package/src/components/ui/Card.tsx +92 -0
  156. package/src/components/ui/Checkbox.tsx +57 -0
  157. package/src/components/ui/FormField.tsx +50 -0
  158. package/src/components/ui/Input.tsx +38 -0
  159. package/src/components/ui/Loading.tsx +201 -0
  160. package/src/components/ui/Select.tsx +42 -0
  161. package/src/components/ui/TextArea.tsx +38 -0
  162. package/src/components/ui/label.tsx +24 -0
  163. package/src/components/ui/switch.tsx +31 -0
  164. package/src/components/ui/tabs.tsx +66 -0
  165. package/src/hooks/useConsent.ts +64 -0
  166. package/src/hooks/useLoadingState.ts +85 -0
  167. package/src/lib/consentService.ts +137 -0
  168. package/src/lib/dpiaQuestions.ts +148 -0
  169. package/src/lib/requestService.ts +75 -0
  170. package/src/lib/sanitize.ts +108 -0
  171. package/src/lib/storage.ts +222 -0
  172. package/src/lib/utils.ts +6 -0
  173. package/src/types/html-to-docx.d.ts +30 -0
  174. package/src/types/index.ts +72 -0
  175. package/tailwind.config.ts +65 -0
  176. package/tsconfig.json +41 -0
  177. package/dist/components/breach/BreachNotificationManager.d.ts +0 -62
  178. package/dist/components/breach/BreachReportForm.d.ts +0 -66
  179. package/dist/components/breach/BreachRiskAssessment.d.ts +0 -50
  180. package/dist/components/breach/RegulatoryReportGenerator.d.ts +0 -94
  181. package/dist/components/consent/ConsentBanner.d.ts +0 -79
  182. package/dist/components/consent/ConsentManager.d.ts +0 -73
  183. package/dist/components/consent/ConsentStorage.d.ts +0 -41
  184. package/dist/components/dpia/DPIAQuestionnaire.d.ts +0 -70
  185. package/dist/components/dpia/DPIAReport.d.ts +0 -40
  186. package/dist/components/dpia/StepIndicator.d.ts +0 -64
  187. package/dist/components/dsr/DSRDashboard.d.ts +0 -58
  188. package/dist/components/dsr/DSRRequestForm.d.ts +0 -74
  189. package/dist/components/dsr/DSRTracker.d.ts +0 -56
  190. package/dist/components/policy/PolicyExporter.d.ts +0 -65
  191. package/dist/components/policy/PolicyGenerator.d.ts +0 -54
  192. package/dist/components/policy/PolicyPreview.d.ts +0 -71
  193. package/dist/hooks/useBreach.d.ts +0 -97
  194. package/dist/hooks/useConsent.d.ts +0 -63
  195. package/dist/hooks/useDPIA.d.ts +0 -92
  196. package/dist/hooks/useDSR.d.ts +0 -72
  197. package/dist/hooks/usePrivacyPolicy.d.ts +0 -87
  198. package/dist/index.esm.js +0 -2
  199. package/dist/index.esm.js.map +0 -1
  200. package/dist/index.js +0 -2
  201. package/dist/index.js.map +0 -1
  202. package/dist/setupTests.d.ts +0 -2
  203. package/dist/types/breach.d.ts +0 -239
  204. package/dist/types/consent.d.ts +0 -95
  205. package/dist/types/dpia.d.ts +0 -196
  206. package/dist/types/dsr.d.ts +0 -162
  207. package/dist/types/privacy.d.ts +0 -204
  208. package/dist/utils/breach.d.ts +0 -14
  209. package/dist/utils/consent.d.ts +0 -10
  210. package/dist/utils/dpia.d.ts +0 -12
  211. package/dist/utils/dsr.d.ts +0 -11
  212. package/dist/utils/privacy.d.ts +0 -12
@@ -0,0 +1,333 @@
1
+ import React, { useState } from 'react';
2
+ import { PolicySection, PolicyVariable } from '../../types/privacy';
3
+
4
+ export interface PolicyPreviewProps {
5
+ /**
6
+ * The policy content to preview
7
+ */
8
+ content: string;
9
+
10
+ /**
11
+ * The policy sections
12
+ */
13
+ sections?: PolicySection[];
14
+
15
+ /**
16
+ * The policy variables
17
+ */
18
+ variables?: PolicyVariable[];
19
+
20
+ /**
21
+ * Callback function called when the policy is exported
22
+ */
23
+ onExport?: (format: 'pdf' | 'html' | 'markdown' | 'docx') => void;
24
+
25
+ /**
26
+ * Callback function called when the policy is edited
27
+ */
28
+ onEdit?: () => void;
29
+
30
+ /**
31
+ * Title displayed on the preview
32
+ * @default "Privacy Policy Preview"
33
+ */
34
+ title?: string;
35
+
36
+ /**
37
+ * Description text displayed on the preview
38
+ * @default "Preview your NDPR-compliant privacy policy before exporting."
39
+ */
40
+ description?: string;
41
+
42
+ /**
43
+ * Custom CSS class for the preview
44
+ */
45
+ className?: string;
46
+
47
+ /**
48
+ * Custom CSS class for the buttons
49
+ */
50
+ buttonClassName?: string;
51
+
52
+ /**
53
+ * Whether to show the export options
54
+ * @default true
55
+ */
56
+ showExportOptions?: boolean;
57
+
58
+ /**
59
+ * Whether to show the edit button
60
+ * @default true
61
+ */
62
+ showEditButton?: boolean;
63
+
64
+ /**
65
+ * Whether to show the table of contents
66
+ * @default true
67
+ */
68
+ showTableOfContents?: boolean;
69
+
70
+ /**
71
+ * Whether to show the policy metadata
72
+ * @default true
73
+ */
74
+ showMetadata?: boolean;
75
+
76
+ /**
77
+ * The organization name to display in the policy
78
+ */
79
+ organizationName?: string;
80
+
81
+ /**
82
+ * The last updated date to display in the policy
83
+ */
84
+ lastUpdated?: Date;
85
+ }
86
+
87
+ export const PolicyPreview: React.FC<PolicyPreviewProps> = ({
88
+ content,
89
+ sections,
90
+ variables,
91
+ onExport,
92
+ onEdit,
93
+ title = "Privacy Policy Preview",
94
+ description = "Preview your NDPR-compliant privacy policy before exporting.",
95
+ className = "",
96
+ buttonClassName = "",
97
+ showExportOptions = true,
98
+ showEditButton = true,
99
+ showTableOfContents = true,
100
+ showMetadata = true,
101
+ organizationName,
102
+ lastUpdated = new Date()
103
+ }) => {
104
+ const [activeTab, setActiveTab] = useState<'preview' | 'markdown'>('preview');
105
+
106
+ // Parse the content to extract section titles for the table of contents
107
+ const extractSectionTitles = (): { id: string, title: string, level: number }[] => {
108
+ const lines = content.split('\n');
109
+ const sectionTitles: { id: string, title: string, level: number }[] = [];
110
+
111
+ lines.forEach(line => {
112
+ if (line.startsWith('## ')) {
113
+ const title = line.substring(3).trim();
114
+ const id = title.toLowerCase().replace(/[^a-z0-9]+/g, '-');
115
+ sectionTitles.push({ id, title, level: 2 });
116
+ } else if (line.startsWith('### ')) {
117
+ const title = line.substring(4).trim();
118
+ const id = title.toLowerCase().replace(/[^a-z0-9]+/g, '-');
119
+ sectionTitles.push({ id, title, level: 3 });
120
+ }
121
+ });
122
+
123
+ return sectionTitles;
124
+ };
125
+
126
+ // Get the section titles for the table of contents
127
+ const sectionTitles = extractSectionTitles();
128
+
129
+ // Handle export button click
130
+ const handleExport = (format: 'pdf' | 'html' | 'markdown' | 'docx') => {
131
+ if (onExport) {
132
+ onExport(format);
133
+ } else {
134
+ // Fallback export functionality
135
+ if (format === 'markdown') {
136
+ const element = document.createElement('a');
137
+ const file = new Blob([content], {type: 'text/markdown'});
138
+ element.href = URL.createObjectURL(file);
139
+ element.download = `privacy-policy-${new Date().toISOString().split('T')[0]}.md`;
140
+ document.body.appendChild(element);
141
+ element.click();
142
+ document.body.removeChild(element);
143
+ }
144
+ }
145
+ };
146
+
147
+ // Render the table of contents
148
+ const renderTableOfContents = () => {
149
+ if (!showTableOfContents || sectionTitles.length === 0) {
150
+ return null;
151
+ }
152
+
153
+ return (
154
+ <div className="mb-6 p-4 bg-gray-50 dark:bg-gray-700 rounded-md">
155
+ <h3 className="text-lg font-medium mb-3">Table of Contents</h3>
156
+ <ul className="space-y-1">
157
+ {sectionTitles.map((section, index) => (
158
+ <li key={index} style={{ marginLeft: `${(section.level - 2) * 1.5}rem` }}>
159
+ <a
160
+ href={`#${section.id}`}
161
+ className="text-blue-600 dark:text-blue-400 hover:underline"
162
+ >
163
+ {section.title}
164
+ </a>
165
+ </li>
166
+ ))}
167
+ </ul>
168
+ </div>
169
+ );
170
+ };
171
+
172
+ // Render the policy metadata
173
+ const renderMetadata = () => {
174
+ if (!showMetadata) {
175
+ return null;
176
+ }
177
+
178
+ return (
179
+ <div className="mb-6">
180
+ <h1 className="text-2xl font-bold mb-2">
181
+ {organizationName ? `${organizationName} Privacy Policy` : 'Privacy Policy'}
182
+ </h1>
183
+ <p className="text-sm text-gray-500 dark:text-gray-400">
184
+ Last Updated: {lastUpdated.toLocaleDateString()}
185
+ </p>
186
+ </div>
187
+ );
188
+ };
189
+
190
+ // Render the policy content in HTML format
191
+ const renderHTMLContent = () => {
192
+ return (
193
+ <div className="prose dark:prose-invert max-w-none">
194
+ {content.split('\n').map((line, index) => {
195
+ if (line.startsWith('## ')) {
196
+ const title = line.substring(3).trim();
197
+ const id = title.toLowerCase().replace(/[^a-z0-9]+/g, '-');
198
+ return <h2 id={id} key={index} className="text-xl font-bold mt-6 mb-3">{title}</h2>;
199
+ } else if (line.startsWith('### ')) {
200
+ const title = line.substring(4).trim();
201
+ const id = title.toLowerCase().replace(/[^a-z0-9]+/g, '-');
202
+ return <h3 id={id} key={index} className="text-lg font-bold mt-4 mb-2">{title}</h3>;
203
+ } else if (line === '') {
204
+ return <br key={index} />;
205
+ } else {
206
+ return <p key={index} className="mb-2">{line}</p>;
207
+ }
208
+ })}
209
+ </div>
210
+ );
211
+ };
212
+
213
+ // Render the export options
214
+ const renderExportOptions = () => {
215
+ if (!showExportOptions) {
216
+ return null;
217
+ }
218
+
219
+ return (
220
+ <div className="mt-6">
221
+ <h3 className="text-lg font-medium mb-3">Export Options</h3>
222
+ <div className="flex flex-wrap gap-3">
223
+ <button
224
+ onClick={() => handleExport('pdf')}
225
+ className={`px-4 py-2 bg-blue-600 text-white rounded hover:bg-blue-700 ${buttonClassName}`}
226
+ >
227
+ Export as PDF
228
+ </button>
229
+ <button
230
+ onClick={() => handleExport('docx')}
231
+ className={`px-4 py-2 bg-blue-600 text-white rounded hover:bg-blue-700 ${buttonClassName}`}
232
+ >
233
+ Export as DOCX
234
+ </button>
235
+ <button
236
+ onClick={() => handleExport('html')}
237
+ className={`px-4 py-2 bg-blue-600 text-white rounded hover:bg-blue-700 ${buttonClassName}`}
238
+ >
239
+ Export as HTML
240
+ </button>
241
+ <button
242
+ onClick={() => handleExport('markdown')}
243
+ className={`px-4 py-2 bg-blue-600 text-white rounded hover:bg-blue-700 ${buttonClassName}`}
244
+ >
245
+ Export as Markdown
246
+ </button>
247
+ </div>
248
+ </div>
249
+ );
250
+ };
251
+
252
+ return (
253
+ <div className={`bg-white dark:bg-gray-800 p-6 rounded-lg shadow-md ${className}`}>
254
+ <div className="flex justify-between items-start mb-6">
255
+ <div>
256
+ <h2 className="text-xl font-bold mb-2">{title}</h2>
257
+ <p className="text-gray-600 dark:text-gray-300">{description}</p>
258
+ </div>
259
+
260
+ {showEditButton && onEdit && (
261
+ <button
262
+ onClick={onEdit}
263
+ className={`px-4 py-2 bg-gray-200 text-gray-800 dark:bg-gray-700 dark:text-white rounded hover:bg-gray-300 dark:hover:bg-gray-600 ${buttonClassName}`}
264
+ >
265
+ Edit Policy
266
+ </button>
267
+ )}
268
+ </div>
269
+
270
+ {/* NDPR Notice */}
271
+ <div className="mb-6 p-4 bg-blue-50 dark:bg-blue-900/20 rounded-md">
272
+ <h3 className="text-sm font-bold text-blue-800 dark:text-blue-200 mb-2">NDPR Compliance Notice</h3>
273
+ <p className="text-blue-700 dark:text-blue-300 text-sm">
274
+ This privacy policy has been generated to align with the Nigeria Data Protection Regulation (NDPR).
275
+ We recommend having the final policy reviewed by a legal professional familiar with NDPR requirements
276
+ before publishing it on your website or sharing it with your users.
277
+ </p>
278
+ </div>
279
+
280
+ {/* Tabs */}
281
+ <div className="mb-6 border-b border-gray-200 dark:border-gray-700">
282
+ <ul className="flex flex-wrap -mb-px">
283
+ <li className="mr-2">
284
+ <button
285
+ onClick={() => setActiveTab('preview')}
286
+ className={`inline-block p-4 ${
287
+ activeTab === 'preview'
288
+ ? 'text-blue-600 border-b-2 border-blue-600 dark:text-blue-500 dark:border-blue-500'
289
+ : 'text-gray-500 hover:text-gray-600 hover:border-gray-300 dark:text-gray-400 dark:hover:text-gray-300'
290
+ }`}
291
+ >
292
+ Preview
293
+ </button>
294
+ </li>
295
+ <li className="mr-2">
296
+ <button
297
+ onClick={() => setActiveTab('markdown')}
298
+ className={`inline-block p-4 ${
299
+ activeTab === 'markdown'
300
+ ? 'text-blue-600 border-b-2 border-blue-600 dark:text-blue-500 dark:border-blue-500'
301
+ : 'text-gray-500 hover:text-gray-600 hover:border-gray-300 dark:text-gray-400 dark:hover:text-gray-300'
302
+ }`}
303
+ >
304
+ Markdown
305
+ </button>
306
+ </li>
307
+ </ul>
308
+ </div>
309
+
310
+ {/* Content */}
311
+ <div className="bg-white dark:bg-gray-800 p-4 rounded-md">
312
+ {activeTab === 'preview' ? (
313
+ <div>
314
+ {renderMetadata()}
315
+ {renderTableOfContents()}
316
+ <div className="bg-gray-50 dark:bg-gray-700 p-6 rounded-md">
317
+ {renderHTMLContent()}
318
+ </div>
319
+ </div>
320
+ ) : (
321
+ <div>
322
+ <pre className="bg-gray-50 dark:bg-gray-700 p-4 rounded-md overflow-auto whitespace-pre-wrap font-mono text-sm text-gray-800 dark:text-gray-200">
323
+ {content}
324
+ </pre>
325
+ </div>
326
+ )}
327
+ </div>
328
+
329
+ {/* Export Options */}
330
+ {renderExportOptions()}
331
+ </div>
332
+ );
333
+ };