@product7/product7-js 0.2.1 → 0.2.3

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.
@@ -1024,8 +1024,12 @@
1024
1024
  if (!env || env === 'production') {
1025
1025
  const hostname =
1026
1026
  (typeof window !== 'undefined' && window.location?.hostname) || '';
1027
+ const port =
1028
+ (typeof window !== 'undefined' && window.location?.port) || '';
1027
1029
  if (hostname.includes('staging')) {
1028
1030
  env = 'staging';
1031
+ } else if (hostname === 'app.localhost' && port === '3005') {
1032
+ env = 'localstack';
1029
1033
  }
1030
1034
  }
1031
1035
 
@@ -1632,250 +1636,6 @@
1632
1636
  }
1633
1637
  }
1634
1638
 
1635
- function generateId(prefix = 'feedback') {
1636
- const timestamp = Date.now();
1637
- const random = Math.random().toString(36).substring(2, 9);
1638
- return `${prefix}_${timestamp}_${random}`;
1639
- }
1640
-
1641
- function deepMerge(target, source) {
1642
- const result = { ...target };
1643
-
1644
- for (const key in source) {
1645
- if (source.hasOwnProperty(key)) {
1646
- if (
1647
- source[key] &&
1648
- typeof source[key] === 'object' &&
1649
- !Array.isArray(source[key])
1650
- ) {
1651
- result[key] = deepMerge(target[key] || {}, source[key]);
1652
- } else {
1653
- result[key] = source[key];
1654
- }
1655
- }
1656
- }
1657
-
1658
- return result;
1659
- }
1660
-
1661
- function debounce(func, wait) {
1662
- let timeout;
1663
- return function executedFunction(...args) {
1664
- const later = () => {
1665
- clearTimeout(timeout);
1666
- func(...args);
1667
- };
1668
- clearTimeout(timeout);
1669
- timeout = setTimeout(later, wait);
1670
- };
1671
- }
1672
-
1673
- function throttle(func, limit) {
1674
- let lastFunc;
1675
- let lastRan;
1676
- return function (...args) {
1677
- if (!lastRan) {
1678
- func(...args);
1679
- lastRan = Date.now();
1680
- } else {
1681
- clearTimeout(lastFunc);
1682
- lastFunc = setTimeout(
1683
- () => {
1684
- if (Date.now() - lastRan >= limit) {
1685
- func(...args);
1686
- lastRan = Date.now();
1687
- }
1688
- },
1689
- limit - (Date.now() - lastRan)
1690
- );
1691
- }
1692
- };
1693
- }
1694
-
1695
- function isValidEmail(email) {
1696
- if (!email || typeof email !== 'string') return false;
1697
-
1698
- const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
1699
- return emailRegex.test(email.trim());
1700
- }
1701
-
1702
- function sanitizeHTML(str) {
1703
- if (!str || typeof str !== 'string') return '';
1704
-
1705
- const div = document.createElement('div');
1706
- div.textContent = str;
1707
- return div.innerHTML;
1708
- }
1709
-
1710
- function getCSSProperty(element, property, fallback = '') {
1711
- if (!element || !property) return fallback;
1712
-
1713
- try {
1714
- const style = window.getComputedStyle(element);
1715
- return style.getPropertyValue(property) || fallback;
1716
- } catch (error) {
1717
- return fallback;
1718
- }
1719
- }
1720
-
1721
- function isInViewport(element) {
1722
- if (!element) return false;
1723
-
1724
- const rect = element.getBoundingClientRect();
1725
- return (
1726
- rect.top >= 0 &&
1727
- rect.left >= 0 &&
1728
- rect.bottom <=
1729
- (window.innerHeight || document.documentElement.clientHeight) &&
1730
- rect.right <= (window.innerWidth || document.documentElement.clientWidth)
1731
- );
1732
- }
1733
-
1734
- function scrollToElement(element, options = {}) {
1735
- if (!element) return;
1736
-
1737
- const defaultOptions = {
1738
- behavior: 'smooth',
1739
- block: 'center',
1740
- inline: 'nearest',
1741
- };
1742
-
1743
- element.scrollIntoView({ ...defaultOptions, ...options });
1744
- }
1745
-
1746
- function getBrowserInfo() {
1747
- const userAgent = navigator.userAgent;
1748
- const platform = navigator.platform;
1749
-
1750
- return {
1751
- userAgent,
1752
- platform,
1753
- language: navigator.language || navigator.userLanguage,
1754
- cookieEnabled: navigator.cookieEnabled,
1755
- screenResolution: `${screen.width}x${screen.height}`,
1756
- windowSize: `${window.innerWidth}x${window.innerHeight}`,
1757
- timezone: Intl.DateTimeFormat().resolvedOptions().timeZone,
1758
- };
1759
- }
1760
-
1761
- function formatFileSize(bytes) {
1762
- if (bytes === 0) return '0 Bytes';
1763
-
1764
- const k = 1024;
1765
- const sizes = ['Bytes', 'KB', 'MB', 'GB'];
1766
- const i = Math.floor(Math.log(bytes) / Math.log(k));
1767
-
1768
- return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
1769
- }
1770
-
1771
- function delay(ms) {
1772
- return new Promise((resolve) => setTimeout(resolve, ms));
1773
- }
1774
-
1775
- function safeJsonParse(str, fallback = null) {
1776
- try {
1777
- return JSON.parse(str);
1778
- } catch (error) {
1779
- return fallback;
1780
- }
1781
- }
1782
-
1783
- function escapeRegex(string) {
1784
- return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
1785
- }
1786
-
1787
- function getNestedProperty(obj, path, defaultValue = undefined) {
1788
- if (!obj || !path) return defaultValue;
1789
-
1790
- const keys = path.split('.');
1791
- let current = obj;
1792
-
1793
- for (const key of keys) {
1794
- if (current === null || current === undefined || !(key in current)) {
1795
- return defaultValue;
1796
- }
1797
- current = current[key];
1798
- }
1799
-
1800
- return current;
1801
- }
1802
-
1803
- function setNestedProperty(obj, path, value) {
1804
- if (!obj || !path) return obj;
1805
-
1806
- const keys = path.split('.');
1807
- const lastKey = keys.pop();
1808
- let current = obj;
1809
-
1810
- for (const key of keys) {
1811
- if (!(key in current) || typeof current[key] !== 'object') {
1812
- current[key] = {};
1813
- }
1814
- current = current[key];
1815
- }
1816
-
1817
- current[lastKey] = value;
1818
- return obj;
1819
- }
1820
-
1821
- function isBrowser() {
1822
- return typeof window !== 'undefined' && typeof document !== 'undefined';
1823
- }
1824
-
1825
- function isMobile() {
1826
- if (!isBrowser()) return false;
1827
-
1828
- return (
1829
- /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(
1830
- navigator.userAgent
1831
- ) || window.innerWidth <= 768
1832
- );
1833
- }
1834
-
1835
- function getCurrentTimestamp() {
1836
- return new Date().toISOString();
1837
- }
1838
-
1839
- function validateConfig(config, required = []) {
1840
- const missing = [];
1841
-
1842
- for (const key of required) {
1843
- if (!config[key]) {
1844
- missing.push(key);
1845
- }
1846
- }
1847
-
1848
- if (missing.length > 0) {
1849
- throw new Error(`Missing required configuration: ${missing.join(', ')}`);
1850
- }
1851
-
1852
- return true;
1853
- }
1854
-
1855
- var helpers = /*#__PURE__*/Object.freeze({
1856
- __proto__: null,
1857
- debounce: debounce,
1858
- deepMerge: deepMerge,
1859
- delay: delay,
1860
- escapeRegex: escapeRegex,
1861
- formatFileSize: formatFileSize,
1862
- generateId: generateId,
1863
- getBrowserInfo: getBrowserInfo,
1864
- getCSSProperty: getCSSProperty,
1865
- getCurrentTimestamp: getCurrentTimestamp,
1866
- getNestedProperty: getNestedProperty,
1867
- isBrowser: isBrowser,
1868
- isInViewport: isInViewport,
1869
- isMobile: isMobile,
1870
- isValidEmail: isValidEmail,
1871
- safeJsonParse: safeJsonParse,
1872
- sanitizeHTML: sanitizeHTML,
1873
- scrollToElement: scrollToElement,
1874
- setNestedProperty: setNestedProperty,
1875
- throttle: throttle,
1876
- validateConfig: validateConfig
1877
- });
1878
-
1879
1639
  const baseStyles = `
1880
1640
  .feedback-widget,
1881
1641
  .messenger-widget,
@@ -6511,6 +6271,250 @@
6511
6271
  surveyStyles +
6512
6272
  messengerStyles;
6513
6273
 
6274
+ function generateId(prefix = 'feedback') {
6275
+ const timestamp = Date.now();
6276
+ const random = Math.random().toString(36).substring(2, 9);
6277
+ return `${prefix}_${timestamp}_${random}`;
6278
+ }
6279
+
6280
+ function deepMerge(target, source) {
6281
+ const result = { ...target };
6282
+
6283
+ for (const key in source) {
6284
+ if (source.hasOwnProperty(key)) {
6285
+ if (
6286
+ source[key] &&
6287
+ typeof source[key] === 'object' &&
6288
+ !Array.isArray(source[key])
6289
+ ) {
6290
+ result[key] = deepMerge(target[key] || {}, source[key]);
6291
+ } else {
6292
+ result[key] = source[key];
6293
+ }
6294
+ }
6295
+ }
6296
+
6297
+ return result;
6298
+ }
6299
+
6300
+ function debounce(func, wait) {
6301
+ let timeout;
6302
+ return function executedFunction(...args) {
6303
+ const later = () => {
6304
+ clearTimeout(timeout);
6305
+ func(...args);
6306
+ };
6307
+ clearTimeout(timeout);
6308
+ timeout = setTimeout(later, wait);
6309
+ };
6310
+ }
6311
+
6312
+ function throttle(func, limit) {
6313
+ let lastFunc;
6314
+ let lastRan;
6315
+ return function (...args) {
6316
+ if (!lastRan) {
6317
+ func(...args);
6318
+ lastRan = Date.now();
6319
+ } else {
6320
+ clearTimeout(lastFunc);
6321
+ lastFunc = setTimeout(
6322
+ () => {
6323
+ if (Date.now() - lastRan >= limit) {
6324
+ func(...args);
6325
+ lastRan = Date.now();
6326
+ }
6327
+ },
6328
+ limit - (Date.now() - lastRan)
6329
+ );
6330
+ }
6331
+ };
6332
+ }
6333
+
6334
+ function isValidEmail(email) {
6335
+ if (!email || typeof email !== 'string') return false;
6336
+
6337
+ const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
6338
+ return emailRegex.test(email.trim());
6339
+ }
6340
+
6341
+ function sanitizeHTML(str) {
6342
+ if (!str || typeof str !== 'string') return '';
6343
+
6344
+ const div = document.createElement('div');
6345
+ div.textContent = str;
6346
+ return div.innerHTML;
6347
+ }
6348
+
6349
+ function getCSSProperty(element, property, fallback = '') {
6350
+ if (!element || !property) return fallback;
6351
+
6352
+ try {
6353
+ const style = window.getComputedStyle(element);
6354
+ return style.getPropertyValue(property) || fallback;
6355
+ } catch (error) {
6356
+ return fallback;
6357
+ }
6358
+ }
6359
+
6360
+ function isInViewport(element) {
6361
+ if (!element) return false;
6362
+
6363
+ const rect = element.getBoundingClientRect();
6364
+ return (
6365
+ rect.top >= 0 &&
6366
+ rect.left >= 0 &&
6367
+ rect.bottom <=
6368
+ (window.innerHeight || document.documentElement.clientHeight) &&
6369
+ rect.right <= (window.innerWidth || document.documentElement.clientWidth)
6370
+ );
6371
+ }
6372
+
6373
+ function scrollToElement(element, options = {}) {
6374
+ if (!element) return;
6375
+
6376
+ const defaultOptions = {
6377
+ behavior: 'smooth',
6378
+ block: 'center',
6379
+ inline: 'nearest',
6380
+ };
6381
+
6382
+ element.scrollIntoView({ ...defaultOptions, ...options });
6383
+ }
6384
+
6385
+ function getBrowserInfo() {
6386
+ const userAgent = navigator.userAgent;
6387
+ const platform = navigator.platform;
6388
+
6389
+ return {
6390
+ userAgent,
6391
+ platform,
6392
+ language: navigator.language || navigator.userLanguage,
6393
+ cookieEnabled: navigator.cookieEnabled,
6394
+ screenResolution: `${screen.width}x${screen.height}`,
6395
+ windowSize: `${window.innerWidth}x${window.innerHeight}`,
6396
+ timezone: Intl.DateTimeFormat().resolvedOptions().timeZone,
6397
+ };
6398
+ }
6399
+
6400
+ function formatFileSize(bytes) {
6401
+ if (bytes === 0) return '0 Bytes';
6402
+
6403
+ const k = 1024;
6404
+ const sizes = ['Bytes', 'KB', 'MB', 'GB'];
6405
+ const i = Math.floor(Math.log(bytes) / Math.log(k));
6406
+
6407
+ return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
6408
+ }
6409
+
6410
+ function delay(ms) {
6411
+ return new Promise((resolve) => setTimeout(resolve, ms));
6412
+ }
6413
+
6414
+ function safeJsonParse(str, fallback = null) {
6415
+ try {
6416
+ return JSON.parse(str);
6417
+ } catch (error) {
6418
+ return fallback;
6419
+ }
6420
+ }
6421
+
6422
+ function escapeRegex(string) {
6423
+ return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
6424
+ }
6425
+
6426
+ function getNestedProperty(obj, path, defaultValue = undefined) {
6427
+ if (!obj || !path) return defaultValue;
6428
+
6429
+ const keys = path.split('.');
6430
+ let current = obj;
6431
+
6432
+ for (const key of keys) {
6433
+ if (current === null || current === undefined || !(key in current)) {
6434
+ return defaultValue;
6435
+ }
6436
+ current = current[key];
6437
+ }
6438
+
6439
+ return current;
6440
+ }
6441
+
6442
+ function setNestedProperty(obj, path, value) {
6443
+ if (!obj || !path) return obj;
6444
+
6445
+ const keys = path.split('.');
6446
+ const lastKey = keys.pop();
6447
+ let current = obj;
6448
+
6449
+ for (const key of keys) {
6450
+ if (!(key in current) || typeof current[key] !== 'object') {
6451
+ current[key] = {};
6452
+ }
6453
+ current = current[key];
6454
+ }
6455
+
6456
+ current[lastKey] = value;
6457
+ return obj;
6458
+ }
6459
+
6460
+ function isBrowser() {
6461
+ return typeof window !== 'undefined' && typeof document !== 'undefined';
6462
+ }
6463
+
6464
+ function isMobile() {
6465
+ if (!isBrowser()) return false;
6466
+
6467
+ return (
6468
+ /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(
6469
+ navigator.userAgent
6470
+ ) || window.innerWidth <= 768
6471
+ );
6472
+ }
6473
+
6474
+ function getCurrentTimestamp() {
6475
+ return new Date().toISOString();
6476
+ }
6477
+
6478
+ function validateConfig(config, required = []) {
6479
+ const missing = [];
6480
+
6481
+ for (const key of required) {
6482
+ if (!config[key]) {
6483
+ missing.push(key);
6484
+ }
6485
+ }
6486
+
6487
+ if (missing.length > 0) {
6488
+ throw new Error(`Missing required configuration: ${missing.join(', ')}`);
6489
+ }
6490
+
6491
+ return true;
6492
+ }
6493
+
6494
+ var helpers = /*#__PURE__*/Object.freeze({
6495
+ __proto__: null,
6496
+ debounce: debounce,
6497
+ deepMerge: deepMerge,
6498
+ delay: delay,
6499
+ escapeRegex: escapeRegex,
6500
+ formatFileSize: formatFileSize,
6501
+ generateId: generateId,
6502
+ getBrowserInfo: getBrowserInfo,
6503
+ getCSSProperty: getCSSProperty,
6504
+ getCurrentTimestamp: getCurrentTimestamp,
6505
+ getNestedProperty: getNestedProperty,
6506
+ isBrowser: isBrowser,
6507
+ isInViewport: isInViewport,
6508
+ isMobile: isMobile,
6509
+ isValidEmail: isValidEmail,
6510
+ safeJsonParse: safeJsonParse,
6511
+ sanitizeHTML: sanitizeHTML,
6512
+ scrollToElement: scrollToElement,
6513
+ setNestedProperty: setNestedProperty,
6514
+ throttle: throttle,
6515
+ validateConfig: validateConfig
6516
+ });
6517
+
6514
6518
  class BaseWidget {
6515
6519
  static STORAGE_KEY = 'feedback_submitted';
6516
6520
  static DEFAULT_COOLDOWN_DAYS = 30;
@@ -9124,7 +9128,9 @@
9124
9128
  }
9125
9129
 
9126
9130
  _attachEvents() {
9127
- const mobileCloseBtn = this.element.querySelector('.messenger-changelog-close-btn');
9131
+ const mobileCloseBtn = this.element.querySelector(
9132
+ '.messenger-changelog-close-btn'
9133
+ );
9128
9134
  if (mobileCloseBtn) {
9129
9135
  mobileCloseBtn.addEventListener('click', () => {
9130
9136
  this.state.setOpen(false);
@@ -9529,7 +9535,9 @@
9529
9535
  this.state.setView('messages');
9530
9536
  });
9531
9537
 
9532
- const mobileCloseBtn = this.element.querySelector('.messenger-mobile-close-btn');
9538
+ const mobileCloseBtn = this.element.querySelector(
9539
+ '.messenger-mobile-close-btn'
9540
+ );
9533
9541
  if (mobileCloseBtn) {
9534
9542
  mobileCloseBtn.addEventListener('click', () => {
9535
9543
  this.state.setOpen(false);
@@ -9757,14 +9765,20 @@
9757
9765
  });
9758
9766
 
9759
9767
  this._emojiOutsideHandler = (e) => {
9760
- if (!container.contains(e.target) && !e.target.closest('.messenger-emoji-btn')) {
9768
+ if (
9769
+ !container.contains(e.target) &&
9770
+ !e.target.closest('.messenger-emoji-btn')
9771
+ ) {
9761
9772
  container.remove();
9762
9773
  this._emojiPickerOpen = false;
9763
9774
  document.removeEventListener('click', this._emojiOutsideHandler);
9764
9775
  this._emojiOutsideHandler = null;
9765
9776
  }
9766
9777
  };
9767
- setTimeout(() => document.addEventListener('click', this._emojiOutsideHandler), 0);
9778
+ setTimeout(
9779
+ () => document.addEventListener('click', this._emojiOutsideHandler),
9780
+ 0
9781
+ );
9768
9782
  }
9769
9783
 
9770
9784
  _insertEmoji(emoji) {
@@ -9772,8 +9786,7 @@
9772
9786
  if (!input) return;
9773
9787
  const start = input.selectionStart;
9774
9788
  const end = input.selectionEnd;
9775
- input.value =
9776
- input.value.slice(0, start) + emoji + input.value.slice(end);
9789
+ input.value = input.value.slice(0, start) + emoji + input.value.slice(end);
9777
9790
  input.selectionStart = input.selectionEnd = start + emoji.length;
9778
9791
  input.focus();
9779
9792
  input.dispatchEvent(new Event('input'));
@@ -10288,7 +10301,9 @@
10288
10301
  }
10289
10302
 
10290
10303
  _attachEvents() {
10291
- const mobileCloseBtn = this.element.querySelector('.messenger-help-close-btn');
10304
+ const mobileCloseBtn = this.element.querySelector(
10305
+ '.messenger-help-close-btn'
10306
+ );
10292
10307
  if (mobileCloseBtn) {
10293
10308
  mobileCloseBtn.addEventListener('click', () => {
10294
10309
  this.state.setOpen(false);
@@ -12505,7 +12520,9 @@
12505
12520
  const pageId = page.id || `page_${this.surveyState.currentPageIndex}`;
12506
12521
 
12507
12522
  if (page.type === 'rating') {
12508
- const isStarRating = !!this.surveyElement.querySelector('.feedback-survey-star-btn');
12523
+ const isStarRating = !!this.surveyElement.querySelector(
12524
+ '.feedback-survey-star-btn'
12525
+ );
12509
12526
 
12510
12527
  this.surveyElement
12511
12528
  .querySelectorAll('.feedback-survey-page-rating-btn')
@@ -12544,7 +12561,9 @@
12544
12561
  });
12545
12562
 
12546
12563
  if (isStarRating) {
12547
- const container = this.surveyElement.querySelector('.feedback-survey-stars');
12564
+ const container = this.surveyElement.querySelector(
12565
+ '.feedback-survey-stars'
12566
+ );
12548
12567
  if (container) {
12549
12568
  container.addEventListener('mouseleave', () => {
12550
12569
  this.surveyElement
@@ -13910,11 +13929,16 @@
13910
13929
  }
13911
13930
 
13912
13931
  const hostname = window.location.hostname.toLowerCase();
13932
+ const port = window.location.port;
13913
13933
 
13914
13934
  if (hostname.includes('staging')) {
13915
13935
  return 'staging';
13916
13936
  }
13917
13937
 
13938
+ if (hostname === 'app.localhost' && port === '3005') {
13939
+ return 'localstack';
13940
+ }
13941
+
13918
13942
  return 'production';
13919
13943
  }
13920
13944