@redacto.io/consent-sdk-react 3.4.0 → 3.6.0

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 (155) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/LICENSE +176 -0
  3. package/dist/index.d.mts +51 -4
  4. package/dist/index.d.ts +51 -4
  5. package/dist/index.js +1912 -345
  6. package/dist/index.mjs +1911 -345
  7. package/dist/privacy-center.d.mts +566 -0
  8. package/dist/privacy-center.d.ts +566 -0
  9. package/dist/privacy-center.js +17174 -0
  10. package/dist/privacy-center.mjs +17136 -0
  11. package/package.json +47 -3
  12. package/src/RedactoNoticeConsent/RedactoNoticeConsent.test.tsx +201 -118
  13. package/src/RedactoNoticeConsent/RedactoNoticeConsent.tsx +1194 -93
  14. package/src/RedactoNoticeConsent/api/index.ts +337 -246
  15. package/src/RedactoNoticeConsent/api/types.ts +140 -41
  16. package/src/RedactoNoticeConsent/components/DigiLockerCallback.tsx +602 -0
  17. package/src/RedactoNoticeConsent/components/index.ts +7 -0
  18. package/src/RedactoNoticeConsent/injectStyles.ts +11 -0
  19. package/src/RedactoNoticeConsent/language-codes.ts +61 -0
  20. package/src/RedactoNoticeConsent/services/storage.ts +122 -0
  21. package/src/RedactoNoticeConsent/types.ts +2 -0
  22. package/src/RedactoNoticeConsentInline/api/index.ts +26 -64
  23. package/src/RedactoNoticeConsentInline/api/types.ts +0 -25
  24. package/src/RedactoPrivacyCenter/PrivacyCenterActivityPage.tsx +19 -0
  25. package/src/RedactoPrivacyCenter/PrivacyCenterConsentManagerPage.tsx +17 -0
  26. package/src/RedactoPrivacyCenter/PrivacyCenterFormPage.tsx +79 -0
  27. package/src/RedactoPrivacyCenter/PrivacyCenterHomePage.tsx +27 -0
  28. package/src/RedactoPrivacyCenter/PrivacyCenterLayout.tsx +142 -0
  29. package/src/RedactoPrivacyCenter/RedactoPrivacyCenter.tsx +51 -0
  30. package/src/RedactoPrivacyCenter/api/actions.ts +444 -0
  31. package/src/RedactoPrivacyCenter/api/client.ts +413 -0
  32. package/src/RedactoPrivacyCenter/api/config.ts +33 -0
  33. package/src/RedactoPrivacyCenter/api/fetcher.ts +181 -0
  34. package/src/RedactoPrivacyCenter/api/upload.ts +93 -0
  35. package/src/RedactoPrivacyCenter/assets/character.svg +31 -0
  36. package/src/RedactoPrivacyCenter/assets/fileAttach.svg +9 -0
  37. package/src/RedactoPrivacyCenter/assets/greenTick.svg +4 -0
  38. package/src/RedactoPrivacyCenter/assets/mail.svg +3 -0
  39. package/src/RedactoPrivacyCenter/assets/poweredByRedacto.svg +9 -0
  40. package/src/RedactoPrivacyCenter/assets/sentImg.svg +9 -0
  41. package/src/RedactoPrivacyCenter/assets/uploadFileIcon.svg +9 -0
  42. package/src/RedactoPrivacyCenter/components/ActivitiesList.tsx +272 -0
  43. package/src/RedactoPrivacyCenter/components/CaseDetailsModal.tsx +468 -0
  44. package/src/RedactoPrivacyCenter/components/CaseHistory.tsx +433 -0
  45. package/src/RedactoPrivacyCenter/components/ConsentManager.tsx +726 -0
  46. package/src/RedactoPrivacyCenter/components/ConsentManagerColumns.tsx +239 -0
  47. package/src/RedactoPrivacyCenter/components/ConsentManagerConstants.ts +7 -0
  48. package/src/RedactoPrivacyCenter/components/ConsentManagerTableSkeleton.tsx +155 -0
  49. package/src/RedactoPrivacyCenter/components/DataRequest/CorrectionDataSection.tsx +189 -0
  50. package/src/RedactoPrivacyCenter/components/DataRequest/GrievanceDataSection.tsx +118 -0
  51. package/src/RedactoPrivacyCenter/components/DataRequest/NominationDataSection.tsx +66 -0
  52. package/src/RedactoPrivacyCenter/components/DataRequest/PurposeSelectionSection.tsx +305 -0
  53. package/src/RedactoPrivacyCenter/components/Form.tsx +1455 -0
  54. package/src/RedactoPrivacyCenter/components/GrievanceTable.tsx +176 -0
  55. package/src/RedactoPrivacyCenter/components/GrievanceTablePagination.tsx +330 -0
  56. package/src/RedactoPrivacyCenter/components/ModifyConsentModal.tsx +329 -0
  57. package/src/RedactoPrivacyCenter/components/Pagination.tsx +140 -0
  58. package/src/RedactoPrivacyCenter/components/PrivacyCenterLayout.tsx +302 -0
  59. package/src/RedactoPrivacyCenter/components/RequestSubmit.tsx +218 -0
  60. package/src/RedactoPrivacyCenter/components/SideMenuBarPC/SideBarPC.tsx +475 -0
  61. package/src/RedactoPrivacyCenter/components/SideMenuBarPC/SideMenuPC.tsx +412 -0
  62. package/src/RedactoPrivacyCenter/components/SideMenuBarPC/constants.tsx +42 -0
  63. package/src/RedactoPrivacyCenter/components/SideMenuBarPC/menuItemsPC.tsx +1 -0
  64. package/src/RedactoPrivacyCenter/components/SideMenuBarPC/types.ts +40 -0
  65. package/src/RedactoPrivacyCenter/components/SideMenuBarPC/utils.ts +38 -0
  66. package/src/RedactoPrivacyCenter/components/ThemeTransitionOverlay.tsx +85 -0
  67. package/src/RedactoPrivacyCenter/components/activitiesColumns.tsx +141 -0
  68. package/src/RedactoPrivacyCenter/components/caseHistoryColumns.tsx +179 -0
  69. package/src/RedactoPrivacyCenter/components/constant.ts +20 -0
  70. package/src/RedactoPrivacyCenter/components/types.ts +68 -0
  71. package/src/RedactoPrivacyCenter/components/utils.tsx +10 -0
  72. package/src/RedactoPrivacyCenter/config/routes.ts +9 -0
  73. package/src/RedactoPrivacyCenter/config/table.ts +25 -0
  74. package/src/RedactoPrivacyCenter/context/AuthContext.tsx +123 -0
  75. package/src/RedactoPrivacyCenter/context/BaseUrlContext.tsx +44 -0
  76. package/src/RedactoPrivacyCenter/context/LocaleContext.tsx +11 -0
  77. package/src/RedactoPrivacyCenter/context/NavigationContext.tsx +64 -0
  78. package/src/RedactoPrivacyCenter/context/OrganizationContext.tsx +30 -0
  79. package/src/RedactoPrivacyCenter/context/PageChromeContext.tsx +60 -0
  80. package/src/RedactoPrivacyCenter/context/theme.tsx +127 -0
  81. package/src/RedactoPrivacyCenter/lib/api.ts +468 -0
  82. package/src/RedactoPrivacyCenter/lib/consent-manager/utils.tsx +63 -0
  83. package/src/RedactoPrivacyCenter/lib/constants.ts +116 -0
  84. package/src/RedactoPrivacyCenter/lib/i18n.ts +81 -0
  85. package/src/RedactoPrivacyCenter/lib/locales.ts +105 -0
  86. package/src/RedactoPrivacyCenter/lib/queries.ts +30 -0
  87. package/src/RedactoPrivacyCenter/lib/types.ts +346 -0
  88. package/src/RedactoPrivacyCenter/lib/useCurrentLanguage.ts +37 -0
  89. package/src/RedactoPrivacyCenter/lib/utils.ts +625 -0
  90. package/src/RedactoPrivacyCenter/locales/as/translation.json +188 -0
  91. package/src/RedactoPrivacyCenter/locales/bho/translation.json +188 -0
  92. package/src/RedactoPrivacyCenter/locales/bn/translation.json +188 -0
  93. package/src/RedactoPrivacyCenter/locales/brx/translation.json +188 -0
  94. package/src/RedactoPrivacyCenter/locales/doi/translation.json +188 -0
  95. package/src/RedactoPrivacyCenter/locales/en/translation.json +188 -0
  96. package/src/RedactoPrivacyCenter/locales/gom/translation.json +188 -0
  97. package/src/RedactoPrivacyCenter/locales/gu/translation.json +188 -0
  98. package/src/RedactoPrivacyCenter/locales/hi/translation.json +188 -0
  99. package/src/RedactoPrivacyCenter/locales/kn/translation.json +188 -0
  100. package/src/RedactoPrivacyCenter/locales/ks/translation.json +188 -0
  101. package/src/RedactoPrivacyCenter/locales/mai/translation.json +188 -0
  102. package/src/RedactoPrivacyCenter/locales/ml/translation.json +188 -0
  103. package/src/RedactoPrivacyCenter/locales/mni-Mtei/translation.json +188 -0
  104. package/src/RedactoPrivacyCenter/locales/mr/translation.json +188 -0
  105. package/src/RedactoPrivacyCenter/locales/ne/translation.json +188 -0
  106. package/src/RedactoPrivacyCenter/locales/or/translation.json +188 -0
  107. package/src/RedactoPrivacyCenter/locales/pa/translation.json +188 -0
  108. package/src/RedactoPrivacyCenter/locales/sa/translation.json +188 -0
  109. package/src/RedactoPrivacyCenter/locales/sat/translation.json +188 -0
  110. package/src/RedactoPrivacyCenter/locales/sd/translation.json +188 -0
  111. package/src/RedactoPrivacyCenter/locales/ta/translation.json +188 -0
  112. package/src/RedactoPrivacyCenter/locales/te/translation.json +188 -0
  113. package/src/RedactoPrivacyCenter/locales/ur/translation.json +188 -0
  114. package/src/RedactoPrivacyCenter/styles/base.css +117 -0
  115. package/src/RedactoPrivacyCenter/styles/injectStyles.ts +1000 -0
  116. package/src/RedactoPrivacyCenter/styles/pcStyles.ts +819 -0
  117. package/src/RedactoPrivacyCenter/styles/responsive.ts +138 -0
  118. package/src/RedactoPrivacyCenter/styles/variables.css +133 -0
  119. package/src/RedactoPrivacyCenter/table/AdvancedTable.tsx +365 -0
  120. package/src/RedactoPrivacyCenter/table/AdvancedTablePagination.tsx +479 -0
  121. package/src/RedactoPrivacyCenter/table/index.ts +2 -0
  122. package/src/RedactoPrivacyCenter/types/images.d.ts +29 -0
  123. package/src/RedactoPrivacyCenter/ui/Footer.tsx +73 -0
  124. package/src/RedactoPrivacyCenter/ui/FormBlockWrapper.tsx +54 -0
  125. package/src/RedactoPrivacyCenter/ui/PCAccordion.tsx +87 -0
  126. package/src/RedactoPrivacyCenter/ui/PCActionIcon.tsx +47 -0
  127. package/src/RedactoPrivacyCenter/ui/PCAvatar.tsx +69 -0
  128. package/src/RedactoPrivacyCenter/ui/PCBadge.tsx +48 -0
  129. package/src/RedactoPrivacyCenter/ui/PCButton.tsx +77 -0
  130. package/src/RedactoPrivacyCenter/ui/PCCheckbox.tsx +55 -0
  131. package/src/RedactoPrivacyCenter/ui/PCCollapse.tsx +97 -0
  132. package/src/RedactoPrivacyCenter/ui/PCEmpty.tsx +35 -0
  133. package/src/RedactoPrivacyCenter/ui/PCInput.tsx +128 -0
  134. package/src/RedactoPrivacyCenter/ui/PCLoader.tsx +30 -0
  135. package/src/RedactoPrivacyCenter/ui/PCModal.tsx +104 -0
  136. package/src/RedactoPrivacyCenter/ui/PCPopover.tsx +175 -0
  137. package/src/RedactoPrivacyCenter/ui/PCSelect.tsx +381 -0
  138. package/src/RedactoPrivacyCenter/ui/PCTable.tsx +137 -0
  139. package/src/RedactoPrivacyCenter/ui/PCText.tsx +39 -0
  140. package/src/RedactoPrivacyCenter/ui/PCTextarea.tsx +43 -0
  141. package/src/RedactoPrivacyCenter/ui/PCTitle.tsx +37 -0
  142. package/src/RedactoPrivacyCenter/ui/PCTooltip.tsx +119 -0
  143. package/src/RedactoPrivacyCenter/ui/SimpleBar.tsx +25 -0
  144. package/src/RedactoPrivacyCenter/ui/StatusBadge.tsx +55 -0
  145. package/src/RedactoPrivacyCenter/ui/ThemeToggle.tsx +70 -0
  146. package/src/RedactoPrivacyCenter/ui/index.ts +18 -0
  147. package/src/RedactoPrivacyCenter/utils/cn.ts +28 -0
  148. package/src/RedactoPrivacyCenter/utils/date.ts +48 -0
  149. package/src/RedactoPrivacyCenter/utils/status.ts +111 -0
  150. package/src/RedactoPrivacyCenter/utils/toast.ts +130 -0
  151. package/src/index.ts +10 -0
  152. package/src/privacy-center.ts +107 -0
  153. package/tsconfig.json +2 -0
  154. package/tsup.config.ts +16 -1
  155. package/src/utils/isLegacyApi.ts +0 -12
