@washingtonpost/subs-de-inputs 1.0.0-react18.0 → 1.0.0-react18.10

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.
@@ -1,540 +1,424 @@
1
- import { getCookie, WPGeo, JSON_HEADERS, ENDPOINTS, ResponseStatus } from '@washingtonpost/subs-sdk';
1
+ import { getCookie, WPGeo, JSON_HEADERS, ResponseStatus, ENDPOINTS, isLoggedIn, listenToCookieStore } from '@washingtonpost/subs-sdk';
2
2
  import React, { useState, useEffect } from 'react';
3
- import { Select, theme, styled } from '@washingtonpost/wpds-ui-kit';
3
+ import { Icon, theme, Select, styled } from '@washingtonpost/wpds-ui-kit';
4
+ import { useWindowSize, useScript, ScriptStatus } from '@washingtonpost/subs-hooks';
5
+ import { ChevronDown } from '@washingtonpost/wpds-assets';
4
6
 
5
- var CollectionBehaviors = {
7
+ const CollectionBehaviors = {
6
8
  COLLECT: 'COLLECT',
7
9
  DO_NOT_COLLECT: 'DO_NOT_COLLECT'
8
10
  };
9
- var AttributesState = {
11
+ const AttributesState = {
10
12
  SUCCESS: '100'
11
13
  };
12
- var IngestResponseState = {
14
+ const IngestType = {
15
+ EXPLICIT: 'explicit',
16
+ IMPLICIT: 'implicit'
17
+ };
18
+ const IngestResponseState = {
13
19
  SUCCESS: '100',
14
20
  SYSTEM_ERROR: '101',
15
21
  INVALID_TYPE: '102',
16
22
  INVALID_IDENTIFIER: '103',
17
23
  INVALID_DATA: '104',
18
24
  INVALID_ATTRIBUTE_DEFINITION: '105',
19
- INVALID_META_DEFINITION: '106'
25
+ INVALID_META_DEFINITION: '106',
26
+ UNAUTHENTICATED: '107',
27
+ MISMATCHED_IDENTIFIER: '108',
28
+ DISABLED_ATTRIBUTE_DEFINITION: '109',
29
+ DO_NOT_COLLECT: '110'
20
30
  };
21
31
 
22
- var hasRequiredPrivacyCookies = function hasRequiredPrivacyCookies() {
32
+ const hasRequiredPrivacyCookies = () => {
23
33
  var _WPGeo;
24
34
  if (typeof window === 'undefined') {
25
35
  return false;
26
36
  }
27
- var wp_usp = getCookie('wp_usp');
28
- var countryCode = (_WPGeo = WPGeo()) == null ? void 0 : _WPGeo.country_code;
37
+ const wp_usp = getCookie('wp_usp');
38
+ const countryCode = (_WPGeo = WPGeo()) === null || _WPGeo === void 0 ? void 0 : _WPGeo.country_code;
29
39
  return !!(wp_usp && countryCode === 'US');
30
40
  };
31
41
 
32
- function _regeneratorRuntime() {
33
- _regeneratorRuntime = function () {
34
- return e;
35
- };
36
- var t,
37
- e = {},
38
- r = Object.prototype,
39
- n = r.hasOwnProperty,
40
- o = Object.defineProperty || function (t, e, r) {
41
- t[e] = r.value;
42
- },
43
- i = "function" == typeof Symbol ? Symbol : {},
44
- a = i.iterator || "@@iterator",
45
- c = i.asyncIterator || "@@asyncIterator",
46
- u = i.toStringTag || "@@toStringTag";
47
- function define(t, e, r) {
48
- return Object.defineProperty(t, e, {
49
- value: r,
50
- enumerable: !0,
51
- configurable: !0,
52
- writable: !0
53
- }), t[e];
42
+ const base$1 = `${ENDPOINTS.base}/de/v1`;
43
+ const attributesCache = {};
44
+ const getAttributes = async ({
45
+ fieldName
46
+ }) => {
47
+ if (attributesCache[fieldName]) {
48
+ return attributesCache[fieldName];
54
49
  }
50
+ const fieldNames = [fieldName];
55
51
  try {
56
- define({}, "");
57
- } catch (t) {
58
- define = function (t, e, r) {
59
- return t[e] = r;
60
- };
61
- }
62
- function wrap(t, e, r, n) {
63
- var i = e && e.prototype instanceof Generator ? e : Generator,
64
- a = Object.create(i.prototype),
65
- c = new Context(n || []);
66
- return o(a, "_invoke", {
67
- value: makeInvokeMethod(t, r, c)
68
- }), a;
69
- }
70
- function tryCatch(t, e, r) {
71
- try {
72
- return {
73
- type: "normal",
74
- arg: t.call(e, r)
75
- };
76
- } catch (t) {
77
- return {
78
- type: "throw",
79
- arg: t
80
- };
52
+ const url = new URL(`${base$1}/attributes`);
53
+ url.searchParams.set('attributes', fieldNames.join(','));
54
+ const data = await fetch(url.toString(), {
55
+ credentials: 'include',
56
+ headers: JSON_HEADERS
57
+ });
58
+ const json = await data.json();
59
+ if (data.ok && json.status === ResponseStatus.SUCCESS) {
60
+ const attributes = json.attributes || [];
61
+ attributesCache[fieldName] = attributes;
62
+ return attributes;
63
+ } else {
64
+ return [];
81
65
  }
66
+ } catch (e) {
67
+ console.debug(e);
68
+ return [];
82
69
  }
83
- e.wrap = wrap;
84
- var h = "suspendedStart",
85
- l = "suspendedYield",
86
- f = "executing",
87
- s = "completed",
88
- y = {};
89
- function Generator() {}
90
- function GeneratorFunction() {}
91
- function GeneratorFunctionPrototype() {}
92
- var p = {};
93
- define(p, a, function () {
94
- return this;
95
- });
96
- var d = Object.getPrototypeOf,
97
- v = d && d(d(values([])));
98
- v && v !== r && n.call(v, a) && (p = v);
99
- var g = GeneratorFunctionPrototype.prototype = Generator.prototype = Object.create(p);
100
- function defineIteratorMethods(t) {
101
- ["next", "throw", "return"].forEach(function (e) {
102
- define(t, e, function (t) {
103
- return this._invoke(e, t);
104
- });
105
- });
70
+ };
71
+
72
+ const sendGAEvent = props => {
73
+ if (typeof window === 'undefined') {
74
+ if (process.env.NODE_ENV !== "production") console.warn('NO WINDOW');
75
+ return;
106
76
  }
107
- function AsyncIterator(t, e) {
108
- function invoke(r, o, i, a) {
109
- var c = tryCatch(t[r], t, o);
110
- if ("throw" !== c.type) {
111
- var u = c.arg,
112
- h = u.value;
113
- return h && "object" == typeof h && n.call(h, "__await") ? e.resolve(h.__await).then(function (t) {
114
- invoke("next", t, i, a);
115
- }, function (t) {
116
- invoke("throw", t, i, a);
117
- }) : e.resolve(h).then(function (t) {
118
- u.value = t, i(u);
119
- }, function (t) {
120
- return invoke("throw", t, i, a);
121
- });
122
- }
123
- a(c.arg);
77
+ // Initialize dataLayer if needed
78
+ window.dataLayer = window.dataLayer || [];
79
+ const eventData = {
80
+ ...props
81
+ };
82
+ window.dataLayer.push(eventData);
83
+ };
84
+ const sendToGA = async ({
85
+ submitData: {
86
+ fieldName,
87
+ value
88
+ },
89
+ source
90
+ }) => {
91
+ sendGAEvent({
92
+ event: 'site-onpage-click',
93
+ action: 'site-onpage-click',
94
+ category: 'profile',
95
+ label: fieldName,
96
+ 'de-label': fieldName,
97
+ [fieldName]: value,
98
+ section: 'profile',
99
+ subsection: source
100
+ });
101
+ return true;
102
+ };
103
+
104
+ const base = `${ENDPOINTS.base}/de/v1`;
105
+ const ingest = async ({
106
+ submitData: {
107
+ fieldName,
108
+ value
109
+ },
110
+ source
111
+ }) => {
112
+ const url = `${base}/ingest`;
113
+ const wapo_login_id = getCookie('wapo_login_id');
114
+ const jucid = localStorage.getItem('uuid');
115
+ const ga = getCookie('_ga');
116
+ const payload = {
117
+ jucid,
118
+ ga,
119
+ type: IngestType.EXPLICIT,
120
+ wapo_login_id,
121
+ // TODO: move this to BE to read from cookie headers
122
+ data: {
123
+ [fieldName]: [value]
124
+ },
125
+ metadata: {
126
+ source
124
127
  }
125
- var r;
126
- o(this, "_invoke", {
127
- value: function (t, n) {
128
- function callInvokeWithMethodAndArg() {
129
- return new e(function (e, r) {
130
- invoke(t, n, e, r);
131
- });
132
- }
133
- return r = r ? r.then(callInvokeWithMethodAndArg, callInvokeWithMethodAndArg) : callInvokeWithMethodAndArg();
134
- }
128
+ };
129
+ try {
130
+ const response = await fetch(url, {
131
+ method: 'POST',
132
+ credentials: 'include',
133
+ headers: JSON_HEADERS,
134
+ body: JSON.stringify(payload)
135
135
  });
136
+ const json = await response.json();
137
+ return json;
138
+ } catch (e) {
139
+ console.debug(e);
140
+ return null;
136
141
  }
137
- function makeInvokeMethod(e, r, n) {
138
- var o = h;
139
- return function (i, a) {
140
- if (o === f) throw Error("Generator is already running");
141
- if (o === s) {
142
- if ("throw" === i) throw a;
143
- return {
144
- value: t,
145
- done: !0
146
- };
147
- }
148
- for (n.method = i, n.arg = a;;) {
149
- var c = n.delegate;
150
- if (c) {
151
- var u = maybeInvokeDelegate(c, n);
152
- if (u) {
153
- if (u === y) continue;
154
- return u;
155
- }
156
- }
157
- if ("next" === n.method) n.sent = n._sent = n.arg;else if ("throw" === n.method) {
158
- if (o === h) throw o = s, n.arg;
159
- n.dispatchException(n.arg);
160
- } else "return" === n.method && n.abrupt("return", n.arg);
161
- o = f;
162
- var p = tryCatch(e, r, n);
163
- if ("normal" === p.type) {
164
- if (o = n.done ? s : l, p.arg === y) continue;
165
- return {
166
- value: p.arg,
167
- done: n.done
168
- };
169
- }
170
- "throw" === p.type && (o = s, n.method = "throw", n.arg = p.arg);
171
- }
172
- };
173
- }
174
- function maybeInvokeDelegate(e, r) {
175
- var n = r.method,
176
- o = e.iterator[n];
177
- if (o === t) return r.delegate = null, "throw" === n && e.iterator.return && (r.method = "return", r.arg = t, maybeInvokeDelegate(e, r), "throw" === r.method) || "return" !== n && (r.method = "throw", r.arg = new TypeError("The iterator does not provide a '" + n + "' method")), y;
178
- var i = tryCatch(o, e.iterator, r.arg);
179
- if ("throw" === i.type) return r.method = "throw", r.arg = i.arg, r.delegate = null, y;
180
- var a = i.arg;
181
- return a ? a.done ? (r[e.resultName] = a.value, r.next = e.nextLoc, "return" !== r.method && (r.method = "next", r.arg = t), r.delegate = null, y) : a : (r.method = "throw", r.arg = new TypeError("iterator result is not an object"), r.delegate = null, y);
142
+ };
143
+
144
+ const isAnonymousWebview = () => {
145
+ if (typeof window === 'undefined') {
146
+ return false;
182
147
  }
183
- function pushTryEntry(t) {
184
- var e = {
185
- tryLoc: t[0]
186
- };
187
- 1 in t && (e.catchLoc = t[1]), 2 in t && (e.finallyLoc = t[2], e.afterLoc = t[3]), this.tryEntries.push(e);
148
+ const wp_wv = getCookie('wp_wv');
149
+ return !!(wp_wv && !isLoggedIn());
150
+ };
151
+
152
+ const push = async ({
153
+ submitData,
154
+ source
155
+ }) => {
156
+ if (!hasRequiredPrivacyCookies()) {
157
+ throw new Error('does not satisfy cookie check');
188
158
  }
189
- function resetTryEntry(t) {
190
- var e = t.completion || {};
191
- e.type = "normal", delete e.arg, t.completion = e;
159
+ if (isAnonymousWebview()) {
160
+ throw new Error('does not satisfy cookie check');
192
161
  }
193
- function Context(t) {
194
- this.tryEntries = [{
195
- tryLoc: "root"
196
- }], t.forEach(pushTryEntry, this), this.reset(!0);
162
+ const {
163
+ fieldName
164
+ } = submitData;
165
+ const attributeInfo = await getAttributes({
166
+ fieldName
167
+ });
168
+ if (attributeInfo[0] && attributeInfo[0].name === fieldName && attributeInfo[0].collection_behavior === CollectionBehaviors.DO_NOT_COLLECT) {
169
+ throw new Error('do not collect');
197
170
  }
198
- function values(e) {
199
- if (e || "" === e) {
200
- var r = e[a];
201
- if (r) return r.call(e);
202
- if ("function" == typeof e.next) return e;
203
- if (!isNaN(e.length)) {
204
- var o = -1,
205
- i = function next() {
206
- for (; ++o < e.length;) if (n.call(e, o)) return next.value = e[o], next.done = !1, next;
207
- return next.value = t, next.done = !0, next;
208
- };
209
- return i.next = i;
210
- }
211
- }
212
- throw new TypeError(typeof e + " is not iterable");
171
+ const type = attributeInfo[0] && attributeInfo[0].explicit === true ? IngestType.EXPLICIT : IngestType.IMPLICIT;
172
+ if (!attributeInfo[0] && process.env.NODE_ENV !== "production") {
173
+ console.warn(`no attribute info found for ${fieldName}, assuming implicit`);
213
174
  }
214
- return GeneratorFunction.prototype = GeneratorFunctionPrototype, o(g, "constructor", {
215
- value: GeneratorFunctionPrototype,
216
- configurable: !0
217
- }), o(GeneratorFunctionPrototype, "constructor", {
218
- value: GeneratorFunction,
219
- configurable: !0
220
- }), GeneratorFunction.displayName = define(GeneratorFunctionPrototype, u, "GeneratorFunction"), e.isGeneratorFunction = function (t) {
221
- var e = "function" == typeof t && t.constructor;
222
- return !!e && (e === GeneratorFunction || "GeneratorFunction" === (e.displayName || e.name));
223
- }, e.mark = function (t) {
224
- return Object.setPrototypeOf ? Object.setPrototypeOf(t, GeneratorFunctionPrototype) : (t.__proto__ = GeneratorFunctionPrototype, define(t, u, "GeneratorFunction")), t.prototype = Object.create(g), t;
225
- }, e.awrap = function (t) {
226
- return {
227
- __await: t
228
- };
229
- }, defineIteratorMethods(AsyncIterator.prototype), define(AsyncIterator.prototype, c, function () {
230
- return this;
231
- }), e.AsyncIterator = AsyncIterator, e.async = function (t, r, n, o, i) {
232
- void 0 === i && (i = Promise);
233
- var a = new AsyncIterator(wrap(t, r, n, o), i);
234
- return e.isGeneratorFunction(r) ? a : a.next().then(function (t) {
235
- return t.done ? t.value : a.next();
175
+ if (type === IngestType.EXPLICIT) {
176
+ return ingest({
177
+ submitData,
178
+ source
236
179
  });
237
- }, defineIteratorMethods(g), define(g, u, "Generator"), define(g, a, function () {
238
- return this;
239
- }), define(g, "toString", function () {
240
- return "[object Generator]";
241
- }), e.keys = function (t) {
242
- var e = Object(t),
243
- r = [];
244
- for (var n in e) r.push(n);
245
- return r.reverse(), function next() {
246
- for (; r.length;) {
247
- var t = r.pop();
248
- if (t in e) return next.value = t, next.done = !1, next;
249
- }
250
- return next.done = !0, next;
251
- };
252
- }, e.values = values, Context.prototype = {
253
- constructor: Context,
254
- reset: function (e) {
255
- if (this.prev = 0, this.next = 0, this.sent = this._sent = t, this.done = !1, this.delegate = null, this.method = "next", this.arg = t, this.tryEntries.forEach(resetTryEntry), !e) for (var r in this) "t" === r.charAt(0) && n.call(this, r) && !isNaN(+r.slice(1)) && (this[r] = t);
256
- },
257
- stop: function () {
258
- this.done = !0;
259
- var t = this.tryEntries[0].completion;
260
- if ("throw" === t.type) throw t.arg;
261
- return this.rval;
262
- },
263
- dispatchException: function (e) {
264
- if (this.done) throw e;
265
- var r = this;
266
- function handle(n, o) {
267
- return a.type = "throw", a.arg = e, r.next = n, o && (r.method = "next", r.arg = t), !!o;
268
- }
269
- for (var o = this.tryEntries.length - 1; o >= 0; --o) {
270
- var i = this.tryEntries[o],
271
- a = i.completion;
272
- if ("root" === i.tryLoc) return handle("end");
273
- if (i.tryLoc <= this.prev) {
274
- var c = n.call(i, "catchLoc"),
275
- u = n.call(i, "finallyLoc");
276
- if (c && u) {
277
- if (this.prev < i.catchLoc) return handle(i.catchLoc, !0);
278
- if (this.prev < i.finallyLoc) return handle(i.finallyLoc);
279
- } else if (c) {
280
- if (this.prev < i.catchLoc) return handle(i.catchLoc, !0);
281
- } else {
282
- if (!u) throw Error("try statement without catch or finally");
283
- if (this.prev < i.finallyLoc) return handle(i.finallyLoc);
284
- }
285
- }
286
- }
287
- },
288
- abrupt: function (t, e) {
289
- for (var r = this.tryEntries.length - 1; r >= 0; --r) {
290
- var o = this.tryEntries[r];
291
- if (o.tryLoc <= this.prev && n.call(o, "finallyLoc") && this.prev < o.finallyLoc) {
292
- var i = o;
293
- break;
294
- }
295
- }
296
- i && ("break" === t || "continue" === t) && i.tryLoc <= e && e <= i.finallyLoc && (i = null);
297
- var a = i ? i.completion : {};
298
- return a.type = t, a.arg = e, i ? (this.method = "next", this.next = i.finallyLoc, y) : this.complete(a);
299
- },
300
- complete: function (t, e) {
301
- if ("throw" === t.type) throw t.arg;
302
- return "break" === t.type || "continue" === t.type ? this.next = t.arg : "return" === t.type ? (this.rval = this.arg = t.arg, this.method = "return", this.next = "end") : "normal" === t.type && e && (this.next = e), y;
303
- },
304
- finish: function (t) {
305
- for (var e = this.tryEntries.length - 1; e >= 0; --e) {
306
- var r = this.tryEntries[e];
307
- if (r.finallyLoc === t) return this.complete(r.completion, r.afterLoc), resetTryEntry(r), y;
308
- }
309
- },
310
- catch: function (t) {
311
- for (var e = this.tryEntries.length - 1; e >= 0; --e) {
312
- var r = this.tryEntries[e];
313
- if (r.tryLoc === t) {
314
- var n = r.completion;
315
- if ("throw" === n.type) {
316
- var o = n.arg;
317
- resetTryEntry(r);
318
- }
319
- return o;
320
- }
321
- }
322
- throw Error("illegal catch attempt");
323
- },
324
- delegateYield: function (e, r, n) {
325
- return this.delegate = {
326
- iterator: values(e),
327
- resultName: r,
328
- nextLoc: n
329
- }, "next" === this.method && (this.arg = t), y;
330
- }
331
- }, e;
332
- }
333
- function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) {
334
- try {
335
- var info = gen[key](arg);
336
- var value = info.value;
337
- } catch (error) {
338
- reject(error);
339
- return;
340
- }
341
- if (info.done) {
342
- resolve(value);
343
180
  } else {
344
- Promise.resolve(value).then(_next, _throw);
345
- }
346
- }
347
- function _asyncToGenerator(fn) {
348
- return function () {
349
- var self = this,
350
- args = arguments;
351
- return new Promise(function (resolve, reject) {
352
- var gen = fn.apply(self, args);
353
- function _next(value) {
354
- asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value);
355
- }
356
- function _throw(err) {
357
- asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err);
358
- }
359
- _next(undefined);
181
+ return sendToGA({
182
+ submitData,
183
+ source
360
184
  });
361
- };
362
- }
363
- function _extends() {
364
- _extends = Object.assign ? Object.assign.bind() : function (target) {
365
- for (var i = 1; i < arguments.length; i++) {
366
- var source = arguments[i];
367
- for (var key in source) {
368
- if (Object.prototype.hasOwnProperty.call(source, key)) {
369
- target[key] = source[key];
370
- }
371
- }
372
- }
373
- return target;
374
- };
375
- return _extends.apply(this, arguments);
376
- }
185
+ }
186
+ };
377
187
 
378
- var base = ENDPOINTS.base + "/de/v1";
379
- var attributesCache = {};
380
- var getAttributes = /*#__PURE__*/function () {
381
- var _ref2 = /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee(_ref) {
382
- var fieldName, fieldNames, url, data, json, attributes;
383
- return _regeneratorRuntime().wrap(function _callee$(_context) {
384
- while (1) switch (_context.prev = _context.next) {
385
- case 0:
386
- fieldName = _ref.fieldName;
387
- if (!attributesCache[fieldName]) {
388
- _context.next = 3;
389
- break;
390
- }
391
- return _context.abrupt("return", attributesCache[fieldName]);
392
- case 3:
393
- fieldNames = [fieldName];
394
- _context.prev = 4;
395
- url = new URL(base + "/attributes");
396
- url.searchParams.set('attributes', fieldNames.join(','));
397
- _context.next = 9;
398
- return fetch(url.toString(), {
399
- credentials: 'include',
400
- headers: JSON_HEADERS
401
- });
402
- case 9:
403
- data = _context.sent;
404
- _context.next = 12;
405
- return data.json();
406
- case 12:
407
- json = _context.sent;
408
- if (!(data.ok && json.status === ResponseStatus.SUCCESS)) {
409
- _context.next = 19;
410
- break;
411
- }
412
- attributes = json.attributes || [];
413
- attributesCache[fieldName] = attributes;
414
- return _context.abrupt("return", attributes);
415
- case 19:
416
- return _context.abrupt("return", []);
417
- case 20:
418
- _context.next = 26;
419
- break;
420
- case 22:
421
- _context.prev = 22;
422
- _context.t0 = _context["catch"](4);
423
- console.debug(_context.t0);
424
- return _context.abrupt("return", []);
425
- case 26:
426
- case "end":
427
- return _context.stop();
428
- }
429
- }, _callee, null, [[4, 22]]);
430
- }));
431
- return function getAttributes(_x) {
432
- return _ref2.apply(this, arguments);
188
+ const StyledMobileSelect = /*#__PURE__*/styled('select', {
189
+ padding: '12px 16px 12px 6px',
190
+ display: 'flex',
191
+ justifyContent: 'space-between',
192
+ width: '100%',
193
+ backgroundColor: '$secondary',
194
+ color: '$primary',
195
+ fontFamily: '$meta',
196
+ fontSize: '$100',
197
+ fontWeight: '$light',
198
+ lineHeight: '$125',
199
+ paddingBlockRight: '$125',
200
+ textOverflow: 'ellipsis',
201
+ position: 'relative',
202
+ borderColor: 'transparent',
203
+ borderRightWidth: '10px',
204
+ borderRightColor: 'transparent',
205
+ appearance: 'none',
206
+ '-webkit-appearance': 'none',
207
+ '&:disabled': {
208
+ backgroundColor: theme.colors.disabled,
209
+ borderColor: theme.colors.disabled,
210
+ color: theme.colors.onDisabled,
211
+ cursor: 'not-allowed'
212
+ }
213
+ });
214
+ const StyledSelectWrapper = /*#__PURE__*/styled('div', {
215
+ width: '100%',
216
+ maxWidth: '380px',
217
+ borderRadius: '$012',
218
+ borderColor: '$subtle',
219
+ borderStyle: 'solid',
220
+ borderWidth: '1px',
221
+ backgroundColor: '$secondary',
222
+ position: 'relative'
223
+ });
224
+ const StyledMobileOption = /*#__PURE__*/styled('option', {
225
+ fontFamily: 'inherit',
226
+ fontSize: 'inherit',
227
+ color: 'inherit'
228
+ });
229
+ /**
230
+ * Dropdown component. Uses wpds-ui-kit on desktop and native select on mobile.
231
+ * @param {IDropdownProps} props The props.
232
+ * @returns {React.ReactElement} The dropdown.
233
+ */
234
+ const Dropdown = ({
235
+ id,
236
+ label,
237
+ values,
238
+ required = false,
239
+ defaultValue,
240
+ onChange = () => {},
241
+ disabled = false
242
+ }) => {
243
+ const [answer, setAnswer] = useState();
244
+ const {
245
+ isMobileSize
246
+ } = useWindowSize();
247
+ useEffect(() => {
248
+ if (answer) onChange(answer);
249
+ }, [answer]);
250
+ const disabledProp = disabled ? {
251
+ disabled: true
252
+ } : {};
253
+ // helps maintain state between WPDS and native dropdowns
254
+ const defaultValueProp = answer ? {
255
+ defaultValue: answer
256
+ } : defaultValue ? {
257
+ defaultValue
258
+ } : {};
259
+ const defaultValuePropMobile = value => {
260
+ if (answer) {
261
+ return value === answer ? {
262
+ selected: true
263
+ } : {};
264
+ }
265
+ return value === defaultValue ? {
266
+ selected: true
267
+ } : {};
433
268
  };
434
- }();
269
+ return isMobileSize ? React.createElement(StyledSelectWrapper, null, React.createElement(StyledMobileSelect, {
270
+ id: "",
271
+ required: required,
272
+ onChange: e => setAnswer(e.target.value),
273
+ ...disabledProp
274
+ }, React.createElement("label", null, label), React.createElement(StyledMobileOption, {
275
+ value: "",
276
+ disabled: true,
277
+ selected: true,
278
+ style: {
279
+ color: '#666666'
280
+ }
281
+ }, label), values.map(value => React.createElement(StyledMobileOption, {
282
+ value: value,
283
+ key: value,
284
+ ...defaultValuePropMobile(value)
285
+ }, value))), React.createElement(Icon, {
286
+ label: "",
287
+ size: "100",
288
+ fill: theme.colors.gray80,
289
+ style: {
290
+ pointerEvents: 'none',
291
+ position: 'absolute',
292
+ right: '10px',
293
+ top: '50%',
294
+ transform: 'translateY(-50%)'
295
+ }
296
+ }, React.createElement(ChevronDown, {
297
+ style: {
298
+ position: 'absolute',
299
+ right: '10px'
300
+ }
301
+ }))) : React.createElement(Select.Root, {
302
+ onValueChange: e => setAnswer(e),
303
+ required: required,
304
+ ...defaultValueProp,
305
+ ...disabledProp
306
+ }, React.createElement(Select.Trigger, {
307
+ "data-test-id": `${id}-select-trigger`
308
+ }, React.createElement(Select.Label, null, label), React.createElement(Select.Value, null)), React.createElement(Select.Content, {
309
+ css: {
310
+ zIndex: theme.zIndices.page
311
+ },
312
+ "data-test-id": `${id}-select-content`
313
+ }, values.map(value => React.createElement(Select.Item, {
314
+ value: value,
315
+ key: value
316
+ }, value))));
317
+ };
435
318
 
436
- var DESelect = function DESelect(_ref) {
437
- var source = _ref.source,
438
- fieldName = _ref.fieldName,
439
- label = _ref.label,
440
- dataDictionaryConfig = _ref.dataDictionaryConfig,
441
- defaultValue = _ref.defaultValue,
442
- disabled = _ref.disabled,
443
- submit = _ref.submit,
444
- _ref$onChange = _ref.onChange,
445
- onChange = _ref$onChange === void 0 ? function () {} : _ref$onChange,
446
- _ref$onFinished = _ref.onFinished,
447
- onFinished = _ref$onFinished === void 0 ? function () {} : _ref$onFinished,
448
- _ref$valuesFilter = _ref.valuesFilter,
449
- valuesFilter = _ref$valuesFilter === void 0 ? function () {
450
- return true;
451
- } : _ref$valuesFilter,
452
- children = _ref.children;
453
- var _useState = useState(dataDictionaryConfig),
454
- config = _useState[0],
455
- setConfig = _useState[1];
456
- var _useState2 = useState(''),
457
- selected = _useState2[0],
458
- setSelected = _useState2[1];
459
- useEffect(function () {
460
- if (children) {
461
- if (process.env.NODE_ENV !== "production") {
462
- console.debug('childen props', children);
319
+ const scriptSrc = `${ENDPOINTS.staticAssets === 'https://subscribe.washingtonpost.com/static' ? 'https://www.washingtonpost.com/subscribe/static/' : ENDPOINTS.staticAssets}/de-utils/twpdeu.min.js`;
320
+ const DESelect = ({
321
+ source,
322
+ fieldName,
323
+ label,
324
+ dataDictionaryConfig,
325
+ defaultValue,
326
+ disabled,
327
+ submit,
328
+ onChange = () => {},
329
+ onFinished = () => {},
330
+ valuesFilter = () => true,
331
+ children
332
+ }) => {
333
+ const [config, setConfig] = useState(dataDictionaryConfig);
334
+ const [selected, setSelected] = useState('');
335
+ const scriptStatus = useScript(scriptSrc);
336
+ useEffect(() => {
337
+ const fetchConfig = async () => {
338
+ try {
339
+ var _window;
340
+ const config = await ((_window = window) === null || _window === void 0 || (_window = _window.__twpdeu) === null || _window === void 0 ? void 0 : _window.getFieldConfigs({
341
+ fieldName
342
+ }));
343
+ if (config) {
344
+ setConfig(config[0]);
345
+ } else {
346
+ console.error('unable to get config', fieldName);
347
+ }
348
+ } catch (e) {
349
+ console.warn('unable to get config', fieldName, e);
463
350
  }
464
- return;
465
- }
466
- if (!config) {
467
- _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee() {
468
- var config;
469
- return _regeneratorRuntime().wrap(function _callee$(_context) {
470
- while (1) switch (_context.prev = _context.next) {
471
- case 0:
472
- _context.next = 2;
473
- return getAttributes({
474
- fieldName: fieldName
475
- });
476
- case 2:
477
- config = _context.sent;
478
- if (process.env.NODE_ENV !== "production") {
479
- console.debug('config from API', config);
480
- }
481
- setConfig(config[0]);
482
- case 5:
483
- case "end":
484
- return _context.stop();
485
- }
486
- }, _callee);
487
- }))();
351
+ };
352
+ if (scriptStatus === ScriptStatus.READY && !(children || config)) {
353
+ fetchConfig();
488
354
  }
489
- }, []);
490
- useEffect(function () {
491
- if (submit && selected) {
492
- if (process.env.NODE_ENV !== "production") {
493
- console.error('push not implemented', selected, source);
355
+ }, [scriptStatus]);
356
+ useEffect(() => {
357
+ const submitSelected = async () => {
358
+ try {
359
+ var _window2;
360
+ const result = await ((_window2 = window) === null || _window2 === void 0 || (_window2 = _window2.__twpdeu) === null || _window2 === void 0 ? void 0 : _window2.push({
361
+ submitData: {
362
+ fieldName,
363
+ value: selected
364
+ },
365
+ source
366
+ }));
367
+ const isError = result === true ? false : result ? result.status !== ResponseStatus.SUCCESS : true;
368
+ onFinished({
369
+ isFinished: true,
370
+ isError
371
+ });
372
+ } catch (e) {
373
+ onFinished({
374
+ isFinished: false,
375
+ isError: true
376
+ });
494
377
  }
495
- onFinished({
496
- isFinished: true,
497
- isError: false
498
- });
378
+ };
379
+ if (scriptStatus === ScriptStatus.READY && submit && selected) {
380
+ submitSelected();
499
381
  }
500
- }, [submit, selected]);
501
- if (!(children || config)) {
502
- return React.createElement("span", null, "loading");
503
- }
504
- var defaultValueProp = defaultValue ? {
505
- defaultValue: defaultValue
382
+ }, [scriptStatus, submit]);
383
+ const defaultValueProp = defaultValue && config ? {
384
+ defaultValue
506
385
  } : {};
507
- var disabledProp = disabled ? {
386
+ const isLoading = !(children || config);
387
+ const disabledProp = disabled || isLoading ? {
508
388
  disabled: true
509
389
  } : {};
510
390
  // sort and filter out archived values
511
- var values = config ? config.values.sort(function (a, b) {
512
- return a.order - b.order;
513
- }).filter(function (value) {
514
- return value.archived !== true;
515
- }).filter(valuesFilter) : [];
516
- return React.createElement(SelectWrapper, null, React.createElement(Select.Root, _extends({
517
- onValueChange: function onValueChange(e) {
391
+ // Note: config.values may be readonly
392
+ const values = config ? [...config.values].sort((a, b) => a.order - b.order).filter(value => value.archived !== true).filter(valuesFilter) : [];
393
+ return React.createElement(SelectWrapper, null, children && React.createElement(Select.Root, {
394
+ onValueChange: e => {
395
+ setSelected(e);
518
396
  onChange({
519
397
  value: e
520
398
  });
399
+ },
400
+ ...defaultValueProp,
401
+ ...disabledProp
402
+ }, children), !children && !config && React.createElement(Dropdown, {
403
+ id: 'loading',
404
+ label: 'Loading...',
405
+ values: [],
406
+ disabled: true
407
+ }), !children && config && React.createElement(Dropdown, {
408
+ id: config.name,
409
+ label: label || config.name,
410
+ onChange: e => {
521
411
  setSelected(e);
522
- }
523
- }, defaultValueProp, disabledProp), children || null, !children && config && React.createElement(React.Fragment, null, React.createElement(Select.Trigger, {
524
- "data-test-id": config.name + "-select-trigger"
525
- }, React.createElement(Select.Label, null, label || config.name), React.createElement(Select.Value, null)), React.createElement(Select.Content, {
526
- css: {
527
- zIndex: theme.zIndices.page
412
+ onChange({
413
+ value: e
414
+ });
528
415
  },
529
- "data-test-id": config.name + "-select-content"
530
- }, values.map(function (value) {
531
- return React.createElement(Select.Item, {
532
- value: value.name,
533
- key: value.name
534
- }, value.name);
535
- })))));
416
+ values: values.map(value => value.name),
417
+ defaultValue: defaultValue,
418
+ disabled: disabled
419
+ }));
536
420
  };
537
- var SelectWrapper = /*#__PURE__*/styled('div', {
421
+ const SelectWrapper = /*#__PURE__*/styled('div', {
538
422
  boxSizing: 'border-box',
539
423
  display: 'flex',
540
424
  marginBottom: '$100',
@@ -547,5 +431,186 @@ var SelectWrapper = /*#__PURE__*/styled('div', {
547
431
  }
548
432
  });
549
433
 
550
- export { AttributesState, CollectionBehaviors, DESelect, IngestResponseState, getAttributes, hasRequiredPrivacyCookies };
434
+ const configSrc = `${ENDPOINTS.base === 'https://subscribe.washingtonpost.com' ? 'https://www.washingtonpost.com/subscribe' : ENDPOINTS.base}/config/de/disclosure.json`;
435
+ const getConfig = async () => {
436
+ let myConfig = undefined;
437
+ // step 1: fetch config
438
+ const response = await fetch(configSrc);
439
+ const remoteConfig = await response.json();
440
+ // step 2: figure out which part of the config to use
441
+ // if country- or region-specific config found, use that
442
+ const {
443
+ country_code,
444
+ intl_region
445
+ } = WPGeo();
446
+ Object.keys(remoteConfig).forEach(configKey => {
447
+ if (country_code && configKey.split('|').includes(country_code.toLowerCase())) {
448
+ myConfig = remoteConfig[configKey];
449
+ } else if (intl_region === 'EEA' && configKey === 'eea') {
450
+ myConfig = remoteConfig[configKey];
451
+ }
452
+ });
453
+ // TODO: Check for billing country also
454
+ // else if no country-specific config, use the default config
455
+ if (typeof myConfig === 'undefined' && remoteConfig['_']) {
456
+ myConfig = remoteConfig['_'];
457
+ }
458
+ return myConfig;
459
+ };
460
+
461
+ const hydrateLinks = str => {
462
+ const array = str.split(/({{PRIVACY_POLICY}})/g);
463
+ const chunks = array.map(str => {
464
+ if (str === '{{PRIVACY_POLICY}}') {
465
+ return React.createElement("a", {
466
+ target: "_blank",
467
+ style: {
468
+ color: 'inherit'
469
+ },
470
+ className: "underline",
471
+ href: "https://www.washingtonpost.com/privacy-policy/"
472
+ }, "Privacy Policy");
473
+ }
474
+ return str;
475
+ });
476
+ const toReturn = chunks.reduce((prev, current) => React.createElement(React.Fragment, null, prev, current), React.createElement(React.Fragment, null));
477
+ return toReturn;
478
+ };
479
+
480
+ const COOKIE$1 = 'OptanonAlertBoxClosed';
481
+ const checkCookie = () => {
482
+ const value = getCookie(COOKIE$1) || '';
483
+ // Wed May 15 2024 06:29:23 GMT-0500 (Central Daylight Time)
484
+ // "Invalid date" is 12 characters long
485
+ return value.length > 12;
486
+ };
487
+
488
+ const COOKIE = 'OptanonAlertBoxClosed';
489
+ const useOneTrustAlertBoxClosed = ({
490
+ allowCookieStore
491
+ }) => {
492
+ const [alertBoxClosed, setAlertBoxClosed] = useState();
493
+ const [listenToCookieStore$1, setListenToCookieStore] = useState(false);
494
+ const [listenToTcfApi, setListenToTcfApi] = useState(false);
495
+ useEffect(() => {
496
+ var _window;
497
+ if (checkCookie()) {
498
+ setAlertBoxClosed(true);
499
+ return;
500
+ }
501
+ if (!window.__tcfapi) {
502
+ console.warn('warning: __tcfapi not found');
503
+ }
504
+ if ((_window = window) !== null && _window !== void 0 && _window.cookieStore && allowCookieStore) {
505
+ setListenToCookieStore(true);
506
+ } else if (window.__tcfapi) {
507
+ setListenToTcfApi(true);
508
+ } else {
509
+ console.warn('warning: neither cookieStore nor __tcfapi found');
510
+ }
511
+ }, []);
512
+ useEffect(() => {
513
+ let cleanupFn = () => {};
514
+ if (listenToCookieStore$1 && window.cookieStore) {
515
+ cleanupFn = listenToCookieStore(COOKIE, () => {
516
+ if (checkCookie()) {
517
+ setAlertBoxClosed(true);
518
+ }
519
+ });
520
+ }
521
+ return cleanupFn || (() => {});
522
+ }, [listenToCookieStore$1]);
523
+ useEffect(() => {
524
+ let listenerId;
525
+ if (listenToTcfApi && window.__tcfapi) {
526
+ const callback = (_tcData, success) => {
527
+ if (success) {
528
+ listenerId = _tcData.listenerId;
529
+ // tcData.eventStatus can be:
530
+ // tcloaded means user has made a choice and we’re ready to check it
531
+ // cmpuishown means the banner is shown
532
+ // useractioncomplete means the user has interacted with the banner
533
+ // but actually if the result for any of these is true, we just use the value of the cookie
534
+ if (checkCookie()) {
535
+ setAlertBoxClosed(true);
536
+ }
537
+ }
538
+ };
539
+ window.__tcfapi('addEventListener', 2, callback);
540
+ }
541
+ // cleanup fn
542
+ return () => {
543
+ if (window.__tcfapi && listenerId) window.__tcfapi('removeEventListener', 2, success => {
544
+ console.debug(success);
545
+ }, listenerId);
546
+ };
547
+ }, [listenToTcfApi]);
548
+ return {
549
+ alertBoxClosed,
550
+ listenToCookieStore: listenToCookieStore$1,
551
+ listenToTcfApi
552
+ };
553
+ };
554
+
555
+ const DEDisclosure = ({
556
+ onFinished = () => {},
557
+ allowCookieStore = true
558
+ }) => {
559
+ const [disclosure, setDisclosure] = useState(null);
560
+ const [disclosureRendering, setDisclosureRendering] = useState(null);
561
+ const [myConfig, setMyConfig] = useState();
562
+ const {
563
+ alertBoxClosed
564
+ } = useOneTrustAlertBoxClosed({
565
+ allowCookieStore
566
+ });
567
+ useEffect(() => {
568
+ (async () => {
569
+ const config = await getConfig();
570
+ setMyConfig(config);
571
+ if (!config) {
572
+ console.error('No config found');
573
+ }
574
+ })();
575
+ }, []);
576
+ useEffect(() => {
577
+ if (myConfig) {
578
+ // step 3: set disclosure based on config
579
+ // if config says to check onetrust, check onetrust
580
+ if ('checkBannerStatus' in myConfig && myConfig.checkBannerStatus) {
581
+ // check if onetrust is closed
582
+ // if it is, show the after banner disclosure
583
+ // if it is not, show the before banner disclosure
584
+ if (alertBoxClosed) {
585
+ setDisclosure(myConfig.disclosure_afterbanner);
586
+ } else {
587
+ setDisclosure(myConfig.disclosure_beforebanner);
588
+ }
589
+ } else if ('disclosure' in myConfig) {
590
+ setDisclosure(myConfig.disclosure);
591
+ } else {
592
+ console.error('Invalid config');
593
+ }
594
+ }
595
+ }, [myConfig, alertBoxClosed]);
596
+ useEffect(() => {
597
+ if (disclosure && Array.isArray(disclosure)) {
598
+ setDisclosureRendering(disclosure.reduce((prev, current) => {
599
+ return React.createElement(React.Fragment, null, prev, React.createElement("p", null, hydrateLinks(current)));
600
+ }, React.createElement(React.Fragment, null)));
601
+ // Is it ok to fire `onFinished` if still waiting for onetrust to load on the page?
602
+ onFinished({
603
+ isFinished: true,
604
+ isError: false
605
+ });
606
+ }
607
+ }, [disclosure]);
608
+ return disclosure === null ? React.createElement("div", {
609
+ "data-test-id": "de-disclosure-loading"
610
+ }) : React.createElement("div", {
611
+ "data-test-id": "de-disclosure"
612
+ }, disclosureRendering);
613
+ };
614
+
615
+ export { AttributesState, CollectionBehaviors, DEDisclosure, DESelect, IngestResponseState, IngestType, getAttributes, hasRequiredPrivacyCookies, push };
551
616
  //# sourceMappingURL=subs-de-inputs.esm.js.map