@redacto.io/consent-sdk-react 5.2.0 → 6.0.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.
- package/.turbo/turbo-build.log +24 -0
- package/CHANGELOG.md +12 -0
- package/dist/index.d.mts +24 -1
- package/dist/index.d.ts +24 -1
- package/dist/index.js +149 -206
- package/dist/index.mjs +148 -206
- package/dist/privacy-center.d.mts +178 -39
- package/dist/privacy-center.d.ts +178 -39
- package/dist/privacy-center.js +10534 -6795
- package/dist/privacy-center.mjs +7922 -4181
- package/package.json +1 -1
- package/src/RedactoNoticeConsent/RedactoNoticeConsent.tsx +16 -20
- package/src/RedactoNoticeConsent/api/index.ts +21 -103
- package/src/RedactoNoticeConsentInline/RedactoNoticeConsentInline.tsx +5 -4
- package/src/RedactoNoticeConsentInline/api/index.ts +64 -117
- package/src/RedactoPrivacyCenter/NotificationsPage.tsx +174 -0
- package/src/RedactoPrivacyCenter/PrivacyCenterHomePage.tsx +3 -0
- package/src/RedactoPrivacyCenter/api/actions.ts +136 -8
- package/src/RedactoPrivacyCenter/api/client.ts +176 -15
- package/src/RedactoPrivacyCenter/components/ConsentManager.tsx +722 -273
- package/src/RedactoPrivacyCenter/components/ConsentManagerCells.tsx +187 -0
- package/src/RedactoPrivacyCenter/components/ConsentManagerColumns.tsx +65 -165
- package/src/RedactoPrivacyCenter/components/ConsentManagerExpandedRow.tsx +179 -0
- package/src/RedactoPrivacyCenter/components/ConsentManagerGroupedColumns.tsx +318 -0
- package/src/RedactoPrivacyCenter/components/ConsentManagerProductCards.tsx +333 -0
- package/src/RedactoPrivacyCenter/components/ConsentManagerPurposeCards.tsx +102 -0
- package/src/RedactoPrivacyCenter/components/ConsentManagerTableSkeleton.tsx +6 -2
- package/src/RedactoPrivacyCenter/components/DataRequest/PurposeSelectionSection.tsx +15 -0
- package/src/RedactoPrivacyCenter/components/ModifyConsentModal.tsx +8 -5
- package/src/RedactoPrivacyCenter/components/NotificationHub/NotificationBell.tsx +160 -0
- package/src/RedactoPrivacyCenter/components/NotificationHub/NotificationCTAButton.tsx +18 -0
- package/src/RedactoPrivacyCenter/components/NotificationHub/NotificationDropdown.tsx +54 -0
- package/src/RedactoPrivacyCenter/components/NotificationHub/NotificationDropdownItem.tsx +57 -0
- package/src/RedactoPrivacyCenter/components/NotificationHub/NotificationIcon.tsx +19 -0
- package/src/RedactoPrivacyCenter/components/NotificationHub/NotificationListPanel.tsx +92 -0
- package/src/RedactoPrivacyCenter/components/NotificationHub/NotificationRefreshButton.tsx +20 -0
- package/src/RedactoPrivacyCenter/components/NotificationHub/NotificationRow.tsx +58 -0
- package/src/RedactoPrivacyCenter/components/NotificationHub/StatCard.tsx +10 -0
- package/src/RedactoPrivacyCenter/components/NotificationHub/useNotificationActions.ts +112 -0
- package/src/RedactoPrivacyCenter/components/NotificationHub/utils.ts +27 -0
- package/src/RedactoPrivacyCenter/components/PrivacyCenterLayout.tsx +105 -55
- package/src/RedactoPrivacyCenter/components/types.ts +2 -5
- package/src/RedactoPrivacyCenter/context/NavigationContext.tsx +2 -2
- package/src/RedactoPrivacyCenter/context/PageChromeContext.tsx +21 -1
- package/src/RedactoPrivacyCenter/lib/api.ts +147 -28
- package/src/RedactoPrivacyCenter/lib/consent-manager/utils.tsx +4 -2
- package/src/RedactoPrivacyCenter/lib/constants.ts +78 -1
- package/src/RedactoPrivacyCenter/lib/types.ts +205 -36
- package/src/RedactoPrivacyCenter/lib/utils.ts +3 -0
- package/src/RedactoPrivacyCenter/locales/as/translation.json +12 -1
- package/src/RedactoPrivacyCenter/locales/bho/translation.json +12 -1
- package/src/RedactoPrivacyCenter/locales/bn/translation.json +12 -1
- package/src/RedactoPrivacyCenter/locales/brx/translation.json +12 -1
- package/src/RedactoPrivacyCenter/locales/doi/translation.json +12 -1
- package/src/RedactoPrivacyCenter/locales/en/translation.json +42 -1
- package/src/RedactoPrivacyCenter/locales/gom/translation.json +12 -1
- package/src/RedactoPrivacyCenter/locales/gu/translation.json +12 -1
- package/src/RedactoPrivacyCenter/locales/hi/translation.json +15 -1
- package/src/RedactoPrivacyCenter/locales/kn/translation.json +12 -1
- package/src/RedactoPrivacyCenter/locales/ks/translation.json +12 -1
- package/src/RedactoPrivacyCenter/locales/mai/translation.json +12 -1
- package/src/RedactoPrivacyCenter/locales/ml/translation.json +12 -1
- package/src/RedactoPrivacyCenter/locales/mni-Mtei/translation.json +12 -1
- package/src/RedactoPrivacyCenter/locales/mr/translation.json +12 -1
- package/src/RedactoPrivacyCenter/locales/ne/translation.json +12 -1
- package/src/RedactoPrivacyCenter/locales/or/translation.json +12 -1
- package/src/RedactoPrivacyCenter/locales/pa/translation.json +12 -1
- package/src/RedactoPrivacyCenter/locales/sa/translation.json +12 -1
- package/src/RedactoPrivacyCenter/locales/sat/translation.json +12 -1
- package/src/RedactoPrivacyCenter/locales/sd/translation.json +12 -1
- package/src/RedactoPrivacyCenter/locales/ta/translation.json +12 -1
- package/src/RedactoPrivacyCenter/locales/te/translation.json +12 -1
- package/src/RedactoPrivacyCenter/locales/ur/translation.json +12 -1
- package/src/RedactoPrivacyCenter/styles/injectStyles.ts +1027 -0
- package/src/RedactoPrivacyCenter/styles/variables.css +5 -0
- package/src/RedactoPrivacyCenter/table/AdvancedTable.tsx +36 -16
- package/src/RedactoPrivacyCenter/table/AdvancedTablePagination.tsx +4 -12
- package/src/RedactoPrivacyCenter/ui/PCInput.tsx +1 -1
- package/src/RedactoPrivacyCenter/ui/PCPopover.tsx +23 -1
- package/src/RedactoPrivacyCenter/ui/PCSelect.tsx +51 -5
- package/src/RedactoPrivacyCenter/ui/ThemeToggle.tsx +2 -4
- package/src/index.ts +5 -0
- package/src/privacy-center.ts +8 -3
- package/src/shared/api-errors.ts +171 -0
|
@@ -4,6 +4,7 @@ import {
|
|
|
4
4
|
fetchCaseHistoryServer,
|
|
5
5
|
fetchProductsServer,
|
|
6
6
|
fetchUserConsentsServer,
|
|
7
|
+
fetchGroupPurposesServer,
|
|
7
8
|
getFormDataServer,
|
|
8
9
|
manageConsentServer,
|
|
9
10
|
getCaseMessagesServer,
|
|
@@ -11,6 +12,12 @@ import {
|
|
|
11
12
|
uploadCaseDocumentServer,
|
|
12
13
|
submitDocumentForRequestServer,
|
|
13
14
|
getCaseDocumentServer,
|
|
15
|
+
getNotificationsServer,
|
|
16
|
+
getNotificationSummaryServer,
|
|
17
|
+
getUnreadCountServer,
|
|
18
|
+
markNotificationReadServer,
|
|
19
|
+
markAllNotificationsReadServer,
|
|
20
|
+
acknowledgeNotificationServer,
|
|
14
21
|
} from '../api/actions';
|
|
15
22
|
import type { BaseUrlContextValue } from '../context/BaseUrlContext';
|
|
16
23
|
import type {
|
|
@@ -20,9 +27,15 @@ import type {
|
|
|
20
27
|
CreateCaseResponse,
|
|
21
28
|
FormData,
|
|
22
29
|
MessageDocument,
|
|
30
|
+
NotificationActionResponse,
|
|
31
|
+
NotificationListResponse,
|
|
32
|
+
NotificationQueryParams,
|
|
33
|
+
NotificationSummary,
|
|
34
|
+
UnreadCountResponse,
|
|
23
35
|
UploadDocumentResponse,
|
|
24
36
|
UserConsentDetail,
|
|
25
37
|
UserDataRequest,
|
|
38
|
+
GroupPurposesOut,
|
|
26
39
|
} from './types';
|
|
27
40
|
import { ensureValidToken } from './utils';
|
|
28
41
|
|
|
@@ -249,37 +262,35 @@ export const fetchProducts = async (
|
|
|
249
262
|
}
|
|
250
263
|
};
|
|
251
264
|
|
|
265
|
+
export type FetchUserConsentsParams = {
|
|
266
|
+
organizationId: string;
|
|
267
|
+
workspaceId: string;
|
|
268
|
+
offset?: number;
|
|
269
|
+
limit?: number;
|
|
270
|
+
nominatedOffset?: number;
|
|
271
|
+
nominatedLimit?: number;
|
|
272
|
+
search?: string;
|
|
273
|
+
status?: string;
|
|
274
|
+
product_uuid?: string;
|
|
275
|
+
language?: string;
|
|
276
|
+
authContext?: AuthContext;
|
|
277
|
+
consentClient?: BaseUrlContextValue['consentClient'];
|
|
278
|
+
};
|
|
279
|
+
|
|
252
280
|
export const fetchUserConsents = async (
|
|
253
|
-
|
|
254
|
-
workspaceId: string,
|
|
255
|
-
contact: string,
|
|
256
|
-
offset?: number,
|
|
257
|
-
limit?: number,
|
|
258
|
-
search?: string,
|
|
259
|
-
status?: string,
|
|
260
|
-
product_uuid?: string,
|
|
261
|
-
authContext?: AuthContext,
|
|
262
|
-
consentClient?: BaseUrlContextValue['consentClient'],
|
|
263
|
-
language?: string
|
|
281
|
+
params: FetchUserConsentsParams
|
|
264
282
|
): Promise<UserConsentDetail | null> => {
|
|
283
|
+
const { organizationId, workspaceId, authContext, consentClient, ...rest } = params;
|
|
265
284
|
try {
|
|
266
|
-
// Ensure we have a valid token before making the API call
|
|
267
285
|
const accessToken = await ensureValidToken(organizationId, workspaceId, undefined, authContext, consentClient);
|
|
268
286
|
if (!accessToken) {
|
|
269
|
-
// ensureValidToken already handled sign out and redirect
|
|
270
287
|
return null;
|
|
271
288
|
}
|
|
272
289
|
|
|
273
290
|
const result = await fetchUserConsentsServer({
|
|
274
291
|
organizationId,
|
|
275
292
|
workspaceId,
|
|
276
|
-
|
|
277
|
-
offset,
|
|
278
|
-
limit,
|
|
279
|
-
search,
|
|
280
|
-
status,
|
|
281
|
-
product_uuid,
|
|
282
|
-
language,
|
|
293
|
+
...rest,
|
|
283
294
|
authToken: accessToken,
|
|
284
295
|
consentClient,
|
|
285
296
|
});
|
|
@@ -287,18 +298,11 @@ export const fetchUserConsents = async (
|
|
|
287
298
|
} catch (error: any) {
|
|
288
299
|
const shouldRetry = await handleClientAuthError(error, organizationId, workspaceId, authContext, consentClient);
|
|
289
300
|
if (shouldRetry) {
|
|
290
|
-
// Read from sessionStorage first (synchronously updated) then fall back to context
|
|
291
301
|
const newAccessToken = sessionStorage.getItem('access_token') || authContext?.accessToken || '';
|
|
292
302
|
return await fetchUserConsentsServer({
|
|
293
303
|
organizationId,
|
|
294
304
|
workspaceId,
|
|
295
|
-
|
|
296
|
-
offset,
|
|
297
|
-
limit,
|
|
298
|
-
search,
|
|
299
|
-
status,
|
|
300
|
-
product_uuid,
|
|
301
|
-
language,
|
|
305
|
+
...rest,
|
|
302
306
|
authToken: newAccessToken || undefined,
|
|
303
307
|
consentClient,
|
|
304
308
|
});
|
|
@@ -308,6 +312,55 @@ export const fetchUserConsents = async (
|
|
|
308
312
|
}
|
|
309
313
|
};
|
|
310
314
|
|
|
315
|
+
export type FetchGroupPurposesParams = {
|
|
316
|
+
organizationId: string;
|
|
317
|
+
workspaceId: string;
|
|
318
|
+
productUuid: string;
|
|
319
|
+
offset?: number;
|
|
320
|
+
limit?: number;
|
|
321
|
+
status?: string;
|
|
322
|
+
search?: string;
|
|
323
|
+
language?: string;
|
|
324
|
+
nominatorUuid?: string;
|
|
325
|
+
authContext?: AuthContext;
|
|
326
|
+
consentClient?: BaseUrlContextValue['consentClient'];
|
|
327
|
+
};
|
|
328
|
+
|
|
329
|
+
export const fetchGroupPurposes = async (
|
|
330
|
+
params: FetchGroupPurposesParams
|
|
331
|
+
): Promise<GroupPurposesOut | null> => {
|
|
332
|
+
const { organizationId, workspaceId, authContext, consentClient, ...rest } = params;
|
|
333
|
+
try {
|
|
334
|
+
const accessToken = await ensureValidToken(organizationId, workspaceId, undefined, authContext, consentClient);
|
|
335
|
+
if (!accessToken) {
|
|
336
|
+
return null;
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
const result = await fetchGroupPurposesServer({
|
|
340
|
+
organizationId,
|
|
341
|
+
workspaceId,
|
|
342
|
+
...rest,
|
|
343
|
+
authToken: accessToken,
|
|
344
|
+
consentClient,
|
|
345
|
+
});
|
|
346
|
+
return result;
|
|
347
|
+
} catch (error: any) {
|
|
348
|
+
const shouldRetry = await handleClientAuthError(error, organizationId, workspaceId, authContext, consentClient);
|
|
349
|
+
if (shouldRetry) {
|
|
350
|
+
const newAccessToken = sessionStorage.getItem('access_token') || authContext?.accessToken || '';
|
|
351
|
+
return await fetchGroupPurposesServer({
|
|
352
|
+
organizationId,
|
|
353
|
+
workspaceId,
|
|
354
|
+
...rest,
|
|
355
|
+
authToken: newAccessToken || undefined,
|
|
356
|
+
consentClient,
|
|
357
|
+
});
|
|
358
|
+
}
|
|
359
|
+
console.error('Error fetching group purposes:', error);
|
|
360
|
+
return null;
|
|
361
|
+
}
|
|
362
|
+
};
|
|
363
|
+
|
|
311
364
|
export const manageConsent = async ({
|
|
312
365
|
organizationId,
|
|
313
366
|
workspaceId,
|
|
@@ -564,3 +617,69 @@ export const getCaseDocument = async (
|
|
|
564
617
|
withAuthRetry(organizationId, workspaceId, authContext, consentClient, 'Error fetching case document:', (token) =>
|
|
565
618
|
getCaseDocumentServer({ organizationId, workspaceId, caseUuid, documentUuid, authToken: token, consentClient })
|
|
566
619
|
);
|
|
620
|
+
|
|
621
|
+
// ─── Notification Hub ───────────────────────────────────────────────────────
|
|
622
|
+
|
|
623
|
+
export const fetchNotifications = async (
|
|
624
|
+
organizationId: string,
|
|
625
|
+
workspaceId: string,
|
|
626
|
+
params?: NotificationQueryParams,
|
|
627
|
+
authContext?: AuthContext,
|
|
628
|
+
consentClient?: BaseUrlContextValue['consentClient'],
|
|
629
|
+
language?: string,
|
|
630
|
+
): Promise<NotificationListResponse | null> =>
|
|
631
|
+
withAuthRetry(organizationId, workspaceId, authContext, consentClient, 'Error fetching notifications:', (token) =>
|
|
632
|
+
getNotificationsServer({ organizationId, workspaceId, ...params, language, authToken: token, consentClient })
|
|
633
|
+
);
|
|
634
|
+
|
|
635
|
+
export const fetchNotificationSummary = async (
|
|
636
|
+
organizationId: string,
|
|
637
|
+
workspaceId: string,
|
|
638
|
+
authContext?: AuthContext,
|
|
639
|
+
consentClient?: BaseUrlContextValue['consentClient']
|
|
640
|
+
): Promise<NotificationSummary | null> =>
|
|
641
|
+
withAuthRetry(organizationId, workspaceId, authContext, consentClient, 'Error fetching notification summary:', (token) =>
|
|
642
|
+
getNotificationSummaryServer({ organizationId, workspaceId, authToken: token, consentClient })
|
|
643
|
+
);
|
|
644
|
+
|
|
645
|
+
export const fetchUnreadCount = async (
|
|
646
|
+
organizationId: string,
|
|
647
|
+
workspaceId: string,
|
|
648
|
+
authContext?: AuthContext,
|
|
649
|
+
consentClient?: BaseUrlContextValue['consentClient']
|
|
650
|
+
): Promise<UnreadCountResponse | null> =>
|
|
651
|
+
withAuthRetry(organizationId, workspaceId, authContext, consentClient, 'Error fetching unread count:', (token) =>
|
|
652
|
+
getUnreadCountServer({ organizationId, workspaceId, authToken: token, consentClient })
|
|
653
|
+
);
|
|
654
|
+
|
|
655
|
+
export const markNotificationRead = async (
|
|
656
|
+
organizationId: string,
|
|
657
|
+
workspaceId: string,
|
|
658
|
+
notificationUuid: string,
|
|
659
|
+
authContext?: AuthContext,
|
|
660
|
+
consentClient?: BaseUrlContextValue['consentClient']
|
|
661
|
+
): Promise<NotificationActionResponse | null> =>
|
|
662
|
+
withAuthRetry(organizationId, workspaceId, authContext, consentClient, 'Error marking notification as read:', (token) =>
|
|
663
|
+
markNotificationReadServer({ organizationId, workspaceId, notificationUuid, authToken: token, consentClient })
|
|
664
|
+
);
|
|
665
|
+
|
|
666
|
+
export const markAllRead = async (
|
|
667
|
+
organizationId: string,
|
|
668
|
+
workspaceId: string,
|
|
669
|
+
authContext?: AuthContext,
|
|
670
|
+
consentClient?: BaseUrlContextValue['consentClient']
|
|
671
|
+
): Promise<NotificationActionResponse | null> =>
|
|
672
|
+
withAuthRetry(organizationId, workspaceId, authContext, consentClient, 'Error marking all notifications as read:', (token) =>
|
|
673
|
+
markAllNotificationsReadServer({ organizationId, workspaceId, authToken: token, consentClient })
|
|
674
|
+
);
|
|
675
|
+
|
|
676
|
+
export const acknowledgeNotification = async (
|
|
677
|
+
organizationId: string,
|
|
678
|
+
workspaceId: string,
|
|
679
|
+
notificationUuid: string,
|
|
680
|
+
authContext?: AuthContext,
|
|
681
|
+
consentClient?: BaseUrlContextValue['consentClient']
|
|
682
|
+
): Promise<NotificationActionResponse | null> =>
|
|
683
|
+
withAuthRetry(organizationId, workspaceId, authContext, consentClient, 'Error acknowledging notification:', (token) =>
|
|
684
|
+
acknowledgeNotificationServer({ organizationId, workspaceId, notificationUuid, authToken: token, consentClient })
|
|
685
|
+
);
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import { useMemo } from 'react';
|
|
2
2
|
import { useTranslation } from 'react-i18next';
|
|
3
3
|
import { ConsentStatusEnum } from '../types';
|
|
4
|
-
import type {
|
|
4
|
+
import type { PurposeItem } from '../types';
|
|
5
|
+
|
|
6
|
+
type CsvRow = Partial<PurposeItem> & Record<string, unknown>;
|
|
5
7
|
import { formatDateTime as formatDateTimeShared } from '../../utils/date';
|
|
6
8
|
|
|
7
9
|
// Re-export shared date formatting
|
|
@@ -20,7 +22,7 @@ export const useStatusOptions = () => {
|
|
|
20
22
|
);
|
|
21
23
|
};
|
|
22
24
|
|
|
23
|
-
export const exportTableToCSV = (rows:
|
|
25
|
+
export const exportTableToCSV = (rows: CsvRow[]) => {
|
|
24
26
|
if (!rows || rows.length === 0) {
|
|
25
27
|
console.warn('No data to export');
|
|
26
28
|
return;
|
|
@@ -4,7 +4,8 @@ import { GRIEVANCE_TAB_IDS } from '../components/constant';
|
|
|
4
4
|
import { menuItemsPC } from '../components/SideMenuBarPC/constants';
|
|
5
5
|
import type { MenuItem } from '../components/SideMenuBarPC/types';
|
|
6
6
|
import type { InternalPage } from '../context/NavigationContext';
|
|
7
|
-
import type { DocumentRequestStatus, DocumentRequestStatusInfo } from './types';
|
|
7
|
+
import type { DocumentRequestStatus, DocumentRequestStatusInfo, NotificationCTA, NotificationType, NotificationCategory, IconCategory, FilterTab } from './types';
|
|
8
|
+
import { IoPersonOutline, IoTimeOutline, IoDocumentOutline, IoShieldCheckmarkOutline, IoAlertCircleOutline, IoSettingsOutline } from 'react-icons/io5';
|
|
8
9
|
|
|
9
10
|
export const useRequestTypeLabels = () => {
|
|
10
11
|
const { t } = useTranslation();
|
|
@@ -89,6 +90,10 @@ export const PAGE_CHROME_BY_PAGE: Record<InternalPage, PageChromeConfig> = {
|
|
|
89
90
|
titleKey: 'caseDetails',
|
|
90
91
|
descriptionKey: 'yourPrivacyCenter',
|
|
91
92
|
},
|
|
93
|
+
notifications: {
|
|
94
|
+
titleKey: 'notificationHub',
|
|
95
|
+
descriptionKey: 'notificationHubSubtitle',
|
|
96
|
+
},
|
|
92
97
|
};
|
|
93
98
|
|
|
94
99
|
const HREF_TO_NAME_KEY: Record<string, string> = {
|
|
@@ -159,3 +164,75 @@ export const ACTIVITY_DATE_FORMATS = {
|
|
|
159
164
|
DISPLAY: 'MMM D, YYYY [at] h:mm A',
|
|
160
165
|
TOOLTIP: 'MMMM D, YYYY [at] h:mm:ss A',
|
|
161
166
|
} as const;
|
|
167
|
+
|
|
168
|
+
|
|
169
|
+
// ─── Notification Hub ──────────────────────────────────────────────────────
|
|
170
|
+
|
|
171
|
+
export const POLL_INTERVAL = 30_000;
|
|
172
|
+
export const NOTIFICATION_PAGE_SIZE = 10;
|
|
173
|
+
export const NOTIFICATION_DROPDOWN_LIMIT = 5;
|
|
174
|
+
|
|
175
|
+
export const TAB_TO_CATEGORY: Record<FilterTab, NotificationCategory | undefined> = {
|
|
176
|
+
all: undefined,
|
|
177
|
+
consent: 'consent',
|
|
178
|
+
request: 'request',
|
|
179
|
+
system: 'system',
|
|
180
|
+
};
|
|
181
|
+
|
|
182
|
+
export const TYPE_TO_ICON_CATEGORY: Record<NotificationType, IconCategory> = {
|
|
183
|
+
guardian_verification_request: 'guardian',
|
|
184
|
+
consent_expiry_warning: 'consent',
|
|
185
|
+
new_consent_notice: 'system',
|
|
186
|
+
consent_withdrawal_confirmation: 'withdrawal',
|
|
187
|
+
data_request_status_update: 'access',
|
|
188
|
+
case_message: 'access',
|
|
189
|
+
grievance_status_update: 'grievance',
|
|
190
|
+
consent_regrant_prompt: 'consent',
|
|
191
|
+
};
|
|
192
|
+
|
|
193
|
+
export const ICON_MAP: Record<IconCategory, typeof IoPersonOutline> = {
|
|
194
|
+
guardian: IoPersonOutline,
|
|
195
|
+
consent: IoTimeOutline,
|
|
196
|
+
access: IoDocumentOutline,
|
|
197
|
+
withdrawal: IoShieldCheckmarkOutline,
|
|
198
|
+
grievance: IoAlertCircleOutline,
|
|
199
|
+
system: IoSettingsOutline,
|
|
200
|
+
};
|
|
201
|
+
|
|
202
|
+
export const ICON_COLORS: Record<IconCategory, string> = {
|
|
203
|
+
guardian: '#7c3aed',
|
|
204
|
+
consent: '#ea580c',
|
|
205
|
+
access: '#16a34a',
|
|
206
|
+
withdrawal: '#2563eb',
|
|
207
|
+
grievance: '#dc2626',
|
|
208
|
+
system: '#6b7280',
|
|
209
|
+
};
|
|
210
|
+
|
|
211
|
+
export const CTA_VARIANT_CLASS: Record<NotificationCTA['style'], string> = {
|
|
212
|
+
primary: 'pc-notification-cta--primary',
|
|
213
|
+
danger: 'pc-notification-cta--danger',
|
|
214
|
+
secondary: 'pc-notification-cta--secondary',
|
|
215
|
+
};
|
|
216
|
+
|
|
217
|
+
export const useNotificationFilterTabs = () => {
|
|
218
|
+
const { t } = useTranslation();
|
|
219
|
+
return [
|
|
220
|
+
{ key: 'all' as FilterTab, label: t('all') },
|
|
221
|
+
{ key: 'consent' as FilterTab, label: t('consent') },
|
|
222
|
+
{ key: 'request' as FilterTab, label: t('requests') },
|
|
223
|
+
{ key: 'system' as FilterTab, label: t('system') },
|
|
224
|
+
];
|
|
225
|
+
};
|
|
226
|
+
|
|
227
|
+
export const useNotificationStatLabels = () => {
|
|
228
|
+
const { t } = useTranslation();
|
|
229
|
+
return {
|
|
230
|
+
total: t('total'),
|
|
231
|
+
unread: t('unread'),
|
|
232
|
+
action_needed: t('actionNeeded'),
|
|
233
|
+
acknowledged: t('acknowledged'),
|
|
234
|
+
};
|
|
235
|
+
};
|
|
236
|
+
|
|
237
|
+
|
|
238
|
+
export const CASE_DETAILS_PREFIX = '/case-details/';
|
|
@@ -180,21 +180,6 @@ export type ConsentDataElement = {
|
|
|
180
180
|
selected: boolean;
|
|
181
181
|
};
|
|
182
182
|
|
|
183
|
-
export type UserConsent = {
|
|
184
|
-
purpose_uuid?: string;
|
|
185
|
-
purpose: string;
|
|
186
|
-
purpose_description: string;
|
|
187
|
-
status: ConsentStatusEnum;
|
|
188
|
-
given_date: string;
|
|
189
|
-
valid_till: string;
|
|
190
|
-
method: string;
|
|
191
|
-
data_elements: ConsentDataElement[];
|
|
192
|
-
product_uuid?: string;
|
|
193
|
-
product_name?: string;
|
|
194
|
-
product_description?: string | null;
|
|
195
|
-
nominator_info?: NominatorInfo;
|
|
196
|
-
};
|
|
197
|
-
|
|
198
183
|
export type NominatorInfo = {
|
|
199
184
|
org_user_id: string;
|
|
200
185
|
name: string | null;
|
|
@@ -202,44 +187,79 @@ export type NominatorInfo = {
|
|
|
202
187
|
email: string | null;
|
|
203
188
|
};
|
|
204
189
|
|
|
190
|
+
export type PurposeItem = {
|
|
191
|
+
purpose_uuid: string;
|
|
192
|
+
name: string;
|
|
193
|
+
description: string | null;
|
|
194
|
+
status: ConsentStatusEnum | string;
|
|
195
|
+
given_date: string | null;
|
|
196
|
+
valid_till: string | null;
|
|
197
|
+
method: string;
|
|
198
|
+
data_elements: ConsentDataElement[];
|
|
199
|
+
link_reason: string | null;
|
|
200
|
+
};
|
|
201
|
+
|
|
202
|
+
export type ConsentGroup = {
|
|
203
|
+
product_uuid: string;
|
|
204
|
+
product_name: string;
|
|
205
|
+
product_description: string | null;
|
|
206
|
+
nominator: NominatorInfo | null;
|
|
207
|
+
total_purposes: number;
|
|
208
|
+
active_purposes: number;
|
|
209
|
+
purposes: PurposeItem[];
|
|
210
|
+
has_more_purposes: boolean;
|
|
211
|
+
};
|
|
212
|
+
|
|
213
|
+
export type PaginationMeta = {
|
|
214
|
+
total_count: number;
|
|
215
|
+
offset: number;
|
|
216
|
+
limit: number;
|
|
217
|
+
};
|
|
218
|
+
|
|
219
|
+
export type Pagination = PaginationMeta;
|
|
220
|
+
|
|
205
221
|
export type ConsentHistoryStatusSummary = {
|
|
206
222
|
total_purposes: number;
|
|
207
223
|
direct_purposes: number;
|
|
208
224
|
nominated_purposes: number;
|
|
209
|
-
nominee_purposes?: number;
|
|
210
225
|
active_purposes: number;
|
|
211
226
|
inactive_purposes: number;
|
|
212
227
|
};
|
|
213
228
|
|
|
214
|
-
export type
|
|
229
|
+
export type DisplayProductGroup = ConsentGroup & {
|
|
230
|
+
withdrawn_purposes: number;
|
|
231
|
+
expired_purposes: number;
|
|
232
|
+
declined_purposes: number;
|
|
233
|
+
latest_given_date: string | null;
|
|
234
|
+
};
|
|
235
|
+
|
|
236
|
+
export type DisplayPurposeRow = PurposeItem & {
|
|
215
237
|
product_uuid: string;
|
|
216
238
|
product_name: string;
|
|
217
239
|
product_description: string | null;
|
|
218
|
-
|
|
219
|
-
total_purposes: number;
|
|
220
|
-
active_purposes: number;
|
|
240
|
+
nominator: NominatorInfo | null;
|
|
221
241
|
};
|
|
222
242
|
|
|
223
|
-
export type
|
|
224
|
-
|
|
225
|
-
|
|
243
|
+
export type ConsentModalRecord = PurposeItem & {
|
|
244
|
+
product_uuid: string;
|
|
245
|
+
product_name: string;
|
|
246
|
+
product_description: string | null;
|
|
247
|
+
nominator: NominatorInfo | null;
|
|
226
248
|
};
|
|
227
249
|
|
|
228
|
-
export type
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
250
|
+
export type UserConsentDetail = {
|
|
251
|
+
direct: ConsentGroup[];
|
|
252
|
+
direct_pagination: PaginationMeta;
|
|
253
|
+
nominated: ConsentGroup[];
|
|
254
|
+
nominated_pagination: PaginationMeta;
|
|
255
|
+
user_status: 'ACTIVE' | 'TRANSFERRED' | null;
|
|
256
|
+
nominators: NominatorInfo[];
|
|
257
|
+
status_summary: ConsentHistoryStatusSummary;
|
|
232
258
|
};
|
|
233
259
|
|
|
234
|
-
export type
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
pagination: Pagination;
|
|
238
|
-
direct_product_groups?: ProductConsentHistoryGroup[];
|
|
239
|
-
user_status?: 'ACTIVE' | 'TRANSFERRED' | null;
|
|
240
|
-
nominated_purposes?: NominatedPurposesGroup[];
|
|
241
|
-
nominators?: NominatorInfo[];
|
|
242
|
-
status_summary?: ConsentHistoryStatusSummary | null;
|
|
260
|
+
export type GroupPurposesOut = {
|
|
261
|
+
purposes: PurposeItem[];
|
|
262
|
+
pagination: PaginationMeta;
|
|
243
263
|
};
|
|
244
264
|
|
|
245
265
|
export type UserConsentResponse = {
|
|
@@ -251,6 +271,7 @@ export type UserConsentResponse = {
|
|
|
251
271
|
export enum ConsentStatusEnum {
|
|
252
272
|
ACTIVE = 'ACTIVE',
|
|
253
273
|
WITHDRAWN = 'WITHDRAW',
|
|
274
|
+
REVOKED = 'REVOKED',
|
|
254
275
|
EXPIRED = 'EXPIRED',
|
|
255
276
|
DECLINED = 'DECLINED',
|
|
256
277
|
}
|
|
@@ -529,3 +550,151 @@ export type SubmitDocumentForRequestInput = Readonly<{
|
|
|
529
550
|
export type DocumentRequestStatusInfo = Readonly<{ labelKey: string; color: string }>;
|
|
530
551
|
|
|
531
552
|
export type CaseDetailsTab = Readonly<{ id: TabId; label: string }>;
|
|
553
|
+
|
|
554
|
+
// ─── Notification Hub ──────────────────────────────────────────────────────
|
|
555
|
+
|
|
556
|
+
export type NotificationType =
|
|
557
|
+
| 'guardian_verification_request'
|
|
558
|
+
| 'consent_expiry_warning'
|
|
559
|
+
| 'new_consent_notice'
|
|
560
|
+
| 'consent_withdrawal_confirmation'
|
|
561
|
+
| 'data_request_status_update'
|
|
562
|
+
| 'case_message'
|
|
563
|
+
| 'grievance_status_update'
|
|
564
|
+
| 'consent_regrant_prompt';
|
|
565
|
+
|
|
566
|
+
export type NotificationCategory = 'consent' | 'request' | 'system';
|
|
567
|
+
|
|
568
|
+
export type NotificationCTA = {
|
|
569
|
+
label: string;
|
|
570
|
+
style: 'primary' | 'secondary' | 'danger';
|
|
571
|
+
action_type: 'link' | 'acknowledge';
|
|
572
|
+
url?: string;
|
|
573
|
+
};
|
|
574
|
+
|
|
575
|
+
export type Notification = {
|
|
576
|
+
uuid: string;
|
|
577
|
+
notification_type: NotificationType;
|
|
578
|
+
category: NotificationCategory;
|
|
579
|
+
title: string;
|
|
580
|
+
description: string;
|
|
581
|
+
is_read: boolean;
|
|
582
|
+
is_acknowledged: boolean;
|
|
583
|
+
source_type: string;
|
|
584
|
+
source_uuid: string | null;
|
|
585
|
+
request_type: string;
|
|
586
|
+
request_type_display?: string | null;
|
|
587
|
+
status_label: string;
|
|
588
|
+
status_label_display?: string | null;
|
|
589
|
+
ctas: NotificationCTA[];
|
|
590
|
+
created_at: string;
|
|
591
|
+
};
|
|
592
|
+
|
|
593
|
+
export type NotificationSummary = {
|
|
594
|
+
total: number;
|
|
595
|
+
unread: number;
|
|
596
|
+
action_needed: number;
|
|
597
|
+
acknowledged: number;
|
|
598
|
+
};
|
|
599
|
+
|
|
600
|
+
export type NotificationListResponse = {
|
|
601
|
+
data: Notification[];
|
|
602
|
+
total: number;
|
|
603
|
+
skip: number;
|
|
604
|
+
limit: number;
|
|
605
|
+
summary: NotificationSummary | null;
|
|
606
|
+
};
|
|
607
|
+
|
|
608
|
+
export type UnreadCountResponse = {
|
|
609
|
+
count: number;
|
|
610
|
+
};
|
|
611
|
+
|
|
612
|
+
export type NotificationActionResponse = {
|
|
613
|
+
message: string;
|
|
614
|
+
};
|
|
615
|
+
|
|
616
|
+
export type NotificationActionBaseParams = {
|
|
617
|
+
organizationId: string;
|
|
618
|
+
workspaceId: string;
|
|
619
|
+
authToken?: string;
|
|
620
|
+
consentClient?: ReturnType<typeof import('../api/client').createConsentClient>;
|
|
621
|
+
};
|
|
622
|
+
|
|
623
|
+
export type StatCardProps = Readonly<{
|
|
624
|
+
value: number; label: string;
|
|
625
|
+
}>
|
|
626
|
+
|
|
627
|
+
export type NotificationDropdownProps = Readonly<{
|
|
628
|
+
notifications: Notification[];
|
|
629
|
+
onMarkAllRead: () => void;
|
|
630
|
+
onRefresh: () => void;
|
|
631
|
+
isRefreshing: boolean;
|
|
632
|
+
onViewAll: () => void;
|
|
633
|
+
onNotificationClick: (notification: Notification) => void;
|
|
634
|
+
onCTAClick: (notification: Notification, cta: NotificationCTA) => void;
|
|
635
|
+
}>;
|
|
636
|
+
|
|
637
|
+
export type NotificationListPanelProps = Readonly<{
|
|
638
|
+
notifications: Notification[];
|
|
639
|
+
totalCount: number;
|
|
640
|
+
activeTab: FilterTab;
|
|
641
|
+
onTabChange: (tab: FilterTab) => void;
|
|
642
|
+
skip: number;
|
|
643
|
+
onSkipChange: (skip: number) => void;
|
|
644
|
+
isLoading: boolean;
|
|
645
|
+
isRefreshing: boolean;
|
|
646
|
+
onRefresh: () => void;
|
|
647
|
+
onMarkAllRead: () => void;
|
|
648
|
+
onNotificationClick: (notification: Notification) => void;
|
|
649
|
+
onCTAClick: (notification: Notification, cta: NotificationCTA) => void;
|
|
650
|
+
}>;
|
|
651
|
+
|
|
652
|
+
|
|
653
|
+
export type NotificationRowProps = Readonly<{
|
|
654
|
+
notification: Notification;
|
|
655
|
+
onClick: () => void;
|
|
656
|
+
onCTAClick: (cta: NotificationCTA) => void;
|
|
657
|
+
}>;
|
|
658
|
+
|
|
659
|
+
export type NotificationIconProps = Readonly<{
|
|
660
|
+
notificationType: NotificationType;
|
|
661
|
+
size?: 'sm' | 'lg';
|
|
662
|
+
}>;
|
|
663
|
+
|
|
664
|
+
export type NotificationCTAButtonProps = Readonly<{
|
|
665
|
+
cta: NotificationCTA;
|
|
666
|
+
onClick: (e: React.MouseEvent) => void;
|
|
667
|
+
size?: 'sm' | 'lg';
|
|
668
|
+
}>;
|
|
669
|
+
|
|
670
|
+
export type FilterTab = 'all' | 'consent' | 'request' | 'system';
|
|
671
|
+
|
|
672
|
+
export type IconCategory = 'guardian' | 'consent' | 'access' | 'withdrawal' | 'grievance' | 'system';
|
|
673
|
+
|
|
674
|
+
export type NotificationDropdownItemProps = Readonly<{
|
|
675
|
+
notification: Notification;
|
|
676
|
+
onNotificationClick: (notification: Notification) => void;
|
|
677
|
+
onCTAClick: (notification: Notification, cta: NotificationCTA) => void;
|
|
678
|
+
}>
|
|
679
|
+
|
|
680
|
+
export type NotificationQueryParams = {
|
|
681
|
+
category?: NotificationCategory;
|
|
682
|
+
notification_type?: NotificationType;
|
|
683
|
+
is_read?: boolean;
|
|
684
|
+
skip?: number;
|
|
685
|
+
limit?: number;
|
|
686
|
+
include_summary?: boolean;
|
|
687
|
+
language?: string;
|
|
688
|
+
};
|
|
689
|
+
|
|
690
|
+
export type NotificationClient = NonNullable<NotificationActionBaseParams['consentClient']>;
|
|
691
|
+
|
|
692
|
+
export type GetNotificationsServerParams = NotificationActionBaseParams & NotificationQueryParams;
|
|
693
|
+
|
|
694
|
+
export type NotificationByUuidServerParams = NotificationActionBaseParams & { notificationUuid: string };
|
|
695
|
+
|
|
696
|
+
export type NotificationRefreshButtonProps = Readonly<{
|
|
697
|
+
isRefreshing: boolean;
|
|
698
|
+
onRefresh: () => void;
|
|
699
|
+
iconSize?: number;
|
|
700
|
+
}>;
|
|
@@ -276,5 +276,16 @@
|
|
|
276
276
|
"removeAttachment": "সংলগ্ন আঁতৰাওক",
|
|
277
277
|
"document": "নথি",
|
|
278
278
|
"downloadAttachment": "{{fileName}} ডাউনলোড কৰক",
|
|
279
|
-
"sortByColumn": "স্তম্ভ অনুসৰি সজাওক"
|
|
279
|
+
"sortByColumn": "স্তম্ভ অনুসৰি সজাওক",
|
|
280
|
+
"manage": "Manage",
|
|
281
|
+
"consents": "Consents",
|
|
282
|
+
"consentCount_one": "{{count}} consent",
|
|
283
|
+
"consentCount_other": "{{count}} consents",
|
|
284
|
+
"purposes": "Purposes",
|
|
285
|
+
"latestActivity": "Latest activity",
|
|
286
|
+
"activeWithCount": "{{count}} active",
|
|
287
|
+
"withdrawnWithCount": "{{count}} withdrawn",
|
|
288
|
+
"expiredWithCount": "{{count}} expired",
|
|
289
|
+
"declinedWithCount": "{{count}} declined",
|
|
290
|
+
"productsAndConsentsSummary": "{{products}} products, {{consents}} consents"
|
|
280
291
|
}
|
|
@@ -276,5 +276,16 @@
|
|
|
276
276
|
"removeAttachment": "संलग्नक हटाईं",
|
|
277
277
|
"document": "दस्तावेज",
|
|
278
278
|
"downloadAttachment": "{{fileName}} डाउनलोड करीं",
|
|
279
|
-
"sortByColumn": "कॉलम अनुसार क्रमबद्ध करीं"
|
|
279
|
+
"sortByColumn": "कॉलम अनुसार क्रमबद्ध करीं",
|
|
280
|
+
"manage": "Manage",
|
|
281
|
+
"consents": "Consents",
|
|
282
|
+
"consentCount_one": "{{count}} consent",
|
|
283
|
+
"consentCount_other": "{{count}} consents",
|
|
284
|
+
"purposes": "Purposes",
|
|
285
|
+
"latestActivity": "Latest activity",
|
|
286
|
+
"activeWithCount": "{{count}} active",
|
|
287
|
+
"withdrawnWithCount": "{{count}} withdrawn",
|
|
288
|
+
"expiredWithCount": "{{count}} expired",
|
|
289
|
+
"declinedWithCount": "{{count}} declined",
|
|
290
|
+
"productsAndConsentsSummary": "{{products}} products, {{consents}} consents"
|
|
280
291
|
}
|
|
@@ -276,5 +276,16 @@
|
|
|
276
276
|
"removeAttachment": "সংযুক্তি সরান",
|
|
277
277
|
"document": "নথি",
|
|
278
278
|
"downloadAttachment": "{{fileName}} ডাউনলোড করুন",
|
|
279
|
-
"sortByColumn": "কলাম অনুসারে সাজান"
|
|
279
|
+
"sortByColumn": "কলাম অনুসারে সাজান",
|
|
280
|
+
"manage": "Manage",
|
|
281
|
+
"consents": "Consents",
|
|
282
|
+
"consentCount_one": "{{count}} consent",
|
|
283
|
+
"consentCount_other": "{{count}} consents",
|
|
284
|
+
"purposes": "Purposes",
|
|
285
|
+
"latestActivity": "Latest activity",
|
|
286
|
+
"activeWithCount": "{{count}} active",
|
|
287
|
+
"withdrawnWithCount": "{{count}} withdrawn",
|
|
288
|
+
"expiredWithCount": "{{count}} expired",
|
|
289
|
+
"declinedWithCount": "{{count}} declined",
|
|
290
|
+
"productsAndConsentsSummary": "{{products}} products, {{consents}} consents"
|
|
280
291
|
}
|