@product7/product7-js 0.2.0 → 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,14 +1024,12 @@
1024
1024
  if (!env || env === 'production') {
1025
1025
  const hostname =
1026
1026
  (typeof window !== 'undefined' && window.location?.hostname) || '';
1027
- const isLocal =
1028
- hostname === 'localhost' ||
1029
- hostname === '127.0.0.1' ||
1030
- /^192\.168\./.test(hostname) ||
1031
- /^10\./.test(hostname) ||
1032
- /^172\.(1[6-9]|2\d|3[01])\./.test(hostname);
1033
- if (hostname.includes('staging') || isLocal) {
1027
+ const port =
1028
+ (typeof window !== 'undefined' && window.location?.port) || '';
1029
+ if (hostname.includes('staging')) {
1034
1030
  env = 'staging';
1031
+ } else if (hostname === 'app.localhost' && port === '3005') {
1032
+ env = 'localstack';
1035
1033
  }
1036
1034
  }
1037
1035
 
@@ -1638,250 +1636,6 @@
1638
1636
  }
1639
1637
  }
1640
1638
 
1641
- function generateId(prefix = 'feedback') {
1642
- const timestamp = Date.now();
1643
- const random = Math.random().toString(36).substring(2, 9);
1644
- return `${prefix}_${timestamp}_${random}`;
1645
- }
1646
-
1647
- function deepMerge(target, source) {
1648
- const result = { ...target };
1649
-
1650
- for (const key in source) {
1651
- if (source.hasOwnProperty(key)) {
1652
- if (
1653
- source[key] &&
1654
- typeof source[key] === 'object' &&
1655
- !Array.isArray(source[key])
1656
- ) {
1657
- result[key] = deepMerge(target[key] || {}, source[key]);
1658
- } else {
1659
- result[key] = source[key];
1660
- }
1661
- }
1662
- }
1663
-
1664
- return result;
1665
- }
1666
-
1667
- function debounce(func, wait) {
1668
- let timeout;
1669
- return function executedFunction(...args) {
1670
- const later = () => {
1671
- clearTimeout(timeout);
1672
- func(...args);
1673
- };
1674
- clearTimeout(timeout);
1675
- timeout = setTimeout(later, wait);
1676
- };
1677
- }
1678
-
1679
- function throttle(func, limit) {
1680
- let lastFunc;
1681
- let lastRan;
1682
- return function (...args) {
1683
- if (!lastRan) {
1684
- func(...args);
1685
- lastRan = Date.now();
1686
- } else {
1687
- clearTimeout(lastFunc);
1688
- lastFunc = setTimeout(
1689
- () => {
1690
- if (Date.now() - lastRan >= limit) {
1691
- func(...args);
1692
- lastRan = Date.now();
1693
- }
1694
- },
1695
- limit - (Date.now() - lastRan)
1696
- );
1697
- }
1698
- };
1699
- }
1700
-
1701
- function isValidEmail(email) {
1702
- if (!email || typeof email !== 'string') return false;
1703
-
1704
- const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
1705
- return emailRegex.test(email.trim());
1706
- }
1707
-
1708
- function sanitizeHTML(str) {
1709
- if (!str || typeof str !== 'string') return '';
1710
-
1711
- const div = document.createElement('div');
1712
- div.textContent = str;
1713
- return div.innerHTML;
1714
- }
1715
-
1716
- function getCSSProperty(element, property, fallback = '') {
1717
- if (!element || !property) return fallback;
1718
-
1719
- try {
1720
- const style = window.getComputedStyle(element);
1721
- return style.getPropertyValue(property) || fallback;
1722
- } catch (error) {
1723
- return fallback;
1724
- }
1725
- }
1726
-
1727
- function isInViewport(element) {
1728
- if (!element) return false;
1729
-
1730
- const rect = element.getBoundingClientRect();
1731
- return (
1732
- rect.top >= 0 &&
1733
- rect.left >= 0 &&
1734
- rect.bottom <=
1735
- (window.innerHeight || document.documentElement.clientHeight) &&
1736
- rect.right <= (window.innerWidth || document.documentElement.clientWidth)
1737
- );
1738
- }
1739
-
1740
- function scrollToElement(element, options = {}) {
1741
- if (!element) return;
1742
-
1743
- const defaultOptions = {
1744
- behavior: 'smooth',
1745
- block: 'center',
1746
- inline: 'nearest',
1747
- };
1748
-
1749
- element.scrollIntoView({ ...defaultOptions, ...options });
1750
- }
1751
-
1752
- function getBrowserInfo() {
1753
- const userAgent = navigator.userAgent;
1754
- const platform = navigator.platform;
1755
-
1756
- return {
1757
- userAgent,
1758
- platform,
1759
- language: navigator.language || navigator.userLanguage,
1760
- cookieEnabled: navigator.cookieEnabled,
1761
- screenResolution: `${screen.width}x${screen.height}`,
1762
- windowSize: `${window.innerWidth}x${window.innerHeight}`,
1763
- timezone: Intl.DateTimeFormat().resolvedOptions().timeZone,
1764
- };
1765
- }
1766
-
1767
- function formatFileSize(bytes) {
1768
- if (bytes === 0) return '0 Bytes';
1769
-
1770
- const k = 1024;
1771
- const sizes = ['Bytes', 'KB', 'MB', 'GB'];
1772
- const i = Math.floor(Math.log(bytes) / Math.log(k));
1773
-
1774
- return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
1775
- }
1776
-
1777
- function delay(ms) {
1778
- return new Promise((resolve) => setTimeout(resolve, ms));
1779
- }
1780
-
1781
- function safeJsonParse(str, fallback = null) {
1782
- try {
1783
- return JSON.parse(str);
1784
- } catch (error) {
1785
- return fallback;
1786
- }
1787
- }
1788
-
1789
- function escapeRegex(string) {
1790
- return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
1791
- }
1792
-
1793
- function getNestedProperty(obj, path, defaultValue = undefined) {
1794
- if (!obj || !path) return defaultValue;
1795
-
1796
- const keys = path.split('.');
1797
- let current = obj;
1798
-
1799
- for (const key of keys) {
1800
- if (current === null || current === undefined || !(key in current)) {
1801
- return defaultValue;
1802
- }
1803
- current = current[key];
1804
- }
1805
-
1806
- return current;
1807
- }
1808
-
1809
- function setNestedProperty(obj, path, value) {
1810
- if (!obj || !path) return obj;
1811
-
1812
- const keys = path.split('.');
1813
- const lastKey = keys.pop();
1814
- let current = obj;
1815
-
1816
- for (const key of keys) {
1817
- if (!(key in current) || typeof current[key] !== 'object') {
1818
- current[key] = {};
1819
- }
1820
- current = current[key];
1821
- }
1822
-
1823
- current[lastKey] = value;
1824
- return obj;
1825
- }
1826
-
1827
- function isBrowser() {
1828
- return typeof window !== 'undefined' && typeof document !== 'undefined';
1829
- }
1830
-
1831
- function isMobile() {
1832
- if (!isBrowser()) return false;
1833
-
1834
- return (
1835
- /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(
1836
- navigator.userAgent
1837
- ) || window.innerWidth <= 768
1838
- );
1839
- }
1840
-
1841
- function getCurrentTimestamp() {
1842
- return new Date().toISOString();
1843
- }
1844
-
1845
- function validateConfig(config, required = []) {
1846
- const missing = [];
1847
-
1848
- for (const key of required) {
1849
- if (!config[key]) {
1850
- missing.push(key);
1851
- }
1852
- }
1853
-
1854
- if (missing.length > 0) {
1855
- throw new Error(`Missing required configuration: ${missing.join(', ')}`);
1856
- }
1857
-
1858
- return true;
1859
- }
1860
-
1861
- var helpers = /*#__PURE__*/Object.freeze({
1862
- __proto__: null,
1863
- debounce: debounce,
1864
- deepMerge: deepMerge,
1865
- delay: delay,
1866
- escapeRegex: escapeRegex,
1867
- formatFileSize: formatFileSize,
1868
- generateId: generateId,
1869
- getBrowserInfo: getBrowserInfo,
1870
- getCSSProperty: getCSSProperty,
1871
- getCurrentTimestamp: getCurrentTimestamp,
1872
- getNestedProperty: getNestedProperty,
1873
- isBrowser: isBrowser,
1874
- isInViewport: isInViewport,
1875
- isMobile: isMobile,
1876
- isValidEmail: isValidEmail,
1877
- safeJsonParse: safeJsonParse,
1878
- sanitizeHTML: sanitizeHTML,
1879
- scrollToElement: scrollToElement,
1880
- setNestedProperty: setNestedProperty,
1881
- throttle: throttle,
1882
- validateConfig: validateConfig
1883
- });
1884
-
1885
1639
  const baseStyles = `
1886
1640
  .feedback-widget,
1887
1641
  .messenger-widget,
@@ -6517,6 +6271,250 @@
6517
6271
  surveyStyles +
6518
6272
  messengerStyles;
6519
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
+
6520
6518
  class BaseWidget {
6521
6519
  static STORAGE_KEY = 'feedback_submitted';
6522
6520
  static DEFAULT_COOLDOWN_DAYS = 30;
@@ -9130,7 +9128,9 @@
9130
9128
  }
9131
9129
 
9132
9130
  _attachEvents() {
9133
- const mobileCloseBtn = this.element.querySelector('.messenger-changelog-close-btn');
9131
+ const mobileCloseBtn = this.element.querySelector(
9132
+ '.messenger-changelog-close-btn'
9133
+ );
9134
9134
  if (mobileCloseBtn) {
9135
9135
  mobileCloseBtn.addEventListener('click', () => {
9136
9136
  this.state.setOpen(false);
@@ -9535,7 +9535,9 @@
9535
9535
  this.state.setView('messages');
9536
9536
  });
9537
9537
 
9538
- const mobileCloseBtn = this.element.querySelector('.messenger-mobile-close-btn');
9538
+ const mobileCloseBtn = this.element.querySelector(
9539
+ '.messenger-mobile-close-btn'
9540
+ );
9539
9541
  if (mobileCloseBtn) {
9540
9542
  mobileCloseBtn.addEventListener('click', () => {
9541
9543
  this.state.setOpen(false);
@@ -9763,14 +9765,20 @@
9763
9765
  });
9764
9766
 
9765
9767
  this._emojiOutsideHandler = (e) => {
9766
- 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
+ ) {
9767
9772
  container.remove();
9768
9773
  this._emojiPickerOpen = false;
9769
9774
  document.removeEventListener('click', this._emojiOutsideHandler);
9770
9775
  this._emojiOutsideHandler = null;
9771
9776
  }
9772
9777
  };
9773
- setTimeout(() => document.addEventListener('click', this._emojiOutsideHandler), 0);
9778
+ setTimeout(
9779
+ () => document.addEventListener('click', this._emojiOutsideHandler),
9780
+ 0
9781
+ );
9774
9782
  }
9775
9783
 
9776
9784
  _insertEmoji(emoji) {
@@ -9778,8 +9786,7 @@
9778
9786
  if (!input) return;
9779
9787
  const start = input.selectionStart;
9780
9788
  const end = input.selectionEnd;
9781
- input.value =
9782
- input.value.slice(0, start) + emoji + input.value.slice(end);
9789
+ input.value = input.value.slice(0, start) + emoji + input.value.slice(end);
9783
9790
  input.selectionStart = input.selectionEnd = start + emoji.length;
9784
9791
  input.focus();
9785
9792
  input.dispatchEvent(new Event('input'));
@@ -10294,7 +10301,9 @@
10294
10301
  }
10295
10302
 
10296
10303
  _attachEvents() {
10297
- const mobileCloseBtn = this.element.querySelector('.messenger-help-close-btn');
10304
+ const mobileCloseBtn = this.element.querySelector(
10305
+ '.messenger-help-close-btn'
10306
+ );
10298
10307
  if (mobileCloseBtn) {
10299
10308
  mobileCloseBtn.addEventListener('click', () => {
10300
10309
  this.state.setOpen(false);
@@ -12511,7 +12520,9 @@
12511
12520
  const pageId = page.id || `page_${this.surveyState.currentPageIndex}`;
12512
12521
 
12513
12522
  if (page.type === 'rating') {
12514
- const isStarRating = !!this.surveyElement.querySelector('.feedback-survey-star-btn');
12523
+ const isStarRating = !!this.surveyElement.querySelector(
12524
+ '.feedback-survey-star-btn'
12525
+ );
12515
12526
 
12516
12527
  this.surveyElement
12517
12528
  .querySelectorAll('.feedback-survey-page-rating-btn')
@@ -12550,7 +12561,9 @@
12550
12561
  });
12551
12562
 
12552
12563
  if (isStarRating) {
12553
- const container = this.surveyElement.querySelector('.feedback-survey-stars');
12564
+ const container = this.surveyElement.querySelector(
12565
+ '.feedback-survey-stars'
12566
+ );
12554
12567
  if (container) {
12555
12568
  container.addEventListener('mouseleave', () => {
12556
12569
  this.surveyElement
@@ -13916,16 +13929,16 @@
13916
13929
  }
13917
13930
 
13918
13931
  const hostname = window.location.hostname.toLowerCase();
13932
+ const port = window.location.port;
13919
13933
 
13920
- if (
13921
- hostname.includes('staging') ||
13922
- hostname.includes('localhost') ||
13923
- hostname.includes('127.0.0.1') ||
13924
- hostname.includes('.local')
13925
- ) {
13934
+ if (hostname.includes('staging')) {
13926
13935
  return 'staging';
13927
13936
  }
13928
13937
 
13938
+ if (hostname === 'app.localhost' && port === '3005') {
13939
+ return 'localstack';
13940
+ }
13941
+
13929
13942
  return 'production';
13930
13943
  }
13931
13944