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

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 +292 -130
  2. package/index.js +292 -130
  3. package/index.mjs +292 -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.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.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.message, 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.message, 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(() => {
@@ -4969,10 +5099,17 @@ class ShopGPT extends r$2 {
4969
5099
  }
4970
5100
  }
4971
5101
  async setSelectedThreadId(threadId, silent) {
5102
+ var _a, _b, _c, _d;
4972
5103
  this.isFailed = false;
5104
+ const currentThreadId = this.selectedThreadId;
4973
5105
  this.selectedThreadId = threadId;
4974
5106
  if (threadId && !silent) {
4975
- this.shopGPTAPI.sendEvent('switchThread');
5107
+ this.shopGPTAPI.sendEvent('switchThread', undefined, undefined, {
5108
+ previousThread: currentThreadId,
5109
+ activeThread: threadId,
5110
+ previousThreadTitle: (_b = (_a = this.chatThreads.get(currentThreadId)) === null || _a === void 0 ? void 0 : _a.title) !== null && _b !== void 0 ? _b : '',
5111
+ activeThreadTitle: (_d = (_c = this.chatThreads.get(this.selectedThreadId)) === null || _c === void 0 ? void 0 : _c.title) !== null && _d !== void 0 ? _d : '',
5112
+ });
4976
5113
  }
4977
5114
  await Promise.all([
4978
5115
  this.loadHistory(threadId),
@@ -4998,6 +5135,7 @@ class ShopGPT extends r$2 {
4998
5135
  }
4999
5136
  }
5000
5137
  handleThreadDelete(e) {
5138
+ var _a, _b;
5001
5139
  e.stopPropagation();
5002
5140
  this.isLoadingThreads = true;
5003
5141
  const threadId = e.detail.threadId;
@@ -5005,7 +5143,10 @@ class ShopGPT extends r$2 {
5005
5143
  logger.error('ThreadId is missing to delete the thread!');
5006
5144
  return;
5007
5145
  }
5008
- this.shopGPTAPI.sendEvent('singleThreadDelete');
5146
+ this.shopGPTAPI.sendEvent('singleThreadDelete', undefined, undefined, {
5147
+ thread: threadId,
5148
+ threadTitle: (_b = (_a = this.chatThreads.get(threadId)) === null || _a === void 0 ? void 0 : _a.title) !== null && _b !== void 0 ? _b : '',
5149
+ });
5009
5150
  this.shopGPTAPI
5010
5151
  .deleteSingleThread(threadId)
5011
5152
  .then(this.loadChatThreads.bind(this))
@@ -5133,7 +5274,10 @@ class ShopGPT extends r$2 {
5133
5274
  try {
5134
5275
  this.isPreviousMessagePrompt = isPrompt;
5135
5276
  if (!isPrompt) {
5136
- this.shopGPTAPI.sendEvent('queryInteractions', this.getSiteCurrency().currency);
5277
+ this.shopGPTAPI.sendEvent('queryInteractions', this.getSiteCurrency().currency, undefined, {
5278
+ query: message,
5279
+ threadId: this.selectedThreadId,
5280
+ });
5137
5281
  }
5138
5282
  this.messages = [{ sender: 'user', message }, ...this.messages];
5139
5283
  this.isTyping = true;
@@ -5165,15 +5309,25 @@ class ShopGPT extends r$2 {
5165
5309
  }
5166
5310
  sendEvent(e) {
5167
5311
  e.stopPropagation();
5168
- this.shopGPTAPI.sendEvent(e.detail.action, this.getSiteCurrency().currency, e.detail.actionData);
5312
+ this.shopGPTAPI.sendEvent(e.detail.action, this.getSiteCurrency().currency, e.detail.actionData, e.detail.clickData);
5169
5313
  }
5170
5314
  productClicked(e) {
5315
+ var _a, _b;
5171
5316
  e.stopPropagation();
5172
- setProductAction(this.destination, this.sessionId, e.detail.productId, 'clicked', true);
5317
+ setProductAction(this.destination, this.sessionId, e.detail.id, 'clicked', true);
5173
5318
  this.shopGPTAPI.sendEvent('productRecommendationClicked', this.getSiteCurrency().currency, {
5174
- productId: e.detail.productId,
5319
+ productId: e.detail.id,
5175
5320
  value: e.detail.value,
5176
5321
  isPrompt: this.isPreviousMessagePrompt,
5322
+ }, {
5323
+ threadId: this.selectedThreadId,
5324
+ query: (_a = e.detail.query) !== null && _a !== void 0 ? _a : '',
5325
+ response: (_b = e.detail.response) !== null && _b !== void 0 ? _b : '',
5326
+ currency: this.getSiteCurrency().currency,
5327
+ variantId: e.detail.variantId,
5328
+ url: e.detail.url,
5329
+ title: e.detail.title,
5330
+ rank: e.detail.rank,
5177
5331
  });
5178
5332
  }
5179
5333
  getSiteCurrency() {
@@ -5204,6 +5358,7 @@ class ShopGPT extends r$2 {
5204
5358
  .css=${this.css}
5205
5359
  ></chat-threads>
5206
5360
  <products-section
5361
+ .messages=${this.messages}
5207
5362
  .merchantImage=${this.merchantImage}
5208
5363
  .products=${this.products}
5209
5364
  .isLoadingHistory=${this.isLoadingHistory}
@@ -5249,26 +5404,23 @@ class ShopGPT extends r$2 {
5249
5404
  <button
5250
5405
  @click=${(e) => {
5251
5406
  e.preventDefault();
5252
- this.shopGPTAPI.sendEvent('chatbotOpened', this.getSiteCurrency().currency);
5253
- this.modalState = 'open';
5254
- this.handleUserInteraction();
5407
+ this.openModal();
5255
5408
  }}
5256
5409
  >
5257
5410
  ${chatIcon}
5258
5411
  </button>
5259
5412
  ${((_a = this.nudge) === null || _a === void 0 ? void 0 : _a.show) && this.showNudge
5260
- ? x `<div
5413
+ ? x ` <div
5261
5414
  class="nudge"
5262
5415
  @click=${(e) => {
5263
5416
  e.preventDefault();
5264
- this.modalState = 'open';
5265
- this.handleUserInteraction();
5417
+ this.openModal();
5266
5418
  }}
5267
5419
  >
5268
5420
  Hi there! I'm an AI Agent to help you find the perfect product.
5269
5421
  What are you looking for today?
5270
5422
  </div>`
5271
- : x `<div class="chatbot-hover-text">
5423
+ : x ` <div class="chatbot-hover-text">
5272
5424
  What are you looking for today?
5273
5425
  </div>`}
5274
5426
  </div>`;
@@ -5312,6 +5464,12 @@ class ShopGPT extends r$2 {
5312
5464
  </div>
5313
5465
  `;
5314
5466
  }
5467
+ openModal() {
5468
+ setIsBotOpened(this.destination, this.sessionId, true);
5469
+ this.shopGPTAPI.sendEvent('chatbotOpened');
5470
+ this.modalState = 'open';
5471
+ this.handleUserInteraction();
5472
+ }
5315
5473
  startNudgeTimer() {
5316
5474
  var _a, _b;
5317
5475
  if (this.view !== 'modal' || !((_a = this.nudge) === null || _a === void 0 ? void 0 : _a.show)) {
@@ -5350,6 +5508,11 @@ class ShopGPT extends r$2 {
5350
5508
  }
5351
5509
  render() {
5352
5510
  if (this.view === 'modal') {
5511
+ const searchParams = new URLSearchParams(window.location.search);
5512
+ const hasSource = searchParams.get('utm_source') === 'shopgpt';
5513
+ if (hasSource) {
5514
+ this.modalState = 'open';
5515
+ }
5353
5516
  return this.modalMode();
5354
5517
  }
5355
5518
  return this.overlayMode();
@@ -5459,14 +5622,13 @@ if (typeof window != 'undefined' && typeof document != 'undefined') {
5459
5622
  logger.log('ShopGPT component added already!');
5460
5623
  return;
5461
5624
  }
5625
+ setWasUserExposed(shopGPT.destination, shopGPT.sessionId, true);
5462
5626
  document.body.append(shopGPT);
5463
- setShopGPTLoaded(shopGPT.destination, shopGPT.sessionId, true);
5464
5627
  },
5465
5628
  destroy() {
5466
5629
  if (!shopGPT) {
5467
5630
  return;
5468
5631
  }
5469
- setShopGPTLoaded(shopGPT.destination, shopGPT.sessionId, false);
5470
5632
  shopGPT.remove();
5471
5633
  shopGPT = undefined;
5472
5634
  delete window[registryKey];