@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.cjs.js CHANGED
@@ -376,6 +376,8 @@ const createDisabled = () => ({
376
376
  groupName: '',
377
377
  isEnabled: false,
378
378
  });
379
+ // userId => 92ae5ac6-b47c-4444-923f-87d98b7e1fac-1743927514247
380
+ // sample => 92ae5ac6
379
381
  const createABTest = ({ userId }) => {
380
382
  const [sample] = userId.split('-');
381
383
  const segment = parseInt(sample, 16) % 2;
@@ -411,6 +413,7 @@ const createExperiment = (props) => {
411
413
  /** Action length should not exceed 42 */
412
414
  const uiActions = new Set([
413
415
  'shopGPTInitialized',
416
+ 'shopGPTLoaded',
414
417
  'chatbotOpened',
415
418
  'chatbotClosed',
416
419
  'singleThreadDelete',
@@ -625,16 +628,16 @@ const setProductAction = (destination, sessionId, productId, action, value) => {
625
628
  const updatedLocal = { [sessionId]: local[sessionId] };
626
629
  saveLocalStorageData(destination, updatedLocal);
627
630
  };
628
- const getShopGPTLoaded = (destination, sessionId) => {
631
+ const getWasUserExposed = (destination, sessionId) => {
629
632
  var _a, _b;
630
633
  const local = getLocalStorageData(destination);
631
634
  if (!local || !sessionId) {
632
635
  logger.error('No local storage data or session id');
633
636
  return false;
634
637
  }
635
- return (_b = (_a = local[sessionId]) === null || _a === void 0 ? void 0 : _a.isShopGPTLoaded) !== null && _b !== void 0 ? _b : false;
638
+ return (_b = (_a = local[sessionId]) === null || _a === void 0 ? void 0 : _a.exposed) !== null && _b !== void 0 ? _b : false;
636
639
  };
637
- const setShopGPTLoaded = (destination, sessionId, value) => {
640
+ const setWasUserExposed = (destination, sessionId, value) => {
638
641
  const local = getLocalStorageData(destination);
639
642
  if (!local || !sessionId) {
640
643
  logger.error('No local storage data or session id');
@@ -642,14 +645,60 @@ const setShopGPTLoaded = (destination, sessionId, value) => {
642
645
  }
643
646
  local[sessionId] = {
644
647
  ...local[sessionId],
645
- isShopGPTLoaded: value,
648
+ exposed: value,
646
649
  };
647
650
  // Clear other sessions
648
651
  const updatedLocal = { [sessionId]: local[sessionId] };
649
652
  saveLocalStorageData(destination, updatedLocal);
650
653
  };
654
+ const setUserType = (destination, sessionId, value) => {
655
+ const local = getLocalStorageData(destination);
656
+ if (!local || !sessionId) {
657
+ logger.error('No session id');
658
+ return;
659
+ }
660
+ local[sessionId] = {
661
+ ...local[sessionId],
662
+ userType: value,
663
+ };
664
+ // Clear other sessions
665
+ const updatedLocal = { [sessionId]: local[sessionId] };
666
+ saveLocalStorageData(destination, updatedLocal);
667
+ };
668
+ const getUserType = (destination, sessionId) => {
669
+ var _a;
670
+ const local = getLocalStorageData(destination);
671
+ if (!sessionId) {
672
+ logger.error('No session id');
673
+ return;
674
+ }
675
+ return (_a = local === null || local === void 0 ? void 0 : local[sessionId]) === null || _a === void 0 ? void 0 : _a.userType;
676
+ };
677
+ const setIsBotOpened = (destination, sessionId, value) => {
678
+ const local = getLocalStorageData(destination);
679
+ if (!local || !sessionId) {
680
+ logger.error('No session id');
681
+ return;
682
+ }
683
+ local[sessionId] = {
684
+ ...local[sessionId],
685
+ opened: value,
686
+ };
687
+ // Clear other sessions
688
+ const updatedLocal = { [sessionId]: local[sessionId] };
689
+ saveLocalStorageData(destination, updatedLocal);
690
+ };
691
+ const getIsBotOpened = (destination, sessionId) => {
692
+ var _a;
693
+ const local = getLocalStorageData(destination);
694
+ if (!sessionId) {
695
+ logger.error('No session id');
696
+ return;
697
+ }
698
+ return (_a = local === null || local === void 0 ? void 0 : local[sessionId]) === null || _a === void 0 ? void 0 : _a.opened;
699
+ };
651
700
 
652
- const createShopGPTAPI = ({ fetch: fetchImpl = window.fetch, baseURL, userId, storeAPI, sessionId, }) => {
701
+ const createShopGPTAPI = ({ fetch: fetchImpl = window.fetch, baseURL, userId, storeAPI, sessionId, sendTag, }) => {
653
702
  if (!baseURL) {
654
703
  throw new Error(`baseURL missing`);
655
704
  }
@@ -779,9 +828,12 @@ const createShopGPTAPI = ({ fetch: fetchImpl = window.fetch, baseURL, userId, st
779
828
  const data = (await response.json());
780
829
  return data.customPrompts;
781
830
  };
782
- const sendEvent = (action, currency, actionData) => {
831
+ const sendEvent = (action, currency, actionData, clickData) => {
783
832
  var _a;
784
833
  const storageData = (_a = getProductActions(baseURL, sessionId)) !== null && _a !== void 0 ? _a : {};
834
+ const userType = getUserType(baseURL, sessionId);
835
+ const exposed = getWasUserExposed(baseURL, sessionId);
836
+ const opened = getIsBotOpened(baseURL, sessionId);
785
837
  // This endpoint sends user events to the server, we don't need to wait for the response
786
838
  fetchImpl(getURL('/user/event'), {
787
839
  method: 'POST',
@@ -793,7 +845,9 @@ const createShopGPTAPI = ({ fetch: fetchImpl = window.fetch, baseURL, userId, st
793
845
  storageData: {
794
846
  session: storageData,
795
847
  preview: hasPreviewKey(),
796
- isShopGPTLoaded: true, // The fact that sendEvent was called means that the ShopGPT is loaded
848
+ userType: userType,
849
+ exposed,
850
+ opened: !!opened,
797
851
  },
798
852
  }),
799
853
  credentials: 'include',
@@ -804,6 +858,21 @@ const createShopGPTAPI = ({ fetch: fetchImpl = window.fetch, baseURL, userId, st
804
858
  }
805
859
  })
806
860
  .catch(logger.error);
861
+ sendTag({
862
+ eventId: crypto.randomUUID(),
863
+ eventName: action,
864
+ data: {
865
+ ...actionData,
866
+ ...clickData,
867
+ userType,
868
+ exposed,
869
+ storageData,
870
+ opened: !!opened,
871
+ },
872
+ providers: {
873
+ shopGPT: true,
874
+ },
875
+ });
807
876
  };
808
877
  return {
809
878
  processQuery,
@@ -821,7 +890,7 @@ const createShopGPTAPI = ({ fetch: fetchImpl = window.fetch, baseURL, userId, st
821
890
  // eslint-disable-next-line @nx/enforce-module-boundaries
822
891
  const error = (message) => console.error(message);
823
892
  const init = (params) => {
824
- var _a, _b, _c, _d, _e, _f;
893
+ var _a, _b, _c;
825
894
  if (typeof window == 'undefined' || typeof document == 'undefined') {
826
895
  // if loaded in non-browser SDKs, return early
827
896
  return;
@@ -840,7 +909,6 @@ const init = (params) => {
840
909
  return;
841
910
  }
842
911
  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 : {};
843
- setShopGPTLoaded(params.baseUrl, (_d = params.session) === null || _d === void 0 ? void 0 : _d.sessionId, !loadUIManually);
844
912
  const experiment = createExperiment({
845
913
  name: getExperimentName(mode),
846
914
  userId: params.userId,
@@ -850,42 +918,65 @@ const init = (params) => {
850
918
  if (experiment.name === 'preview' && shouldShowUI) {
851
919
  logger.log('Enabling UI in preview mode');
852
920
  }
853
- if (shouldShowUI) {
854
- const uiImplementation = window[registryKey].ui;
855
- if (!uiImplementation) {
856
- error('UI implementation is missing');
857
- return;
921
+ // once we implement a general version with togglable option to discriminate
922
+ // between anon/known, we'll be able to skip creating this promise before
923
+ // init and possibly loading the UI
924
+ new Promise((resolve) => {
925
+ var _a;
926
+ const userType = getUserType(params.baseUrl, (_a = params.session) === null || _a === void 0 ? void 0 : _a.sessionId);
927
+ if (userType) {
928
+ return resolve();
858
929
  }
930
+ params.getEdgeData(['email'], (data) => {
931
+ var _a;
932
+ setUserType(params.baseUrl, (_a = params.session) === null || _a === void 0 ? void 0 : _a.sessionId, data['emailExists'] ? 'known' : 'anon');
933
+ resolve();
934
+ });
935
+ }).then(() => {
936
+ var _a, _b;
859
937
  const shopGPTAPI = createShopGPTAPI({
860
938
  baseURL: params.baseUrl,
861
939
  storeAPI,
862
940
  userId: params.userId,
863
- sessionId: (_e = params.session) === null || _e === void 0 ? void 0 : _e.sessionId,
941
+ sessionId: (_a = params.session) === null || _a === void 0 ? void 0 : _a.sessionId,
942
+ sendTag: params.sendTag,
864
943
  });
865
- uiImplementation.init({
866
- destination: params.baseUrl,
867
- storeAPI,
868
- shopGPTAPI,
869
- devMode,
870
- view,
871
- merchantUrl,
872
- profiles,
873
- productHandles,
874
- path: targetPath,
875
- brandName,
876
- quickPrompts,
877
- merchantImage,
878
- latestThreadLoad: latestThreadLoad !== null && latestThreadLoad !== void 0 ? latestThreadLoad : DEFAULT_MAX_THREAD_AGE,
879
- botIconUrl,
880
- css,
881
- nudge,
882
- sessionId: (_f = params.session) === null || _f === void 0 ? void 0 : _f.sessionId,
883
- loadUIManually,
944
+ shopGPTAPI.sendEvent('shopGPTInitialized', undefined, undefined, {
945
+ groupName: experiment.groupName,
884
946
  });
885
- if (!loadUIManually) {
886
- uiImplementation.loadUI();
947
+ if (shouldShowUI) {
948
+ const uiImplementation = window[registryKey].ui;
949
+ if (!uiImplementation) {
950
+ error('UI implementation is missing');
951
+ return;
952
+ }
953
+ uiImplementation.init({
954
+ destination: params.baseUrl,
955
+ storeAPI,
956
+ shopGPTAPI,
957
+ devMode,
958
+ view,
959
+ merchantUrl,
960
+ profiles,
961
+ productHandles,
962
+ path: targetPath,
963
+ brandName,
964
+ quickPrompts,
965
+ merchantImage,
966
+ latestThreadLoad: latestThreadLoad !== null && latestThreadLoad !== void 0 ? latestThreadLoad : DEFAULT_MAX_THREAD_AGE,
967
+ botIconUrl,
968
+ css,
969
+ nudge,
970
+ sessionId: (_b = params.session) === null || _b === void 0 ? void 0 : _b.sessionId,
971
+ loadUIManually,
972
+ });
973
+ const searchParams = new URLSearchParams(window.location.search);
974
+ const hasSource = searchParams.get('utm_source') === 'shopgpt';
975
+ if (!loadUIManually || hasSource) {
976
+ uiImplementation.loadUI();
977
+ }
887
978
  }
888
- }
979
+ });
889
980
  };
890
981
 
891
982
  const getClickedProductsInContents = (destination, sessionId, data) => {
@@ -897,7 +988,7 @@ const getClickedProductsInContents = (destination, sessionId, data) => {
897
988
  return contents.flatMap((content) => { var _a; return ((_a = storedData[content.id]) === null || _a === void 0 ? void 0 : _a.clicked) ? [content.id] : []; });
898
989
  };
899
990
  const tag = ({ eventName, destination, data, sessionId, }) => {
900
- var _a;
991
+ var _a, _b;
901
992
  const clickedProducts = getClickedProductsInContents(destination, sessionId, data);
902
993
  if (eventName === 'AddToCart') {
903
994
  clickedProducts === null || clickedProducts === void 0 ? void 0 : clickedProducts.forEach((id) => {
@@ -912,7 +1003,9 @@ const tag = ({ eventName, destination, data, sessionId, }) => {
912
1003
  return {
913
1004
  session: getProductActions(destination, sessionId),
914
1005
  preview: hasPreviewKey(),
915
- isShopGPTLoaded: (_a = getShopGPTLoaded(destination, sessionId)) !== null && _a !== void 0 ? _a : false,
1006
+ exposed: (_a = getWasUserExposed(destination, sessionId)) !== null && _a !== void 0 ? _a : false,
1007
+ userType: getUserType(destination, sessionId),
1008
+ opened: (_b = getIsBotOpened(destination, sessionId)) !== null && _b !== void 0 ? _b : false,
916
1009
  };
917
1010
  };
918
1011
 
@@ -1782,13 +1875,13 @@ const productItemStyles = i$4 `
1782
1875
  .product {
1783
1876
  display: flex;
1784
1877
  gap: 16px;
1878
+ cursor: pointer;
1785
1879
 
1786
1880
  img {
1787
1881
  width: 150px;
1788
1882
  height: 186px;
1789
1883
  object-position: center;
1790
1884
  object-fit: contain;
1791
- cursor: pointer;
1792
1885
  }
1793
1886
  }
1794
1887
 
@@ -1813,7 +1906,6 @@ const productItemStyles = i$4 `
1813
1906
  text-overflow: ellipsis;
1814
1907
  word-break: break-word;
1815
1908
  white-space: normal;
1816
- cursor: pointer;
1817
1909
  }
1818
1910
 
1819
1911
  .product-variation-details {
@@ -1924,12 +2016,14 @@ class ProductItem extends r$2 {
1924
2016
  ${this.getLocalPrice(comparedAtPrice)}
1925
2017
  </p>`;
1926
2018
  }
1927
- redirect(url) {
1928
- var _a;
2019
+ openProduct(url) {
1929
2020
  if (!url) {
1930
2021
  return;
1931
2022
  }
1932
- (_a = open(url, '_blank')) === null || _a === void 0 ? void 0 : _a.focus();
2023
+ const link = new URL(url);
2024
+ link.searchParams.set('utm_source', 'shopgpt');
2025
+ link.searchParams.set('utm_medium', 'chat');
2026
+ open(link, '_self');
1933
2027
  }
1934
2028
  renderVariantTitles() {
1935
2029
  if (this.product.hasOnlyDefaultVariant) {
@@ -1939,39 +2033,32 @@ class ProductItem extends r$2 {
1939
2033
  <p class="product-variation-details">${option.name}: ${option.value}</p>
1940
2034
  `);
1941
2035
  }
1942
- productClicked(productId, price, url) {
1943
- if (productId) {
2036
+ productClicked(product) {
2037
+ if (product.id) {
2038
+ const price = product.variants[0].price;
1944
2039
  this.dispatchEvent(new CustomEvent('product-clicked', {
1945
2040
  detail: {
1946
- productId,
2041
+ id: product.id,
1947
2042
  value: price ? parseFloat(price) : undefined,
2043
+ variantId: product.variants[0].id,
2044
+ title: product.title,
2045
+ url: product.url,
2046
+ query: this.query,
2047
+ response: this.response,
2048
+ rank: this.rank,
1948
2049
  },
1949
2050
  composed: true,
1950
2051
  bubbles: true,
1951
2052
  }));
1952
2053
  }
1953
- this.redirect(url);
2054
+ this.openProduct(product.url);
1954
2055
  }
1955
2056
  render() {
1956
2057
  return x `
1957
- <div class="product">
1958
- <img
1959
- src=${this.product.image.url}
1960
- alt=${this.product.image.alt}
1961
- @click=${() => {
1962
- var _a;
1963
- return this.productClicked(this.product.id, this.product.variants[0].price, (_a = this.product) === null || _a === void 0 ? void 0 : _a.url);
1964
- }}
1965
- />
2058
+ <div class="product" @click=${() => this.productClicked(this.product)}>
2059
+ <img src=${this.product.image.url} alt=${this.product.image.alt} />
1966
2060
  <div class="content">
1967
- <p
1968
- class="product-name"
1969
- title=${this.product.title}
1970
- @click=${() => {
1971
- var _a;
1972
- return this.productClicked(this.product.id, this.product.variants[0].price, (_a = this.product) === null || _a === void 0 ? void 0 : _a.url);
1973
- }}
1974
- >
2061
+ <p class="product-name" title=${this.product.title}>
1975
2062
  ${this.product.title}
1976
2063
  </p>
1977
2064
  ${this.renderVariantTitles()}
@@ -1979,15 +2066,7 @@ class ProductItem extends r$2 {
1979
2066
  ${this.getComparedAtPrice(this.product.variants[0].comparedAtPrice, this.product.variants[0].price)}
1980
2067
  <p>${this.getLocalPrice(this.product.variants[0].price)}</p>
1981
2068
  </div>
1982
- <button
1983
- class="btn-view-product"
1984
- @click=${() => {
1985
- var _a;
1986
- return this.productClicked(this.product.id, this.product.variants[0].price, (_a = this.product) === null || _a === void 0 ? void 0 : _a.url);
1987
- }}
1988
- >
1989
- View Product
1990
- </button>
2069
+ <button class="btn-view-product">View Product</button>
1991
2070
  </div>
1992
2071
  </div>
1993
2072
  `;
@@ -2002,6 +2081,18 @@ __decorate([
2002
2081
  n({ type: Object }),
2003
2082
  __metadata("design:type", Object)
2004
2083
  ], ProductItem.prototype, "siteCurrency", void 0);
2084
+ __decorate([
2085
+ n({ type: String }),
2086
+ __metadata("design:type", Object)
2087
+ ], ProductItem.prototype, "query", void 0);
2088
+ __decorate([
2089
+ n({ type: String }),
2090
+ __metadata("design:type", String)
2091
+ ], ProductItem.prototype, "response", void 0);
2092
+ __decorate([
2093
+ n({ type: Number }),
2094
+ __metadata("design:type", Number)
2095
+ ], ProductItem.prototype, "rank", void 0);
2005
2096
  if (!customElements.get('product-item')) {
2006
2097
  customElements.define('product-item', ProductItem);
2007
2098
  }
@@ -2118,7 +2209,7 @@ class ProductsList extends r$2 {
2118
2209
  return x `
2119
2210
  <div class="products-wrapper">
2120
2211
  <div class="products" @scroll=${this.updateButtonsState}>
2121
- ${o$1(this.products, (product) => x `
2212
+ ${o$1(this.products, (product, index) => x `
2122
2213
  <div
2123
2214
  class=${e$1({
2124
2215
  'product-container': true,
@@ -2126,8 +2217,11 @@ class ProductsList extends r$2 {
2126
2217
  })}
2127
2218
  >
2128
2219
  <product-item
2220
+ .query=${this.query}
2221
+ .response=${this.response}
2129
2222
  .product=${product}
2130
2223
  .siteCurrency=${this.siteCurrency}
2224
+ .rank=${index + 1}
2131
2225
  ></product-item>
2132
2226
  </div>
2133
2227
  `)}
@@ -2155,6 +2249,14 @@ __decorate([
2155
2249
  n({ type: Object }),
2156
2250
  __metadata("design:type", Object)
2157
2251
  ], ProductsList.prototype, "siteCurrency", void 0);
2252
+ __decorate([
2253
+ n({ type: String }),
2254
+ __metadata("design:type", Object)
2255
+ ], ProductsList.prototype, "query", void 0);
2256
+ __decorate([
2257
+ n({ type: String }),
2258
+ __metadata("design:type", String)
2259
+ ], ProductsList.prototype, "response", void 0);
2158
2260
  __decorate([
2159
2261
  r(),
2160
2262
  __metadata("design:type", Object)
@@ -2201,6 +2303,7 @@ class ProductsSection extends r$2 {
2201
2303
  `;
2202
2304
  }
2203
2305
  render() {
2306
+ var _a;
2204
2307
  if (this.isLoadingHistory || this.isLoadingThreads) {
2205
2308
  return x ` <load-spinner></load-spinner> `;
2206
2309
  }
@@ -2211,18 +2314,25 @@ class ProductsSection extends r$2 {
2211
2314
  }
2212
2315
  const topResult = this.products[0];
2213
2316
  const others = this.products.slice(1);
2317
+ const query = (_a = this.messages) === null || _a === void 0 ? void 0 : _a[1];
2318
+ const response = this.messages[0];
2214
2319
  return x `
2215
2320
  <div class="top-result">
2216
2321
  <h2>Top Result</h2>
2217
2322
  <product-item
2323
+ .query=${query === null || query === void 0 ? void 0 : query.message}
2324
+ .response=${response === null || response === void 0 ? void 0 : response.message}
2218
2325
  .product=${topResult}
2219
2326
  .siteCurrency=${this.siteCurrency}
2327
+ .rank=${1}
2220
2328
  ></product-item>
2221
2329
  </div>
2222
2330
  <span class="line"></span>
2223
2331
  <div class="others">
2224
2332
  <h2>Other Recommendations</h2>
2225
2333
  <products-list
2334
+ .query=${query === null || query === void 0 ? void 0 : query.message}
2335
+ .response=${response === null || response === void 0 ? void 0 : response.message}
2226
2336
  .products=${others}
2227
2337
  .siteCurrency=${this.siteCurrency}
2228
2338
  .viewType=${'overlay'}
@@ -2268,6 +2378,10 @@ __decorate([
2268
2378
  n({ type: String }),
2269
2379
  __metadata("design:type", String)
2270
2380
  ], ProductsSection.prototype, "css", void 0);
2381
+ __decorate([
2382
+ n({ type: Array }),
2383
+ __metadata("design:type", Array)
2384
+ ], ProductsSection.prototype, "messages", void 0);
2271
2385
  if (!customElements.get('products-section')) {
2272
2386
  customElements.define('products-section', ProductsSection);
2273
2387
  }
@@ -3994,9 +4108,9 @@ class ChatSection extends r$2 {
3994
4108
  }
3995
4109
  await this.sendMessageToServer(e, message, isPrompt);
3996
4110
  }
3997
- sendEvent(action, actionData) {
4111
+ sendEvent(action, actionData, clickData) {
3998
4112
  this.dispatchEvent(new CustomEvent('send-event', {
3999
- detail: { action, actionData },
4113
+ detail: { action, actionData, clickData },
4000
4114
  composed: true,
4001
4115
  bubbles: true,
4002
4116
  }));
@@ -4027,24 +4141,38 @@ class ChatSection extends r$2 {
4027
4141
  }));
4028
4142
  this.deleteThreadId = '';
4029
4143
  }
4030
- handleFeedback(rating, messageId, queryMessageId, comment) {
4031
- var _a, _b;
4144
+ handleFeedback(rating, messageId, queryMessageId, comment, query, response) {
4145
+ var _a, _b, _c, _d;
4032
4146
  if (rating === 'bad') {
4033
- this.sendEvent('thumbsDown');
4147
+ this.sendEvent('thumbsDown', undefined, {
4148
+ messageId,
4149
+ threadId: ((_a = this.thread) === null || _a === void 0 ? void 0 : _a.threadId) || '',
4150
+ rating,
4151
+ comment: comment !== null && comment !== void 0 ? comment : '',
4152
+ query: query !== null && query !== void 0 ? query : '',
4153
+ response: response !== null && response !== void 0 ? response : '',
4154
+ });
4034
4155
  this.feedbackDetails = {
4035
4156
  messageId,
4036
4157
  queryMessageId,
4037
- threadId: ((_a = this.thread) === null || _a === void 0 ? void 0 : _a.threadId) || '',
4158
+ threadId: ((_b = this.thread) === null || _b === void 0 ? void 0 : _b.threadId) || '',
4038
4159
  comment,
4039
4160
  };
4040
4161
  return;
4041
4162
  }
4042
- this.sendEvent('thumbsUp');
4163
+ this.sendEvent('thumbsUp', undefined, {
4164
+ messageId,
4165
+ threadId: ((_c = this.thread) === null || _c === void 0 ? void 0 : _c.threadId) || '',
4166
+ rating,
4167
+ comment: comment !== null && comment !== void 0 ? comment : '',
4168
+ query: query !== null && query !== void 0 ? query : '',
4169
+ response: response !== null && response !== void 0 ? response : '',
4170
+ });
4043
4171
  this.dispatchEvent(new CustomEvent('submit-feedback', {
4044
4172
  detail: {
4045
4173
  messageId: messageId,
4046
4174
  queryMessageId: queryMessageId,
4047
- threadId: (_b = this.thread) === null || _b === void 0 ? void 0 : _b.threadId,
4175
+ threadId: (_d = this.thread) === null || _d === void 0 ? void 0 : _d.threadId,
4048
4176
  feedback: {
4049
4177
  rating,
4050
4178
  comment: null,
@@ -4079,8 +4207,11 @@ class ChatSection extends r$2 {
4079
4207
  <span class="line"></span>
4080
4208
  <div class="product-container">
4081
4209
  <product-item
4210
+ .query=${queryMessage.message}
4211
+ .response=${message.message}
4082
4212
  .product=${message.products[0]}
4083
4213
  .siteCurrency=${this.siteCurrency}
4214
+ .rank=${1}
4084
4215
  ></product-item>
4085
4216
  </div>
4086
4217
  `
@@ -4089,16 +4220,18 @@ class ChatSection extends r$2 {
4089
4220
  </div>
4090
4221
  ${this.viewType === 'modal' && message.products
4091
4222
  ? x ` <products-list
4223
+ .query=${queryMessage.message}
4224
+ .response=${message.message}
4092
4225
  .products=${message.products}
4093
4226
  .siteCurrency=${this.siteCurrency}
4094
4227
  .viewType=${this.viewType}
4095
4228
  ></products-list>`
4096
4229
  : E}
4097
4230
  ${message.messageId && (queryMessage === null || queryMessage === void 0 ? void 0 : queryMessage.messageId)
4098
- ? x `<div class="bot-response-actions">
4231
+ ? x ` <div class="bot-response-actions">
4099
4232
  <button
4100
4233
  type="button"
4101
- @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)}
4234
+ @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)}
4102
4235
  >
4103
4236
  ${((_c = message.feedback) === null || _c === void 0 ? void 0 : _c.rating) === 'good'
4104
4237
  ? thumbsUpFilledBtn
@@ -4106,7 +4239,7 @@ class ChatSection extends r$2 {
4106
4239
  </button>
4107
4240
  <button
4108
4241
  type="button"
4109
- @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)}
4242
+ @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)}
4110
4243
  >
4111
4244
  ${((_e = message.feedback) === null || _e === void 0 ? void 0 : _e.rating) === 'bad'
4112
4245
  ? thumbsDownFilledBtn
@@ -4119,7 +4252,7 @@ class ChatSection extends r$2 {
4119
4252
  }
4120
4253
  renderBotIcon() {
4121
4254
  if (this.botIconUrl) {
4122
- return x `<div class="bot-icon">
4255
+ return x ` <div class="bot-icon">
4123
4256
  <img src=${this.botIconUrl} width="30" height="30" />
4124
4257
  </div>`;
4125
4258
  }
@@ -4127,7 +4260,7 @@ class ChatSection extends r$2 {
4127
4260
  }
4128
4261
  chatWindow() {
4129
4262
  if (this.isLoadingHistory || this.isLoadingThreads) {
4130
- return x `<div class="messages loading">
4263
+ return x ` <div class="messages loading">
4131
4264
  <load-spinner></load-spinner>
4132
4265
  </div>`;
4133
4266
  }
@@ -4140,7 +4273,7 @@ class ChatSection extends r$2 {
4140
4273
  </div>`
4141
4274
  : ''}
4142
4275
  ${this.isFailed
4143
- ? x `<div class="message bot">
4276
+ ? x ` <div class="message bot">
4144
4277
  <div>${this.renderBotIcon()}</div>
4145
4278
  <div>
4146
4279
  <p>
@@ -4160,18 +4293,20 @@ class ChatSection extends r$2 {
4160
4293
  })}
4161
4294
  ${!this.fromAd || !this.thread
4162
4295
  ? x `
4163
- <div class="message bot">
4164
- <div>${this.renderBotIcon()}</div>
4165
- <div>
4166
- <p>
4167
- Hi,
4168
- ${this.brandName ? x `Welcome to ${this.brandName}.` : E}
4169
- I'm here to help you find the perfect product. Pick a suggested
4170
- prompt from below, or enter your own query.
4171
- </p>
4172
- </div>
4173
- </div>
4174
- </div>`
4296
+ <div class="message bot">
4297
+ <div>${this.renderBotIcon()}</div>
4298
+ <div>
4299
+ <p>
4300
+ Hi,
4301
+ ${this.brandName
4302
+ ? x `Welcome to ${this.brandName}.`
4303
+ : E}
4304
+ I'm here to help you find the perfect product. Pick a suggested
4305
+ prompt from below, or enter your own query.
4306
+ </p>
4307
+ </div>
4308
+ </div>
4309
+ </div>`
4175
4310
  : E}
4176
4311
  </div>
4177
4312
  `;
@@ -4198,7 +4333,9 @@ class ChatSection extends r$2 {
4198
4333
  class="prompt"
4199
4334
  @click=${(e) => {
4200
4335
  this.processMessage(e, prompt, true);
4201
- this.sendEvent('promptClicked');
4336
+ this.sendEvent('promptClicked', undefined, {
4337
+ promptName: prompt,
4338
+ });
4202
4339
  }}
4203
4340
  >
4204
4341
  ${prompt}
@@ -4212,7 +4349,9 @@ class ChatSection extends r$2 {
4212
4349
  href=${link}
4213
4350
  target="_blank"
4214
4351
  rel="noopener"
4215
- @click=${() => this.sendEvent('promptClicked')}
4352
+ @click=${() => this.sendEvent('promptClicked', undefined, {
4353
+ promptName: prompt,
4354
+ })}
4216
4355
  >
4217
4356
  ${prompt}
4218
4357
  </a>
@@ -4403,7 +4542,7 @@ class ChatSection extends r$2 {
4403
4542
  <div class="title-wrapper">
4404
4543
  <h2>Search History</h2>
4405
4544
  ${this.chatThreads.size
4406
- ? x `<div
4545
+ ? x ` <div
4407
4546
  class="trash-icon"
4408
4547
  @click=${() => {
4409
4548
  if (this.isStreaming) {
@@ -4809,9 +4948,6 @@ class ShopGPT extends r$2 {
4809
4948
  this.startNudgeTimer();
4810
4949
  }
4811
4950
  disconnectedCallback() {
4812
- if (!this.loadUIManually) {
4813
- window.removeEventListener('edgetag-initialized', this.loadData);
4814
- }
4815
4951
  window.removeEventListener('popstate', this.onPopState);
4816
4952
  if (this.nudgeTimer) {
4817
4953
  window.clearTimeout(this.nudgeTimer);
@@ -4819,16 +4955,9 @@ class ShopGPT extends r$2 {
4819
4955
  super.disconnectedCallback();
4820
4956
  }
4821
4957
  init() {
4822
- if (this.loadUIManually) {
4823
- // this is because edgetag-initialized will already be
4824
- // triggered before the loadUI function is called to load the UI
4825
- this.loadData();
4826
- }
4827
- else {
4828
- window.addEventListener('edgetag-initialized', this.loadData);
4829
- }
4958
+ this.loadData();
4830
4959
  window.addEventListener('popstate', this.onPopState);
4831
- this.shopGPTAPI.sendEvent('shopGPTInitialized', this.getSiteCurrency().currency);
4960
+ this.shopGPTAPI.sendEvent('shopGPTLoaded');
4832
4961
  if (!this.view || this.view === 'overlay') {
4833
4962
  delay(DIALOG_DELAY)
4834
4963
  .then(() => {
@@ -4972,10 +5101,17 @@ class ShopGPT extends r$2 {
4972
5101
  }
4973
5102
  }
4974
5103
  async setSelectedThreadId(threadId, silent) {
5104
+ var _a, _b, _c, _d;
4975
5105
  this.isFailed = false;
5106
+ const currentThreadId = this.selectedThreadId;
4976
5107
  this.selectedThreadId = threadId;
4977
5108
  if (threadId && !silent) {
4978
- this.shopGPTAPI.sendEvent('switchThread');
5109
+ this.shopGPTAPI.sendEvent('switchThread', undefined, undefined, {
5110
+ previousThread: currentThreadId,
5111
+ activeThread: threadId,
5112
+ previousThreadTitle: (_b = (_a = this.chatThreads.get(currentThreadId)) === null || _a === void 0 ? void 0 : _a.title) !== null && _b !== void 0 ? _b : '',
5113
+ activeThreadTitle: (_d = (_c = this.chatThreads.get(this.selectedThreadId)) === null || _c === void 0 ? void 0 : _c.title) !== null && _d !== void 0 ? _d : '',
5114
+ });
4979
5115
  }
4980
5116
  await Promise.all([
4981
5117
  this.loadHistory(threadId),
@@ -5001,6 +5137,7 @@ class ShopGPT extends r$2 {
5001
5137
  }
5002
5138
  }
5003
5139
  handleThreadDelete(e) {
5140
+ var _a, _b;
5004
5141
  e.stopPropagation();
5005
5142
  this.isLoadingThreads = true;
5006
5143
  const threadId = e.detail.threadId;
@@ -5008,7 +5145,10 @@ class ShopGPT extends r$2 {
5008
5145
  logger.error('ThreadId is missing to delete the thread!');
5009
5146
  return;
5010
5147
  }
5011
- this.shopGPTAPI.sendEvent('singleThreadDelete');
5148
+ this.shopGPTAPI.sendEvent('singleThreadDelete', undefined, undefined, {
5149
+ thread: threadId,
5150
+ threadTitle: (_b = (_a = this.chatThreads.get(threadId)) === null || _a === void 0 ? void 0 : _a.title) !== null && _b !== void 0 ? _b : '',
5151
+ });
5012
5152
  this.shopGPTAPI
5013
5153
  .deleteSingleThread(threadId)
5014
5154
  .then(this.loadChatThreads.bind(this))
@@ -5136,7 +5276,10 @@ class ShopGPT extends r$2 {
5136
5276
  try {
5137
5277
  this.isPreviousMessagePrompt = isPrompt;
5138
5278
  if (!isPrompt) {
5139
- this.shopGPTAPI.sendEvent('queryInteractions', this.getSiteCurrency().currency);
5279
+ this.shopGPTAPI.sendEvent('queryInteractions', this.getSiteCurrency().currency, undefined, {
5280
+ query: message,
5281
+ threadId: this.selectedThreadId,
5282
+ });
5140
5283
  }
5141
5284
  this.messages = [{ sender: 'user', message }, ...this.messages];
5142
5285
  this.isTyping = true;
@@ -5168,15 +5311,25 @@ class ShopGPT extends r$2 {
5168
5311
  }
5169
5312
  sendEvent(e) {
5170
5313
  e.stopPropagation();
5171
- this.shopGPTAPI.sendEvent(e.detail.action, this.getSiteCurrency().currency, e.detail.actionData);
5314
+ this.shopGPTAPI.sendEvent(e.detail.action, this.getSiteCurrency().currency, e.detail.actionData, e.detail.clickData);
5172
5315
  }
5173
5316
  productClicked(e) {
5317
+ var _a, _b;
5174
5318
  e.stopPropagation();
5175
- setProductAction(this.destination, this.sessionId, e.detail.productId, 'clicked', true);
5319
+ setProductAction(this.destination, this.sessionId, e.detail.id, 'clicked', true);
5176
5320
  this.shopGPTAPI.sendEvent('productRecommendationClicked', this.getSiteCurrency().currency, {
5177
- productId: e.detail.productId,
5321
+ productId: e.detail.id,
5178
5322
  value: e.detail.value,
5179
5323
  isPrompt: this.isPreviousMessagePrompt,
5324
+ }, {
5325
+ threadId: this.selectedThreadId,
5326
+ query: (_a = e.detail.query) !== null && _a !== void 0 ? _a : '',
5327
+ response: (_b = e.detail.response) !== null && _b !== void 0 ? _b : '',
5328
+ currency: this.getSiteCurrency().currency,
5329
+ variantId: e.detail.variantId,
5330
+ url: e.detail.url,
5331
+ title: e.detail.title,
5332
+ rank: e.detail.rank,
5180
5333
  });
5181
5334
  }
5182
5335
  getSiteCurrency() {
@@ -5207,6 +5360,7 @@ class ShopGPT extends r$2 {
5207
5360
  .css=${this.css}
5208
5361
  ></chat-threads>
5209
5362
  <products-section
5363
+ .messages=${this.messages}
5210
5364
  .merchantImage=${this.merchantImage}
5211
5365
  .products=${this.products}
5212
5366
  .isLoadingHistory=${this.isLoadingHistory}
@@ -5252,26 +5406,23 @@ class ShopGPT extends r$2 {
5252
5406
  <button
5253
5407
  @click=${(e) => {
5254
5408
  e.preventDefault();
5255
- this.shopGPTAPI.sendEvent('chatbotOpened', this.getSiteCurrency().currency);
5256
- this.modalState = 'open';
5257
- this.handleUserInteraction();
5409
+ this.openModal();
5258
5410
  }}
5259
5411
  >
5260
5412
  ${chatIcon}
5261
5413
  </button>
5262
5414
  ${((_a = this.nudge) === null || _a === void 0 ? void 0 : _a.show) && this.showNudge
5263
- ? x `<div
5415
+ ? x ` <div
5264
5416
  class="nudge"
5265
5417
  @click=${(e) => {
5266
5418
  e.preventDefault();
5267
- this.modalState = 'open';
5268
- this.handleUserInteraction();
5419
+ this.openModal();
5269
5420
  }}
5270
5421
  >
5271
5422
  Hi there! I'm an AI Agent to help you find the perfect product.
5272
5423
  What are you looking for today?
5273
5424
  </div>`
5274
- : x `<div class="chatbot-hover-text">
5425
+ : x ` <div class="chatbot-hover-text">
5275
5426
  What are you looking for today?
5276
5427
  </div>`}
5277
5428
  </div>`;
@@ -5315,6 +5466,12 @@ class ShopGPT extends r$2 {
5315
5466
  </div>
5316
5467
  `;
5317
5468
  }
5469
+ openModal() {
5470
+ setIsBotOpened(this.destination, this.sessionId, true);
5471
+ this.shopGPTAPI.sendEvent('chatbotOpened');
5472
+ this.modalState = 'open';
5473
+ this.handleUserInteraction();
5474
+ }
5318
5475
  startNudgeTimer() {
5319
5476
  var _a, _b;
5320
5477
  if (this.view !== 'modal' || !((_a = this.nudge) === null || _a === void 0 ? void 0 : _a.show)) {
@@ -5353,6 +5510,11 @@ class ShopGPT extends r$2 {
5353
5510
  }
5354
5511
  render() {
5355
5512
  if (this.view === 'modal') {
5513
+ const searchParams = new URLSearchParams(window.location.search);
5514
+ const hasSource = searchParams.get('utm_source') === 'shopgpt';
5515
+ if (hasSource) {
5516
+ this.modalState = 'open';
5517
+ }
5356
5518
  return this.modalMode();
5357
5519
  }
5358
5520
  return this.overlayMode();
@@ -5462,14 +5624,13 @@ if (typeof window != 'undefined' && typeof document != 'undefined') {
5462
5624
  logger.log('ShopGPT component added already!');
5463
5625
  return;
5464
5626
  }
5627
+ setWasUserExposed(shopGPT.destination, shopGPT.sessionId, true);
5465
5628
  document.body.append(shopGPT);
5466
- setShopGPTLoaded(shopGPT.destination, shopGPT.sessionId, true);
5467
5629
  },
5468
5630
  destroy() {
5469
5631
  if (!shopGPT) {
5470
5632
  return;
5471
5633
  }
5472
- setShopGPTLoaded(shopGPT.destination, shopGPT.sessionId, false);
5473
5634
  shopGPT.remove();
5474
5635
  shopGPT = undefined;
5475
5636
  delete window[registryKey];