@redacto.io/consent-sdk-react 10.2.1-beta.0 → 10.2.1-beta.2

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/dist/index.js CHANGED
@@ -745,7 +745,9 @@ var DPO_AUDIO_ELEMENT_MAP = [
745
745
  { audioKey: "dpo_anchor_text_audio_url", elementId: "dpo-dpo-link" }
746
746
  ];
747
747
  var PRODUCT_SECTION_COPY = {
748
- toggleSelection: (productName, purposeCount) => `Toggle all ${purposeCount} purposes for ${productName}`
748
+ toggleSelection: (productName, purposeCount) => `Toggle all ${purposeCount} purposes for ${productName}`,
749
+ toggleRequired: (productName, purposeCount) => `Toggle the ${purposeCount} required purposes for ${productName}`,
750
+ settled: (productName) => `Already consented to ${productName}`
749
751
  };
750
752
 
751
753
  // src/RedactoNoticeConsent/styles.ts
@@ -2128,6 +2130,7 @@ var ProductSectionHeader = ({
2128
2130
  product,
2129
2131
  isRequired,
2130
2132
  purposeCount,
2133
+ requiredOnly,
2131
2134
  allSelected,
2132
2135
  someSelected,
2133
2136
  collapsed,
@@ -2183,7 +2186,39 @@ var ProductSectionHeader = ({
2183
2186
  }
2184
2187
  ) })
2185
2188
  ] }),
2186
- !locked && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
2189
+ locked ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
2190
+ "div",
2191
+ {
2192
+ role: "img",
2193
+ style: {
2194
+ ...reviewIndicatorStyle(20),
2195
+ backgroundColor: "#10B981",
2196
+ marginLeft: "12px"
2197
+ },
2198
+ "aria-label": PRODUCT_SECTION_COPY.settled(name),
2199
+ children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
2200
+ "svg",
2201
+ {
2202
+ width: "12",
2203
+ height: "12",
2204
+ viewBox: "0 0 12 12",
2205
+ fill: "none",
2206
+ xmlns: "http://www.w3.org/2000/svg",
2207
+ "aria-hidden": "true",
2208
+ children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
2209
+ "path",
2210
+ {
2211
+ d: "M4 6L5.5 7.5L8.5 4.5",
2212
+ stroke: "white",
2213
+ strokeWidth: "2",
2214
+ strokeLinecap: "round",
2215
+ strokeLinejoin: "round"
2216
+ }
2217
+ )
2218
+ }
2219
+ )
2220
+ }
2221
+ ) : /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
2187
2222
  "input",
2188
2223
  {
2189
2224
  ref: checkboxRef,
@@ -2191,7 +2226,7 @@ var ProductSectionHeader = ({
2191
2226
  type: "checkbox",
2192
2227
  checked: allSelected,
2193
2228
  onChange: handleToggleSelect,
2194
- "aria-label": PRODUCT_SECTION_COPY.toggleSelection(name, purposeCount)
2229
+ "aria-label": requiredOnly ? PRODUCT_SECTION_COPY.toggleRequired(name, purposeCount) : PRODUCT_SECTION_COPY.toggleSelection(name, purposeCount)
2195
2230
  }
2196
2231
  )
2197
2232
  ] });
