@saasquatch/squatch-js 2.8.2-30 → 2.8.2-32

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.
@@ -1236,629 +1236,6 @@ class EmbedWidget extends Widget {
1236
1236
  return isVerified && (noContainer || isComponent);
1237
1237
  }
1238
1238
  }
1239
- const _log$6 = browserExports.debug("squatch-js:POPUPwidget");
1240
- let popupId = 0;
1241
- class PopupWidget extends Widget {
1242
- constructor(params, trigger = ".squatchpop") {
1243
- super(params);
1244
- __publicField(this, "trigger");
1245
- __publicField(this, "id");
1246
- __publicField(this, "show", this.open);
1247
- __publicField(this, "hide", this.close);
1248
- this.trigger = trigger;
1249
- if (this.container) {
1250
- this.id = "squatchModal";
1251
- } else {
1252
- this.id = popupId === 0 ? `squatchModal` : `squatchModal__${popupId}`;
1253
- popupId = popupId + 1;
1254
- }
1255
- document.head.insertAdjacentHTML(
1256
- "beforeend",
1257
- `<style>#${this.id}::-webkit-scrollbar { display: none; }</style>`
1258
- );
1259
- }
1260
- _initialiseCTA() {
1261
- if (!this.trigger) return;
1262
- let triggerElement;
1263
- try {
1264
- triggerElement = document.querySelector(this.trigger) || document.querySelector(".impactpop");
1265
- if (this.trigger && !triggerElement)
1266
- _log$6("No element found with trigger selector", this.trigger);
1267
- } catch {
1268
- _log$6("Not a valid selector", this.trigger);
1269
- }
1270
- if (triggerElement) {
1271
- triggerElement.onclick = () => {
1272
- this.open();
1273
- };
1274
- }
1275
- }
1276
- _createPopupDialog() {
1277
- var _a2, _b, _c;
1278
- const dialog = document.createElement("dialog");
1279
- const brandingConfig = (_b = (_a2 = this.context.widgetConfig) == null ? void 0 : _a2.values) == null ? void 0 : _b.brandingConfig;
1280
- const sizes = (_c = brandingConfig == null ? void 0 : brandingConfig.widgetSize) == null ? void 0 : _c.popupWidgets;
1281
- const minWidth = (sizes == null ? void 0 : sizes.minWidth) ? formatWidth(sizes.minWidth) : "auto";
1282
- const maxWidth = (sizes == null ? void 0 : sizes.maxWidth) ? formatWidth(sizes.maxWidth) : "500px";
1283
- dialog.id = this.id;
1284
- dialog.setAttribute(
1285
- "style",
1286
- `width: 100%; min-width: ${minWidth}; max-width: ${maxWidth}; border: none; padding: 0;`
1287
- );
1288
- const onClick = (e) => {
1289
- e.stopPropagation();
1290
- if (e.target === dialog) dialog.close();
1291
- };
1292
- dialog.addEventListener("click", onClick);
1293
- return dialog;
1294
- }
1295
- async load() {
1296
- var _a2;
1297
- const frame = this._createFrame();
1298
- this._initialiseCTA();
1299
- const element = this.container ? this._findElement() : document.body;
1300
- const dialogParent = element.shadowRoot || element;
1301
- const dialog = this._createPopupDialog();
1302
- dialog.appendChild(frame);
1303
- if (((_a2 = dialogParent.lastChild) == null ? void 0 : _a2.nodeName) === "DIALOG") {
1304
- dialogParent.replaceChild(dialog, dialogParent.lastChild);
1305
- } else {
1306
- dialogParent.appendChild(dialog);
1307
- }
1308
- const { contentWindow } = frame;
1309
- if (!contentWindow) {
1310
- throw new Error("Frame needs a content window");
1311
- }
1312
- const frameDoc = contentWindow.document;
1313
- frameDoc.open();
1314
- frameDoc.write(this.content);
1315
- frameDoc.write(
1316
- `<script src="${this.npmCdn}/resize-observer-polyfill@1.5.x"><\/script>`
1317
- );
1318
- frameDoc.close();
1319
- _log$6("Popup template loaded into iframe");
1320
- await this._setupResizeHandler(frame);
1321
- }
1322
- async _setupResizeHandler(frame) {
1323
- const { contentWindow } = frame;
1324
- if (!contentWindow) {
1325
- throw new Error("Frame needs a content window");
1326
- }
1327
- const frameDoc = contentWindow.document;
1328
- domready(frameDoc, async () => {
1329
- frameDoc.body.style.overflowY = "hidden";
1330
- frame.height = `${frameDoc.body.offsetHeight}px`;
1331
- const ro = new contentWindow["ResizeObserver"]((entries) => {
1332
- for (const entry of entries) {
1333
- const { top, bottom } = entry.contentRect;
1334
- const computedHeight = bottom + top;
1335
- frame.height = computedHeight + "";
1336
- entry.target.style = ``;
1337
- }
1338
- });
1339
- ro.observe(await this._findInnerContainer(frame));
1340
- });
1341
- }
1342
- open() {
1343
- const element = this.container ? this._findElement() : document.body;
1344
- const parent = element.shadowRoot || element;
1345
- const dialog = parent.querySelector(`#${this.id}`);
1346
- if (!dialog) throw new Error("Could not determine container div");
1347
- dialog.showModal();
1348
- const frame = this._findFrame();
1349
- if (!frame) throw new Error("Could not find iframe");
1350
- const { contentWindow } = frame;
1351
- if (!contentWindow) throw new Error("Squatch.js has an empty iframe");
1352
- const frameDoc = contentWindow.document;
1353
- domready(frameDoc, () => {
1354
- var _a2;
1355
- const _sqh = contentWindow.squatch || contentWindow.widgetIdent;
1356
- (_a2 = frame.contentDocument) == null ? void 0 : _a2.dispatchEvent(new CustomEvent("sq:refresh"));
1357
- if (this.context.user) {
1358
- this._loadEvent(_sqh);
1359
- _log$6("Popup opened");
1360
- } else {
1361
- this._attachLoadEventListener(frameDoc, _sqh);
1362
- }
1363
- });
1364
- }
1365
- close() {
1366
- const frame = this._findFrame();
1367
- if (frame == null ? void 0 : frame.contentDocument)
1368
- this._detachLoadEventListener(frame.contentDocument);
1369
- const element = this.container ? this._findElement() : document.body;
1370
- const parent = element.shadowRoot || element;
1371
- const dialog = parent.querySelector(`#${this.id}`);
1372
- if (!dialog) throw new Error("Could not determine container div");
1373
- dialog.close();
1374
- _log$6("Popup closed");
1375
- }
1376
- _clickedOutside({ target }) {
1377
- }
1378
- _error(rs, mode = "modal", style = "") {
1379
- const _style = "body { margin: 0; } .modal { box-shadow: none; border: 0; }";
1380
- return super._error(rs, mode, style || _style);
1381
- }
1382
- }
1383
- const _log$5 = browserExports.debug("squatch-js:widgets");
1384
- class Widgets {
1385
- /**
1386
- * Initialize a new {@link Widgets} instance.
1387
- *
1388
- * @param {ConfigOptions} config Config details
1389
- *
1390
- * @example <caption>Browser example</caption>
1391
- * var widgets = new squatch.Widgets({tenantAlias:'test_12b5bo1b25125'});
1392
- *
1393
- * @example <caption>Browserify/Webpack example</caption>
1394
- * var Widgets = require('@saasquatch/squatch-js').Widgets;
1395
- * var widgets = new Widgets({tenantAlias:'test_12b5bo1b25125'});
1396
- *
1397
- * @example <caption>Babel+Browserify/Webpack example</caption>
1398
- * import {Widgets} from '@saasquatch/squatch-js';
1399
- * let widgets = new Widgets({tenantAlias:'test_12b5bo1b25125'});
1400
- */
1401
- constructor(configin) {
1402
- /**
1403
- * Instance of {@link WidgetApi}
1404
- */
1405
- __publicField(this, "api");
1406
- /**
1407
- * Tenant alias of SaaSquatch tenant
1408
- */
1409
- __publicField(this, "tenantAlias");
1410
- /**
1411
- * SaaSquatch domain for API requests
1412
- * @default "https://app.referralsaasquatch.com"
1413
- */
1414
- __publicField(this, "domain");
1415
- /**
1416
- * Hosted CDN for npm packages
1417
- * @default "https://fast.ssqt.io/npm"
1418
- */
1419
- __publicField(this, "npmCdn");
1420
- const config = validateConfig(configin);
1421
- this.tenantAlias = config.tenantAlias;
1422
- this.domain = config.domain;
1423
- this.npmCdn = config.npmCdn;
1424
- this.api = new WidgetApi(config);
1425
- }
1426
- /**
1427
- * This function calls the {@link WidgetApi.upsertUser} method, and it renders
1428
- * the widget if it is successful. Otherwise it shows the "error" widget.
1429
- *
1430
- * @param {Object} config Config details
1431
- * @param {Object} config.user The user details
1432
- * @param {string} config.user.id The user id
1433
- * @param {string} config.user.accountId The user account id
1434
- * @param {WidgetType} config.widgetType The content of the widget
1435
- * @param {EngagementMedium} config.engagementMedium How to display the widget
1436
- * @param {string} config.jwt the JSON Web Token (JWT) that is used to validate the data (can be disabled)
1437
- * @param {HTMLElement | string | undefined} config.container Element to load the widget into
1438
- * @param {string | undefined} config.trigger Trigger element for opening the popup widget
1439
- *
1440
- * @return {Promise<WidgetResult>} json object if true, with a Widget and user details
1441
- */
1442
- async upsertUser(config) {
1443
- const raw = config;
1444
- const clean = validateWidgetConfig(raw);
1445
- try {
1446
- const response = await this.api.upsertUser(clean);
1447
- return {
1448
- widget: this._renderWidget(response, clean, {
1449
- type: "upsert",
1450
- user: clean.user,
1451
- engagementMedium: config.engagementMedium,
1452
- container: config.container,
1453
- trigger: config.trigger,
1454
- widgetConfig: {
1455
- values: {
1456
- brandingConfig: response == null ? void 0 : response.brandingConfig
1457
- }
1458
- }
1459
- }),
1460
- user: response.user
1461
- };
1462
- } catch (err) {
1463
- _log$5(err);
1464
- if (err.apiErrorCode) {
1465
- this._renderErrorWidget(err, config.engagementMedium);
1466
- }
1467
- throw new Error(err);
1468
- }
1469
- }
1470
- /**
1471
- * This function calls the {@link WidgetApi.render} method, and it renders
1472
- * the widget if it is successful. Otherwise it shows the "error" widget.
1473
- *
1474
- * @param {Object} config Config details
1475
- * @param {Object} config.user The user details
1476
- * @param {string} config.user.id The user id
1477
- * @param {string} config.user.accountId The user account id
1478
- * @param {WidgetType} config.widgetType The content of the widget
1479
- * @param {EngagementMedium} config.engagementMedium How to display the widget
1480
- * @param {string} config.jwt the JSON Web Token (JWT) that is used
1481
- * to validate the data (can be disabled)
1482
- *
1483
- * @return {Promise<WidgetResult>} json object if true, with a Widget and user details
1484
- */
1485
- async render(config) {
1486
- const raw = config;
1487
- const clean = validatePasswordlessConfig(raw);
1488
- try {
1489
- const response = await this.api.render(clean);
1490
- return {
1491
- widget: this._renderWidget(response, clean, {
1492
- type: "passwordless",
1493
- engagementMedium: clean.engagementMedium,
1494
- container: clean.container,
1495
- trigger: clean.trigger,
1496
- widgetConfig: {
1497
- values: {
1498
- brandingConfig: response == null ? void 0 : response.brandingConfig
1499
- }
1500
- }
1501
- }),
1502
- user: response.user
1503
- };
1504
- } catch (err) {
1505
- if (err.apiErrorCode) {
1506
- this._renderErrorWidget(err, clean.engagementMedium);
1507
- }
1508
- throw new Error(err);
1509
- }
1510
- }
1511
- /**
1512
- * Autofills a referral code into an element when someone has been referred.
1513
- * Uses {@link WidgetApi.squatchReferralCookie} behind the scenes.
1514
- *
1515
- * @param selector Element class/id selector, or a callback function
1516
- * @returns
1517
- */
1518
- async autofill(selector) {
1519
- const input = selector;
1520
- if (typeof input === "function") {
1521
- try {
1522
- const response = await this.api.squatchReferralCookie();
1523
- input(response);
1524
- } catch (e) {
1525
- _log$5("Autofill error", e);
1526
- throw new Error(e);
1527
- }
1528
- return;
1529
- }
1530
- if (typeof input !== "string")
1531
- throw new Error("Autofill accepts a string or function");
1532
- let elems = document.querySelectorAll(input);
1533
- let elem;
1534
- if (elems.length > 0) {
1535
- elem = elems[0];
1536
- } else {
1537
- _log$5("Element id/class or function missing");
1538
- throw new Error("Element id/class or function missing");
1539
- }
1540
- try {
1541
- const response = await this.api.squatchReferralCookie();
1542
- elem.value = response.codes[0];
1543
- } catch (e) {
1544
- throw new Error(e);
1545
- }
1546
- }
1547
- /**
1548
- * @hidden
1549
- * @param {Object} response The json object return from the WidgetApi
1550
- * @param {Object} config Config details
1551
- * @param {string} config.widgetType The widget type (REFERRER_WIDGET, CONVERSION_WIDGET)
1552
- * @param {string} config.engagementMedium (POPUP, EMBED)
1553
- * @returns {Widget} widget (PopupWidget or EmbedWidget)
1554
- */
1555
- _renderWidget(response, config, context) {
1556
- var _a2;
1557
- _log$5("Rendering Widget...");
1558
- if (!response) throw new Error("Unable to get a response");
1559
- let widget2;
1560
- let displayOnLoad = !!config.displayOnLoad;
1561
- const opts = response.jsOptions || {};
1562
- const params = {
1563
- content: response.template,
1564
- type: config.widgetType || ((_a2 = opts.widget) == null ? void 0 : _a2.defaultWidgetType),
1565
- api: this.api,
1566
- domain: this.domain,
1567
- npmCdn: this.npmCdn,
1568
- context
1569
- };
1570
- if (opts.widgetUrlMappings) {
1571
- opts.widgetUrlMappings.forEach((rule) => {
1572
- var _a3, _b;
1573
- if (Widgets._matchesUrl(rule.url)) {
1574
- if (rule.widgetType !== "CONVERSION_WIDGET" || ((_b = (_a3 = response.user) == null ? void 0 : _a3.referredBy) == null ? void 0 : _b.code)) {
1575
- displayOnLoad = rule.displayOnLoad;
1576
- _log$5(`Display ${rule.widgetType} on ${rule.url}`);
1577
- } else {
1578
- _log$5(
1579
- `Don't display ${rule.widgetType} when no referral on widget rule match ${rule.url}`
1580
- );
1581
- }
1582
- }
1583
- });
1584
- }
1585
- if (opts.fuelTankAutofillUrls) {
1586
- _log$5("We found a fuel tank autofill!");
1587
- opts.fuelTankAutofillUrls.forEach(({ url, formSelector }) => {
1588
- var _a3, _b, _c;
1589
- if (Widgets._matchesUrl(url)) {
1590
- _log$5("Fuel Tank URL matches");
1591
- if ((_b = (_a3 = response.user) == null ? void 0 : _a3.referredBy) == null ? void 0 : _b.code) {
1592
- const formAutofill = document.querySelector(formSelector);
1593
- if (formAutofill) {
1594
- formAutofill.value = ((_c = response.user.referredBy.referredReward) == null ? void 0 : _c.fuelTankCode) || "";
1595
- } else {
1596
- _log$5(
1597
- new Error(
1598
- `Element with id/class ${formSelector} was not found.`
1599
- )
1600
- );
1601
- }
1602
- }
1603
- }
1604
- });
1605
- }
1606
- if (config.engagementMedium === "EMBED") {
1607
- widget2 = this._renderEmbedWidget(params);
1608
- } else {
1609
- widget2 = this._renderPopupWidget(params);
1610
- if (displayOnLoad) widget2.open();
1611
- }
1612
- return widget2;
1613
- }
1614
- _renderPopupWidget(params) {
1615
- const widget2 = new PopupWidget(params, params.context.trigger);
1616
- widget2.load();
1617
- return widget2;
1618
- }
1619
- _renderEmbedWidget(params) {
1620
- const widget2 = new EmbedWidget(params, params.context.container);
1621
- widget2.load();
1622
- return widget2;
1623
- }
1624
- /**
1625
- * @hidden
1626
- * @param {Object} error The json object containing the error details
1627
- * @param {string} em The engagementMedium
1628
- * @returns {void}
1629
- */
1630
- _renderErrorWidget(props, em = "POPUP") {
1631
- const { apiErrorCode, rsCode, message } = props;
1632
- _log$5(new Error(`${apiErrorCode} (${rsCode}) ${message}`));
1633
- const params = {
1634
- content: "error",
1635
- rsCode,
1636
- api: this.api,
1637
- domain: this.domain,
1638
- npmCdn: this.npmCdn,
1639
- type: "ERROR_WIDGET",
1640
- context: { type: "error" }
1641
- };
1642
- let widget2;
1643
- if (em === "EMBED") {
1644
- widget2 = new EmbedWidget(params);
1645
- widget2.load();
1646
- } else if (em === "POPUP") {
1647
- widget2 = new PopupWidget(params);
1648
- widget2.load();
1649
- }
1650
- }
1651
- /**
1652
- * @hidden
1653
- * @param {string} rule A regular expression
1654
- * @returns {boolean} true if rule matches Url, false otherwise
1655
- */
1656
- static _matchesUrl(rule) {
1657
- return window.location.href.match(new RegExp(rule)) ? true : false;
1658
- }
1659
- }
1660
- class EventsApi {
1661
- /**
1662
- * Initialize a new {@link EventsApi} instance.
1663
- *
1664
- * @param {ConfigOptions} config Config details
1665
- *
1666
- * @example <caption>Browser example</caption>
1667
- * var squatchApi = new squatch.EventsApi({tenantAlias:'test_12b5bo1b25125'});
1668
- *
1669
- * @example <caption>Browserify/Webpack example</caption>
1670
- * var EventsApi = require('@saasquatch/squatch-js').EventsApi;
1671
- * var squatchApi = new EventsApi({tenantAlias:'test_12b5bo1b25125'});
1672
- *
1673
- * @example <caption>Babel+Browserify/Webpack example</caption>
1674
- * import {EventsApi} from '@saasquatch/squatch-js';
1675
- * let squatchApi = new EventsApi({tenantAlias:'test_12b5bo1b25125'});
1676
- */
1677
- constructor(config) {
1678
- __publicField(this, "tenantAlias");
1679
- __publicField(this, "domain");
1680
- const raw = config;
1681
- const clean = validateConfig(raw);
1682
- this.tenantAlias = clean.tenantAlias;
1683
- this.domain = clean.domain;
1684
- }
1685
- /**
1686
- * Track an event for a user
1687
- *
1688
- * @param params Parameters for request
1689
- * @param options.jwt the JSON Web Token (JWT) that is used to authenticate the user
1690
- *
1691
- * @return An ID to confirm the event has been accepted for asynchronous processing
1692
- */
1693
- track(params, options) {
1694
- const raw = params;
1695
- const rawOpts = options;
1696
- const body = _validateEvent(raw);
1697
- const { jwt } = _validateTrackOptions(rawOpts);
1698
- const ta = encodeURIComponent(this.tenantAlias);
1699
- const userId = encodeURIComponent(body.userId);
1700
- const accountId = encodeURIComponent(body.accountId);
1701
- const path = `/api/v1/${ta}/open/account/${accountId}/user/${userId}/events`;
1702
- const url = this.domain + path;
1703
- return doPost(url, JSON.stringify(body), jwt);
1704
- }
1705
- }
1706
- function _validateEvent(raw) {
1707
- if (!isObject$1(raw)) throw new Error("tracking parameter must be an object");
1708
- if (!(raw == null ? void 0 : raw["accountId"])) throw new Error("accountId field is required");
1709
- if (!(raw == null ? void 0 : raw["events"])) throw new Error("events field is required");
1710
- if (!(raw == null ? void 0 : raw["userId"])) throw new Error("userId field is required");
1711
- const clean = raw;
1712
- if (!Array.isArray(clean.events))
1713
- throw new Error("'events' should be an array");
1714
- return clean;
1715
- }
1716
- function _validateTrackOptions(raw) {
1717
- if (!isObject$1(raw)) throw new Error("'options' should be an object");
1718
- return raw;
1719
- }
1720
- function asyncLoad() {
1721
- var _a2;
1722
- const namespace = window[IMPACT_NAMESPACE] ? IMPACT_NAMESPACE : DEFAULT_NAMESPACE;
1723
- const cached = ((_a2 = window["_" + namespace]) == null ? void 0 : _a2.ready) || [];
1724
- const declarativeCache = window.impactOnReady || window.squatchOnReady;
1725
- const readyFns = [...cached, declarativeCache].filter((a) => !!a);
1726
- setTimeout(() => {
1727
- if (!window[DEFAULT_NAMESPACE]) return;
1728
- window[IMPACT_NAMESPACE] = window[DEFAULT_NAMESPACE];
1729
- readyFns.forEach((cb) => cb());
1730
- window[DEFAULT_NAMESPACE]._auto();
1731
- window["_" + namespace] = void 0;
1732
- delete window["_" + namespace];
1733
- }, 0);
1734
- }
1735
- const _log$4 = browserExports.debug("squatch-js");
1736
- const isObject = (item) => typeof item === "object" && !Array.isArray(item);
1737
- const deepMerge = (target, source) => {
1738
- const isDeep = (prop) => isObject(source[prop]) && target.hasOwnProperty(prop) && isObject(target[prop]);
1739
- const replaced = Object.getOwnPropertyNames(source).map((prop) => ({
1740
- [prop]: isDeep(prop) ? deepMerge(target[prop], source[prop]) : source[prop]
1741
- })).reduce((a, b) => ({ ...a, ...b }), {});
1742
- return {
1743
- ...target,
1744
- ...replaced
1745
- };
1746
- };
1747
- function b64decode(input) {
1748
- const binary = atob(input.replace(/_/g, "/").replace(/-/g, "+"));
1749
- const bytes = new Uint8Array(binary.length);
1750
- for (let i = 0; i < binary.length; i++) {
1751
- bytes[i] = binary.charCodeAt(i);
1752
- }
1753
- return new TextDecoder("utf8").decode(bytes);
1754
- }
1755
- function b64encode(input) {
1756
- const encodedInput = new TextEncoder().encode(input);
1757
- const binary = Array.from(
1758
- encodedInput,
1759
- (byte) => String.fromCodePoint(byte)
1760
- ).join("");
1761
- return btoa(binary).replace(/=/g, "").replace(/\+/g, "-").replace(/\//g, "_");
1762
- }
1763
- function getTopDomain() {
1764
- var i, h, weird_cookie = "weird_get_top_level_domain=cookie", hostname = document.location.hostname.split(".");
1765
- for (i = hostname.length - 1; i >= 0; i--) {
1766
- h = hostname.slice(i).join(".");
1767
- document.cookie = weird_cookie + ";domain=." + h + ";";
1768
- if (document.cookie.indexOf(weird_cookie) > -1) {
1769
- document.cookie = weird_cookie.split("=")[0] + "=;domain=." + h + ";expires=Thu, 01 Jan 1970 00:00:01 GMT;";
1770
- return h;
1771
- }
1772
- }
1773
- }
1774
- function _pushCookie() {
1775
- const queryString = window.location.search;
1776
- const urlParams = new URLSearchParams(queryString);
1777
- const refParam = urlParams.get("_saasquatch") || "";
1778
- if (refParam) {
1779
- let paramsJSON = "", existingCookie = "", reEncodedCookie = "";
1780
- try {
1781
- paramsJSON = JSON.parse(b64decode(refParam));
1782
- } catch (error) {
1783
- _log$4("Unable to decode params", error);
1784
- return;
1785
- }
1786
- try {
1787
- existingCookie = JSON.parse(b64decode(api$1.get("_saasquatch")));
1788
- _log$4("existing cookie", existingCookie);
1789
- } catch (error) {
1790
- _log$4("Unable to retrieve cookie", error);
1791
- }
1792
- try {
1793
- const domain = getTopDomain();
1794
- _log$4("domain retrieved:", domain);
1795
- if (existingCookie) {
1796
- const newCookie = deepMerge(existingCookie, paramsJSON);
1797
- reEncodedCookie = b64encode(JSON.stringify(newCookie));
1798
- _log$4("cookie to store:", newCookie);
1799
- } else {
1800
- reEncodedCookie = b64encode(JSON.stringify(paramsJSON));
1801
- _log$4("cookie to store:", paramsJSON);
1802
- }
1803
- api$1.set("_saasquatch", reEncodedCookie, {
1804
- expires: 365,
1805
- secure: false,
1806
- sameSite: "Lax",
1807
- domain,
1808
- path: "/"
1809
- });
1810
- } catch (error) {
1811
- _log$4("Unable to set cookie", error);
1812
- }
1813
- }
1814
- }
1815
- const _log$3 = browserExports.debug("squatch-js");
1816
- function _getAutoConfig() {
1817
- var _a2;
1818
- const queryString = window.location.search;
1819
- const urlParams = new URLSearchParams(queryString);
1820
- const refParam = urlParams.get("_saasquatchExtra") || "";
1821
- if (!refParam) {
1822
- _log$3("No _saasquatchExtra param");
1823
- return;
1824
- }
1825
- const config = validateConfig({
1826
- tenantAlias: "UNKNOWN"
1827
- });
1828
- if (!config.domain) {
1829
- _log$3("domain must be provided in config to use _saasquatchExtra");
1830
- return;
1831
- }
1832
- let raw;
1833
- try {
1834
- raw = JSON.parse(b64decode(refParam));
1835
- } catch (e) {
1836
- _log$3("Unable to decode _saasquatchExtra config");
1837
- return;
1838
- }
1839
- function normalizeDomain(domain) {
1840
- return domain.replace(/^https?:\/\//, "");
1841
- }
1842
- const normalizedDomain = normalizeDomain(config.domain);
1843
- const tenantAlias = Object.keys((raw == null ? void 0 : raw[normalizedDomain]) || {})[0];
1844
- const widgetConfig = (_a2 = raw == null ? void 0 : raw[normalizedDomain]) == null ? void 0 : _a2[tenantAlias];
1845
- if (!widgetConfig) {
1846
- _log$3("_saasquatchExtra did not have an expected structure");
1847
- return void 0;
1848
- }
1849
- const { autoPopupWidgetType, ...rest } = widgetConfig;
1850
- return {
1851
- widgetConfig: {
1852
- widgetType: autoPopupWidgetType,
1853
- displayOnLoad: true,
1854
- ...rest
1855
- },
1856
- squatchConfig: {
1857
- ...config,
1858
- tenantAlias
1859
- }
1860
- };
1861
- }
1862
1239
  const getSkeleton = ({
1863
1240
  type = "verified-access",
1864
1241
  height = "500px",
@@ -2071,52 +1448,743 @@ const getSkeleton = ({
2071
1448
  padding: 30px 0;
2072
1449
  /* Removed border-top and border-bottom */
2073
1450
  }
2074
- .stat-card { flex: 1; display: flex; flex-direction: column; align-items: center; }
2075
- .stat-divider { padding-left: 24px; }
2076
- .sk-stat-num { height: 48px; width: 120px; margin-bottom: 8px; }
2077
- .sk-stat-label { height: 18px; width: 80px; }
2078
-
2079
- /* Table Styles */
2080
- .table-header { display: flex; gap: 16px; margin-bottom: 16px; }
2081
- .sk-th { height: 16px; }
2082
- .table-row {
2083
- display: flex;
2084
- align-items: center;
2085
- gap: 16px;
2086
- padding: 16px 0;
2087
- /* Removed border-bottom */
1451
+ .stat-card { flex: 1; display: flex; flex-direction: column; align-items: center; }
1452
+ .stat-divider { padding-left: 24px; }
1453
+ .sk-stat-num { height: 48px; width: 120px; margin-bottom: 8px; }
1454
+ .sk-stat-label { height: 18px; width: 80px; }
1455
+
1456
+ /* Table Styles */
1457
+ .table-header { display: flex; gap: 16px; margin-bottom: 16px; }
1458
+ .sk-th { height: 16px; }
1459
+ .table-row {
1460
+ display: flex;
1461
+ align-items: center;
1462
+ gap: 16px;
1463
+ padding: 16px 0;
1464
+ /* Removed border-bottom */
1465
+ }
1466
+
1467
+ .col-user { flex: 2; }
1468
+ .col-status { flex: 1; }
1469
+ .col-reward { flex: 2; }
1470
+ .col-date { flex: 1; }
1471
+
1472
+ .sk-badge { height: 28px; width: 90px; border-radius: 14px; }
1473
+ .sk-reward-block { height: 36px; width: 100%; border-radius: 6px; }
1474
+
1475
+ .pagination { display: flex; justify-content: flex-end; gap: 8px; margin-top: 24px; }
1476
+ .sk-btn-page { height: 36px; width: 64px; border-radius: 6px; margin-bottom: 0; }
1477
+
1478
+ @media (max-width: 768px) {
1479
+ body { padding: 20px; }
1480
+ .widget-container { padding: 24px; }
1481
+
1482
+ .hero-section { flex-direction: column-reverse; gap: 24px; }
1483
+ .instant-access-layout { flex-direction: column; }
1484
+
1485
+ .hero-image { height: 220px; width: 100%; }
1486
+ .sk-title-lg { width: 100%; }
1487
+
1488
+ .col-date { display: none; }
1489
+ }
1490
+ </style>
1491
+
1492
+ <div class="widget-container">
1493
+ ${type === "verified-access" ? referrerHTML : instantAccessHTML}
1494
+ </div>
1495
+ `;
1496
+ };
1497
+ const _log$6 = browserExports.debug("squatch-js:POPUPwidget");
1498
+ let popupId = 0;
1499
+ class PopupWidget extends Widget {
1500
+ constructor(params, trigger = ".squatchpop") {
1501
+ super(params);
1502
+ __publicField(this, "trigger");
1503
+ __publicField(this, "id");
1504
+ __publicField(this, "show", this.open);
1505
+ __publicField(this, "hide", this.close);
1506
+ this.trigger = trigger;
1507
+ if (this.container) {
1508
+ this.id = "squatchModal";
1509
+ } else {
1510
+ this.id = popupId === 0 ? `squatchModal` : `squatchModal__${popupId}`;
1511
+ popupId = popupId + 1;
1512
+ }
1513
+ document.head.insertAdjacentHTML(
1514
+ "beforeend",
1515
+ `<style>#${this.id}::-webkit-scrollbar { display: none; }</style>`
1516
+ );
1517
+ }
1518
+ _initialiseCTA() {
1519
+ if (!this.trigger) return;
1520
+ let triggerElement;
1521
+ try {
1522
+ triggerElement = document.querySelector(this.trigger) || document.querySelector(".impactpop");
1523
+ if (this.trigger && !triggerElement)
1524
+ _log$6("No element found with trigger selector", this.trigger);
1525
+ } catch {
1526
+ _log$6("Not a valid selector", this.trigger);
1527
+ }
1528
+ if (triggerElement) {
1529
+ triggerElement.onclick = () => {
1530
+ this.open();
1531
+ };
1532
+ }
1533
+ }
1534
+ _createPopupDialog() {
1535
+ var _a2, _b, _c;
1536
+ const dialog = document.createElement("dialog");
1537
+ const brandingConfig = (_b = (_a2 = this.context.widgetConfig) == null ? void 0 : _a2.values) == null ? void 0 : _b.brandingConfig;
1538
+ const sizes = (_c = brandingConfig == null ? void 0 : brandingConfig.widgetSize) == null ? void 0 : _c.popupWidgets;
1539
+ const minWidth = (sizes == null ? void 0 : sizes.minWidth) ? formatWidth(sizes.minWidth) : "auto";
1540
+ const maxWidth = (sizes == null ? void 0 : sizes.maxWidth) ? formatWidth(sizes.maxWidth) : "500px";
1541
+ dialog.id = this.id;
1542
+ dialog.setAttribute(
1543
+ "style",
1544
+ `width: 100%; min-width: ${minWidth}; max-width: ${maxWidth}; border: none; padding: 0;`
1545
+ );
1546
+ const onClick = (e) => {
1547
+ e.stopPropagation();
1548
+ if (e.target === dialog) dialog.close();
1549
+ };
1550
+ dialog.addEventListener("click", onClick);
1551
+ return dialog;
1552
+ }
1553
+ /*
1554
+ async load() {
1555
+ const frame = this._createFrame();
1556
+ this._initialiseCTA();
1557
+
1558
+ const element = this.container ? this._findElement() : document.body;
1559
+
1560
+ const dialogParent = element.shadowRoot || element;
1561
+ const dialog = this._createPopupDialog();
1562
+ dialog.appendChild(frame);
1563
+
1564
+ const skeletonHTML = getSkeleton({
1565
+ height: "100%",
1566
+ type: "verified-access",
1567
+ });
1568
+
1569
+ const skeletonContainer = document.createElement("div");
1570
+ skeletonContainer.id = "loading-skeleton";
1571
+ skeletonContainer.innerHTML = skeletonHTML;
1572
+
1573
+ if (dialogParent.lastChild?.nodeName === "DIALOG") {
1574
+ // Was reloaded
1575
+ dialogParent.replaceChild(dialog, dialogParent.lastChild);
1576
+ } else {
1577
+ // First time rendering
1578
+ dialogParent.appendChild(dialog);
1579
+ }
1580
+
1581
+ const { contentWindow } = frame;
1582
+ if (!contentWindow) {
1583
+ throw new Error("Frame needs a content window");
1584
+ }
1585
+
1586
+ const frameDoc = contentWindow.document;
1587
+ frameDoc.open();
1588
+ frameDoc.write(this.content);
1589
+ frameDoc.write(
1590
+ `<script src="${this.npmCdn}/resize-observer-polyfill@1.5.x"><\/script>`
1591
+ );
1592
+ frameDoc.close();
1593
+ _log("Popup template loaded into iframe");
1594
+ await this._setupResizeHandler(frame);
1595
+ }
1596
+ */
1597
+ async load() {
1598
+ var _a2;
1599
+ const frame = this._createFrame();
1600
+ this._initialiseCTA();
1601
+ const element = this.container ? this._findElement() : document.body;
1602
+ const dialogParent = element.shadowRoot || element;
1603
+ const dialog = this._createPopupDialog();
1604
+ const skeletonHTML = getSkeleton({
1605
+ height: "100%",
1606
+ type: "verified-access"
1607
+ });
1608
+ const skeletonContainer = document.createElement("div");
1609
+ skeletonContainer.id = "loading-skeleton";
1610
+ skeletonContainer.innerHTML = skeletonHTML;
1611
+ skeletonContainer.style.width = "100%";
1612
+ frame.style.display = "none";
1613
+ dialog.appendChild(skeletonContainer);
1614
+ dialog.appendChild(frame);
1615
+ if (((_a2 = dialogParent.lastChild) == null ? void 0 : _a2.nodeName) === "DIALOG") {
1616
+ dialogParent.replaceChild(dialog, dialogParent.lastChild);
1617
+ } else {
1618
+ dialogParent.appendChild(dialog);
1619
+ }
1620
+ const removeSkeleton = () => {
1621
+ const skel = dialog.querySelector("#loading-skeleton");
1622
+ if (skel) {
1623
+ skel.remove();
1624
+ }
1625
+ frame.style.display = "block";
1626
+ };
1627
+ frame.addEventListener("sq:load", removeSkeleton);
1628
+ frame.addEventListener("load", removeSkeleton);
1629
+ const safetyTimer = setTimeout(() => {
1630
+ removeSkeleton();
1631
+ }, 5e3);
1632
+ const { contentWindow } = frame;
1633
+ if (!contentWindow) {
1634
+ throw new Error("Frame needs a content window");
1635
+ }
1636
+ const frameDoc = contentWindow.document;
1637
+ frameDoc.open();
1638
+ frameDoc.write(this.content);
1639
+ frameDoc.write(
1640
+ `<script src="${this.npmCdn}/resize-observer-polyfill@1.5.x"><\/script>`
1641
+ );
1642
+ frameDoc.close();
1643
+ _log$6("Popup template loaded into iframe");
1644
+ await this._setupResizeHandler(frame);
1645
+ clearTimeout(safetyTimer);
1646
+ removeSkeleton();
1647
+ }
1648
+ async _setupResizeHandler(frame) {
1649
+ const { contentWindow } = frame;
1650
+ if (!contentWindow) {
1651
+ throw new Error("Frame needs a content window");
1652
+ }
1653
+ const frameDoc = contentWindow.document;
1654
+ domready(frameDoc, async () => {
1655
+ frameDoc.body.style.overflowY = "hidden";
1656
+ frame.height = `${frameDoc.body.offsetHeight}px`;
1657
+ const ro = new contentWindow["ResizeObserver"]((entries) => {
1658
+ for (const entry of entries) {
1659
+ const { top, bottom } = entry.contentRect;
1660
+ const computedHeight = bottom + top;
1661
+ frame.height = computedHeight + "";
1662
+ entry.target.style = ``;
1663
+ }
1664
+ });
1665
+ ro.observe(await this._findInnerContainer(frame));
1666
+ });
1667
+ }
1668
+ open() {
1669
+ const element = this.container ? this._findElement() : document.body;
1670
+ const parent = element.shadowRoot || element;
1671
+ const dialog = parent.querySelector(`#${this.id}`);
1672
+ if (!dialog) throw new Error("Could not determine container div");
1673
+ dialog.showModal();
1674
+ const frame = this._findFrame();
1675
+ if (!frame) throw new Error("Could not find iframe");
1676
+ const { contentWindow } = frame;
1677
+ if (!contentWindow) throw new Error("Squatch.js has an empty iframe");
1678
+ const frameDoc = contentWindow.document;
1679
+ domready(frameDoc, () => {
1680
+ var _a2;
1681
+ const _sqh = contentWindow.squatch || contentWindow.widgetIdent;
1682
+ (_a2 = frame.contentDocument) == null ? void 0 : _a2.dispatchEvent(new CustomEvent("sq:refresh"));
1683
+ if (this.context.user) {
1684
+ this._loadEvent(_sqh);
1685
+ _log$6("Popup opened");
1686
+ } else {
1687
+ this._attachLoadEventListener(frameDoc, _sqh);
1688
+ }
1689
+ });
1690
+ }
1691
+ close() {
1692
+ const frame = this._findFrame();
1693
+ if (frame == null ? void 0 : frame.contentDocument)
1694
+ this._detachLoadEventListener(frame.contentDocument);
1695
+ const element = this.container ? this._findElement() : document.body;
1696
+ const parent = element.shadowRoot || element;
1697
+ const dialog = parent.querySelector(`#${this.id}`);
1698
+ if (!dialog) throw new Error("Could not determine container div");
1699
+ dialog.close();
1700
+ _log$6("Popup closed");
1701
+ }
1702
+ _clickedOutside({ target }) {
1703
+ }
1704
+ _error(rs, mode = "modal", style = "") {
1705
+ const _style = "body { margin: 0; } .modal { box-shadow: none; border: 0; }";
1706
+ return super._error(rs, mode, style || _style);
1707
+ }
1708
+ }
1709
+ const _log$5 = browserExports.debug("squatch-js:widgets");
1710
+ class Widgets {
1711
+ /**
1712
+ * Initialize a new {@link Widgets} instance.
1713
+ *
1714
+ * @param {ConfigOptions} config Config details
1715
+ *
1716
+ * @example <caption>Browser example</caption>
1717
+ * var widgets = new squatch.Widgets({tenantAlias:'test_12b5bo1b25125'});
1718
+ *
1719
+ * @example <caption>Browserify/Webpack example</caption>
1720
+ * var Widgets = require('@saasquatch/squatch-js').Widgets;
1721
+ * var widgets = new Widgets({tenantAlias:'test_12b5bo1b25125'});
1722
+ *
1723
+ * @example <caption>Babel+Browserify/Webpack example</caption>
1724
+ * import {Widgets} from '@saasquatch/squatch-js';
1725
+ * let widgets = new Widgets({tenantAlias:'test_12b5bo1b25125'});
1726
+ */
1727
+ constructor(configin) {
1728
+ /**
1729
+ * Instance of {@link WidgetApi}
1730
+ */
1731
+ __publicField(this, "api");
1732
+ /**
1733
+ * Tenant alias of SaaSquatch tenant
1734
+ */
1735
+ __publicField(this, "tenantAlias");
1736
+ /**
1737
+ * SaaSquatch domain for API requests
1738
+ * @default "https://app.referralsaasquatch.com"
1739
+ */
1740
+ __publicField(this, "domain");
1741
+ /**
1742
+ * Hosted CDN for npm packages
1743
+ * @default "https://fast.ssqt.io/npm"
1744
+ */
1745
+ __publicField(this, "npmCdn");
1746
+ const config = validateConfig(configin);
1747
+ this.tenantAlias = config.tenantAlias;
1748
+ this.domain = config.domain;
1749
+ this.npmCdn = config.npmCdn;
1750
+ this.api = new WidgetApi(config);
1751
+ }
1752
+ /**
1753
+ * This function calls the {@link WidgetApi.upsertUser} method, and it renders
1754
+ * the widget if it is successful. Otherwise it shows the "error" widget.
1755
+ *
1756
+ * @param {Object} config Config details
1757
+ * @param {Object} config.user The user details
1758
+ * @param {string} config.user.id The user id
1759
+ * @param {string} config.user.accountId The user account id
1760
+ * @param {WidgetType} config.widgetType The content of the widget
1761
+ * @param {EngagementMedium} config.engagementMedium How to display the widget
1762
+ * @param {string} config.jwt the JSON Web Token (JWT) that is used to validate the data (can be disabled)
1763
+ * @param {HTMLElement | string | undefined} config.container Element to load the widget into
1764
+ * @param {string | undefined} config.trigger Trigger element for opening the popup widget
1765
+ *
1766
+ * @return {Promise<WidgetResult>} json object if true, with a Widget and user details
1767
+ */
1768
+ async upsertUser(config) {
1769
+ const raw = config;
1770
+ const clean = validateWidgetConfig(raw);
1771
+ try {
1772
+ const response = await this.api.upsertUser(clean);
1773
+ return {
1774
+ widget: this._renderWidget(response, clean, {
1775
+ type: "upsert",
1776
+ user: clean.user,
1777
+ engagementMedium: config.engagementMedium,
1778
+ container: config.container,
1779
+ trigger: config.trigger,
1780
+ widgetConfig: {
1781
+ values: {
1782
+ brandingConfig: response == null ? void 0 : response.brandingConfig
1783
+ }
1784
+ }
1785
+ }),
1786
+ user: response.user
1787
+ };
1788
+ } catch (err) {
1789
+ _log$5(err);
1790
+ if (err.apiErrorCode) {
1791
+ this._renderErrorWidget(err, config.engagementMedium);
1792
+ }
1793
+ throw new Error(err);
1794
+ }
1795
+ }
1796
+ /**
1797
+ * This function calls the {@link WidgetApi.render} method, and it renders
1798
+ * the widget if it is successful. Otherwise it shows the "error" widget.
1799
+ *
1800
+ * @param {Object} config Config details
1801
+ * @param {Object} config.user The user details
1802
+ * @param {string} config.user.id The user id
1803
+ * @param {string} config.user.accountId The user account id
1804
+ * @param {WidgetType} config.widgetType The content of the widget
1805
+ * @param {EngagementMedium} config.engagementMedium How to display the widget
1806
+ * @param {string} config.jwt the JSON Web Token (JWT) that is used
1807
+ * to validate the data (can be disabled)
1808
+ *
1809
+ * @return {Promise<WidgetResult>} json object if true, with a Widget and user details
1810
+ */
1811
+ async render(config) {
1812
+ const raw = config;
1813
+ const clean = validatePasswordlessConfig(raw);
1814
+ try {
1815
+ const response = await this.api.render(clean);
1816
+ return {
1817
+ widget: this._renderWidget(response, clean, {
1818
+ type: "passwordless",
1819
+ engagementMedium: clean.engagementMedium,
1820
+ container: clean.container,
1821
+ trigger: clean.trigger,
1822
+ widgetConfig: {
1823
+ values: {
1824
+ brandingConfig: response == null ? void 0 : response.brandingConfig
1825
+ }
1826
+ }
1827
+ }),
1828
+ user: response.user
1829
+ };
1830
+ } catch (err) {
1831
+ if (err.apiErrorCode) {
1832
+ this._renderErrorWidget(err, clean.engagementMedium);
2088
1833
  }
2089
-
2090
- .col-user { flex: 2; }
2091
- .col-status { flex: 1; }
2092
- .col-reward { flex: 2; }
2093
- .col-date { flex: 1; }
2094
-
2095
- .sk-badge { height: 28px; width: 90px; border-radius: 14px; }
2096
- .sk-reward-block { height: 36px; width: 100%; border-radius: 6px; }
2097
-
2098
- .pagination { display: flex; justify-content: flex-end; gap: 8px; margin-top: 24px; }
2099
- .sk-btn-page { height: 36px; width: 64px; border-radius: 6px; margin-bottom: 0; }
2100
-
2101
- @media (max-width: 768px) {
2102
- body { padding: 20px; }
2103
- .widget-container { padding: 24px; }
2104
-
2105
- .hero-section { flex-direction: column-reverse; gap: 24px; }
2106
- .instant-access-layout { flex-direction: column; }
2107
-
2108
- .hero-image { height: 220px; width: 100%; }
2109
- .sk-title-lg { width: 100%; }
2110
-
2111
- .col-date { display: none; }
1834
+ throw new Error(err);
1835
+ }
1836
+ }
1837
+ /**
1838
+ * Autofills a referral code into an element when someone has been referred.
1839
+ * Uses {@link WidgetApi.squatchReferralCookie} behind the scenes.
1840
+ *
1841
+ * @param selector Element class/id selector, or a callback function
1842
+ * @returns
1843
+ */
1844
+ async autofill(selector) {
1845
+ const input = selector;
1846
+ if (typeof input === "function") {
1847
+ try {
1848
+ const response = await this.api.squatchReferralCookie();
1849
+ input(response);
1850
+ } catch (e) {
1851
+ _log$5("Autofill error", e);
1852
+ throw new Error(e);
2112
1853
  }
2113
- </style>
2114
-
2115
- <div class="widget-container">
2116
- ${type === "verified-access" ? referrerHTML : instantAccessHTML}
2117
- </div>
2118
- `;
1854
+ return;
1855
+ }
1856
+ if (typeof input !== "string")
1857
+ throw new Error("Autofill accepts a string or function");
1858
+ let elems = document.querySelectorAll(input);
1859
+ let elem;
1860
+ if (elems.length > 0) {
1861
+ elem = elems[0];
1862
+ } else {
1863
+ _log$5("Element id/class or function missing");
1864
+ throw new Error("Element id/class or function missing");
1865
+ }
1866
+ try {
1867
+ const response = await this.api.squatchReferralCookie();
1868
+ elem.value = response.codes[0];
1869
+ } catch (e) {
1870
+ throw new Error(e);
1871
+ }
1872
+ }
1873
+ /**
1874
+ * @hidden
1875
+ * @param {Object} response The json object return from the WidgetApi
1876
+ * @param {Object} config Config details
1877
+ * @param {string} config.widgetType The widget type (REFERRER_WIDGET, CONVERSION_WIDGET)
1878
+ * @param {string} config.engagementMedium (POPUP, EMBED)
1879
+ * @returns {Widget} widget (PopupWidget or EmbedWidget)
1880
+ */
1881
+ _renderWidget(response, config, context) {
1882
+ var _a2;
1883
+ _log$5("Rendering Widget...");
1884
+ if (!response) throw new Error("Unable to get a response");
1885
+ let widget2;
1886
+ let displayOnLoad = !!config.displayOnLoad;
1887
+ const opts = response.jsOptions || {};
1888
+ const params = {
1889
+ content: response.template,
1890
+ type: config.widgetType || ((_a2 = opts.widget) == null ? void 0 : _a2.defaultWidgetType),
1891
+ api: this.api,
1892
+ domain: this.domain,
1893
+ npmCdn: this.npmCdn,
1894
+ context
1895
+ };
1896
+ if (opts.widgetUrlMappings) {
1897
+ opts.widgetUrlMappings.forEach((rule) => {
1898
+ var _a3, _b;
1899
+ if (Widgets._matchesUrl(rule.url)) {
1900
+ if (rule.widgetType !== "CONVERSION_WIDGET" || ((_b = (_a3 = response.user) == null ? void 0 : _a3.referredBy) == null ? void 0 : _b.code)) {
1901
+ displayOnLoad = rule.displayOnLoad;
1902
+ _log$5(`Display ${rule.widgetType} on ${rule.url}`);
1903
+ } else {
1904
+ _log$5(
1905
+ `Don't display ${rule.widgetType} when no referral on widget rule match ${rule.url}`
1906
+ );
1907
+ }
1908
+ }
1909
+ });
1910
+ }
1911
+ if (opts.fuelTankAutofillUrls) {
1912
+ _log$5("We found a fuel tank autofill!");
1913
+ opts.fuelTankAutofillUrls.forEach(({ url, formSelector }) => {
1914
+ var _a3, _b, _c;
1915
+ if (Widgets._matchesUrl(url)) {
1916
+ _log$5("Fuel Tank URL matches");
1917
+ if ((_b = (_a3 = response.user) == null ? void 0 : _a3.referredBy) == null ? void 0 : _b.code) {
1918
+ const formAutofill = document.querySelector(formSelector);
1919
+ if (formAutofill) {
1920
+ formAutofill.value = ((_c = response.user.referredBy.referredReward) == null ? void 0 : _c.fuelTankCode) || "";
1921
+ } else {
1922
+ _log$5(
1923
+ new Error(
1924
+ `Element with id/class ${formSelector} was not found.`
1925
+ )
1926
+ );
1927
+ }
1928
+ }
1929
+ }
1930
+ });
1931
+ }
1932
+ if (config.engagementMedium === "EMBED") {
1933
+ widget2 = this._renderEmbedWidget(params);
1934
+ } else {
1935
+ widget2 = this._renderPopupWidget(params);
1936
+ if (displayOnLoad) widget2.open();
1937
+ }
1938
+ return widget2;
1939
+ }
1940
+ _renderPopupWidget(params) {
1941
+ const widget2 = new PopupWidget(params, params.context.trigger);
1942
+ widget2.load();
1943
+ return widget2;
1944
+ }
1945
+ _renderEmbedWidget(params) {
1946
+ const widget2 = new EmbedWidget(params, params.context.container);
1947
+ widget2.load();
1948
+ return widget2;
1949
+ }
1950
+ /**
1951
+ * @hidden
1952
+ * @param {Object} error The json object containing the error details
1953
+ * @param {string} em The engagementMedium
1954
+ * @returns {void}
1955
+ */
1956
+ _renderErrorWidget(props, em = "POPUP") {
1957
+ const { apiErrorCode, rsCode, message } = props;
1958
+ _log$5(new Error(`${apiErrorCode} (${rsCode}) ${message}`));
1959
+ const params = {
1960
+ content: "error",
1961
+ rsCode,
1962
+ api: this.api,
1963
+ domain: this.domain,
1964
+ npmCdn: this.npmCdn,
1965
+ type: "ERROR_WIDGET",
1966
+ context: { type: "error" }
1967
+ };
1968
+ let widget2;
1969
+ if (em === "EMBED") {
1970
+ widget2 = new EmbedWidget(params);
1971
+ widget2.load();
1972
+ } else if (em === "POPUP") {
1973
+ widget2 = new PopupWidget(params);
1974
+ widget2.load();
1975
+ }
1976
+ }
1977
+ /**
1978
+ * @hidden
1979
+ * @param {string} rule A regular expression
1980
+ * @returns {boolean} true if rule matches Url, false otherwise
1981
+ */
1982
+ static _matchesUrl(rule) {
1983
+ return window.location.href.match(new RegExp(rule)) ? true : false;
1984
+ }
1985
+ }
1986
+ class EventsApi {
1987
+ /**
1988
+ * Initialize a new {@link EventsApi} instance.
1989
+ *
1990
+ * @param {ConfigOptions} config Config details
1991
+ *
1992
+ * @example <caption>Browser example</caption>
1993
+ * var squatchApi = new squatch.EventsApi({tenantAlias:'test_12b5bo1b25125'});
1994
+ *
1995
+ * @example <caption>Browserify/Webpack example</caption>
1996
+ * var EventsApi = require('@saasquatch/squatch-js').EventsApi;
1997
+ * var squatchApi = new EventsApi({tenantAlias:'test_12b5bo1b25125'});
1998
+ *
1999
+ * @example <caption>Babel+Browserify/Webpack example</caption>
2000
+ * import {EventsApi} from '@saasquatch/squatch-js';
2001
+ * let squatchApi = new EventsApi({tenantAlias:'test_12b5bo1b25125'});
2002
+ */
2003
+ constructor(config) {
2004
+ __publicField(this, "tenantAlias");
2005
+ __publicField(this, "domain");
2006
+ const raw = config;
2007
+ const clean = validateConfig(raw);
2008
+ this.tenantAlias = clean.tenantAlias;
2009
+ this.domain = clean.domain;
2010
+ }
2011
+ /**
2012
+ * Track an event for a user
2013
+ *
2014
+ * @param params Parameters for request
2015
+ * @param options.jwt the JSON Web Token (JWT) that is used to authenticate the user
2016
+ *
2017
+ * @return An ID to confirm the event has been accepted for asynchronous processing
2018
+ */
2019
+ track(params, options) {
2020
+ const raw = params;
2021
+ const rawOpts = options;
2022
+ const body = _validateEvent(raw);
2023
+ const { jwt } = _validateTrackOptions(rawOpts);
2024
+ const ta = encodeURIComponent(this.tenantAlias);
2025
+ const userId = encodeURIComponent(body.userId);
2026
+ const accountId = encodeURIComponent(body.accountId);
2027
+ const path = `/api/v1/${ta}/open/account/${accountId}/user/${userId}/events`;
2028
+ const url = this.domain + path;
2029
+ return doPost(url, JSON.stringify(body), jwt);
2030
+ }
2031
+ }
2032
+ function _validateEvent(raw) {
2033
+ if (!isObject$1(raw)) throw new Error("tracking parameter must be an object");
2034
+ if (!(raw == null ? void 0 : raw["accountId"])) throw new Error("accountId field is required");
2035
+ if (!(raw == null ? void 0 : raw["events"])) throw new Error("events field is required");
2036
+ if (!(raw == null ? void 0 : raw["userId"])) throw new Error("userId field is required");
2037
+ const clean = raw;
2038
+ if (!Array.isArray(clean.events))
2039
+ throw new Error("'events' should be an array");
2040
+ return clean;
2041
+ }
2042
+ function _validateTrackOptions(raw) {
2043
+ if (!isObject$1(raw)) throw new Error("'options' should be an object");
2044
+ return raw;
2045
+ }
2046
+ function asyncLoad() {
2047
+ var _a2;
2048
+ const namespace = window[IMPACT_NAMESPACE] ? IMPACT_NAMESPACE : DEFAULT_NAMESPACE;
2049
+ const cached = ((_a2 = window["_" + namespace]) == null ? void 0 : _a2.ready) || [];
2050
+ const declarativeCache = window.impactOnReady || window.squatchOnReady;
2051
+ const readyFns = [...cached, declarativeCache].filter((a) => !!a);
2052
+ setTimeout(() => {
2053
+ if (!window[DEFAULT_NAMESPACE]) return;
2054
+ window[IMPACT_NAMESPACE] = window[DEFAULT_NAMESPACE];
2055
+ readyFns.forEach((cb) => cb());
2056
+ window[DEFAULT_NAMESPACE]._auto();
2057
+ window["_" + namespace] = void 0;
2058
+ delete window["_" + namespace];
2059
+ }, 0);
2060
+ }
2061
+ const _log$4 = browserExports.debug("squatch-js");
2062
+ const isObject = (item) => typeof item === "object" && !Array.isArray(item);
2063
+ const deepMerge = (target, source) => {
2064
+ const isDeep = (prop) => isObject(source[prop]) && target.hasOwnProperty(prop) && isObject(target[prop]);
2065
+ const replaced = Object.getOwnPropertyNames(source).map((prop) => ({
2066
+ [prop]: isDeep(prop) ? deepMerge(target[prop], source[prop]) : source[prop]
2067
+ })).reduce((a, b) => ({ ...a, ...b }), {});
2068
+ return {
2069
+ ...target,
2070
+ ...replaced
2071
+ };
2119
2072
  };