@@ -0,0 +1,444 @@
1
+ import type { BaseRequest } from './client';
2
+ import { useBaseUrl } from '../context/BaseUrlContext';
3
+
4
+ export type ConsentApiErrorCode = 'NOMINATOR_NOT_FOUND' | 'NOMINEE_MUST_SPECIFY_NOMINATOR';
5
+
6
+ export class ConsentApiError extends Error {
7
+ code: ConsentApiErrorCode;
8
+ constructor(code: ConsentApiErrorCode, message: string) {
9
+ super(message);
10
+ this.name = 'ConsentApiError';
11
+ this.code = code;
12
+ }
13
+ }
14
+
15
+ import type {
16
+ ActivityDetail,
17
+ CaseHistoryDetail,
18
+ ConsentAction,
19
+ CreateCaseResponse,
20
+ FormData,
21
+ OtpResponse,
22
+ OtpVerificationResponse,
23
+ Pagination,
24
+ TokenExchangeResponse,
25
+ UserConsentDetail,
26
+ } from '../lib/types';
27
+
28
+ /**
29
+ * Check if an error is an authentication/JWT related error
30
+ */
31
+ function isAuthError(error: any): boolean {
32
+ const errorMessage = error?.message || '';
33
+ return (
34
+ errorMessage.includes('JWT') ||
35
+ errorMessage.includes('401') ||
36
+ errorMessage.includes('expired') ||
37
+ errorMessage.includes('token')
38
+ );
39
+ }
40
+
41
+ /**
42
+ * Handle server action errors - re-throws auth errors, logs others
43
+ */
44
+ function handleServerActionError(
45
+ error: any,
46
+ errorContext: string,
47
+ shouldThrow404 = false
48
+ ): null {
49
+ // Re-throw auth errors so client can handle refresh
50
+ if (isAuthError(error)) {
51
+ throw error;
52
+ }
53
+ console.error(`Error ${errorContext}:`, error);
54
+ if (shouldThrow404 && error.message?.includes('404')) {
55
+ throw error;
56
+ }
57
+ return null;
58
+ }
59
+
60
+ export async function getFormDataServer(
61
+ organizationId: string,
62
+ workspaceId: string,
63
+ contact: string,
64
+ authToken?: string,
65
+ useSessionAuth?: boolean,
66
+ consentClient?: ReturnType<typeof import('./client').createConsentClient>,
67
+ language?: string
68
+ ): Promise<FormData | null> {
69
+ try {
70
+ if (!consentClient) {
71
+ throw new Error('Consent client is required');
72
+ }
73
+ const baseRequest: BaseRequest = {
74
+ organisationUuid: organizationId,
75
+ workspaceUuid: workspaceId,
76
+ authToken: authToken || '',
77
+ };
78
+
79
+ // If useSessionAuth is true (case management), use X-Auth-Token
80
+ // Otherwise (privacy center), use JWT Bearer token
81
+ const result = await consentClient.getFormData(baseRequest, contact, authToken, {
82
+ useSessionAuth: useSessionAuth ?? false, // Default to false for privacy center
83
+ }, language);
84
+ return result as FormData;
85
+ } catch (error: any) {
86
+ return handleServerActionError(error, 'fetching form data', true);
87
+ }
88
+ }
89
+
90
+ export async function createCaseRequestServer(
91
+ organizationId: string,
92
+ workspaceId: string,
93
+ data: unknown,
94
+ authToken?: string,
95
+ useSessionAuth?: boolean,
96
+ consentClient?: ReturnType<typeof import('./client').createConsentClient>
97
+ ): Promise<CreateCaseResponse | null> {
98
+ try {
99
+ if (!consentClient) {
100
+ throw new Error('Consent client is required');
101
+ }
102
+ const baseRequest: BaseRequest = {
103
+ organisationUuid: organizationId,
104
+ workspaceUuid: workspaceId,
105
+ authToken: authToken || '',
106
+ };
107
+
108
+ // If useSessionAuth is true (case management), use X-Auth-Token
109
+ // Otherwise (privacy center), use JWT Bearer token
110
+ const result = await consentClient.createCaseRequest(baseRequest, data, authToken, {
111
+ useSessionAuth: useSessionAuth ?? false, // Default to false for privacy center
112
+ });
113
+ return result as CreateCaseResponse;
114
+ } catch (error: any) {
115
+ return handleServerActionError(error, 'creating case request');
116
+ }
117
+ }
118
+
119
+ export async function createOtpServer(
120
+ email: string,
121
+ organizationId: string,
122
+ workspaceId: string,
123
+ consentClient?: ReturnType<typeof import('./client').createConsentClient>
124
+ ): Promise<OtpResponse> {
125
+ try {
126
+ if (!consentClient) {
127
+ throw new Error('Consent client is required');
128
+ }
129
+ const result = await consentClient.createOtp(organizationId, workspaceId, email);
130
+ return result as OtpResponse;
131
+ } catch (error) {
132
+ console.error('Error creating OTP:', error);
133
+ throw error;
134
+ }
135
+ }
136
+
137
+ export async function verifyOtpServer(
138
+ otpId: string,
139
+ otp: string,
140
+ organizationId: string,
141
+ workspaceId: string,
142
+ consentClient?: ReturnType<typeof import('./client').createConsentClient>
143
+ ): Promise<OtpVerificationResponse> {
144
+ try {
145
+ if (!consentClient) {
146
+ throw new Error('Consent client is required');
147
+ }
148
+ const result = await consentClient.verifyOtp(organizationId, workspaceId, otpId, otp);
149
+ const response = result as OtpVerificationResponse;
150
+ return response;
151
+ } catch (error) {
152
+ console.error('Error verifying OTP:', error);
153
+ throw error;
154
+ }
155
+ }
156
+
157
+ export async function exchangeTokenServer(
158
+ token: string,
159
+ consentClient?: ReturnType<typeof import('./client').createConsentClient>
160
+ ): Promise<TokenExchangeResponse> {
161
+ try {
162
+ if (!consentClient) {
163
+ throw new Error('Consent client is required');
164
+ }
165
+ const result = await consentClient.exchangeToken(token);
166
+ return result as TokenExchangeResponse;
167
+ } catch (error) {
168
+ console.error('Error exchanging token:', error);
169
+ throw error;
170
+ }
171
+ }
172
+
173
+ export async function refreshOtpTokenServer(
174
+ organizationId: string,
175
+ workspaceId: string,
176
+ refreshToken: string,
177
+ consentClient?: ReturnType<typeof import('./client').createConsentClient>
178
+ ): Promise<OtpResponse | null> {
179
+ // Validate refreshToken before making API call
180
+ if (!refreshToken || typeof refreshToken !== 'string' || refreshToken.trim() === '') {
181
+ console.error('[Token Refresh] Invalid refresh token provided');
182
+ return null;
183
+ }
184
+
185
+ // Validate organizationId and workspaceId
186
+ if (!organizationId || !workspaceId) {
187
+ console.error('[Token Refresh] Missing organizationId or workspaceId');
188
+ return null;
189
+ }
190
+
191
+ try {
192
+ if (!consentClient) {
193
+ throw new Error('Consent client is required');
194
+ }
195
+ const result = await consentClient.refreshOtpToken(
196
+ organizationId,
197
+ workspaceId,
198
+ refreshToken
199
+ );
200
+
201
+ const response = result as OtpResponse;
202
+ // Check if the response indicates failure
203
+ if (response && response.success === false) {
204
+ // Return null to indicate refresh failed
205
+ return null;
206
+ }
207
+ return response;
208
+ } catch (error: any) {
209
+ // Check if this is an expired refresh token error (expected scenario)
210
+ const errorMessage = error?.message || '';
211
+ const isExpiredTokenError =
212
+ errorMessage.includes('expired') ||
213
+ errorMessage.includes('Invalid refresh token') ||
214
+ errorMessage.includes('Refresh token') ||
215
+ errorMessage.includes('revoked');
216
+
217
+ // For expired/revoked tokens, return null gracefully (don't log as error)
218
+ if (isExpiredTokenError) {
219
+ return null;
220
+ }
221
+
222
+ // For other errors (network, etc.), log and re-throw
223
+ console.error('Error refreshing token:', error);
224
+ throw error;
225
+ }
226
+ }
227
+
228
+ export async function fetchProductsServer(params: {
229
+ organizationId: string;
230
+ workspaceId: string;
231
+ skip?: number;
232
+ limit?: number;
233
+ authToken?: string;
234
+ consentClient?: ReturnType<typeof import('./client').createConsentClient>;
235
+ }): Promise<Array<{ uuid: string; name: string; description?: string }> | null> {
236
+ try {
237
+ if (!params.consentClient) {
238
+ throw new Error('Consent client is required');
239
+ }
240
+ // Privacy center endpoints use JWT Bearer tokens, not session-based auth
241
+ const baseRequest: BaseRequest = {
242
+ organisationUuid: params.organizationId,
243
+ workspaceUuid: params.workspaceId,
244
+ authToken: params.authToken || '',
245
+ };
246
+
247
+ const result = await params.consentClient.getProducts(
248
+ baseRequest,
249
+ params.skip || 0,
250
+ params.limit || 100 // Get more products for filter dropdown
251
+ );
252
+ return (result as { data?: Array<{ uuid: string; name: string; description?: string }> })?.data || [];
253
+ } catch (error: any) {
254
+ return handleServerActionError(error, 'fetching products');
255
+ }
256
+ }
257
+
258
+ export async function fetchUserConsentsServer(params: {
259
+ organizationId: string;
260
+ workspaceId: string;
261
+ contact: string;
262
+ offset?: number;
263
+ limit?: number;
264
+ search?: string;
265
+ status?: string;
266
+ product_uuid?: string;
267
+ language?: string;
268
+ authToken?: string;
269
+ consentClient?: ReturnType<typeof import('./client').createConsentClient>;
270
+ }): Promise<UserConsentDetail | null> {
271
+ try {
272
+ if (!params.consentClient) {
273
+ throw new Error('Consent client is required');
274
+ }
275
+ // Privacy center endpoints use JWT Bearer tokens, not session-based auth
276
+ const baseRequest: BaseRequest = {
277
+ organisationUuid: params.organizationId,
278
+ workspaceUuid: params.workspaceId,
279
+ authToken: params.authToken || '',
280
+ };
281
+
282
+ const result = await params.consentClient.getUserConsents(
283
+ baseRequest,
284
+ params.contact,
285
+ params.offset,
286
+ params.limit,
287
+ params.search,
288
+ params.status,
289
+ params.product_uuid,
290
+ params.language,
291
+ params.authToken
292
+ );
293
+
294
+ return result as UserConsentDetail;
295
+ } catch (error: any) {
296
+ return handleServerActionError(error, 'fetching user consents');
297
+ }
298
+ }
299
+
300
+ export async function manageConsentServer(params: {
301
+ organizationId: string;
302
+ workspaceId: string;
303
+ purposeId: string;
304
+ contact: string;
305
+ action: ConsentAction;
306
+ authToken?: string;
307
+ consentClient?: ReturnType<typeof import('./client').createConsentClient>;
308
+ nominatorContact?: string;
309
+ dataElementUuids?: string[];
310
+ }): Promise<boolean | null> {
311
+ try {
312
+ if (!params.consentClient) {
313
+ throw new Error('Consent client is required');
314
+ }
315
+ // Privacy center endpoints use JWT Bearer tokens, not session-based auth
316
+ const baseRequest: BaseRequest = {
317
+ organisationUuid: params.organizationId,
318
+ workspaceUuid: params.workspaceId,
319
+ authToken: params.authToken || '',
320
+ };
321
+
322
+ const result = await params.consentClient.manageConsent(
323
+ baseRequest,
324
+ params.purposeId,
325
+ params.contact,
326
+ params.action,
327
+ params.authToken,
328
+ undefined,
329
+ params.nominatorContact,
330
+ params.dataElementUuids
331
+ );
332
+ return (result as { success: boolean })?.success ?? null;
333
+ } catch (error: any) {
334
+ // Normalize nominator-specific errors into stable error codes
335
+ const errorMsg = error?.message || '';
336
+ if (errorMsg.includes('nominator_not_found')) {
337
+ throw new ConsentApiError('NOMINATOR_NOT_FOUND', errorMsg);
338
+ }
339
+ if (errorMsg.includes('nominee_must_specify_nominator')) {
340
+ throw new ConsentApiError('NOMINEE_MUST_SPECIFY_NOMINATOR', errorMsg);
341
+ }
342
+ return handleServerActionError(error, `${params.action} consent`);
343
+ }
344
+ }
345
+
346
+ export async function fetchActivitiesServer(params: {
347
+ organizationId: string;
348
+ workspaceId: string;
349
+ offset?: number;
350
+ limit?: number;
351
+ language?: string;
352
+ authToken?: string;
353
+ consentClient?: ReturnType<typeof import('./client').createConsentClient>;
354
+ }): Promise<ActivityDetail | null> {
355
+ try {
356
+ if (!params.consentClient) {
357
+ throw new Error('Consent client is required');
358
+ }
359
+
360
+ // Privacy center endpoints use JWT Bearer tokens, not session-based auth
361
+ const baseRequest: BaseRequest = {
362
+ organisationUuid: params.organizationId,
363
+ workspaceUuid: params.workspaceId,
364
+ authToken: params.authToken || '',
365
+ };
366
+
367
+ const result = await params.consentClient.getActivities(
368
+ baseRequest,
369
+ params.offset,
370
+ params.limit,
371
+ params.language,
372
+ params.authToken
373
+ );
374
+ return result as ActivityDetail;
375
+ } catch (error: any) {
376
+ return handleServerActionError(error, 'fetching activities');
377
+ }
378
+ }
379
+
380
+ export async function fetchCaseHistoryServer(params: {
381
+ organizationId: string;
382
+ workspaceId: string;
383
+ contact: string;
384
+ offset?: number;
385
+ limit?: number;
386
+ language?: string;
387
+ authToken?: string;
388
+ consentClient?: ReturnType<typeof import('./client').createConsentClient>;
389
+ }): Promise<CaseHistoryDetail | null> {
390
+ try {
391
+ if (!params.consentClient) {
392
+ throw new Error('Consent client is required');
393
+ }
394
+ // Privacy center endpoints use JWT Bearer tokens, not session-based auth
395
+ const baseRequest: BaseRequest = {
396
+ organisationUuid: params.organizationId,
397
+ workspaceUuid: params.workspaceId,
398
+ authToken: params.authToken || '',
399
+ };
400
+
401
+ const result = await params.consentClient.getCaseHistory(
402
+ baseRequest,
403
+ params.contact,
404
+ params.offset,
405
+ params.limit,
406
+ params.language,
407
+ params.authToken
408
+ );
409
+
410
+ if (Array.isArray(result)) {
411
+ return {
412
+ data: result,
413
+ pagination: {
414
+ total_count: result.length,
415
+ offset: params.offset || 0,
416
+ limit: params.limit || 10
417
+ },
418
+ } as CaseHistoryDetail;
419
+ }
420
+
421
+ if (result && typeof result === 'object' && 'data' in result) {
422
+ const resultData = result as { data?: unknown[]; pagination?: Pagination };
423
+ return {
424
+ data: resultData.data || [],
425
+ pagination: resultData.pagination || {
426
+ total_count: resultData.data?.length || 0,
427
+ offset: params.offset || 0,
428
+ limit: params.limit || 10
429
+ },
430
+ } as CaseHistoryDetail;
431
+ }
432
+
433
+ return {
434
+ data: [],
435
+ pagination: {
436
+ total_count: 0,
437
+ offset: params.offset || 0,
438
+ limit: params.limit || 10
439
+ },
440
+ } as CaseHistoryDetail;
441
+ } catch (error: any) {
442
+ return handleServerActionError(error, 'fetching case history');
443
+ }
444
+ }