@redacto.io/consent-sdk-react 7.0.0 → 7.2.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.
@@ -7402,7 +7402,8 @@ async function manageConsentServer(params) {
7402
7402
  params.authToken,
7403
7403
  void 0,
7404
7404
  params.nominatorContact,
7405
- params.dataElementUuids
7405
+ params.dataElementUuids,
7406
+ params.productUuid
7406
7407
  );
7407
7408
  return (_a = result == null ? void 0 : result.success) != null ? _a : null;
7408
7409
  } catch (error) {
@@ -7767,7 +7768,8 @@ var manageConsent = async ({
7767
7768
  authContext,
7768
7769
  consentClient,
7769
7770
  nominatorContact,
7770
- dataElementUuids
7771
+ dataElementUuids,
7772
+ productUuid
7771
7773
  }) => {
7772
7774
  try {
7773
7775
  const accessToken = await ensureValidToken(organizationId, workspaceId, void 0, authContext, consentClient);
@@ -7783,7 +7785,8 @@ var manageConsent = async ({
7783
7785
  authToken: accessToken,
7784
7786
  consentClient,
7785
7787
  nominatorContact,
7786
- dataElementUuids
7788
+ dataElementUuids,
7789
+ productUuid
7787
7790
  });
7788
7791
  return result;
7789
7792
  } catch (error) {
@@ -7802,7 +7805,8 @@ var manageConsent = async ({
7802
7805
  authToken: newAccessToken || void 0,
7803
7806
  consentClient,
7804
7807
  nominatorContact,
7805
- dataElementUuids
7808
+ dataElementUuids,
7809
+ productUuid
7806
7810
  });
7807
7811
  }
7808
7812
  console.error(`Error ${action} consent:`, error);
@@ -8678,7 +8682,7 @@ function createConsentClient(baseUrl) {
8678
8682
  /**
8679
8683
  * Manage consent (privacy center) - revoke, regrant, or renew
8680
8684
  */
8681
- async manageConsent(baseRequest, purposeId, contact, status, authToken, options, nominatorContact, dataElementUuids) {
8685
+ async manageConsent(baseRequest, purposeId, contact, status, authToken, options, nominatorContact, dataElementUuids, productUuid) {
8682
8686
  const url = privacyCenterUrl(baseRequest, `/manage-consent?status=${status}`);
8683
8687
  const body = { purpose_uuid: purposeId, contact };
8684
8688
  if (nominatorContact) {
@@ -8687,6 +8691,9 @@ function createConsentClient(baseUrl) {
8687
8691
  if (Array.isArray(dataElementUuids) && dataElementUuids.length > 0) {
8688
8692
  body.data_element_uuids = dataElementUuids;
8689
8693
  }
8694
+ if (productUuid) {
8695
+ body.product_uuid = productUuid;
8696
+ }
8690
8697
  return privacyCenterApiFetch(url, {
8691
8698
  ...options,
8692
8699
  method: "POST",
@@ -13459,7 +13466,7 @@ function AdvancedTable({
13459
13466
  /* @__PURE__ */ jsx39(PCTable.Body, { className: classNames == null ? void 0 : classNames.bodyClassName, children: table.getRowModel().rows.map((row) => {
13460
13467
  const meta = table.options.meta || {};
13461
13468
  const onRowClick = meta.onRowClick;
13462
- const handleRowClick = onRowClick ? (e) => {
13469
+ const handleRowClick = onRowClick ? () => {
13463
13470
  onRowClick(row.original, row);
13464
13471
  } : void 0;
13465
13472
  const rowExpandedComponent = expandedComponent || meta.expandedComponent;
@@ -14719,7 +14726,8 @@ var ModifyConsentModal = ({
14719
14726
  selectedRecord.purpose_uuid,
14720
14727
  actionConfig.action,
14721
14728
  nomContact,
14722
- isRegrantAction ? selectedDataElementUuids : void 0
14729
+ isRegrantAction ? selectedDataElementUuids : void 0,
14730
+ selectedRecord.product_uuid
14723
14731
  );
14724
14732
  }
14725
14733
  },
@@ -16117,9 +16125,6 @@ function ConsentManager({ variant }) {
16117
16125
  useEffect13(() => {
16118
16126
  fetchData();
16119
16127
  }, [fetchData]);
16120
- const hasActiveFilters = Boolean(
16121
- debouncedSearch.trim() || (statusFilter == null ? void 0 : statusFilter.value) || (productFilter == null ? void 0 : productFilter.value)
16122
- );
16123
16128
  const groupedPurposeCount = useMemo11(
16124
16129
  () => consentGroups.reduce((sum, group) => sum + group.purposes.length, 0),
16125
16130
  [consentGroups]
@@ -16319,7 +16324,7 @@ function ConsentManager({ variant }) {
16319
16324
  ]
16320
16325
  );
16321
16326
  const handleManageConsent = useCallback9(
16322
- async (purposeId, action, nominatorContact, dataElementUuids) => {
16327
+ async (purposeId, action, nominatorContact, dataElementUuids, productUuid) => {
16323
16328
  if (!organizationId || !workspaceId || !contact) {
16324
16329
  toast.error(t("missingInfoToManage"));
16325
16330
  return;
@@ -16345,7 +16350,8 @@ function ConsentManager({ variant }) {
16345
16350
  authContext,
16346
16351
  consentClient,
16347
16352
  nominatorContact,
16348
- dataElementUuids
16353
+ dataElementUuids,
16354
+ productUuid
16349
16355
  });
16350
16356
  if (response) {
16351
16357
  toast.success(successMessages[action]);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@redacto.io/consent-sdk-react",
3
- "version": "7.0.0",
3
+ "version": "7.2.0",
4
4
  "main": "dist/index.cjs",
5
5
  "module": "dist/index.mjs",
6
6
  "types": "dist/index.d.ts",
@@ -1511,6 +1511,15 @@ export const RedactoNoticeConsent = ({
1511
1511
  height: isMobile ? "auto" : undefined,
1512
1512
  width: isMobile ? "auto" : undefined,
1513
1513
  },
1514
+ topSection: {
1515
+ flexDirection: isMobile ? ("column" as const) : ("row" as const),
1516
+ alignItems: isMobile ? ("stretch" as const) : ("flex-start" as const),
1517
+ gap: isMobile ? "12px" : "10px",
1518
+ },
1519
+ logo: {
1520
+ maxWidth: isMobile ? "96px" : "140px",
1521
+ maxHeight: isMobile ? "28px" : "32px",
1522
+ },
1514
1523
  languageItem: {
1515
1524
  fontSize: isMobile ? "11px" : "12px",
1516
1525
  padding: isMobile ? "6px 10px" : "8px 12px",
@@ -3663,176 +3672,221 @@ export const RedactoNoticeConsent = ({
3663
3672
  </button>
3664
3673
  </div>
3665
3674
  )}
3666
- <div style={{ ...styles.topSection, ...sectionStyle }}>
3667
- <div style={styles.topLeft}>
3668
- <img
3669
- style={styles.logo}
3670
- src={content?.logo_url || logo}
3671
- alt="Redacto Logo"
3672
- />
3673
- <h2
3674
- key={`privacy-notice-title-${selectedLanguage}`}
3675
- id="privacy-notice-title"
3676
- style={{
3677
- ...styles.title,
3678
- ...responsiveStyles.title,
3679
- ...componentHeadingStyle,
3680
- }}
3681
- >
3682
- {getTranslatedText(
3683
- "notice_banner_heading",
3684
- content?.notice_banner_heading || "Privacy Notice"
3685
- )}
3686
- </h2>
3687
- </div>
3688
- <div style={styles.languageSelectorContainer}>
3689
- <div
3690
- style={{
3691
- display: "flex",
3692
- alignItems: "center",
3693
- gap: "8px",
3694
- }}
3695
- >
3696
- {/* Speaker icon button - only visible when TTS is available */}
3697
- {isTTSAvailable && (
3698
- <button
3699
- onClick={toggleAudio}
3675
+ <div
3676
+ style={{
3677
+ ...styles.topSection,
3678
+ ...responsiveStyles.topSection,
3679
+ ...sectionStyle,
3680
+ }}
3681
+ >
3682
+ {(() => {
3683
+ const logoNode = (
3684
+ <img
3685
+ style={{ ...styles.logo, ...responsiveStyles.logo }}
3686
+ src={content?.logo_url || logo}
3687
+ alt="Redacto Logo"
3688
+ />
3689
+ );
3690
+ const titleNode = (
3691
+ <h2
3692
+ key={`privacy-notice-title-${selectedLanguage}`}
3693
+ id="privacy-notice-title"
3694
+ style={{
3695
+ ...styles.title,
3696
+ ...responsiveStyles.title,
3697
+ ...componentHeadingStyle,
3698
+ }}
3699
+ >
3700
+ {getTranslatedText(
3701
+ "notice_banner_heading",
3702
+ content?.notice_banner_heading || "Privacy Notice"
3703
+ )}
3704
+ </h2>
3705
+ );
3706
+ const controlsBlock = (
3707
+ <div style={styles.languageSelectorContainer}>
3708
+ <div
3700
3709
  style={{
3701
- ...styles.topRight,
3702
- ...responsiveStyles.topRight,
3703
- ...languageSelectorStyle,
3704
- padding: "3px 9px",
3705
3710
  display: "flex",
3706
3711
  alignItems: "center",
3707
- justifyContent: "center",
3712
+ gap: "8px",
3708
3713
  }}
3709
- aria-label={
3710
- isPlaying && !isPaused
3711
- ? "Pause audio playback"
3712
- : isPaused
3713
- ? "Resume audio playback"
3714
- : "Start audio playback"
3715
- }
3716
- title={
3717
- isPlaying && !isPaused
3718
- ? "Pause Talkback"
3719
- : isPaused
3720
- ? "Resume Talkback"
3721
- : "Start Talkback"
3722
- }
3723
3714
  >
3724
- {isPlaying && !isPaused ? (
3725
- // Pause icon
3726
- <svg
3727
- xmlns="http://www.w3.org/2000/svg"
3728
- width="16"
3729
- height="16"
3730
- viewBox="0 0 24 24"
3731
- fill="none"
3732
- stroke={
3733
- settings?.button?.language?.textColor ||
3734
- "currentColor"
3715
+ {/* Speaker icon button - only visible when TTS is available */}
3716
+ {isTTSAvailable && (
3717
+ <button
3718
+ onClick={toggleAudio}
3719
+ style={{
3720
+ ...styles.topRight,
3721
+ ...responsiveStyles.topRight,
3722
+ ...languageSelectorStyle,
3723
+ padding: "3px 9px",
3724
+ display: "flex",
3725
+ alignItems: "center",
3726
+ justifyContent: "center",
3727
+ }}
3728
+ aria-label={
3729
+ isPlaying && !isPaused
3730
+ ? "Pause audio playback"
3731
+ : isPaused
3732
+ ? "Resume audio playback"
3733
+ : "Start audio playback"
3735
3734
  }
3736
- strokeWidth="2"
3737
- strokeLinecap="round"
3738
- strokeLinejoin="round"
3739
- aria-hidden="true"
3740
- >
3741
- <rect x="6" y="4" width="4" height="16" />
3742
- <rect x="14" y="4" width="4" height="16" />
3743
- </svg>
3744
- ) : (
3745
- // Play/Sound icon
3746
- <svg
3747
- xmlns="http://www.w3.org/2000/svg"
3748
- width="16"
3749
- height="16"
3750
- viewBox="0 0 24 24"
3751
- fill="none"
3752
- stroke={
3753
- settings?.button?.language?.textColor ||
3754
- "currentColor"
3735
+ title={
3736
+ isPlaying && !isPaused
3737
+ ? "Pause Talkback"
3738
+ : isPaused
3739
+ ? "Resume Talkback"
3740
+ : "Start Talkback"
3755
3741
  }
3756
- strokeWidth="2"
3757
- strokeLinecap="round"
3758
- strokeLinejoin="round"
3759
- aria-hidden="true"
3760
3742
  >
3761
- <polygon points="11 5 6 9 2 9 2 15 6 15 11 19 11 5" />
3762
- <path d="M19.07 4.93a10 10 0 0 1 0 14.14M15.54 8.46a5 5 0 0 1 0 7.07" />
3763
- </svg>
3743
+ {isPlaying && !isPaused ? (
3744
+ // Pause icon
3745
+ <svg
3746
+ xmlns="http://www.w3.org/2000/svg"
3747
+ width="16"
3748
+ height="16"
3749
+ viewBox="0 0 24 24"
3750
+ fill="none"
3751
+ stroke={
3752
+ settings?.button?.language?.textColor ||
3753
+ "currentColor"
3754
+ }
3755
+ strokeWidth="2"
3756
+ strokeLinecap="round"
3757
+ strokeLinejoin="round"
3758
+ aria-hidden="true"
3759
+ >
3760
+ <rect x="6" y="4" width="4" height="16" />
3761
+ <rect x="14" y="4" width="4" height="16" />
3762
+ </svg>
3763
+ ) : (
3764
+ // Play/Sound icon
3765
+ <svg
3766
+ xmlns="http://www.w3.org/2000/svg"
3767
+ width="16"
3768
+ height="16"
3769
+ viewBox="0 0 24 24"
3770
+ fill="none"
3771
+ stroke={
3772
+ settings?.button?.language?.textColor ||
3773
+ "currentColor"
3774
+ }
3775
+ strokeWidth="2"
3776
+ strokeLinecap="round"
3777
+ strokeLinejoin="round"
3778
+ aria-hidden="true"
3779
+ >
3780
+ <polygon points="11 5 6 9 2 9 2 15 6 15 11 19 11 5" />
3781
+ <path d="M19.07 4.93a10 10 0 0 1 0 14.14M15.54 8.46a5 5 0 0 1 0 7.07" />
3782
+ </svg>
3783
+ )}
3784
+ </button>
3764
3785
  )}
3765
- </button>
3766
- )}
3767
- <div>
3768
- <button
3769
- ref={firstFocusableRef}
3786
+ <div>
3787
+ <button
3788
+ ref={firstFocusableRef}
3789
+ style={{
3790
+ ...styles.topRight,
3791
+ ...responsiveStyles.topRight,
3792
+ ...languageSelectorStyle,
3793
+ }}
3794
+ onClick={toggleLanguageDropdown}
3795
+ aria-expanded={isLanguageDropdownOpen}
3796
+ aria-haspopup="listbox"
3797
+ aria-controls="language-listbox"
3798
+ aria-label={`Select language. Current language: ${toNativeLabel(selectedLanguage)}`}
3799
+ >
3800
+ {toNativeLabel(selectedLanguage)}
3801
+ <svg
3802
+ xmlns="http://www.w3.org/2000/svg"
3803
+ width="16"
3804
+ height="16"
3805
+ viewBox="0 0 16 16"
3806
+ fill="none"
3807
+ stroke={
3808
+ settings?.button?.language?.textColor ||
3809
+ "currentColor"
3810
+ }
3811
+ strokeWidth="2"
3812
+ strokeLinecap="round"
3813
+ strokeLinejoin="round"
3814
+ style={{ flexShrink: 0, marginLeft: "4px" }}
3815
+ aria-hidden="true"
3816
+ >
3817
+ <path d="M4 6l4 4 4-4" />
3818
+ </svg>
3819
+ </button>
3820
+ </div>
3821
+ </div>
3822
+ {isLanguageDropdownOpen && (
3823
+ <ul
3824
+ id="language-listbox"
3825
+ style={{
3826
+ ...styles.languageDropdown,
3827
+ ...languageSelectorStyle,
3828
+ }}
3829
+ role="listbox"
3830
+ aria-label="Select language"
3831
+ >
3832
+ {availableLanguages.map((lang: string) => (
3833
+ <li
3834
+ key={lang}
3835
+ style={{
3836
+ ...styles.languageItem,
3837
+ ...responsiveStyles.languageItem,
3838
+ ...(selectedLanguage === lang
3839
+ ? selectedLanguageItemStyle
3840
+ : languageSelectorStyle),
3841
+ listStyle: "none",
3842
+ }}
3843
+ onClick={() => handleLanguageSelect(lang)}
3844
+ role="option"
3845
+ aria-selected={selectedLanguage === lang}
3846
+ tabIndex={0}
3847
+ aria-label={`Select ${toNativeLabel(lang)} language`}
3848
+ >
3849
+ {toNativeLabel(lang)}
3850
+ </li>
3851
+ ))}
3852
+ </ul>
3853
+ )}
3854
+ </div>
3855
+ );
3856
+ return isMobile ? (
3857
+ <>
3858
+ <div
3770
3859
  style={{
3771
- ...styles.topRight,
3772
- ...responsiveStyles.topRight,
3773
- ...languageSelectorStyle,
3860
+ display: "flex",
3861
+ alignItems: "center",
3862
+ gap: "10px",
3863
+ width: "100%",
3774
3864
  }}
3775
- onClick={toggleLanguageDropdown}
3776
- aria-expanded={isLanguageDropdownOpen}
3777
- aria-haspopup="listbox"
3778
- aria-controls="language-listbox"
3779
- aria-label={`Select language. Current language: ${toNativeLabel(selectedLanguage)}`}
3780
3865
  >
3781
- {toNativeLabel(selectedLanguage)}
3782
- <svg
3783
- xmlns="http://www.w3.org/2000/svg"
3784
- width="16"
3785
- height="16"
3786
- viewBox="0 0 16 16"
3787
- fill="none"
3788
- stroke={
3789
- settings?.button?.language?.textColor ||
3790
- "currentColor"
3791
- }
3792
- strokeWidth="2"
3793
- strokeLinecap="round"
3794
- strokeLinejoin="round"
3795
- style={{ flexShrink: 0, marginLeft: "4px" }}
3796
- aria-hidden="true"
3797
- >
3798
- <path d="M4 6l4 4 4-4" />
3799
- </svg>
3800
- </button>
3801
- </div>
3802
- </div>
3803
- {isLanguageDropdownOpen && (
3804
- <ul
3805
- id="language-listbox"
3806
- style={{
3807
- ...styles.languageDropdown,
3808
- ...languageSelectorStyle,
3809
- }}
3810
- role="listbox"
3811
- aria-label="Select language"
3812
- >
3813
- {availableLanguages.map((lang: string) => (
3814
- <li
3815
- key={lang}
3866
+ {logoNode}
3867
+ <div
3816
3868
  style={{
3817
- ...styles.languageItem,
3818
- ...responsiveStyles.languageItem,
3819
- ...(selectedLanguage === lang
3820
- ? selectedLanguageItemStyle
3821
- : languageSelectorStyle),
3822
- listStyle: "none",
3869
+ marginLeft: "auto",
3870
+ display: "flex",
3871
+ alignItems: "center",
3872
+ flexShrink: 0,
3823
3873
  }}
3824
- onClick={() => handleLanguageSelect(lang)}
3825
- role="option"
3826
- aria-selected={selectedLanguage === lang}
3827
- tabIndex={0}
3828
- aria-label={`Select ${toNativeLabel(lang)} language`}
3829
3874
  >
3830
- {toNativeLabel(lang)}
3831
- </li>
3832
- ))}
3833
- </ul>
3834
- )}
3835
- </div>
3875
+ {controlsBlock}
3876
+ </div>
3877
+ </div>
3878
+ {titleNode}
3879
+ </>
3880
+ ) : (
3881
+ <>
3882
+ <div style={styles.topLeft}>
3883
+ {logoNode}
3884
+ {titleNode}
3885
+ </div>
3886
+ {controlsBlock}
3887
+ </>
3888
+ );
3889
+ })()}
3836
3890
  </div>
3837
3891
  <div
3838
3892
  id="privacy-notice-description"
@@ -52,7 +52,8 @@ export const styles = {
52
52
  topSection: {
53
53
  display: "flex",
54
54
  justifyContent: "space-between",
55
- alignItems: "center",
55
+ alignItems: "flex-start",
56
+ gap: "10px",
56
57
  paddingBottom: "15px",
57
58
  borderBottom: "none",
58
59
  backgroundColor: "#ffffff",
@@ -65,6 +66,8 @@ export const styles = {
65
66
  display: "flex",
66
67
  alignItems: "center",
67
68
  gap: "10px",
69
+ flex: "1 1 0",
70
+ minWidth: 0,
68
71
  margin: 0,
69
72
  padding: 0,
70
73
  boxSizing: "border-box",
@@ -73,7 +76,9 @@ export const styles = {
73
76
  logo: {
74
77
  height: "32px",
75
78
  width: "auto",
79
+ maxWidth: "140px",
76
80
  objectFit: "contain",
81
+ flexShrink: 0,
77
82
  margin: 0,
78
83
  padding: 0,
79
84
  display: "block",
@@ -86,6 +91,10 @@ export const styles = {
86
91
  letterSpacing: "0.2px",
87
92
  verticalAlign: "middle",
88
93
  color: "#101828",
94
+ flex: "1 1 auto",
95
+ minWidth: 0,
96
+ wordBreak: "normal",
97
+ overflowWrap: "anywhere",
89
98
  margin: 0,
90
99
  padding: 0,
91
100
  textAlign: "left",
@@ -355,6 +355,7 @@ export async function manageConsentServer(params: {
355
355
  consentClient?: ReturnType<typeof import('./client').createConsentClient>;
356
356
  nominatorContact?: string;
357
357
  dataElementUuids?: string[];
358
+ productUuid?: string;
358
359
  }): Promise<boolean | null> {
359
360
  try {
360
361
  if (!params.consentClient) {
@@ -371,7 +372,8 @@ export async function manageConsentServer(params: {
371
372
  params.authToken,
372
373
  undefined,
373
374
  params.nominatorContact,
374
- params.dataElementUuids
375
+ params.dataElementUuids,
376
+ params.productUuid
375
377
  );
376
378
  return (result as { success: boolean })?.success ?? null;
377
379
  } catch (error: any) {
@@ -419,7 +419,8 @@ export function createConsentClient(baseUrl: string) {
419
419
  authToken?: string,
420
420
  options?: Omit<ApiFetchOptions, "getAuthToken">,
421
421
  nominatorContact?: string,
422
- dataElementUuids?: string[]
422
+ dataElementUuids?: string[],
423
+ productUuid?: string
423
424
  ): Promise<unknown> {
424
425
  const url = privacyCenterUrl(baseRequest, `/manage-consent?status=${status}`);
425
426
  const body: Record<string, unknown> = { purpose_uuid: purposeId, contact };
@@ -429,6 +430,9 @@ export function createConsentClient(baseUrl: string) {
429
430
  if (Array.isArray(dataElementUuids) && dataElementUuids.length > 0) {
430
431
  body.data_element_uuids = dataElementUuids;
431
432
  }
433
+ if (productUuid) {
434
+ body.product_uuid = productUuid;
435
+ }
432
436
  return privacyCenterApiFetch(url, {
433
437
  ...options,
434
438
  method: "POST",
@@ -495,10 +495,6 @@ export default function ConsentManager({ variant }: ConsentManagerProps) {
495
495
  fetchData();
496
496
  }, [fetchData]);
497
497
 
498
- const hasActiveFilters = Boolean(
499
- debouncedSearch.trim() || statusFilter?.value || productFilter?.value
500
- );
501
-
502
498
  const groupedPurposeCount = useMemo(
503
499
  () => consentGroups.reduce((sum, group) => sum + group.purposes.length, 0),
504
500
  [consentGroups]
@@ -729,7 +725,8 @@ export default function ConsentManager({ variant }: ConsentManagerProps) {
729
725
  purposeId: string,
730
726
  action: ConsentAction,
731
727
  nominatorContact?: string,
732
- dataElementUuids?: string[]
728
+ dataElementUuids?: string[],
729
+ productUuid?: string
733
730
  ) => {
734
731
  if (!organizationId || !workspaceId || !contact) {
735
732
  toast.error(t('missingInfoToManage'));
@@ -761,6 +758,7 @@ export default function ConsentManager({ variant }: ConsentManagerProps) {
761
758
  consentClient,
762
759
  nominatorContact,
763
760
  dataElementUuids,
761
+ productUuid,
764
762
  });
765
763
 
766
764
  if (response) {
@@ -317,7 +317,8 @@ export const ModifyConsentModal = ({
317
317
  selectedRecord.purpose_uuid,
318
318
  actionConfig.action,
319
319
  nomContact,
320
- isRegrantAction ? selectedDataElementUuids : undefined
320
+ isRegrantAction ? selectedDataElementUuids : undefined,
321
+ selectedRecord.product_uuid
321
322
  );
322
323
  }
323
324
  }}
@@ -67,7 +67,8 @@ export type ModifyConsentModalProps = {
67
67
  purposeId: string,
68
68
  action: import('../lib/types').ConsentAction,
69
69
  nominatorContact?: string,
70
- dataElementUuids?: string[]
70
+ dataElementUuids?: string[],
71
+ productUuid?: string
71
72
  ) => void;
72
73
  };
73
74