2073
+ function b64decode(input) {
2074
+ const binary = atob(input.replace(/_/g, "/").replace(/-/g, "+"));
2075
+ const bytes = new Uint8Array(binary.length);
2076
+ for (let i = 0; i < binary.length; i++) {
2077
+ bytes[i] = binary.charCodeAt(i);
2078
+ }
2079
+ return new TextDecoder("utf8").decode(bytes);
2080
+ }
2081
+ function b64encode(input) {
2082
+ const encodedInput = new TextEncoder().encode(input);
2083
+ const binary = Array.from(
2084
+ encodedInput,
2085
+ (byte) => String.fromCodePoint(byte)
2086
+ ).join("");
2087
+ return btoa(binary).replace(/=/g, "").replace(/\+/g, "-").replace(/\//g, "_");
2088
+ }
2089
+ function getTopDomain() {
2090
+ var i, h, weird_cookie = "weird_get_top_level_domain=cookie", hostname = document.location.hostname.split(".");
2091
+ for (i = hostname.length - 1; i >= 0; i--) {
2092
+ h = hostname.slice(i).join(".");
2093
+ document.cookie = weird_cookie + ";domain=." + h + ";";
2094
+ if (document.cookie.indexOf(weird_cookie) > -1) {
2095
+ document.cookie = weird_cookie.split("=")[0] + "=;domain=." + h + ";expires=Thu, 01 Jan 1970 00:00:01 GMT;";
2096
+ return h;
2097
+ }
2098
+ }
2099
+ }
2100
+ function _pushCookie() {
2101
+ const queryString = window.location.search;
2102
+ const urlParams = new URLSearchParams(queryString);
2103
+ const refParam = urlParams.get("_saasquatch") || "";
2104
+ if (refParam) {
2105
+ let paramsJSON = "", existingCookie = "", reEncodedCookie = "";
2106
+ try {
2107
+ paramsJSON = JSON.parse(b64decode(refParam));
2108
+ } catch (error) {
2109
+ _log$4("Unable to decode params", error);
2110
+ return;
2111
+ }
2112
+ try {
2113
+ existingCookie = JSON.parse(b64decode(api$1.get("_saasquatch")));
2114
+ _log$4("existing cookie", existingCookie);
2115
+ } catch (error) {
2116
+ _log$4("Unable to retrieve cookie", error);
2117
+ }
2118
+ try {
2119
+ const domain = getTopDomain();
2120
+ _log$4("domain retrieved:", domain);
2121
+ if (existingCookie) {
2122
+ const newCookie = deepMerge(existingCookie, paramsJSON);
2123
+ reEncodedCookie = b64encode(JSON.stringify(newCookie));
2124
+ _log$4("cookie to store:", newCookie);
2125
+ } else {
2126
+ reEncodedCookie = b64encode(JSON.stringify(paramsJSON));
2127
+ _log$4("cookie to store:", paramsJSON);
2128
+ }
2129
+ api$1.set("_saasquatch", reEncodedCookie, {
2130
+ expires: 365,
2131
+ secure: false,
2132
+ sameSite: "Lax",
2133
+ domain,
2134
+ path: "/"
2135
+ });
2136
+ } catch (error) {
2137
+ _log$4("Unable to set cookie", error);
2138
+ }
2139
+ }
2140
+ }
2141
+ const _log$3 = browserExports.debug("squatch-js");
2142
+ function _getAutoConfig() {
2143
+ var _a2;
2144
+ const queryString = window.location.search;
2145
+ const urlParams = new URLSearchParams(queryString);
2146
+ const refParam = urlParams.get("_saasquatchExtra") || "";
2147
+ if (!refParam) {
2148
+ _log$3("No _saasquatchExtra param");
2149
+ return;
2150
+ }
2151
+ const config = validateConfig({
2152
+ tenantAlias: "UNKNOWN"
2153
+ });
2154
+ if (!config.domain) {
2155
+ _log$3("domain must be provided in config to use _saasquatchExtra");
2156
+ return;
2157
+ }
2158
+ let raw;
2159
+ try {
2160
+ raw = JSON.parse(b64decode(refParam));
2161
+ } catch (e) {
2162
+ _log$3("Unable to decode _saasquatchExtra config");
2163
+ return;
2164
+ }
2165
+ function normalizeDomain(domain) {
2166
+ return domain.replace(/^https?:\/\//, "");
2167
+ }
2168
+ const normalizedDomain = normalizeDomain(config.domain);
2169
+ const tenantAlias = Object.keys((raw == null ? void 0 : raw[normalizedDomain]) || {})[0];
2170
+ const widgetConfig = (_a2 = raw == null ? void 0 : raw[normalizedDomain]) == null ? void 0 : _a2[tenantAlias];
2171
+ if (!widgetConfig) {
2172
+ _log$3("_saasquatchExtra did not have an expected structure");
2173
+ return void 0;
2174
+ }
2175
+ const { autoPopupWidgetType, ...rest } = widgetConfig;
2176
+ return {
2177
+ widgetConfig: {
2178
+ widgetType: autoPopupWidgetType,
2179
+ displayOnLoad: true,
2180
+ ...rest
2181
+ },
2182
+ squatchConfig: {
2183
+ ...config,
2184
+ tenantAlias
2185
+ }
2186
+ };
2187
+ }
2120
2188
  const _log$2 = browserExports.debug("squatch-js:decodeUserJwt");
2121
2189
  function decodeUserJwt(tokenStr) {
2122
2190
  var _a2;
@@ -2414,8 +2482,12 @@ class DeclarativePopupWidget extends DeclarativeWidget {
2414
2482
  skeletonContainer.id = "loading-skeleton";
2415
2483
  skeletonContainer.innerHTML = skeletonHTML;
2416
2484
  const root = this.shadowRoot || this.attachShadow({ mode: "open" });
2417
- root.innerHTML = "";
2418
- root.appendChild(skeletonContainer);
2485
+ const container = root.getElementById("#squatchModal");
2486
+ console.log("Container is ", container);
2487
+ if (container) {
2488
+ container.innerHTML = "";
2489
+ container.appendChild(skeletonContainer);
2490
+ }
2419
2491
  await this.renderWidget();
2420
2492
  const loadingElement = root.getElementById("loading-skeleton");
2421
2493
  if (loadingElement) {