@@ -2312,6 +2347,7 @@ var PurposeItem = ({
2312
2347
  isAlreadyConsented && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
2313
2348
  "div",
2314
2349
  {
2350
+ role: "img",
2315
2351
  style: {
2316
2352
  ...reviewIndicatorStyle(20),
2317
2353
  backgroundColor: "#10B981",
@@ -2401,6 +2437,7 @@ var PurposeItem = ({
2401
2437
  return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
2402
2438
  "div",
2403
2439
  {
2440
+ role: "img",
2404
2441
  style: {
2405
2442
  ...reviewIndicatorStyle(16),
2406
2443
  backgroundColor: "#10B981"
@@ -2437,6 +2474,7 @@ var PurposeItem = ({
2437
2474
  return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
2438
2475
  "div",
2439
2476
  {
2477
+ role: "img",
2440
2478
  style: {
2441
2479
  ...reviewIndicatorStyle(16),
2442
2480
  border: "2px solid #d0d5dd",
@@ -3985,14 +4023,39 @@ var RedactoNoticeConsent = ({
3985
4023
  if (purposeSelections || productPurposeSelections) {
3986
4024
  const settled = {};
3987
4025
  const settledRows = {};
4026
+ const rowNeedsAttention = ({
4027
+ purpose,
4028
+ productUuid
4029
+ }) => {
4030
+ var _a3;
4031
+ return ((_a3 = recordedFor(purpose.uuid, productUuid)) == null ? void 0 : _a3.needs_reconsent) === true;
4032
+ };
4033
+ const gated = gatedProductUuids(activeConfig.products);
4034
+ const marksMandatory = serverMarksMandatoryProducts(
4035
+ activeConfig.products
4036
+ );
4037
+ const rowIsMandatory = (row) => {
4038
+ const resolved = rowProductUuid(row, activeConfig.products);
4039
+ return (!marksMandatory || !!resolved && gated.has(resolved)) && hasRequiredDataElement(row.purpose);
4040
+ };
4041
+ const rowsByProduct = /* @__PURE__ */ new Map();
3988
4042
  seedRows.forEach((row) => {
3989
4043
  var _a3;
3990
- const recorded = rowIsRecorded(row);
3991
- if (!row.productUuid) {
4044
+ const resolved = rowProductUuid(row, activeConfig.products);
4045
+ if (!resolved) {
3992
4046
  return;
3993
4047
  }
3994
- settledRows[productPurposeKey(row.productUuid, row.purpose.uuid)] = recorded;
3995
- settled[row.productUuid] = ((_a3 = settled[row.productUuid]) != null ? _a3 : true) && recorded;
4048
+ settledRows[productPurposeKey(row.productUuid, row.purpose.uuid)] = rowIsRecorded(row) && !rowNeedsAttention(row);
4049
+ const rows = (_a3 = rowsByProduct.get(resolved)) != null ? _a3 : [];
4050
+ rows.push(row);
4051
+ rowsByProduct.set(resolved, rows);
4052
+ });
4053
+ rowsByProduct.forEach((rows, productUuid) => {
4054
+ const mandatory = rows.filter(rowIsMandatory);
4055
+ const deciding = mandatory.length > 0 ? mandatory : rows;
4056
+ settled[productUuid] = deciding.every(
4057
+ (row) => rowIsRecorded(row) && !rowNeedsAttention(row)
4058
+ );
3996
4059
  });
3997
4060
  setConsentedProducts(settled);
3998
4061
  setConsentedPurposes(settledRows);
@@ -4122,6 +4185,16 @@ var RedactoNoticeConsent = ({
4122
4185
  });
4123
4186
  setSelectedDataElements((prev) => ({ ...prev, ...elementOverrides }));
4124
4187
  };
4188
+ const productBoxPurposes = (0, import_react3.useCallback)(
4189
+ (product, purposes) => {
4190
+ if (productIsRequiredFor(product) === false) {
4191
+ return purposes;
4192
+ }
4193
+ const required = purposes.filter(hasRequiredDataElement);
4194
+ return required.length > 0 ? required : purposes;
4195
+ },
4196
+ [productIsRequiredFor]
4197
+ );
4125
4198
  const handleProductCheckboxChange = (productUuid) => {
4126
4199
  if (!content) {
4127
4200
  return;
@@ -4132,7 +4205,7 @@ var RedactoNoticeConsent = ({
4132
4205
  if (!group) {
4133
4206
  return;
4134
4207
  }
4135
- const editable = group.purposes.filter(
4208
+ const editable = productBoxPurposes(productUuid, group.purposes).filter(
4136
4209
  (purpose) => !consentedPurposes[productPurposeKey(productUuid, purpose.uuid)]
4137
4210
  );
4138
4211
  if (editable.length === 0) {
@@ -4148,7 +4221,8 @@ var RedactoNoticeConsent = ({
4148
4221
  }
4149
4222
  const product = products[0];
4150
4223
  const purposes = (_a2 = content == null ? void 0 : content.purposes) != null ? _a2 : [];
4151
- const selectedCount = purposes.filter(
4224
+ const boxPurposes = productBoxPurposes(product.uuid, purposes);
4225
+ const selectedCount = boxPurposes.filter(
4152
4226
  (purpose) => selectedPurposes[productPurposeKey(void 0, purpose.uuid)]
4153
4227
  ).length;
4154
4228
  return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { children: [
@@ -4157,8 +4231,9 @@ var RedactoNoticeConsent = ({
4157
4231
  {
4158
4232
  product,
4159
4233
  isRequired: productIsRequiredFor(product.uuid),
4160
- purposeCount: purposes.length,
4161
- allSelected: purposes.length > 0 && selectedCount === purposes.length,
4234
+ purposeCount: boxPurposes.length,
4235
+ requiredOnly: boxPurposes.length < purposes.length,
4236
+ allSelected: boxPurposes.length > 0 && selectedCount === boxPurposes.length,
4162
4237
  someSelected: selectedCount > 0,
4163
4238
  collapsed: collapsedProducts[product.uuid] || false,
4164
4239
  locked: (_b2 = consentedProducts[product.uuid]) != null ? _b2 : isFullyConsentedReviewMode,
@@ -4166,7 +4241,7 @@ var RedactoNoticeConsent = ({
4166
4241
  styles,
4167
4242
  responsiveStyles,
4168
4243
  onToggleCollapse: () => toggleProductCollapse(product.uuid),
4169
- onToggleSelect: () => toggleSection(purposes, void 0),
4244
+ onToggleSelect: () => toggleSection(boxPurposes, void 0),
4170
4245
  getTranslatedText
4171
4246
  }
4172
4247
  ),
@@ -5811,7 +5886,11 @@ var RedactoNoticeConsent = ({
5811
5886
  /* Regular consent UI */
5812
5887
  /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { style: styles.optionsContainer, children: isMultiProduct(content == null ? void 0 : content.products) ? productGroups.map((group) => {
5813
5888
  var _a2;
5814
- const selectedInGroup = group.purposes.filter(
5889
+ const boxPurposes = productBoxPurposes(
5890
+ group.product.uuid,
5891
+ group.purposes
5892
+ );
5893
+ const selectedInGroup = boxPurposes.filter(
5815
5894
  (purpose) => selectedPurposes[productPurposeKey(
5816
5895
  group.product.uuid,
5817
5896
  purpose.uuid
@@ -5825,8 +5904,9 @@ var RedactoNoticeConsent = ({
5825
5904
  isRequired: productIsRequiredFor(
5826
5905
  group.product.uuid
5827
5906
  ),
5828
- purposeCount: group.purposes.length,
5829
- allSelected: selectedInGroup === group.purposes.length,
5907
+ purposeCount: boxPurposes.length,
5908
+ requiredOnly: boxPurposes.length < group.purposes.length,
5909
+ allSelected: selectedInGroup === boxPurposes.length,
5830
5910
  someSelected: selectedInGroup > 0,
5831
5911
  collapsed: collapsedProducts[group.product.uuid] || false,
5832
5912
  locked: (_a2 = consentedProducts[group.product.uuid]) != null ? _a2 : false,
package/dist/index.mjs CHANGED
@@ -621,7 +621,9 @@ var DPO_AUDIO_ELEMENT_MAP = [
621
621
  { audioKey: "dpo_anchor_text_audio_url", elementId: "dpo-dpo-link" }
622
622
  ];
623
623
  var PRODUCT_SECTION_COPY = {
624
- toggleSelection: (productName, purposeCount) => `Toggle all ${purposeCount} purposes for ${productName}`
624
+ toggleSelection: (productName, purposeCount) => `Toggle all ${purposeCount} purposes for ${productName}`,
625
+ toggleRequired: (productName, purposeCount) => `Toggle the ${purposeCount} required purposes for ${productName}`,
626
+ settled: (productName) => `Already consented to ${productName}`
625
627
  };
626
628
 
627
629
  // src/RedactoNoticeConsent/styles.ts
@@ -1803,6 +1805,7 @@ var ProductSectionHeader = ({
1803
1805
  product,
1804
1806
  isRequired,
1805
1807
  purposeCount,
1808
+ requiredOnly,
1806
1809
  allSelected,
1807
1810
  someSelected,
1808
1811
  collapsed,
@@ -1858,7 +1861,39 @@ var ProductSectionHeader = ({
1858
1861
  }
1859
1862
  ) })
1860
1863
  ] }),
1861
- !locked && /* @__PURE__ */ jsx3(
1864
+ locked ? /* @__PURE__ */ jsx3(
1865
+ "div",
1866
+ {
1867
+ role: "img",
1868
+ style: {
1869
+ ...reviewIndicatorStyle(20),
1870
+ backgroundColor: "#10B981",
1871
+ marginLeft: "12px"
1872
+ },
1873
+ "aria-label": PRODUCT_SECTION_COPY.settled(name),
1874
+ children: /* @__PURE__ */ jsx3(
1875
+ "svg",
1876
+ {
1877
+ width: "12",
1878
+ height: "12",
1879
+ viewBox: "0 0 12 12",
1880
+ fill: "none",
1881
+ xmlns: "http://www.w3.org/2000/svg",
1882
+ "aria-hidden": "true",
1883
+ children: /* @__PURE__ */ jsx3(
1884
+ "path",
1885
+ {
1886
+ d: "M4 6L5.5 7.5L8.5 4.5",
1887
+ stroke: "white",
1888
+ strokeWidth: "2",
1889
+ strokeLinecap: "round",
1890
+ strokeLinejoin: "round"
1891
+ }
1892
+ )
1893
+ }
1894
+ )
1895
+ }
1896
+ ) : /* @__PURE__ */ jsx3(
1862
1897
  "input",
1863
1898
  {
1864
1899
  ref: checkboxRef,
@@ -1866,7 +1901,7 @@ var ProductSectionHeader = ({
1866
1901
  type: "checkbox",
1867
1902
  checked: allSelected,
1868
1903
  onChange: handleToggleSelect,
1869
- "aria-label": PRODUCT_SECTION_COPY.toggleSelection(name, purposeCount)
1904
+ "aria-label": requiredOnly ? PRODUCT_SECTION_COPY.toggleRequired(name, purposeCount) : PRODUCT_SECTION_COPY.toggleSelection(name, purposeCount)
1870
1905
  }
1871
1906
  )
1872
1907
  ] });
@@ -1987,6 +2022,7 @@ var PurposeItem = ({
1987
2022
  isAlreadyConsented && /* @__PURE__ */ jsx3(
1988
2023
  "div",
1989
2024
  {
2025
+ role: "img",
1990
2026
  style: {
1991
2027
  ...reviewIndicatorStyle(20),
1992
2028
  backgroundColor: "#10B981",
@@ -2076,6 +2112,7 @@ var PurposeItem = ({
2076
2112
  return /* @__PURE__ */ jsx3(
2077
2113
  "div",
2078
2114
  {
2115
+ role: "img",
2079
2116
  style: {
2080
2117
  ...reviewIndicatorStyle(16),
2081
2118
  backgroundColor: "#10B981"
@@ -2112,6 +2149,7 @@ var PurposeItem = ({
2112
2149
  return /* @__PURE__ */ jsx3(
2113
2150
  "div",
2114
2151
  {
2152
+ role: "img",
2115
2153
  style: {
2116
2154
  ...reviewIndicatorStyle(16),
2117
2155
  border: "2px solid #d0d5dd",
@@ -3660,14 +3698,39 @@ var RedactoNoticeConsent = ({
3660
3698
  if (purposeSelections || productPurposeSelections) {
3661
3699
  const settled = {};
3662
3700
  const settledRows = {};
3701
+ const rowNeedsAttention = ({
3702
+ purpose,
3703
+ productUuid
3704
+ }) => {
3705
+ var _a3;
3706
+ return ((_a3 = recordedFor(purpose.uuid, productUuid)) == null ? void 0 : _a3.needs_reconsent) === true;
3707
+ };
3708
+ const gated = gatedProductUuids(activeConfig.products);
3709
+ const marksMandatory = serverMarksMandatoryProducts(
3710
+ activeConfig.products
3711
+ );
3712
+ const rowIsMandatory = (row) => {
3713
+ const resolved = rowProductUuid(row, activeConfig.products);
3714
+ return (!marksMandatory || !!resolved && gated.has(resolved)) && hasRequiredDataElement(row.purpose);
3715
+ };
3716
+ const rowsByProduct = /* @__PURE__ */ new Map();
3663
3717
  seedRows.forEach((row) => {
3664
3718
  var _a3;
3665
- const recorded = rowIsRecorded(row);
3666
- if (!row.productUuid) {
3719
+ const resolved = rowProductUuid(row, activeConfig.products);
3720
+ if (!resolved) {
3667
3721
  return;
3668
3722
  }
3669
- settledRows[productPurposeKey(row.productUuid, row.purpose.uuid)] = recorded;
3670
- settled[row.productUuid] = ((_a3 = settled[row.productUuid]) != null ? _a3 : true) && recorded;
3723
+ settledRows[productPurposeKey(row.productUuid, row.purpose.uuid)] = rowIsRecorded(row) && !rowNeedsAttention(row);
3724
+ const rows = (_a3 = rowsByProduct.get(resolved)) != null ? _a3 : [];
3725
+ rows.push(row);
3726
+ rowsByProduct.set(resolved, rows);
3727
+ });
3728
+ rowsByProduct.forEach((rows, productUuid) => {
3729
+ const mandatory = rows.filter(rowIsMandatory);
3730
+ const deciding = mandatory.length > 0 ? mandatory : rows;
3731
+ settled[productUuid] = deciding.every(
3732
+ (row) => rowIsRecorded(row) && !rowNeedsAttention(row)
3733
+ );
3671
3734
  });
3672
3735
  setConsentedProducts(settled);
3673
3736
  setConsentedPurposes(settledRows);
@@ -3797,6 +3860,16 @@ var RedactoNoticeConsent = ({
3797
3860
  });
3798
3861
  setSelectedDataElements((prev) => ({ ...prev, ...elementOverrides }));
3799
3862
  };
3863
+ const productBoxPurposes = useCallback(
3864
+ (product, purposes) => {
3865
+ if (productIsRequiredFor(product) === false) {
3866
+ return purposes;
3867
+ }
3868
+ const required = purposes.filter(hasRequiredDataElement);
3869
+ return required.length > 0 ? required : purposes;
3870
+ },
3871
+ [productIsRequiredFor]
3872
+ );
3800
3873
  const handleProductCheckboxChange = (productUuid) => {
3801
3874
  if (!content) {
3802
3875
  return;
@@ -3807,7 +3880,7 @@ var RedactoNoticeConsent = ({
3807
3880
  if (!group) {
3808
3881
  return;
3809
3882
  }
3810
- const editable = group.purposes.filter(
3883
+ const editable = productBoxPurposes(productUuid, group.purposes).filter(
3811
3884
  (purpose) => !consentedPurposes[productPurposeKey(productUuid, purpose.uuid)]
3812
3885
  );
3813
3886
  if (editable.length === 0) {
@@ -3823,7 +3896,8 @@ var RedactoNoticeConsent = ({
3823
3896
  }
3824
3897
  const product = products[0];
3825
3898
  const purposes = (_a2 = content == null ? void 0 : content.purposes) != null ? _a2 : [];
3826
- const selectedCount = purposes.filter(
3899
+ const boxPurposes = productBoxPurposes(product.uuid, purposes);
3900
+ const selectedCount = boxPurposes.filter(
3827
3901
  (purpose) => selectedPurposes[productPurposeKey(void 0, purpose.uuid)]
3828
3902
  ).length;
3829
3903
  return /* @__PURE__ */ jsxs2("div", { children: [
@@ -3832,8 +3906,9 @@ var RedactoNoticeConsent = ({
3832
3906
  {
3833
3907
  product,
3834
3908
  isRequired: productIsRequiredFor(product.uuid),
3835
- purposeCount: purposes.length,
3836
- allSelected: purposes.length > 0 && selectedCount === purposes.length,
3909
+ purposeCount: boxPurposes.length,
3910
+ requiredOnly: boxPurposes.length < purposes.length,
3911
+ allSelected: boxPurposes.length > 0 && selectedCount === boxPurposes.length,
3837
3912
  someSelected: selectedCount > 0,
3838
3913
  collapsed: collapsedProducts[product.uuid] || false,
3839
3914
  locked: (_b2 = consentedProducts[product.uuid]) != null ? _b2 : isFullyConsentedReviewMode,
@@ -3841,7 +3916,7 @@ var RedactoNoticeConsent = ({
3841
3916
  styles,
3842
3917
  responsiveStyles,
3843
3918
  onToggleCollapse: () => toggleProductCollapse(product.uuid),
3844
- onToggleSelect: () => toggleSection(purposes, void 0),
3919
+ onToggleSelect: () => toggleSection(boxPurposes, void 0),
3845
3920
  getTranslatedText
3846
3921
  }
3847
3922
  ),
@@ -5486,7 +5561,11 @@ var RedactoNoticeConsent = ({
5486
5561
  /* Regular consent UI */
5487
5562
  /* @__PURE__ */ jsx3("div", { style: styles.optionsContainer, children: isMultiProduct(content == null ? void 0 : content.products) ? productGroups.map((group) => {
5488
5563
  var _a2;
5489
- const selectedInGroup = group.purposes.filter(
5564
+ const boxPurposes = productBoxPurposes(
5565
+ group.product.uuid,
5566
+ group.purposes
5567
+ );
5568
+ const selectedInGroup = boxPurposes.filter(
5490
5569
  (purpose) => selectedPurposes[productPurposeKey(
5491
5570
  group.product.uuid,
5492
5571
  purpose.uuid
@@ -5500,8 +5579,9 @@ var RedactoNoticeConsent = ({
5500
5579
  isRequired: productIsRequiredFor(
5501
5580
  group.product.uuid
5502
5581
  ),
5503
- purposeCount: group.purposes.length,
5504
- allSelected: selectedInGroup === group.purposes.length,
5582
+ purposeCount: boxPurposes.length,
5583
+ requiredOnly: boxPurposes.length < group.purposes.length,
5584
+ allSelected: selectedInGroup === boxPurposes.length,
5505
5585
  someSelected: selectedInGroup > 0,
5506
5586
  collapsed: collapsedProducts[group.product.uuid] || false,
5507
5587
  locked: (_a2 = consentedProducts[group.product.uuid]) != null ? _a2 : false,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@redacto.io/consent-sdk-react",
3
- "version": "10.2.1-beta.0",
3
+ "version": "10.2.1-beta.2",
4
4
  "main": "dist/index.cjs",
5
5
  "module": "dist/index.mjs",
6
6
  "types": "dist/index.d.ts",