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