@blotoutio/providers-shop-gpt-sdk 1.11.2 → 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 -131
  2. package/index.js +292 -131
  3. package/index.mjs +292 -131
  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,12 +2014,14 @@ class ProductItem extends r$2 {
1922
2014
  ${this.getLocalPrice(comparedAtPrice)}
1923
2015
  </p>`;
1924
2016
  }
1925
- redirect(url) {
1926
- var _a;
2017
+ openProduct(url) {
1927
2018
  if (!url) {
1928
2019
  return;
1929
2020
  }
1930
- (_a = open(url, '_blank')) === null || _a === void 0 ? void 0 : _a.focus();
2021
+ const link = new URL(url);
2022
+ link.searchParams.set('utm_source', 'shopgpt');
2023
+ link.searchParams.set('utm_medium', 'chat');
2024
+ open(link, '_self');
1931
2025
  }
1932
2026
  renderVariantTitles() {
1933
2027
  if (this.product.hasOnlyDefaultVariant) {
@@ -1937,39 +2031,32 @@ class ProductItem extends r$2 {
1937
2031
  <p class="product-variation-details">${option.name}: ${option.value}</p>
1938
2032
  `);
1939
2033
  }
1940
- productClicked(productId, price, url) {
1941
- if (productId) {
2034
+ productClicked(product) {
2035
+ if (product.id) {
2036
+ const price = product.variants[0].price;
1942
2037
  this.dispatchEvent(new CustomEvent('product-clicked', {
1943
2038
  detail: {
1944
- productId,
2039
+ id: product.id,
1945
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,
1946
2047
  },
1947
2048
  composed: true,
1948
2049
  bubbles: true,
1949
2050
  }));
1950
2051
  }
1951
- this.redirect(url);
2052
+ this.openProduct(product.url);
1952
2053
  }
1953
2054
  render() {
1954
2055
  return x `
1955
- <div class="product">
1956
- <img
1957
- src=${this.product.image.url}
1958
- alt=${this.product.image.alt}
1959
- @click=${() => {
1960
- var _a;
1961
- return this.productClicked(this.product.id, this.product.variants[0].price, (_a = this.product) === null || _a === void 0 ? void 0 : _a.url);
1962
- }}
1963
- />
2056
+ <div class="product" @click=${() => this.productClicked(this.product)}>
2057
+ <img src=${this.product.image.url} alt=${this.product.image.alt} />
1964
2058
  <div class="content">
1965
- <p
1966
- class="product-name"
1967
- title=${this.product.title}
1968
- @click=${() => {
1969
- var _a;
1970
- return this.productClicked(this.product.id, this.product.variants[0].price, (_a = this.product) === null || _a === void 0 ? void 0 : _a.url);
1971
- }}
1972
- >
2059
+ <p class="product-name" title=${this.product.title}>
1973
2060
  ${this.product.title}
1974
2061
  </p>
1975
2062
  ${this.renderVariantTitles()}
@@ -1977,15 +2064,7 @@ class ProductItem extends r$2 {
1977
2064
  ${this.getComparedAtPrice(this.product.variants[0].comparedAtPrice, this.product.variants[0].price)}
1978
2065
  <p>${this.getLocalPrice(this.product.variants[0].price)}</p>
1979
2066
  </div>
1980
- <button
1981
- class="btn-view-product"
1982
- @click=${() => {
1983
- var _a;
1984
- return this.productClicked(this.product.id, this.product.variants[0].price, (_a = this.product) === null || _a === void 0 ? void 0 : _a.url);
1985
- }}
1986
- >
1987
- View Product
1988
- </button>
2067
+ <button class="btn-view-product">View Product</button>
1989
2068
  </div>
1990
2069
  </div>
1991
2070
  `;
@@ -2000,6 +2079,18 @@ __decorate([
2000
2079
  n({ type: Object }),
2001
2080
  __metadata("design:type", Object)
2002
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);
2003
2094
  if (!customElements.get('product-item')) {
2004
2095
  customElements.define('product-item', ProductItem);
2005
2096
  }
@@ -2116,7 +2207,7 @@ class ProductsList extends r$2 {
2116
2207
  return x `
2117
2208
  <div class="products-wrapper">
2118
2209
  <div class="products" @scroll=${this.updateButtonsState}>
2119
- ${o$1(this.products, (product) => x `
2210
+ ${o$1(this.products, (product, index) => x `
2120
2211
  <div
2121
2212
  class=${e$1({
2122
2213
  'product-container': true,
@@ -2124,8 +2215,11 @@ class ProductsList extends r$2 {
2124
2215
  })}
2125
2216
  >
2126
2217
  <product-item
2218
+ .query=${this.query}
2219
+ .response=${this.response}
2127
2220
  .product=${product}
2128
2221
  .siteCurrency=${this.siteCurrency}
2222
+ .rank=${index + 1}
2129
2223
  ></product-item>
2130
2224
  </div>
2131
2225
  `)}
@@ -2153,6 +2247,14 @@ __decorate([
2153
2247
  n({ type: Object }),
2154
2248
  __metadata("design:type", Object)
2155
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);
2156
2258
  __decorate([
2157
2259
  r(),
2158
2260
  __metadata("design:type", Object)
@@ -2199,6 +2301,7 @@ class ProductsSection extends r$2 {
2199
2301
  `;
2200
2302
  }
2201
2303
  render() {
2304
+ var _a;
2202
2305
  if (this.isLoadingHistory || this.isLoadingThreads) {
2203
2306
  return x ` <load-spinner></load-spinner> `;
2204
2307
  }
@@ -2209,18 +2312,25 @@ class ProductsSection extends r$2 {
2209
2312
  }
2210
2313
  const topResult = this.products[0];
2211
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];
2212
2317
  return x `
2213
2318
  <div class="top-result">
2214
2319
  <h2>Top Result</h2>
2215
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}
2216
2323
  .product=${topResult}
2217
2324
  .siteCurrency=${this.siteCurrency}
2325
+ .rank=${1}
2218
2326
  ></product-item>
2219
2327
  </div>
2220
2328
  <span class="line"></span>
2221
2329
  <div class="others">
2222
2330
  <h2>Other Recommendations</h2>
2223
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}
2224
2334
  .products=${others}
2225
2335
  .siteCurrency=${this.siteCurrency}
2226
2336
  .viewType=${'overlay'}
@@ -2266,6 +2376,10 @@ __decorate([
2266
2376
  n({ type: String }),
2267
2377
  __metadata("design:type", String)
2268
2378
  ], ProductsSection.prototype, "css", void 0);
2379
+ __decorate([
2380
+ n({ type: Array }),
2381
+ __metadata("design:type", Array)
2382
+ ], ProductsSection.prototype, "messages", void 0);
2269
2383
  if (!customElements.get('products-section')) {
2270
2384
  customElements.define('products-section', ProductsSection);
2271
2385
  }
@@ -3992,9 +4106,9 @@ class ChatSection extends r$2 {
3992
4106
  }
3993
4107
  await this.sendMessageToServer(e, message, isPrompt);
3994
4108
  }
3995
- sendEvent(action, actionData) {
4109
+ sendEvent(action, actionData, clickData) {
3996
4110
  this.dispatchEvent(new CustomEvent('send-event', {
3997
- detail: { action, actionData },
4111
+ detail: { action, actionData, clickData },
3998
4112
  composed: true,
3999
4113
  bubbles: true,
4000
4114
  }));
@@ -4025,24 +4139,38 @@ class ChatSection extends r$2 {
4025
4139
  }));
4026
4140
  this.deleteThreadId = '';
4027
4141
  }
4028
- handleFeedback(rating, messageId, queryMessageId, comment) {
4029
- var _a, _b;
4142
+ handleFeedback(rating, messageId, queryMessageId, comment, query, response) {
4143
+ var _a, _b, _c, _d;
4030
4144
  if (rating === 'bad') {
4031
- 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
+ });
4032
4153
  this.feedbackDetails = {
4033
4154
  messageId,
4034
4155
  queryMessageId,
4035
- 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) || '',
4036
4157
  comment,
4037
4158
  };
4038
4159
  return;
4039
4160
  }
4040
- 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
+ });
4041
4169
  this.dispatchEvent(new CustomEvent('submit-feedback', {
4042
4170
  detail: {
4043
4171
  messageId: messageId,
4044
4172
  queryMessageId: queryMessageId,
4045
- 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,
4046
4174
  feedback: {
4047
4175
  rating,
4048
4176
  comment: null,
@@ -4077,8 +4205,11 @@ class ChatSection extends r$2 {
4077
4205
  <span class="line"></span>
4078
4206
  <div class="product-container">
4079
4207
  <product-item
4208
+ .query=${queryMessage.message}
4209
+ .response=${message.message}
4080
4210
  .product=${message.products[0]}
4081
4211
  .siteCurrency=${this.siteCurrency}
4212
+ .rank=${1}
4082
4213
  ></product-item>
4083
4214
  </div>
4084
4215
  `
@@ -4087,16 +4218,18 @@ class ChatSection extends r$2 {
4087
4218
  </div>
4088
4219
  ${this.viewType === 'modal' && message.products
4089
4220
  ? x ` <products-list
4221
+ .query=${queryMessage.message}
4222
+ .response=${message.message}
4090
4223
  .products=${message.products}
4091
4224
  .siteCurrency=${this.siteCurrency}
4092
4225
  .viewType=${this.viewType}
4093
4226
  ></products-list>`
4094
4227
  : E}
4095
4228
  ${message.messageId && (queryMessage === null || queryMessage === void 0 ? void 0 : queryMessage.messageId)
4096
- ? x `<div class="bot-response-actions">
4229
+ ? x ` <div class="bot-response-actions">
4097
4230
  <button
4098
4231
  type="button"
4099
- @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)}
4100
4233
  >
4101
4234
  ${((_c = message.feedback) === null || _c === void 0 ? void 0 : _c.rating) === 'good'
4102
4235
  ? thumbsUpFilledBtn
@@ -4104,7 +4237,7 @@ class ChatSection extends r$2 {
4104
4237
  </button>
4105
4238
  <button
4106
4239
  type="button"
4107
- @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)}
4108
4241
  >
4109
4242
  ${((_e = message.feedback) === null || _e === void 0 ? void 0 : _e.rating) === 'bad'
4110
4243
  ? thumbsDownFilledBtn
@@ -4117,7 +4250,7 @@ class ChatSection extends r$2 {
4117
4250
  }
4118
4251
  renderBotIcon() {
4119
4252
  if (this.botIconUrl) {
4120
- return x `<div class="bot-icon">
4253
+ return x ` <div class="bot-icon">
4121
4254
  <img src=${this.botIconUrl} width="30" height="30" />
4122
4255
  </div>`;
4123
4256
  }
@@ -4125,7 +4258,7 @@ class ChatSection extends r$2 {
4125
4258
  }
4126
4259
  chatWindow() {
4127
4260
  if (this.isLoadingHistory || this.isLoadingThreads) {
4128
- return x `<div class="messages loading">
4261
+ return x ` <div class="messages loading">
4129
4262
  <load-spinner></load-spinner>
4130
4263
  </div>`;
4131
4264
  }
@@ -4138,7 +4271,7 @@ class ChatSection extends r$2 {
4138
4271
  </div>`
4139
4272
  : ''}
4140
4273
  ${this.isFailed
4141
- ? x `<div class="message bot">
4274
+ ? x ` <div class="message bot">
4142
4275
  <div>${this.renderBotIcon()}</div>
4143
4276
  <div>
4144
4277
  <p>
@@ -4158,18 +4291,20 @@ class ChatSection extends r$2 {
4158
4291
  })}
4159
4292
  ${!this.fromAd || !this.thread
4160
4293
  ? x `
4161
- <div class="message bot">
4162
- <div>${this.renderBotIcon()}</div>
4163
- <div>
4164
- <p>
4165
- Hi,
4166
- ${this.brandName ? x `Welcome to ${this.brandName}.` : E}
4167
- I'm here to help you find the perfect product. Pick a suggested
4168
- prompt from below, or enter your own query.
4169
- </p>
4170
- </div>
4171
- </div>
4172
- </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>`
4173
4308
  : E}
4174
4309
  </div>
4175
4310
  `;
@@ -4196,7 +4331,9 @@ class ChatSection extends r$2 {
4196
4331
  class="prompt"
4197
4332
  @click=${(e) => {
4198
4333
  this.processMessage(e, prompt, true);
4199
- this.sendEvent('promptClicked');
4334
+ this.sendEvent('promptClicked', undefined, {
4335
+ promptName: prompt,
4336
+ });
4200
4337
  }}
4201
4338
  >
4202
4339
  ${prompt}
@@ -4210,7 +4347,9 @@ class ChatSection extends r$2 {
4210
4347
  href=${link}
4211
4348
  target="_blank"
4212
4349
  rel="noopener"
4213
- @click=${() => this.sendEvent('promptClicked')}
4350
+ @click=${() => this.sendEvent('promptClicked', undefined, {
4351
+ promptName: prompt,
4352
+ })}
4214
4353
  >
4215
4354
  ${prompt}
4216
4355
  </a>
@@ -4401,7 +4540,7 @@ class ChatSection extends r$2 {
4401
4540
  <div class="title-wrapper">
4402
4541
  <h2>Search History</h2>
4403
4542
  ${this.chatThreads.size
4404
- ? x `<div
4543
+ ? x ` <div
4405
4544
  class="trash-icon"
4406
4545
  @click=${() => {
4407
4546
  if (this.isStreaming) {
@@ -4807,9 +4946,6 @@ class ShopGPT extends r$2 {
4807
4946
  this.startNudgeTimer();
4808
4947
  }
4809
4948
  disconnectedCallback() {
4810
- if (!this.loadUIManually) {
4811
- window.removeEventListener('edgetag-initialized', this.loadData);
4812
- }
4813
4949
  window.removeEventListener('popstate', this.onPopState);
4814
4950
  if (this.nudgeTimer) {
4815
4951
  window.clearTimeout(this.nudgeTimer);
@@ -4817,16 +4953,9 @@ class ShopGPT extends r$2 {
4817
4953
  super.disconnectedCallback();
4818
4954
  }
4819
4955
  init() {
4820
- if (this.loadUIManually) {
4821
- // this is because edgetag-initialized will already be
4822
- // triggered before the loadUI function is called to load the UI
4823
- this.loadData();
4824
- }
4825
- else {
4826
- window.addEventListener('edgetag-initialized', this.loadData);
4827
- }
4956
+ this.loadData();
4828
4957
  window.addEventListener('popstate', this.onPopState);
4829
- this.shopGPTAPI.sendEvent('shopGPTInitialized', this.getSiteCurrency().currency);
4958
+ this.shopGPTAPI.sendEvent('shopGPTLoaded');
4830
4959
  if (!this.view || this.view === 'overlay') {
4831
4960
  delay(DIALOG_DELAY)
4832
4961
  .then(() => {
@@ -4970,10 +5099,17 @@ class ShopGPT extends r$2 {
4970
5099
  }
4971
5100
  }
4972
5101
  async setSelectedThreadId(threadId, silent) {
5102
+ var _a, _b, _c, _d;
4973
5103
  this.isFailed = false;
5104
+ const currentThreadId = this.selectedThreadId;
4974
5105
  this.selectedThreadId = threadId;
4975
5106
  if (threadId && !silent) {
4976
- 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
+ });
4977
5113
  }
4978
5114
  await Promise.all([
4979
5115
  this.loadHistory(threadId),
@@ -4999,6 +5135,7 @@ class ShopGPT extends r$2 {
4999
5135
  }
5000
5136
  }
5001
5137
  handleThreadDelete(e) {
5138
+ var _a, _b;
5002
5139
  e.stopPropagation();
5003
5140
  this.isLoadingThreads = true;
5004
5141
  const threadId = e.detail.threadId;
@@ -5006,7 +5143,10 @@ class ShopGPT extends r$2 {
5006
5143
  logger.error('ThreadId is missing to delete the thread!');
5007
5144
  return;
5008
5145
  }
5009
- 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
+ });
5010
5150
  this.shopGPTAPI
5011
5151
  .deleteSingleThread(threadId)
5012
5152
  .then(this.loadChatThreads.bind(this))
@@ -5134,7 +5274,10 @@ class ShopGPT extends r$2 {
5134
5274
  try {
5135
5275
  this.isPreviousMessagePrompt = isPrompt;
5136
5276
  if (!isPrompt) {
5137
- this.shopGPTAPI.sendEvent('queryInteractions', this.getSiteCurrency().currency);
5277
+ this.shopGPTAPI.sendEvent('queryInteractions', this.getSiteCurrency().currency, undefined, {
5278
+ query: message,
5279
+ threadId: this.selectedThreadId,
5280
+ });
5138
5281
  }
5139
5282
  this.messages = [{ sender: 'user', message }, ...this.messages];
5140
5283
  this.isTyping = true;
@@ -5166,15 +5309,25 @@ class ShopGPT extends r$2 {
5166
5309
  }
5167
5310
  sendEvent(e) {
5168
5311
  e.stopPropagation();
5169
- 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);
5170
5313
  }
5171
5314
  productClicked(e) {
5315
+ var _a, _b;
5172
5316
  e.stopPropagation();
5173
- setProductAction(this.destination, this.sessionId, e.detail.productId, 'clicked', true);
5317
+ setProductAction(this.destination, this.sessionId, e.detail.id, 'clicked', true);
5174
5318
  this.shopGPTAPI.sendEvent('productRecommendationClicked', this.getSiteCurrency().currency, {
5175
- productId: e.detail.productId,
5319
+ productId: e.detail.id,
5176
5320
  value: e.detail.value,
5177
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,
5178
5331
  });
5179
5332
  }
5180
5333
  getSiteCurrency() {
@@ -5205,6 +5358,7 @@ class ShopGPT extends r$2 {
5205
5358
  .css=${this.css}
5206
5359
  ></chat-threads>
5207
5360
  <products-section
5361
+ .messages=${this.messages}
5208
5362
  .merchantImage=${this.merchantImage}
5209
5363
  .products=${this.products}
5210
5364
  .isLoadingHistory=${this.isLoadingHistory}
@@ -5250,26 +5404,23 @@ class ShopGPT extends r$2 {
5250
5404
  <button
5251
5405
  @click=${(e) => {
5252
5406
  e.preventDefault();
5253
- this.shopGPTAPI.sendEvent('chatbotOpened', this.getSiteCurrency().currency);
5254
- this.modalState = 'open';
5255
- this.handleUserInteraction();
5407
+ this.openModal();
5256
5408
  }}
5257
5409
  >
5258
5410
  ${chatIcon}
5259
5411
  </button>
5260
5412
  ${((_a = this.nudge) === null || _a === void 0 ? void 0 : _a.show) && this.showNudge
5261
- ? x `<div
5413
+ ? x ` <div
5262
5414
  class="nudge"
5263
5415
  @click=${(e) => {
5264
5416
  e.preventDefault();
5265
- this.modalState = 'open';
5266
- this.handleUserInteraction();
5417
+ this.openModal();
5267
5418
  }}
5268
5419
  >
5269
5420
  Hi there! I'm an AI Agent to help you find the perfect product.
5270
5421
  What are you looking for today?
5271
5422
  </div>`
5272
- : x `<div class="chatbot-hover-text">
5423
+ : x ` <div class="chatbot-hover-text">
5273
5424
  What are you looking for today?
5274
5425
  </div>`}
5275
5426
  </div>`;
@@ -5313,6 +5464,12 @@ class ShopGPT extends r$2 {
5313
5464
  </div>
5314
5465
  `;
5315
5466
  }
5467
+ openModal() {
5468
+ setIsBotOpened(this.destination, this.sessionId, true);
5469
+ this.shopGPTAPI.sendEvent('chatbotOpened');
5470
+ this.modalState = 'open';
5471
+ this.handleUserInteraction();
5472
+ }
5316
5473
  startNudgeTimer() {
5317
5474
  var _a, _b;
5318
5475
  if (this.view !== 'modal' || !((_a = this.nudge) === null || _a === void 0 ? void 0 : _a.show)) {
@@ -5351,6 +5508,11 @@ class ShopGPT extends r$2 {
5351
5508
  }
5352
5509
  render() {
5353
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
+ }
5354
5516
  return this.modalMode();
5355
5517
  }
5356
5518
  return this.overlayMode();
@@ -5460,14 +5622,13 @@ if (typeof window != 'undefined' && typeof document != 'undefined') {
5460
5622
  logger.log('ShopGPT component added already!');
5461
5623
  return;
5462
5624
  }
5625
+ setWasUserExposed(shopGPT.destination, shopGPT.sessionId, true);
5463
5626
  document.body.append(shopGPT);
5464
- setShopGPTLoaded(shopGPT.destination, shopGPT.sessionId, true);
5465
5627
  },
5466
5628
  destroy() {
5467
5629
  if (!shopGPT) {
5468
5630
  return;
5469
5631
  }
5470
- setShopGPTLoaded(shopGPT.destination, shopGPT.sessionId, false);
5471
5632
  shopGPT.remove();
5472
5633
  shopGPT = undefined;
5473
5634
  delete window[registryKey];