@washingtonpost/subs-de-inputs 0.5.7 → 1.0.0-react18.1

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.
@@ -2,11 +2,8 @@
2
2
 
3
3
  Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
- function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; }
6
-
7
5
  var subsSdk = require('@washingtonpost/subs-sdk');
8
6
  var React = require('react');
9
- var React__default = _interopDefault(React);
10
7
  var wpdsUiKit = require('@washingtonpost/wpds-ui-kit');
11
8
  var subsHooks = require('@washingtonpost/subs-hooks');
12
9
  var wpdsAssets = require('@washingtonpost/wpds-assets');
@@ -18,12 +15,6 @@ const CollectionBehaviors = {
18
15
  const AttributesState = {
19
16
  SUCCESS: '100'
20
17
  };
21
- const DeleteAttributeState = {
22
- SUCCESS: '150',
23
- SYSTEM_ERROR: '151',
24
- INVALID_ATTRIBUTE_NAME: '152',
25
- INVALID_ATTRIBUTE_NOT_EXISTS: '153'
26
- };
27
18
  const IngestType = {
28
19
  EXPLICIT: 'explicit',
29
20
  IMPLICIT: 'implicit'
@@ -54,10 +45,9 @@ const hasRequiredPrivacyCookies = () => {
54
45
 
55
46
  const base = `${subsSdk.ENDPOINTS.base}/de/v1`;
56
47
  const attributesCache = {};
57
- const getAttributes = async _ref => {
58
- let {
59
- fieldName
60
- } = _ref;
48
+ const getAttributes = async ({
49
+ fieldName
50
+ }) => {
61
51
  if (attributesCache[fieldName]) {
62
52
  return attributesCache[fieldName];
63
53
  }
@@ -82,58 +72,36 @@ const getAttributes = async _ref => {
82
72
  return [];
83
73
  }
84
74
  };
85
-
86
- const sendGAEvent = props => {
87
- if (typeof window === 'undefined') {
88
- if (process.env.NODE_ENV !== "production") console.warn('NO WINDOW');
89
- return;
90
- }
91
- // Initialize dataLayer if needed
92
- window.dataLayer = window.dataLayer || [];
93
- const eventData = {
94
- ...props
95
- };
96
- window.dataLayer.push(eventData);
97
- };
98
- const sendToGA = async _ref => {
99
- let {
100
- submitData: {
101
- fieldName,
102
- value
103
- },
104
- source
105
- } = _ref;
106
- sendGAEvent({
107
- event: 'site-onpage-click',
108
- action: 'site-onpage-click',
109
- category: 'profile',
110
- label: fieldName,
111
- 'de-label': fieldName,
112
- [fieldName]: value,
113
- section: 'profile',
114
- subsection: source
115
- });
116
- return true;
117
- };
118
-
119
- const base$1 = `${subsSdk.ENDPOINTS.base}/de/v1`;
120
- const ingest = async _ref => {
121
- let {
122
- submitData: {
123
- fieldName,
124
- value
125
- },
126
- source
127
- } = _ref;
128
- const url = `${base$1}/ingest`;
75
+ const ingest = async ({
76
+ submitData: {
77
+ fieldName,
78
+ value
79
+ },
80
+ type = IngestType.IMPLICIT,
81
+ source
82
+ }) => {
83
+ const url = `${base}/ingest`;
129
84
  const wapo_login_id = subsSdk.getCookie('wapo_login_id');
85
+ if (!hasRequiredPrivacyCookies()) {
86
+ throw new Error('does not satisfy cookie check');
87
+ }
88
+ let attributeInfo = attributesCache[fieldName];
89
+ if (!attributeInfo) {
90
+ attributeInfo = await getAttributes({
91
+ fieldName
92
+ });
93
+ }
94
+ if (attributeInfo[0] && attributeInfo[0].name === fieldName && attributeInfo[0].collection_behavior === CollectionBehaviors.DO_NOT_COLLECT) {
95
+ throw new Error('do not collect');
96
+ }
130
97
  const jucid = localStorage.getItem('uuid');
131
98
  const ga = subsSdk.getCookie('_ga');
132
99
  const payload = {
133
100
  jucid,
134
101
  ga,
135
- type: IngestType.EXPLICIT,
102
+ type,
136
103
  wapo_login_id,
104
+ // TODO: move this to BE to read from cookie headers
137
105
  data: {
138
106
  [fieldName]: [value]
139
107
  },
@@ -156,51 +124,6 @@ const ingest = async _ref => {
156
124
  }
157
125
  };
158
126
 
159
- const isAnonymousWebview = () => {
160
- if (typeof window === 'undefined') {
161
- return false;
162
- }
163
- const wp_wv = subsSdk.getCookie('wp_wv');
164
- return !!(wp_wv && !subsSdk.isLoggedIn());
165
- };
166
-
167
- const push = async _ref => {
168
- let {
169
- submitData,
170
- source
171
- } = _ref;
172
- if (!hasRequiredPrivacyCookies()) {
173
- throw new Error('does not satisfy cookie check');
174
- }
175
- if (isAnonymousWebview()) {
176
- throw new Error('does not satisfy cookie check');
177
- }
178
- const {
179
- fieldName
180
- } = submitData;
181
- const attributeInfo = await getAttributes({
182
- fieldName
183
- });
184
- if (attributeInfo[0] && attributeInfo[0].name === fieldName && attributeInfo[0].collection_behavior === CollectionBehaviors.DO_NOT_COLLECT) {
185
- throw new Error('do not collect');
186
- }
187
- const type = attributeInfo[0] && attributeInfo[0].explicit === true ? IngestType.EXPLICIT : IngestType.IMPLICIT;
188
- if (!attributeInfo[0] && process.env.NODE_ENV !== "production") {
189
- console.warn(`no attribute info found for ${fieldName}, assuming implicit`);
190
- }
191
- if (type === IngestType.EXPLICIT) {
192
- return ingest({
193
- submitData,
194
- source
195
- });
196
- } else {
197
- return sendToGA({
198
- submitData,
199
- source
200
- });
201
- }
202
- };
203
-
204
127
  const StyledMobileSelect = /*#__PURE__*/wpdsUiKit.styled('select', {
205
128
  padding: '12px 16px 12px 6px',
206
129
  display: 'flex',
@@ -242,21 +165,20 @@ const StyledMobileOption = /*#__PURE__*/wpdsUiKit.styled('option', {
242
165
  fontSize: 'inherit',
243
166
  color: 'inherit'
244
167
  });
245
- /**
246
- * Dropdown component. Uses wpds-ui-kit on desktop and native select on mobile.
247
- * @param {IDropdownProps} props The props.
248
- * @returns {React.ReactElement} The dropdown.
168
+ /**
169
+ * Dropdown component. Uses wpds-ui-kit on desktop and native select on mobile.
170
+ * @param {IDropdownProps} props The props.
171
+ * @returns {React.ReactElement} The dropdown.
249
172
  */
250
- const Dropdown = _ref => {
251
- let {
252
- id,
253
- label,
254
- values,
255
- required = false,
256
- defaultValue,
257
- onChange = () => {},
258
- disabled = false
259
- } = _ref;
173
+ const Dropdown = ({
174
+ id,
175
+ label,
176
+ values,
177
+ required = false,
178
+ defaultValue,
179
+ onChange = () => {},
180
+ disabled = false
181
+ }) => {
260
182
  const [answer, setAnswer] = React.useState();
261
183
  const {
262
184
  isMobileSize
@@ -283,27 +205,26 @@ const Dropdown = _ref => {
283
205
  selected: true
284
206
  } : {};
285
207
  };
286
- return isMobileSize ? React__default.createElement(StyledSelectWrapper, null, React__default.createElement(StyledMobileSelect, {
208
+ return isMobileSize ? React.createElement(StyledSelectWrapper, null, React.createElement(StyledMobileSelect, {
287
209
  id: "",
288
210
  required: required,
289
211
  onChange: e => setAnswer(e.target.value),
290
- placeholder: label,
291
212
  ...disabledProp
292
- }, React__default.createElement("label", null, label), React__default.createElement(StyledMobileOption, {
213
+ }, React.createElement("label", null, label), React.createElement(StyledMobileOption, {
293
214
  value: "",
294
215
  disabled: true,
295
216
  selected: true,
296
217
  style: {
297
218
  color: '#666666'
298
219
  }
299
- }, label), values.map(value => React__default.createElement(StyledMobileOption, {
220
+ }, label), values.map(value => React.createElement(StyledMobileOption, {
300
221
  value: value,
301
222
  key: value,
302
223
  ...defaultValuePropMobile(value)
303
- }, value))), React__default.createElement(wpdsUiKit.Icon, {
224
+ }, value))), React.createElement(wpdsUiKit.Icon, {
304
225
  label: "",
305
226
  size: "100",
306
- fill: wpdsUiKit.theme.colors['gray80'],
227
+ fill: wpdsUiKit.theme.colors.gray80,
307
228
  style: {
308
229
  pointerEvents: 'none',
309
230
  position: 'absolute',
@@ -311,44 +232,43 @@ const Dropdown = _ref => {
311
232
  top: '50%',
312
233
  transform: 'translateY(-50%)'
313
234
  }
314
- }, React__default.createElement(wpdsAssets.ChevronDown, {
235
+ }, React.createElement(wpdsAssets.ChevronDown, {
315
236
  style: {
316
237
  position: 'absolute',
317
238
  right: '10px'
318
239
  }
319
- }))) : React__default.createElement(wpdsUiKit.Select.Root, {
240
+ }))) : React.createElement(wpdsUiKit.Select.Root, {
320
241
  onValueChange: e => setAnswer(e),
321
242
  required: required,
322
243
  ...defaultValueProp,
323
244
  ...disabledProp
324
- }, React__default.createElement(wpdsUiKit.Select.Trigger, {
245
+ }, React.createElement(wpdsUiKit.Select.Trigger, {
325
246
  "data-test-id": `${id}-select-trigger`
326
- }, React__default.createElement(wpdsUiKit.Select.Label, null, label), React__default.createElement(wpdsUiKit.Select.Value, null)), React__default.createElement(wpdsUiKit.Select.Content, {
247
+ }, React.createElement(wpdsUiKit.Select.Label, null, label), React.createElement(wpdsUiKit.Select.Value, null)), React.createElement(wpdsUiKit.Select.Content, {
327
248
  css: {
328
249
  zIndex: wpdsUiKit.theme.zIndices.page
329
250
  },
330
251
  "data-test-id": `${id}-select-content`
331
- }, values.map(value => React__default.createElement(wpdsUiKit.Select.Item, {
252
+ }, values.map(value => React.createElement(wpdsUiKit.Select.Item, {
332
253
  value: value,
333
254
  key: value
334
255
  }, value))));
335
256
  };
336
257
 
337
258
  const scriptSrc = `${subsSdk.ENDPOINTS.staticAssets === 'https://subscribe.washingtonpost.com/static' ? 'https://www.washingtonpost.com/subscribe/static/' : subsSdk.ENDPOINTS.staticAssets}/de-utils/twpdeu.min.js`;
338
- const DESelect = _ref => {
339
- let {
340
- source,
341
- fieldName,
342
- label,
343
- dataDictionaryConfig,
344
- defaultValue,
345
- disabled,
346
- submit,
347
- onChange = () => {},
348
- onFinished = () => {},
349
- valuesFilter = () => true,
350
- children
351
- } = _ref;
259
+ const DESelect = ({
260
+ source,
261
+ fieldName,
262
+ label,
263
+ dataDictionaryConfig,
264
+ defaultValue,
265
+ disabled,
266
+ submit,
267
+ onChange = () => {},
268
+ onFinished = () => {},
269
+ valuesFilter = () => true,
270
+ children
271
+ }) => {
352
272
  const [config, setConfig] = React.useState(dataDictionaryConfig);
353
273
  const [selected, setSelected] = React.useState('');
354
274
  const scriptStatus = subsHooks.useScript(scriptSrc);
@@ -376,14 +296,16 @@ const DESelect = _ref => {
376
296
  const submitSelected = async () => {
377
297
  try {
378
298
  var _window2;
299
+ // TODO: Log to GA?
379
300
  const result = await ((_window2 = window) === null || _window2 === void 0 || (_window2 = _window2.__twpdeu) === null || _window2 === void 0 ? void 0 : _window2.push({
380
301
  submitData: {
381
302
  fieldName,
382
303
  value: selected
383
304
  },
305
+ type: config !== null && config !== void 0 && config.explicit ? IngestType.EXPLICIT : IngestType.IMPLICIT,
384
306
  source
385
307
  }));
386
- const isError = result === true ? false : result ? result.status !== subsSdk.ResponseStatus.SUCCESS : true;
308
+ const isError = result ? result.status !== subsSdk.ResponseStatus.SUCCESS : true;
387
309
  onFinished({
388
310
  isFinished: true,
389
311
  isError
@@ -407,9 +329,8 @@ const DESelect = _ref => {
407
329
  disabled: true
408
330
  } : {};
409
331
  // sort and filter out archived values
410
- // Note: config.values may be readonly
411
- const values = config ? [...config.values].sort((a, b) => a.order - b.order).filter(value => value.archived !== true).filter(valuesFilter) : [];
412
- return React__default.createElement(SelectWrapper, null, children && React__default.createElement(wpdsUiKit.Select.Root, {
332
+ const values = config ? config.values.sort((a, b) => a.order - b.order).filter(value => value.archived !== true).filter(valuesFilter) : [];
333
+ return React.createElement(SelectWrapper, null, children && React.createElement(wpdsUiKit.Select.Root, {
413
334
  onValueChange: e => {
414
335
  setSelected(e);
415
336
  onChange({
@@ -418,12 +339,12 @@ const DESelect = _ref => {
418
339
  },
419
340
  ...defaultValueProp,
420
341
  ...disabledProp
421
- }, children), !children && !config && React__default.createElement(Dropdown, {
342
+ }, children), !children && !config && React.createElement(Dropdown, {
422
343
  id: 'loading',
423
344
  label: 'Loading...',
424
345
  values: [],
425
346
  disabled: true
426
- }), !children && config && React__default.createElement(Dropdown, {
347
+ }), !children && config && React.createElement(Dropdown, {
427
348
  id: config.name,
428
349
  label: label || config.name,
429
350
  onChange: e => {
@@ -450,216 +371,12 @@ const SelectWrapper = /*#__PURE__*/wpdsUiKit.styled('div', {
450
371
  }
451
372
  });
452
373
 
453
- const configSrc = `${subsSdk.ENDPOINTS.base === 'https://subscribe.washingtonpost.com' ? 'https://www.washingtonpost.com/subscribe' : subsSdk.ENDPOINTS.base}/config/de/disclosure.json`;
454
- const getConfig = async () => {
455
- let myConfig = undefined;
456
- // step 1: fetch config
457
- const response = await fetch(configSrc);
458
- const remoteConfig = await response.json();
459
- // step 2: figure out which part of the config to use
460
- // if country- or region-specific config found, use that
461
- const {
462
- country_code,
463
- intl_region
464
- } = subsSdk.WPGeo();
465
- Object.keys(remoteConfig).forEach(configKey => {
466
- if (country_code && configKey.split('|').includes(country_code.toLowerCase())) {
467
- myConfig = remoteConfig[configKey];
468
- } else if (intl_region === 'EEA' && configKey === 'eea') {
469
- myConfig = remoteConfig[configKey];
470
- }
471
- });
472
- // TODO: Check for billing country also
473
- // else if no country-specific config, use the default config
474
- if (typeof myConfig === 'undefined' && remoteConfig['_']) {
475
- myConfig = remoteConfig['_'];
476
- }
477
- return myConfig;
478
- };
479
-
480
- const hydrateLinks = str => {
481
- const array = str.split(/({{PRIVACY_POLICY}})/g);
482
- const chunks = array.map(str => {
483
- if (str === '{{PRIVACY_POLICY}}') {
484
- return React__default.createElement("a", {
485
- target: "_blank",
486
- style: {
487
- color: 'inherit'
488
- },
489
- className: "underline",
490
- href: "https://www.washingtonpost.com/privacy-policy/"
491
- }, "Privacy Policy");
492
- }
493
- return str;
494
- });
495
- const toReturn = chunks.reduce((prev, current) => React__default.createElement(React__default.Fragment, null, prev, current), React__default.createElement(React__default.Fragment, null));
496
- return toReturn;
497
- };
498
-
499
- const COOKIE = 'OptanonAlertBoxClosed';
500
- const checkCookie = () => {
501
- const value = subsSdk.getCookie(COOKIE) || '';
502
- // Wed May 15 2024 06:29:23 GMT-0500 (Central Daylight Time)
503
- // "Invalid date" is 12 characters long
504
- return value.length > 12;
505
- };
506
-
507
- const COOKIE$1 = 'OptanonAlertBoxClosed';
508
- const useOneTrustAlertBoxClosed = _ref => {
509
- let {
510
- allowCookieStore
511
- } = _ref;
512
- const [alertBoxClosed, setAlertBoxClosed] = React.useState();
513
- const [listenToCookieStore, setListenToCookieStore] = React.useState(false);
514
- const [listenToTcfApi, setListenToTcfApi] = React.useState(false);
515
- React.useEffect(() => {
516
- var _window;
517
- if (checkCookie()) {
518
- setAlertBoxClosed(true);
519
- return;
520
- }
521
- if (!window.__tcfapi) {
522
- console.warn('warning: __tcfapi not found');
523
- }
524
- if ((_window = window) !== null && _window !== void 0 && _window.cookieStore && allowCookieStore) {
525
- setListenToCookieStore(true);
526
- } else if (window.__tcfapi) {
527
- setListenToTcfApi(true);
528
- } else {
529
- console.warn('warning: neither cookieStore nor __tcfapi found');
530
- }
531
- }, []);
532
- React.useEffect(() => {
533
- let cleanupFn = () => {};
534
- if (listenToCookieStore && window.cookieStore) {
535
- cleanupFn = subsSdk.listenToCookieStore(COOKIE$1, () => {
536
- if (checkCookie()) {
537
- setAlertBoxClosed(true);
538
- } else {
539
- setAlertBoxClosed(false);
540
- }
541
- });
542
- }
543
- return cleanupFn || (() => {});
544
- }, [listenToCookieStore]);
545
- React.useEffect(() => {
546
- let listenerId;
547
- if (listenToTcfApi && window.__tcfapi) {
548
- const callback = (_tcData, success) => {
549
- if (success) {
550
- listenerId = _tcData.listenerId;
551
- // tcData.eventStatus can be:
552
- // tcloaded means user has made a choice and we’re ready to check it
553
- // cmpuishown means the banner is shown
554
- // useractioncomplete means the user has interacted with the banner
555
- // but actually if the result for any of these is true, we just use the value of the cookie
556
- if (checkCookie()) {
557
- setAlertBoxClosed(true);
558
- }
559
- }
560
- };
561
- window.__tcfapi('addEventListener', 2, callback);
562
- }
563
- // cleanup fn
564
- return () => {
565
- if (window.__tcfapi && listenerId) window.__tcfapi('removeEventListener', 2, success => {
566
- console.debug(success);
567
- }, listenerId);
568
- };
569
- }, [listenToTcfApi]);
570
- return {
571
- alertBoxClosed,
572
- listenToCookieStore,
573
- listenToTcfApi
574
- };
575
- };
576
-
577
- const DEDisclosure = _ref => {
578
- let {
579
- onFinished = () => {},
580
- allowCookieStore = true
581
- } = _ref;
582
- const [disclosure, setDisclosure] = React.useState(null);
583
- const [disclosureRendering, setDisclosureRendering] = React.useState(null);
584
- const [myConfig, setMyConfig] = React.useState();
585
- const {
586
- alertBoxClosed
587
- } = useOneTrustAlertBoxClosed({
588
- allowCookieStore
589
- });
590
- React.useEffect(() => {
591
- (async () => {
592
- const config = await getConfig();
593
- setMyConfig(config);
594
- if (!config) {
595
- console.error('No config found');
596
- }
597
- })();
598
- }, []);
599
- React.useEffect(() => {
600
- if (myConfig) {
601
- // step 3: set disclosure based on config
602
- // if config says to check onetrust, check onetrust
603
- if ('checkBannerStatus' in myConfig && myConfig.checkBannerStatus) {
604
- // check if onetrust is closed
605
- // if it is, show the after banner disclosure
606
- // if it is not, show the before banner disclosure
607
- if (alertBoxClosed) {
608
- setDisclosure(myConfig.disclosure_afterbanner);
609
- } else {
610
- setDisclosure(myConfig.disclosure_beforebanner);
611
- }
612
- } else if ('disclosure' in myConfig) {
613
- setDisclosure(myConfig.disclosure);
614
- } else {
615
- console.error('Invalid config');
616
- }
617
- }
618
- }, [myConfig, alertBoxClosed]);
619
- React.useEffect(() => {
620
- if (disclosure && Array.isArray(disclosure)) {
621
- setDisclosureRendering(disclosure.reduce((prev, current) => {
622
- return React__default.createElement(React__default.Fragment, null, prev, React__default.createElement("p", null, hydrateLinks(current)));
623
- }, React__default.createElement(React__default.Fragment, null)));
624
- // Is it ok to fire `onFinished` if still waiting for onetrust to load on the page?
625
- onFinished({
626
- isFinished: true,
627
- isError: false
628
- });
629
- }
630
- }, [disclosure]);
631
- return disclosure === null ? React__default.createElement("div", {
632
- "data-test-id": "de-disclosure-loading"
633
- }) : React__default.createElement("div", {
634
- "data-test-id": "de-disclosure"
635
- }, disclosureRendering);
636
- };
637
-
638
- const FirstPartyIngestDataTypes = {
639
- JOB_LEVEL: 'profile_job_level',
640
- JOB_INDUSTRY: 'profile_job_industry',
641
- JOB_TITLE: 'profile_job_title',
642
- PERSONAL_GOALS: 'personal_goals',
643
- HOBBIES: 'hobbies',
644
- PROFESSIONAL_GOALS: 'professional_goals',
645
- INDUSTRY: 'industry',
646
- NEWS_LOCATION: 'news_location',
647
- NY_PERSONAL_GOALS: 'new_year_personal_goals',
648
- NY_HOBBIES: 'new_year_hobbies',
649
- NY_PROFESSIONAL_GOALS: 'new_year_professional_goals',
650
- NY_INDUSTRY: 'new_year_industry',
651
- NY_NEWS_LOCATION: 'new_year_news_location'
652
- };
653
-
654
374
  exports.AttributesState = AttributesState;
655
375
  exports.CollectionBehaviors = CollectionBehaviors;
656
- exports.DEDisclosure = DEDisclosure;
657
376
  exports.DESelect = DESelect;
658
- exports.DeleteAttributeState = DeleteAttributeState;
659
- exports.FirstPartyIngestDataTypes = FirstPartyIngestDataTypes;
660
377
  exports.IngestResponseState = IngestResponseState;
661
378
  exports.IngestType = IngestType;
662
379
  exports.getAttributes = getAttributes;
663
380
  exports.hasRequiredPrivacyCookies = hasRequiredPrivacyCookies;
664
- exports.push = push;
381
+ exports.ingest = ingest;
665
382
  //# sourceMappingURL=subs-de-inputs.cjs.development.js.map