@blotoutio/providers-shop-gpt-sdk 1.11.3 → 1.11.5

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.
Files changed (4) hide show
  1. package/index.cjs.js +295 -130
  2. package/index.js +295 -130
  3. package/index.mjs +295 -130
  4. package/package.json +1 -1
package/index.mjs CHANGED
@@ -374,6 +374,8 @@ const createDisabled = () => ({
374
374
  groupName: '',
375
375
  isEnabled: false,
376
376
  });
377
+ // userId => 92ae5ac6-b47c-4444-923f-87d98b7e1fac-1743927514247
378
+ // sample => 92ae5ac6
377
379
  const createABTest = ({ userId }) => {
378
380
  const [sample] = userId.split('-');
379
381
  const segment = parseInt(sample, 16) % 2;
@@ -409,6 +411,7 @@ const createExperiment = (props) => {
409
411
  /** Action length should not exceed 42 */
410
412
  const uiActions = new Set([
411
413
  'shopGPTInitialized',
414
+ 'shopGPTLoaded',
412
415
  'chatbotOpened',
413
416
  'chatbotClosed',
414
417
  'singleThreadDelete',
@@ -623,16 +626,16 @@ const setProductAction = (destination, sessionId, productId, action, value) => {
623
626
  const updatedLocal = { [sessionId]: local[sessionId] };
624
627
  saveLocalStorageData(destination, updatedLocal);
625
628
  };
626
- const getShopGPTLoaded = (destination, sessionId) => {
629
+ const getWasUserExposed = (destination, sessionId) => {
627
630
  var _a, _b;
628
631
  const local = getLocalStorageData(destination);
629
632
  if (!local || !sessionId) {
630
633
  logger.error('No local storage data or session id');
631
634
  return false;
632
635
  }
633
- return (_b = (_a = local[sessionId]) === null || _a === void 0 ? void 0 : _a.isShopGPTLoaded) !== null && _b !== void 0 ? _b : false;
636
+ return (_b = (_a = local[sessionId]) === null || _a === void 0 ? void 0 : _a.exposed) !== null && _b !== void 0 ? _b : false;
634
637
  };
635
- const setShopGPTLoaded = (destination, sessionId, value) => {
638
+ const setWasUserExposed = (destination, sessionId, value) => {
636
639
  const local = getLocalStorageData(destination);
637
640
  if (!local || !sessionId) {
638
641
  logger.error('No local storage data or session id');
@@ -640,14 +643,60 @@ const setShopGPTLoaded = (destination, sessionId, value) => {
640
643
  }
641
644
  local[sessionId] = {
642
645
  ...local[sessionId],
643
- isShopGPTLoaded: value,
646
+ exposed: value,
644
647
  };
645
648
  // Clear other sessions
646
649
  const updatedLocal = { [sessionId]: local[sessionId] };
647
650
  saveLocalStorageData(destination, updatedLocal);
648
651
  };
652
+ const setUserType = (destination, sessionId, value) => {
653
+ const local = getLocalStorageData(destination);
654
+ if (!local || !sessionId) {
655
+ logger.error('No session id');
656
+ return;
657
+ }
658
+ local[sessionId] = {
659
+ ...local[sessionId],
660
+ userType: value,
661
+ };
662
+ // Clear other sessions
663
+ const updatedLocal = { [sessionId]: local[sessionId] };
664
+ saveLocalStorageData(destination, updatedLocal);
665
+ };
666
+ const getUserType = (destination, sessionId) => {
667
+ var _a;
668
+ const local = getLocalStorageData(destination);
669
+ if (!sessionId) {
670
+ logger.error('No session id');
671
+ return;
672
+ }
673
+ return (_a = local === null || local === void 0 ? void 0 : local[sessionId]) === null || _a === void 0 ? void 0 : _a.userType;
674
+ };
675
+ const setIsBotOpened = (destination, sessionId, value) => {
676
+ const local = getLocalStorageData(destination);
677
+ if (!local || !sessionId) {
678
+ logger.error('No session id');
679
+ return;
680
+ }
681
+ local[sessionId] = {
682
+ ...local[sessionId],
683
+ opened: value,
684
+ };
685
+ // Clear other sessions
686
+ const updatedLocal = { [sessionId]: local[sessionId] };
687
+ saveLocalStorageData(destination, updatedLocal);
688
+ };
689
+ const getIsBotOpened = (destination, sessionId) => {
690
+ var _a;
691
+ const local = getLocalStorageData(destination);
692
+ if (!sessionId) {
693
+ logger.error('No session id');
694
+ return;
695
+ }
696
+ return (_a = local === null || local === void 0 ? void 0 : local[sessionId]) === null || _a === void 0 ? void 0 : _a.opened;
697
+ };
649
698
 
650
- const createShopGPTAPI = ({ fetch: fetchImpl = window.fetch, baseURL, userId, storeAPI, sessionId, }) => {
699
+ const createShopGPTAPI = ({ fetch: fetchImpl = window.fetch, baseURL, userId, storeAPI, sessionId, sendTag, }) => {
651
700
  if (!baseURL) {
652
701
  throw new Error(`baseURL missing`);
653
702
  }
@@ -777,9 +826,12 @@ const createShopGPTAPI = ({ fetch: fetchImpl = window.fetch, baseURL, userId, st
777
826
  const data = (await response.json());
778
827
  return data.customPrompts;
779
828
  };
780
- const sendEvent = (action, currency, actionData) => {
829
+ const sendEvent = (action, currency, actionData, clickData) => {
781
830
  var _a;
782
831
  const storageData = (_a = getProductActions(baseURL, sessionId)) !== null && _a !== void 0 ? _a : {};
832
+ const userType = getUserType(baseURL, sessionId);
833
+ const exposed = getWasUserExposed(baseURL, sessionId);
834
+ const opened = getIsBotOpened(baseURL, sessionId);
783
835
  // This endpoint sends user events to the server, we don't need to wait for the response
784
836
  fetchImpl(getURL('/user/event'), {
785
837
  method: 'POST',
@@ -791,7 +843,9 @@ const createShopGPTAPI = ({ fetch: fetchImpl = window.fetch, baseURL, userId, st
791
843
  storageData: {
792
844
  session: storageData,
793
845
  preview: hasPreviewKey(),
794
- isShopGPTLoaded: true, // The fact that sendEvent was called means that the ShopGPT is loaded
846
+ userType: userType,
847
+ exposed,
848
+ opened: !!opened,
795
849
  },
796
850
  }),
797
851
  credentials: 'include',
@@ -802,6 +856,21 @@ const createShopGPTAPI = ({ fetch: fetchImpl = window.fetch, baseURL, userId, st
802
856
  }
803
857
  })
804
858
  .catch(logger.error);
859
+ sendTag({
860
+ eventId: crypto.randomUUID(),
861
+ eventName: action,
862
+ data: {
863
+ ...actionData,
864
+ ...clickData,
865
+ userType,
866
+ exposed,
867
+ storageData,
868
+ opened: !!opened,
869
+ },
870
+ providers: {
871
+ shopGPT: true,
872
+ },
873
+ });
805
874
  };
806
875
  return {
807
876
  processQuery,
@@ -819,7 +888,7 @@ const createShopGPTAPI = ({ fetch: fetchImpl = window.fetch, baseURL, userId, st
819
888
  // eslint-disable-next-line @nx/enforce-module-boundaries
820
889
  const error = (message) => console.error(message);
821
890
  const init = (params) => {
822
- var _a, _b, _c, _d, _e, _f;
891
+ var _a, _b, _c;
823
892
  if (typeof window == 'undefined' || typeof document == 'undefined') {
824
893
  // if loaded in non-browser SDKs, return early
825
894
  return;
@@ -838,7 +907,6 @@ const init = (params) => {
838
907
  return;
839
908
  }
840
909
  const { enabled, mode, devMode, merchantUrl, profiles, productHandles, targetPath, view, brandName, quickPrompts, merchantImage, latestThreadLoad, botIconUrl, css, nudge, loadUIManually, } = (_c = params.manifest.variables) !== null && _c !== void 0 ? _c : {};
841
- setShopGPTLoaded(params.baseUrl, (_d = params.session) === null || _d === void 0 ? void 0 : _d.sessionId, !loadUIManually);
842
910
  const experiment = createExperiment({
843
911
  name: getExperimentName(mode),
844
912
  userId: params.userId,
@@ -848,42 +916,65 @@ const init = (params) => {
848
916
  if (experiment.name === 'preview' && shouldShowUI) {
849
917
  logger.log('Enabling UI in preview mode');
850
918
  }
851
- if (shouldShowUI) {
852
- const uiImplementation = window[registryKey].ui;
853
- if (!uiImplementation) {
854
- error('UI implementation is missing');
855
- return;
919
+ // once we implement a general version with togglable option to discriminate
920
+ // between anon/known, we'll be able to skip creating this promise before
921
+ // init and possibly loading the UI
922
+ new Promise((resolve) => {
923
+ var _a;
924
+ const userType = getUserType(params.baseUrl, (_a = params.session) === null || _a === void 0 ? void 0 : _a.sessionId);
925
+ if (userType) {
926
+ return resolve();
856
927
  }
928
+ params.getEdgeData(['email'], (data) => {
929
+ var _a;
930
+ setUserType(params.baseUrl, (_a = params.session) === null || _a === void 0 ? void 0 : _a.sessionId, data['emailExists'] ? 'known' : 'anon');
931
+ resolve();
932
+ });
933
+ }).then(() => {
934
+ var _a, _b;
857
935
  const shopGPTAPI = createShopGPTAPI({
858
936
  baseURL: params.baseUrl,
859
937
  storeAPI,
860
938
  userId: params.userId,
861
- sessionId: (_e = params.session) === null || _e === void 0 ? void 0 : _e.sessionId,
939
+ sessionId: (_a = params.session) === null || _a === void 0 ? void 0 : _a.sessionId,
940
+ sendTag: params.sendTag,
862
941
  });
863
- uiImplementation.init({
864
- destination: params.baseUrl,
865
- storeAPI,
866
- shopGPTAPI,
867
- devMode,
868
- view,
869
- merchantUrl,
870
- profiles,
871
- productHandles,
872
- path: targetPath,
873
- brandName,
874
- quickPrompts,
875
- merchantImage,
876
- latestThreadLoad: latestThreadLoad !== null && latestThreadLoad !== void 0 ? latestThreadLoad : DEFAULT_MAX_THREAD_AGE,
877
- botIconUrl,
878
- css,
879
- nudge,
880
- sessionId: (_f = params.session) === null || _f === void 0 ? void 0 : _f.sessionId,
881
- loadUIManually,
942
+ shopGPTAPI.sendEvent('shopGPTInitialized', undefined, undefined, {
943
+ groupName: experiment.groupName,
882
944
  });
883
- if (!loadUIManually) {
884
- uiImplementation.loadUI();
945
+ if (shouldShowUI) {
946
+ const uiImplementation = window[registryKey].ui;
947
+ if (!uiImplementation) {
948
+ error('UI implementation is missing');
949
+ return;
950
+ }
951
+ uiImplementation.init({
952
+ destination: params.baseUrl,
953
+ storeAPI,
954
+ shopGPTAPI,
955
+ devMode,
956
+ view,
957
+ merchantUrl,
958
+ profiles,
959
+ productHandles,
960
+ path: targetPath,
961
+ brandName,
962
+ quickPrompts,
963
+ merchantImage,
964
+ latestThreadLoad: latestThreadLoad !== null && latestThreadLoad !== void 0 ? latestThreadLoad : DEFAULT_MAX_THREAD_AGE,
965
+ botIconUrl,
966
+ css,
967
+ nudge,
968
+ sessionId: (_b = params.session) === null || _b === void 0 ? void 0 : _b.sessionId,
969
+ loadUIManually,
970
+ });
971
+ const searchParams = new URLSearchParams(window.location.search);
972
+ const hasSource = searchParams.get('utm_source') === 'shopgpt';
973
+ if (!loadUIManually || hasSource) {
974
+ uiImplementation.loadUI();
975
+ }
885
976
  }
886
- }
977
+ });
887
978
  };
888
979
 
889
980
  const getClickedProductsInContents = (destination, sessionId, data) => {
@@ -895,7 +986,7 @@ const getClickedProductsInContents = (destination, sessionId, data) => {
895
986
  return contents.flatMap((content) => { var _a; return ((_a = storedData[content.id]) === null || _a === void 0 ? void 0 : _a.clicked) ? [content.id] : []; });
896
987
  };
897
988
  const tag = ({ eventName, destination, data, sessionId, }) => {
898
- var _a;
989
+ var _a, _b;
899
990
  const clickedProducts = getClickedProductsInContents(destination, sessionId, data);
900
991
  if (eventName === 'AddToCart') {
901
992
  clickedProducts === null || clickedProducts === void 0 ? void 0 : clickedProducts.forEach((id) => {
@@ -910,7 +1001,9 @@ const tag = ({ eventName, destination, data, sessionId, }) => {
910
1001
  return {
911
1002
  session: getProductActions(destination, sessionId),
912
1003
  preview: hasPreviewKey(),
913
- isShopGPTLoaded: (_a = getShopGPTLoaded(destination, sessionId)) !== null && _a !== void 0 ? _a : false,
1004
+ exposed: (_a = getWasUserExposed(destination, sessionId)) !== null && _a !== void 0 ? _a : false,
1005
+ userType: getUserType(destination, sessionId),
1006
+ opened: (_b = getIsBotOpened(destination, sessionId)) !== null && _b !== void 0 ? _b : false,
914
1007
  };
915
1008
  };
916
1009
 
@@ -1780,13 +1873,13 @@ const productItemStyles = i$4 `
1780
1873
  .product {
1781
1874
  display: flex;
1782
1875
  gap: 16px;
1876
+ cursor: pointer;
1783
1877
 
1784
1878
  img {
1785
1879
  width: 150px;
1786
1880
  height: 186px;
1787
1881
  object-position: center;
1788
1882
  object-fit: contain;
1789
- cursor: pointer;
1790
1883
  }
1791
1884
  }
1792
1885
 
@@ -1811,7 +1904,6 @@ const productItemStyles = i$4 `
1811
1904
  text-overflow: ellipsis;
1812
1905
  word-break: break-word;
1813
1906
  white-space: normal;
1814
- cursor: pointer;
1815
1907
  }
1816
1908
 
1817
1909
  .product-variation-details {
@@ -1922,11 +2014,14 @@ class ProductItem extends r$2 {
1922
2014
  ${this.getLocalPrice(comparedAtPrice)}
1923
2015
  </p>`;
1924
2016
  }
1925
- redirect(url) {
2017
+ openProduct(url) {
1926
2018
  if (!url) {
1927
2019
  return;
1928
2020
  }
1929
- open(url, '_self');
2021
+ const link = new URL(url);
2022
+ link.searchParams.set('utm_source', 'shopgpt');
2023
+ link.searchParams.set('utm_medium', 'chat');
2024
+ open(link, '_self');
1930
2025
  }
1931
2026
  renderVariantTitles() {
1932
2027
  if (this.product.hasOnlyDefaultVariant) {
@@ -1936,39 +2031,32 @@ class ProductItem extends r$2 {
1936
2031
  <p class="product-variation-details">${option.name}: ${option.value}</p>
1937
2032
  `);
1938
2033
  }
1939
- productClicked(productId, price, url) {
1940
- if (productId) {
2034
+ productClicked(product) {
2035
+ if (product.id) {
2036
+ const price = product.variants[0].price;
1941
2037
  this.dispatchEvent(new CustomEvent('product-clicked', {
1942
2038
  detail: {
1943
- productId,
2039
+ id: product.id,
1944
2040
  value: price ? parseFloat(price) : undefined,
2041
+ variantId: product.variants[0].id,
2042
+ title: product.title,
2043
+ url: product.url,
2044
+ query: this.query,
2045
+ response: this.response,
2046
+ rank: this.rank,
1945
2047
  },
1946
2048
  composed: true,
1947
2049
  bubbles: true,
1948
2050
  }));
1949
2051
  }
1950
- this.redirect(url);
2052
+ this.openProduct(product.url);
1951
2053
  }
1952
2054
  render() {
1953
2055
  return x `
1954
- <div class="product">
1955
- <img
1956
- src=${this.product.image.url}
1957
- alt=${this.product.image.alt}
1958
- @click=${() => {
1959
- var _a;
1960
- return this.productClicked(this.product.id, this.product.variants[0].price, (_a = this.product) === null || _a === void 0 ? void 0 : _a.url);
1961
- }}
1962
- />
2056
+ <div class="product" @click=${() => this.productClicked(this.product)}>
2057
+ <img src=${this.product.image.url} alt=${this.product.image.alt} />
1963
2058
  <div class="content">
1964
- <p
1965
- class="product-name"
1966
- title=${this.product.title}
1967
- @click=${() => {
1968
- var _a;
1969
- return this.productClicked(this.product.id, this.product.variants[0].price, (_a = this.product) === null || _a === void 0 ? void 0 : _a.url);
1970
- }}
1971
- >
2059
+ <p class="product-name" title=${this.product.title}>
1972
2060
  ${this.product.title}
1973
2061
  </p>
1974
2062
  ${this.renderVariantTitles()}
@@ -1976,15 +2064,7 @@ class ProductItem extends r$2 {
1976
2064
  ${this.getComparedAtPrice(this.product.variants[0].comparedAtPrice, this.product.variants[0].price)}
1977
2065
  <p>${this.getLocalPrice(this.product.variants[0].price)}</p>
1978
2066
  </div>
1979
- <button
1980
- class="btn-view-product"
1981
- @click=${() => {
1982
- var _a;
1983
- return this.productClicked(this.product.id, this.product.variants[0].price, (_a = this.product) === null || _a === void 0 ? void 0 : _a.url);
1984
- }}
1985
- >
1986
- View Product
1987
- </button>
2067
+ <button class="btn-view-product">View Product</button>
1988
2068
  </div>
1989
2069
  </div>
1990
2070
  `;
@@ -1999,6 +2079,18 @@ __decorate([
1999
2079
  n({ type: Object }),
2000
2080
  __metadata("design:type", Object)
2001
2081
  ], ProductItem.prototype, "siteCurrency", void 0);
2082
+ __decorate([
2083
+ n({ type: String }),
2084
+ __metadata("design:type", Object)
2085
+ ], ProductItem.prototype, "query", void 0);
2086
+ __decorate([
2087
+ n({ type: String }),
2088
+ __metadata("design:type", String)
2089
+ ], ProductItem.prototype, "response", void 0);
2090
+ __decorate([
2091
+ n({ type: Number }),
2092
+ __metadata("design:type", Number)
2093
+ ], ProductItem.prototype, "rank", void 0);
2002
2094
  if (!customElements.get('product-item')) {
2003
2095
  customElements.define('product-item', ProductItem);
2004
2096
  }
@@ -2115,7 +2207,7 @@ class ProductsList extends r$2 {
2115
2207
  return x `
2116
2208
  <div class="products-wrapper">
2117
2209
  <div class="products" @scroll=${this.updateButtonsState}>
2118
- ${o$1(this.products, (product) => x `
2210
+ ${o$1(this.products, (product, index) => x `
2119
2211
  <div
2120
2212
  class=${e$1({
2121
2213
  'product-container': true,
@@ -2123,8 +2215,11 @@ class ProductsList extends r$2 {
2123
2215
  })}
2124
2216
  >
2125
2217
  <product-item
2218
+ .query=${this.query}
2219
+ .response=${this.response}
2126
2220
  .product=${product}
2127
2221
  .siteCurrency=${this.siteCurrency}
2222
+ .rank=${index + 1}
2128
2223
  ></product-item>
2129
2224
  </div>
2130
2225
  `)}
@@ -2152,6 +2247,14 @@ __decorate([
2152
2247
  n({ type: Object }),
2153
2248
  __metadata("design:type", Object)
2154
2249
  ], ProductsList.prototype, "siteCurrency", void 0);
2250
+ __decorate([
2251
+ n({ type: String }),
2252
+ __metadata("design:type", Object)
2253
+ ], ProductsList.prototype, "query", void 0);
2254
+ __decorate([
2255
+ n({ type: String }),
2256
+ __metadata("design:type", String)
2257
+ ], ProductsList.prototype, "response", void 0);
2155
2258
  __decorate([
2156
2259
  r(),
2157
2260
  __metadata("design:type", Object)
@@ -2198,6 +2301,7 @@ class ProductsSection extends r$2 {
2198
2301
  `;
2199
2302
  }
2200
2303
  render() {
2304
+ var _a;
2201
2305
  if (this.isLoadingHistory || this.isLoadingThreads) {
2202
2306
  return x ` <load-spinner></load-spinner> `;
2203
2307
  }
@@ -2208,18 +2312,25 @@ class ProductsSection extends r$2 {
2208
2312
  }
2209
2313
  const topResult = this.products[0];
2210
2314
  const others = this.products.slice(1);
2315
+ const query = (_a = this.messages) === null || _a === void 0 ? void 0 : _a[1];
2316
+ const response = this.messages[0];
2211
2317
  return x `
2212
2318
  <div class="top-result">
2213
2319
  <h2>Top Result</h2>
2214
2320
  <product-item
2321
+ .query=${query === null || query === void 0 ? void 0 : query.message}
2322
+ .response=${response === null || response === void 0 ? void 0 : response.message}
2215
2323
  .product=${topResult}
2216
2324
  .siteCurrency=${this.siteCurrency}
2325
+ .rank=${1}
2217
2326
  ></product-item>
2218
2327
  </div>
2219
2328
  <span class="line"></span>
2220
2329
  <div class="others">
2221
2330
  <h2>Other Recommendations</h2>
2222
2331
  <products-list
2332
+ .query=${query === null || query === void 0 ? void 0 : query.message}
2333
+ .response=${response === null || response === void 0 ? void 0 : response.message}
2223
2334
  .products=${others}
2224
2335
  .siteCurrency=${this.siteCurrency}
2225
2336
  .viewType=${'overlay'}
@@ -2265,6 +2376,10 @@ __decorate([
2265
2376
  n({ type: String }),
2266
2377
  __metadata("design:type", String)
2267
2378
  ], ProductsSection.prototype, "css", void 0);
2379
+ __decorate([
2380
+ n({ type: Array }),
2381
+ __metadata("design:type", Array)
2382
+ ], ProductsSection.prototype, "messages", void 0);
2268
2383
  if (!customElements.get('products-section')) {
2269
2384
  customElements.define('products-section', ProductsSection);
2270
2385
  }
@@ -3991,9 +4106,9 @@ class ChatSection extends r$2 {
3991
4106
  }
3992
4107
  await this.sendMessageToServer(e, message, isPrompt);
3993
4108
  }
3994
- sendEvent(action, actionData) {
4109
+ sendEvent(action, actionData, clickData) {
3995
4110
  this.dispatchEvent(new CustomEvent('send-event', {
3996
- detail: { action, actionData },
4111
+ detail: { action, actionData, clickData },
3997
4112
  composed: true,
3998
4113
  bubbles: true,
3999
4114
  }));
@@ -4024,24 +4139,38 @@ class ChatSection extends r$2 {
4024
4139
  }));
4025
4140
  this.deleteThreadId = '';
4026
4141
  }
4027
- handleFeedback(rating, messageId, queryMessageId, comment) {
4028
- var _a, _b;
4142
+ handleFeedback(rating, messageId, queryMessageId, comment, query, response) {
4143
+ var _a, _b, _c, _d;
4029
4144
  if (rating === 'bad') {
4030
- this.sendEvent('thumbsDown');
4145
+ this.sendEvent('thumbsDown', undefined, {
4146
+ messageId,
4147
+ threadId: ((_a = this.thread) === null || _a === void 0 ? void 0 : _a.threadId) || '',
4148
+ rating,
4149
+ comment: comment !== null && comment !== void 0 ? comment : '',
4150
+ query: query !== null && query !== void 0 ? query : '',
4151
+ response: response !== null && response !== void 0 ? response : '',
4152
+ });
4031
4153
  this.feedbackDetails = {
4032
4154
  messageId,
4033
4155
  queryMessageId,
4034
- threadId: ((_a = this.thread) === null || _a === void 0 ? void 0 : _a.threadId) || '',
4156
+ threadId: ((_b = this.thread) === null || _b === void 0 ? void 0 : _b.threadId) || '',
4035
4157
  comment,
4036
4158
  };
4037
4159
  return;
4038
4160
  }
4039
- this.sendEvent('thumbsUp');
4161
+ this.sendEvent('thumbsUp', undefined, {
4162
+ messageId,
4163
+ threadId: ((_c = this.thread) === null || _c === void 0 ? void 0 : _c.threadId) || '',
4164
+ rating,
4165
+ comment: comment !== null && comment !== void 0 ? comment : '',
4166
+ query: query !== null && query !== void 0 ? query : '',
4167
+ response: response !== null && response !== void 0 ? response : '',
4168
+ });
4040
4169
  this.dispatchEvent(new CustomEvent('submit-feedback', {
4041
4170
  detail: {
4042
4171
  messageId: messageId,
4043
4172
  queryMessageId: queryMessageId,
4044
- threadId: (_b = this.thread) === null || _b === void 0 ? void 0 : _b.threadId,
4173
+ threadId: (_d = this.thread) === null || _d === void 0 ? void 0 : _d.threadId,
4045
4174
  feedback: {
4046
4175
  rating,
4047
4176
  comment: null,
@@ -4076,8 +4205,11 @@ class ChatSection extends r$2 {
4076
4205
  <span class="line"></span>
4077
4206
  <div class="product-container">
4078
4207
  <product-item
4208
+ .query=${queryMessage === null || queryMessage === void 0 ? void 0 : queryMessage.message}
4209
+ .response=${message.message}
4079
4210
  .product=${message.products[0]}
4080
4211
  .siteCurrency=${this.siteCurrency}
4212
+ .rank=${1}
4081
4213
  ></product-item>
4082
4214
  </div>
4083
4215
  `
@@ -4086,16 +4218,18 @@ class ChatSection extends r$2 {
4086
4218
  </div>
4087
4219
  ${this.viewType === 'modal' && message.products
4088
4220
  ? x ` <products-list
4221
+ .query=${queryMessage === null || queryMessage === void 0 ? void 0 : queryMessage.message}
4222
+ .response=${message.message}
4089
4223
  .products=${message.products}
4090
4224
  .siteCurrency=${this.siteCurrency}
4091
4225
  .viewType=${this.viewType}
4092
4226
  ></products-list>`
4093
4227
  : E}
4094
4228
  ${message.messageId && (queryMessage === null || queryMessage === void 0 ? void 0 : queryMessage.messageId)
4095
- ? x `<div class="bot-response-actions">
4229
+ ? x ` <div class="bot-response-actions">
4096
4230
  <button
4097
4231
  type="button"
4098
- @click=${this.handleFeedback.bind(this, 'good', message.messageId, queryMessage === null || queryMessage === void 0 ? void 0 : queryMessage.messageId, (_b = message.feedback) === null || _b === void 0 ? void 0 : _b.comment)}
4232
+ @click=${this.handleFeedback.bind(this, 'good', message.messageId, queryMessage === null || queryMessage === void 0 ? void 0 : queryMessage.messageId, (_b = message.feedback) === null || _b === void 0 ? void 0 : _b.comment, queryMessage === null || queryMessage === void 0 ? void 0 : queryMessage.message, message === null || message === void 0 ? void 0 : message.message)}
4099
4233
  >
4100
4234
  ${((_c = message.feedback) === null || _c === void 0 ? void 0 : _c.rating) === 'good'
4101
4235
  ? thumbsUpFilledBtn
@@ -4103,7 +4237,7 @@ class ChatSection extends r$2 {
4103
4237
  </button>
4104
4238
  <button
4105
4239
  type="button"
4106
- @click=${this.handleFeedback.bind(this, 'bad', message.messageId, queryMessage === null || queryMessage === void 0 ? void 0 : queryMessage.messageId, (_d = message.feedback) === null || _d === void 0 ? void 0 : _d.comment)}
4240
+ @click=${this.handleFeedback.bind(this, 'bad', message.messageId, queryMessage === null || queryMessage === void 0 ? void 0 : queryMessage.messageId, (_d = message.feedback) === null || _d === void 0 ? void 0 : _d.comment, queryMessage === null || queryMessage === void 0 ? void 0 : queryMessage.message, message === null || message === void 0 ? void 0 : message.message)}
4107
4241
  >
4108
4242
  ${((_e = message.feedback) === null || _e === void 0 ? void 0 : _e.rating) === 'bad'
4109
4243
  ? thumbsDownFilledBtn
@@ -4116,7 +4250,7 @@ class ChatSection extends r$2 {
4116
4250
  }
4117
4251
  renderBotIcon() {
4118
4252
  if (this.botIconUrl) {
4119
- return x `<div class="bot-icon">
4253
+ return x ` <div class="bot-icon">
4120
4254
  <img src=${this.botIconUrl} width="30" height="30" />
4121
4255
  </div>`;
4122
4256
  }
@@ -4124,7 +4258,7 @@ class ChatSection extends r$2 {
4124
4258
  }
4125
4259
  chatWindow() {
4126
4260
  if (this.isLoadingHistory || this.isLoadingThreads) {
4127
- return x `<div class="messages loading">
4261
+ return x ` <div class="messages loading">
4128
4262
  <load-spinner></load-spinner>
4129
4263
  </div>`;
4130
4264
  }
@@ -4137,7 +4271,7 @@ class ChatSection extends r$2 {
4137
4271
  </div>`
4138
4272
  : ''}
4139
4273
  ${this.isFailed
4140
- ? x `<div class="message bot">
4274
+ ? x ` <div class="message bot">
4141
4275
  <div>${this.renderBotIcon()}</div>
4142
4276
  <div>
4143
4277
  <p>
@@ -4157,18 +4291,20 @@ class ChatSection extends r$2 {
4157
4291
  })}
4158
4292
  ${!this.fromAd || !this.thread
4159
4293
  ? x `
4160
- <div class="message bot">
4161
- <div>${this.renderBotIcon()}</div>
4162
- <div>
4163
- <p>
4164
- Hi,
4165
- ${this.brandName ? x `Welcome to ${this.brandName}.` : E}
4166
- I'm here to help you find the perfect product. Pick a suggested
4167
- prompt from below, or enter your own query.
4168
- </p>
4169
- </div>
4170
- </div>
4171
- </div>`
4294
+ <div class="message bot">
4295
+ <div>${this.renderBotIcon()}</div>
4296
+ <div>
4297
+ <p>
4298
+ Hi,
4299
+ ${this.brandName
4300
+ ? x `Welcome to ${this.brandName}.`
4301
+ : E}
4302
+ I'm here to help you find the perfect product. Pick a suggested
4303
+ prompt from below, or enter your own query.
4304
+ </p>
4305
+ </div>
4306
+ </div>
4307
+ </div>`
4172
4308
  : E}
4173
4309
  </div>
4174
4310
  `;
@@ -4195,7 +4331,9 @@ class ChatSection extends r$2 {
4195
4331
  class="prompt"
4196
4332
  @click=${(e) => {
4197
4333
  this.processMessage(e, prompt, true);
4198
- this.sendEvent('promptClicked');
4334
+ this.sendEvent('promptClicked', undefined, {
4335
+ promptName: prompt,
4336
+ });
4199
4337
  }}
4200
4338
  >
4201
4339
  ${prompt}
@@ -4209,7 +4347,9 @@ class ChatSection extends r$2 {
4209
4347
  href=${link}
4210
4348
  target="_blank"
4211
4349
  rel="noopener"
4212
- @click=${() => this.sendEvent('promptClicked')}
4350
+ @click=${() => this.sendEvent('promptClicked', undefined, {
4351
+ promptName: prompt,
4352
+ })}
4213
4353
  >
4214
4354
  ${prompt}
4215
4355
  </a>
@@ -4400,7 +4540,7 @@ class ChatSection extends r$2 {
4400
4540
  <div class="title-wrapper">
4401
4541
  <h2>Search History</h2>
4402
4542
  ${this.chatThreads.size
4403
- ? x `<div
4543
+ ? x ` <div
4404
4544
  class="trash-icon"
4405
4545
  @click=${() => {
4406
4546
  if (this.isStreaming) {
@@ -4806,9 +4946,6 @@ class ShopGPT extends r$2 {
4806
4946
  this.startNudgeTimer();
4807
4947
  }
4808
4948
  disconnectedCallback() {
4809
- if (!this.loadUIManually) {
4810
- window.removeEventListener('edgetag-initialized', this.loadData);
4811
- }
4812
4949
  window.removeEventListener('popstate', this.onPopState);
4813
4950
  if (this.nudgeTimer) {
4814
4951
  window.clearTimeout(this.nudgeTimer);
@@ -4816,16 +4953,9 @@ class ShopGPT extends r$2 {
4816
4953
  super.disconnectedCallback();
4817
4954
  }
4818
4955
  init() {
4819
- if (this.loadUIManually) {
4820
- // this is because edgetag-initialized will already be
4821
- // triggered before the loadUI function is called to load the UI
4822
- this.loadData();
4823
- }
4824
- else {
4825
- window.addEventListener('edgetag-initialized', this.loadData);
4826
- }
4956
+ this.loadData();
4827
4957
  window.addEventListener('popstate', this.onPopState);
4828
- this.shopGPTAPI.sendEvent('shopGPTInitialized', this.getSiteCurrency().currency);
4958
+ this.shopGPTAPI.sendEvent('shopGPTLoaded');
4829
4959
  if (!this.view || this.view === 'overlay') {
4830
4960
  delay(DIALOG_DELAY)
4831
4961
  .then(() => {
@@ -4841,6 +4971,14 @@ class ShopGPT extends r$2 {
4841
4971
  })
4842
4972
  .catch(logger.error);
4843
4973
  }
4974
+ else if (this.view === 'modal') {
4975
+ const searchParams = new URLSearchParams(window.location.search);
4976
+ const hasSource = searchParams.get('utm_source') === 'shopgpt';
4977
+ // If the url has `utm_source` open the popup when reloaded
4978
+ if (hasSource) {
4979
+ this.modalState = 'open';
4980
+ }
4981
+ }
4844
4982
  }
4845
4983
  setChatTitle(threadId, title) {
4846
4984
  if (!title || !threadId) {
@@ -4969,10 +5107,17 @@ class ShopGPT extends r$2 {
4969
5107
  }
4970
5108
  }
4971
5109
  async setSelectedThreadId(threadId, silent) {
5110
+ var _a, _b, _c, _d;
4972
5111
  this.isFailed = false;
5112
+ const currentThreadId = this.selectedThreadId;
4973
5113
  this.selectedThreadId = threadId;
4974
5114
  if (threadId && !silent) {
4975
- this.shopGPTAPI.sendEvent('switchThread');
5115
+ this.shopGPTAPI.sendEvent('switchThread', undefined, undefined, {
5116
+ previousThread: currentThreadId,
5117
+ activeThread: threadId,
5118
+ previousThreadTitle: (_b = (_a = this.chatThreads.get(currentThreadId)) === null || _a === void 0 ? void 0 : _a.title) !== null && _b !== void 0 ? _b : '',
5119
+ activeThreadTitle: (_d = (_c = this.chatThreads.get(this.selectedThreadId)) === null || _c === void 0 ? void 0 : _c.title) !== null && _d !== void 0 ? _d : '',
5120
+ });
4976
5121
  }
4977
5122
  await Promise.all([
4978
5123
  this.loadHistory(threadId),
@@ -4998,6 +5143,7 @@ class ShopGPT extends r$2 {
4998
5143
  }
4999
5144
  }
5000
5145
  handleThreadDelete(e) {
5146
+ var _a, _b;
5001
5147
  e.stopPropagation();
5002
5148
  this.isLoadingThreads = true;
5003
5149
  const threadId = e.detail.threadId;
@@ -5005,7 +5151,10 @@ class ShopGPT extends r$2 {
5005
5151
  logger.error('ThreadId is missing to delete the thread!');
5006
5152
  return;
5007
5153
  }
5008
- this.shopGPTAPI.sendEvent('singleThreadDelete');
5154
+ this.shopGPTAPI.sendEvent('singleThreadDelete', undefined, undefined, {
5155
+ thread: threadId,
5156
+ threadTitle: (_b = (_a = this.chatThreads.get(threadId)) === null || _a === void 0 ? void 0 : _a.title) !== null && _b !== void 0 ? _b : '',
5157
+ });
5009
5158
  this.shopGPTAPI
5010
5159
  .deleteSingleThread(threadId)
5011
5160
  .then(this.loadChatThreads.bind(this))
@@ -5133,7 +5282,10 @@ class ShopGPT extends r$2 {
5133
5282
  try {
5134
5283
  this.isPreviousMessagePrompt = isPrompt;
5135
5284
  if (!isPrompt) {
5136
- this.shopGPTAPI.sendEvent('queryInteractions', this.getSiteCurrency().currency);
5285
+ this.shopGPTAPI.sendEvent('queryInteractions', this.getSiteCurrency().currency, undefined, {
5286
+ query: message,
5287
+ threadId: this.selectedThreadId,
5288
+ });
5137
5289
  }
5138
5290
  this.messages = [{ sender: 'user', message }, ...this.messages];
5139
5291
  this.isTyping = true;
@@ -5165,15 +5317,25 @@ class ShopGPT extends r$2 {
5165
5317
  }
5166
5318
  sendEvent(e) {
5167
5319
  e.stopPropagation();
5168
- this.shopGPTAPI.sendEvent(e.detail.action, this.getSiteCurrency().currency, e.detail.actionData);
5320
+ this.shopGPTAPI.sendEvent(e.detail.action, this.getSiteCurrency().currency, e.detail.actionData, e.detail.clickData);
5169
5321
  }
5170
5322
  productClicked(e) {
5323
+ var _a, _b;
5171
5324
  e.stopPropagation();
5172
- setProductAction(this.destination, this.sessionId, e.detail.productId, 'clicked', true);
5325
+ setProductAction(this.destination, this.sessionId, e.detail.id, 'clicked', true);
5173
5326
  this.shopGPTAPI.sendEvent('productRecommendationClicked', this.getSiteCurrency().currency, {
5174
- productId: e.detail.productId,
5327
+ productId: e.detail.id,
5175
5328
  value: e.detail.value,
5176
5329
  isPrompt: this.isPreviousMessagePrompt,
5330
+ }, {
5331
+ threadId: this.selectedThreadId,
5332
+ query: (_a = e.detail.query) !== null && _a !== void 0 ? _a : '',
5333
+ response: (_b = e.detail.response) !== null && _b !== void 0 ? _b : '',
5334
+ currency: this.getSiteCurrency().currency,
5335
+ variantId: e.detail.variantId,
5336
+ url: e.detail.url,
5337
+ title: e.detail.title,
5338
+ rank: e.detail.rank,
5177
5339
  });
5178
5340
  }
5179
5341
  getSiteCurrency() {
@@ -5204,6 +5366,7 @@ class ShopGPT extends r$2 {
5204
5366
  .css=${this.css}
5205
5367
  ></chat-threads>
5206
5368
  <products-section
5369
+ .messages=${this.messages}
5207
5370
  .merchantImage=${this.merchantImage}
5208
5371
  .products=${this.products}
5209
5372
  .isLoadingHistory=${this.isLoadingHistory}
@@ -5249,26 +5412,23 @@ class ShopGPT extends r$2 {
5249
5412
  <button
5250
5413
  @click=${(e) => {
5251
5414
  e.preventDefault();
5252
- this.shopGPTAPI.sendEvent('chatbotOpened', this.getSiteCurrency().currency);
5253
- this.modalState = 'open';
5254
- this.handleUserInteraction();
5415
+ this.openModal();
5255
5416
  }}
5256
5417
  >
5257
5418
  ${chatIcon}
5258
5419
  </button>
5259
5420
  ${((_a = this.nudge) === null || _a === void 0 ? void 0 : _a.show) && this.showNudge
5260
- ? x `<div
5421
+ ? x ` <div
5261
5422
  class="nudge"
5262
5423
  @click=${(e) => {
5263
5424
  e.preventDefault();
5264
- this.modalState = 'open';
5265
- this.handleUserInteraction();
5425
+ this.openModal();
5266
5426
  }}
5267
5427
  >
5268
5428
  Hi there! I'm an AI Agent to help you find the perfect product.
5269
5429
  What are you looking for today?
5270
5430
  </div>`
5271
- : x `<div class="chatbot-hover-text">
5431
+ : x ` <div class="chatbot-hover-text">
5272
5432
  What are you looking for today?
5273
5433
  </div>`}
5274
5434
  </div>`;
@@ -5312,6 +5472,12 @@ class ShopGPT extends r$2 {
5312
5472
  </div>
5313
5473
  `;
5314
5474
  }
5475
+ openModal() {
5476
+ setIsBotOpened(this.destination, this.sessionId, true);
5477
+ this.shopGPTAPI.sendEvent('chatbotOpened');
5478
+ this.modalState = 'open';
5479
+ this.handleUserInteraction();
5480
+ }
5315
5481
  startNudgeTimer() {
5316
5482
  var _a, _b;
5317
5483
  if (this.view !== 'modal' || !((_a = this.nudge) === null || _a === void 0 ? void 0 : _a.show)) {
@@ -5459,14 +5625,13 @@ if (typeof window != 'undefined' && typeof document != 'undefined') {
5459
5625
  logger.log('ShopGPT component added already!');
5460
5626
  return;
5461
5627
  }
5628
+ setWasUserExposed(shopGPT.destination, shopGPT.sessionId, true);
5462
5629
  document.body.append(shopGPT);
5463
- setShopGPTLoaded(shopGPT.destination, shopGPT.sessionId, true);
5464
5630
  },
5465
5631
  destroy() {
5466
5632
  if (!shopGPT) {
5467
5633
  return;
5468
5634
  }
5469
- setShopGPTLoaded(shopGPT.destination, shopGPT.sessionId, false);
5470
5635
  shopGPT.remove();
5471
5636
  shopGPT = undefined;
5472
5637
  delete window[registryKey];