@inappstory/slide-api 0.1.26 → 0.1.27

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.
package/dist/index.cjs CHANGED
@@ -1045,6 +1045,12 @@ class EsModuleSdkApi {
1045
1045
  constructor(sdkBinding) {
1046
1046
  this.sdkBinding = sdkBinding;
1047
1047
  }
1048
+ onWidgetRequirePauseUI() {
1049
+ return this.sdkBinding.onWidgetRequirePauseUI();
1050
+ }
1051
+ onWidgetRequireResumeUI() {
1052
+ return this.sdkBinding.onWidgetRequireResumeUI();
1053
+ }
1048
1054
  getCardServerData(cardId) {
1049
1055
  return this.sdkBinding.getCardServerData(cardId);
1050
1056
  }
@@ -1138,8 +1144,8 @@ class EsModuleSdkApi {
1138
1144
  isSdkSupportUpdateTimeline() {
1139
1145
  return true;
1140
1146
  }
1141
- updateTimeline(slideIndex, action, currentTime, duration, showLoader, showError) {
1142
- this.sdkBinding.updateTimeline(slideIndex, action, currentTime, duration, showLoader, showError);
1147
+ async updateTimeline(slideIndex, action, currentTime, duration, showLoader, showError) {
1148
+ await this.sdkBinding.updateTimeline(slideIndex, action, currentTime, duration, showLoader, showError);
1143
1149
  }
1144
1150
  cardPausedCallback(currentTime) { }
1145
1151
  cardResumedCallback(currentTime) { }
@@ -1185,6 +1191,18 @@ class EsModuleSdkApi {
1185
1191
  // console.log("onCardLoadingStateChange", { state });
1186
1192
  this.sdkBinding.onCardLoadingStateChange(state, reason);
1187
1193
  }
1194
+ get isSdkSupportProductCart() {
1195
+ return true;
1196
+ }
1197
+ productCartUpdate(data) {
1198
+ return this.sdkBinding.productCartUpdate(data);
1199
+ }
1200
+ productCartGetState() {
1201
+ return this.sdkBinding.productCartGetState();
1202
+ }
1203
+ productCartClicked() {
1204
+ this.sdkBinding.productCartClicked();
1205
+ }
1188
1206
  static get [Symbol.for("___CTOR_ARGS___")]() { return [`SDKInterface`]; }
1189
1207
  }
1190
1208
 
@@ -3413,7 +3431,7 @@ class SlideTimeline {
3413
3431
  await this.slideReady.then();
3414
3432
  // window._log(`updateTimeline, a: ${action} ct: ${currentTime} d: ${duration} tds: ${this.timelineDisabledState}`, true);
3415
3433
  // console.trace(`updateTimeline ${action} slideIndex: ${this.slideIndex} currentTime:${currentTime} duration:${duration} tds: ${this.timelineDisabledState} showLoader: ${showLoader} showError: ${showError}`);
3416
- this.slideApiDeps.updateTimeline(this.slideIndex, action, currentTime, duration, showLoader, showError);
3434
+ await this.slideApiDeps.updateTimeline(this.slideIndex, action, currentTime, duration, showLoader, showError);
3417
3435
  if (action === "pause" /* TIMELINE_ACTION.PAUSE */ && showLoader) {
3418
3436
  this.dataWaitingStartedAt = Date.now();
3419
3437
  }
@@ -3439,13 +3457,13 @@ class SlideTimeline {
3439
3457
  * Start timeline after slide started
3440
3458
  * Nothing do if old sdk
3441
3459
  */
3442
- slideStarted() {
3460
+ async slideStarted() {
3443
3461
  // console.trace("slideStarted");
3444
3462
  this.onBeforeStateChanged();
3445
3463
  if (this.isSDKSupportUpdateTimeline) {
3446
3464
  this.resumedAt = new Date().getTime();
3447
3465
  this.timeSpent = 0; // for case when instance exists, but we return to slide again
3448
- this.updateTimeline("start" /* TIMELINE_ACTION.START */);
3466
+ await this.updateTimeline("start" /* TIMELINE_ACTION.START */);
3449
3467
  }
3450
3468
  }
3451
3469
  slideRestarted() {
@@ -3651,10 +3669,20 @@ class Layer {
3651
3669
  });
3652
3670
  };
3653
3671
  const onWidgetRequirePauseUI = (cardId, slideIndex) => {
3654
- this._slidePauseUI();
3672
+ if (this.slideApiDeps.isWeb) {
3673
+ this.slideApiDeps.onWidgetRequirePauseUI();
3674
+ }
3675
+ else {
3676
+ this._slidePauseUI();
3677
+ }
3655
3678
  };
3656
3679
  const onWidgetRequireResumeUI = (cardId, slideIndex) => {
3657
- this._slideResumeUI();
3680
+ if (this.slideApiDeps.isWeb) {
3681
+ this.slideApiDeps.onWidgetRequireResumeUI();
3682
+ }
3683
+ else {
3684
+ this._slideResumeUI();
3685
+ }
3658
3686
  };
3659
3687
  const _elementsNodes = this._nodeRef.querySelectorAll(".narrative-slide-elements .narrative-element:not(.narrative-element-child-element)");
3660
3688
  let layerWithWidgetQuest = false;
@@ -3893,7 +3921,7 @@ class Layer {
3893
3921
  }
3894
3922
  // skip start timeline if we returned to slide with enabled timer and opened WidgetProducts modal
3895
3923
  if (!this.isLayerForcePaused) {
3896
- this.timeline.slideStarted();
3924
+ await this.timeline.slideStarted();
3897
3925
  }
3898
3926
  return { currentTime };
3899
3927
  }
@@ -5488,6 +5516,12 @@ class SlideApiDepsMultiSlideMode {
5488
5516
  this.sdkApi = sdkApi;
5489
5517
  this.slider = slider;
5490
5518
  }
5519
+ onWidgetRequirePauseUI() {
5520
+ return this.sdkApi.onWidgetRequirePauseUI();
5521
+ }
5522
+ onWidgetRequireResumeUI() {
5523
+ return this.sdkApi.onWidgetRequireResumeUI();
5524
+ }
5491
5525
  getWidgetsSharedData(cardId, widget) {
5492
5526
  return this.sdkApi.getWidgetsSharedData(cardId, widget);
5493
5527
  }
@@ -5611,6 +5645,18 @@ class SlideApiDepsMultiSlideMode {
5611
5645
  showLayer(index) {
5612
5646
  this.sdkApi.showLayer(index);
5613
5647
  }
5648
+ get isSdkSupportProductCart() {
5649
+ return this.sdkApi.isSdkSupportProductCart;
5650
+ }
5651
+ productCartUpdate(data) {
5652
+ return this.sdkApi.productCartUpdate(data);
5653
+ }
5654
+ productCartGetState() {
5655
+ return this.sdkApi.productCartGetState();
5656
+ }
5657
+ productCartClicked() {
5658
+ this.sdkApi.productCartClicked();
5659
+ }
5614
5660
  /**
5615
5661
  * For single slide mode - proxy these methods via SDKApi
5616
5662
  * =================================================================================================================
@@ -5624,8 +5670,8 @@ class SlideApiDepsMultiSlideMode {
5624
5670
  isSdkSupportUpdateTimeline() {
5625
5671
  return true;
5626
5672
  }
5627
- updateTimeline(slideIndex, action, currentTime, duration, showLoader, showError) {
5628
- this.slider.updateTimeline(slideIndex, action, currentTime, duration, showLoader, showError);
5673
+ async updateTimeline(slideIndex, action, currentTime, duration, showLoader, showError) {
5674
+ await this.slider.updateTimeline(slideIndex, action, currentTime, duration, showLoader, showError);
5629
5675
  }
5630
5676
  isSdkSupportTimelineOnBeforeStart() {
5631
5677
  return true;
@@ -5644,6 +5690,12 @@ class SlideApiDepsSingleSlideMode {
5644
5690
  constructor(sdkApi) {
5645
5691
  this.sdkApi = sdkApi;
5646
5692
  }
5693
+ onWidgetRequirePauseUI() {
5694
+ return this.sdkApi.onWidgetRequirePauseUI();
5695
+ }
5696
+ onWidgetRequireResumeUI() {
5697
+ return this.sdkApi.onWidgetRequireResumeUI();
5698
+ }
5647
5699
  getWidgetsSharedData(cardId, widget) {
5648
5700
  return this.sdkApi.getWidgetsSharedData(cardId, widget);
5649
5701
  }
@@ -5765,6 +5817,18 @@ class SlideApiDepsSingleSlideMode {
5765
5817
  showLayer(index) {
5766
5818
  this.sdkApi.showLayer(index);
5767
5819
  }
5820
+ get isSdkSupportProductCart() {
5821
+ return this.sdkApi.isSdkSupportProductCart;
5822
+ }
5823
+ productCartUpdate(data) {
5824
+ return this.sdkApi.productCartUpdate(data);
5825
+ }
5826
+ productCartGetState() {
5827
+ return this.sdkApi.productCartGetState();
5828
+ }
5829
+ productCartClicked() {
5830
+ this.sdkApi.productCartClicked();
5831
+ }
5768
5832
  /**
5769
5833
  * For single slide mode - proxy these methods via SDKApi
5770
5834
  */
@@ -5777,8 +5841,8 @@ class SlideApiDepsSingleSlideMode {
5777
5841
  isSdkSupportUpdateTimeline() {
5778
5842
  return this.sdkApi.isSdkSupportUpdateTimeline();
5779
5843
  }
5780
- updateTimeline(slideIndex, action, currentTime, duration, showLoader, showError) {
5781
- this.sdkApi.updateTimeline(slideIndex, action, currentTime, duration, showLoader, showError);
5844
+ async updateTimeline(slideIndex, action, currentTime, duration, showLoader, showError) {
5845
+ await this.sdkApi.updateTimeline(slideIndex, action, currentTime, duration, showLoader, showError);
5782
5846
  }
5783
5847
  isSdkSupportTimelineOnBeforeStart() {
5784
5848
  return this.sdkApi.isSdkSupportTimelineOnBeforeStart();
@@ -5942,6 +6006,8 @@ class Slider {
5942
6006
  });
5943
6007
  }
5944
6008
  isAnimating = false;
6009
+ // block click while slide loading and starting (prevent several timeline starting)
6010
+ isSlideStarting = false;
5945
6011
  activeIndex = -1;
5946
6012
  get activeSlide() {
5947
6013
  return this.slides[this.activeIndex];
@@ -5958,7 +6024,7 @@ class Slider {
5958
6024
  css += `--navbar-edge-offset: ${navbarAppearance.edge_offset};`;
5959
6025
  }
5960
6026
  if (navbarAppearance.active_timeline_width != null) {
5961
- css += `--navbar-active-timeline_width: ${navbarAppearance.active_timeline_width};`;
6027
+ css += `--navbar-active-timeline-width: ${navbarAppearance.active_timeline_width};`;
5962
6028
  }
5963
6029
  if (navbarAppearance.background_color != null) {
5964
6030
  css += `--navbar-background-color: ${navbarAppearance.background_color};`;
@@ -6051,25 +6117,28 @@ class Slider {
6051
6117
  bullets.classList.add("cards-slider__navbar--position-bottom");
6052
6118
  }
6053
6119
  bullets.dir = getLayoutDirection();
6054
- for (let i = 0; i < count; ++i) {
6055
- const bullet = document.createElement("div");
6056
- bullet.classList.add("cards-slider__timeline", "touchable");
6057
- bullet.setAttribute("data-index", String(i));
6058
- bullet.onclick = (e) => {
6059
- e.stopPropagation();
6060
- e.preventDefault();
6061
- const bullet = e.target;
6062
- if (bullet != null) {
6063
- const index = bullet.dataset.index;
6064
- if (index != null) {
6065
- this.showByIndex(parseInt(index));
6120
+ // skip creating view elements for single slide
6121
+ if (count > 1) {
6122
+ for (let i = 0; i < count; ++i) {
6123
+ const bullet = document.createElement("div");
6124
+ bullet.classList.add("cards-slider__timeline", "touchable");
6125
+ bullet.setAttribute("data-index", String(i));
6126
+ bullet.onclick = (e) => {
6127
+ e.stopPropagation();
6128
+ e.preventDefault();
6129
+ const bullet = e.target;
6130
+ if (bullet != null) {
6131
+ const index = bullet.dataset.index;
6132
+ if (index != null) {
6133
+ this.showByIndex(parseInt(index));
6134
+ }
6066
6135
  }
6067
- }
6068
- };
6069
- const bulletFill = document.createElement("div");
6070
- bulletFill.classList.add("cards-slider__timeline-fill");
6071
- bullet.append(bulletFill);
6072
- bullets.appendChild(bullet);
6136
+ };
6137
+ const bulletFill = document.createElement("div");
6138
+ bulletFill.classList.add("cards-slider__timeline-fill");
6139
+ bullet.append(bulletFill);
6140
+ bullets.appendChild(bullet);
6141
+ }
6073
6142
  }
6074
6143
  // const onUpdateActiveIndex = (activeIndex: number) => {
6075
6144
  // if (activeIndex >= 0 && activeIndex < count) {
@@ -6097,42 +6166,25 @@ class Slider {
6097
6166
  }
6098
6167
  async showByIndex(newIndex) {
6099
6168
  const prevIndex = this.activeIndex;
6100
- if (this.isAnimating)
6169
+ if (this.isAnimating) {
6101
6170
  return prevIndex;
6102
- if (newIndex === prevIndex)
6103
- return prevIndex;
6104
- if (prevIndex !== -1) {
6105
- // skip for slider start
6106
- this.config.onSlideLeft(this.slides[prevIndex].element, prevIndex);
6107
- await this.config.onSlideStop();
6108
- }
6109
- const { index, loadingError } = await this.initAndRenderSlide(newIndex);
6110
- if (loadingError) {
6111
- // todo via updateTimeline ????
6112
- this.config.onSlideLoadingError(index, loadingError);
6113
6171
  }
6114
- if (!loadingError) {
6115
- this.onShowSlide(index);
6116
- }
6117
- await this.slideTo(index);
6118
- if (!loadingError) {
6119
- this.config.onSlideStart();
6172
+ if (this.isSlideStarting) {
6173
+ // block click while slide loading and starting (prevent several timeline starting)
6174
+ return prevIndex;
6120
6175
  }
6121
- return newIndex;
6122
- }
6123
- async showNextSlide() {
6124
- const prevIndex = this.activeIndex;
6125
- if (this.isAnimating)
6176
+ if (newIndex === prevIndex) {
6126
6177
  return prevIndex;
6127
- const newIndex = prevIndex + 1;
6178
+ }
6128
6179
  if (newIndex < 0 || newIndex >= this.slides.length) {
6129
- return null;
6180
+ return prevIndex;
6130
6181
  }
6131
6182
  if (prevIndex !== -1) {
6132
6183
  // skip for slider start
6133
6184
  this.config.onSlideLeft(this.slides[prevIndex].element, prevIndex);
6134
6185
  await this.config.onSlideStop();
6135
6186
  }
6187
+ this.isSlideStarting = true;
6136
6188
  const { index, loadingError } = await this.initAndRenderSlide(newIndex);
6137
6189
  if (loadingError) {
6138
6190
  // todo via updateTimeline ????
@@ -6141,12 +6193,16 @@ class Slider {
6141
6193
  if (!loadingError) {
6142
6194
  this.onShowSlide(index);
6143
6195
  }
6144
- await this.slideTo(index);
6196
+ this.config.onSlideChangeActiveIndex(await this.slideTo(index));
6145
6197
  if (!loadingError) {
6146
- this.config.onSlideStart();
6198
+ await this.config.onSlideStart();
6147
6199
  }
6200
+ this.isSlideStarting = false;
6148
6201
  return newIndex;
6149
6202
  }
6203
+ async showNextSlide() {
6204
+ return this.showByIndex(this.activeIndex + 1);
6205
+ }
6150
6206
  async initAndRenderSlide(index) {
6151
6207
  this.config.onBeforeLoadSlide(index);
6152
6208
  let showSlidePromise;
@@ -6194,11 +6250,13 @@ class Slider {
6194
6250
  return k * index * cardWidth;
6195
6251
  }
6196
6252
  async slideTo(index, speed = 300) {
6197
- if (index < 0 || index > this.slides.length - 1 || this.isAnimating)
6198
- return;
6253
+ if (index < 0 || index > this.slides.length - 1 || this.isAnimating) {
6254
+ return this.activeIndex;
6255
+ }
6199
6256
  const cardOffset = this.getSlideOffset(index);
6200
6257
  await this.translateTo(cardOffset, speed);
6201
6258
  this.activeIndex = index;
6259
+ return this.activeIndex;
6202
6260
  }
6203
6261
  setTranslate(value) {
6204
6262
  this.sliderTrack?.style.setProperty("transform", `translateX(${value}px)`);
@@ -6237,7 +6295,7 @@ class Slider {
6237
6295
  this.config.root.removeChild(this.slideWrapperElement);
6238
6296
  }
6239
6297
  }
6240
- updateTimeline(slideIndex, action, currentTime, duration, showLoader, showError) {
6298
+ async updateTimeline(slideIndex, action, currentTime, duration, showLoader, showError) {
6241
6299
  switch (action) {
6242
6300
  case "before_start" /* TIMELINE_ACTION.BEFORE_START */: {
6243
6301
  // switch timeline to active slide and wait for start (wait VOD loading)
@@ -6311,6 +6369,7 @@ class Slider {
6311
6369
  getLayoutDirection: GetLayoutDirection;
6312
6370
 
6313
6371
  onSlideTimerEnd: OnSlideTimerEnd;
6372
+ onSlideChangeActiveIndex: OnSlideChangeActiveIndex;
6314
6373
  onSlideStart: OnSlideStart;
6315
6374
  onSlideStop: OnSlideStop;
6316
6375
  onSlideDataWaiting: OnSlideDataWaiting;
@@ -6699,6 +6758,7 @@ class CardApi {
6699
6758
  onSlideLeft,
6700
6759
  getLayoutDirection: () => this.layoutDirection,
6701
6760
  onSlideTimerEnd: () => this.activeSlide.slideTimerEnd(),
6761
+ onSlideChangeActiveIndex: index => (this.activeSlide = this.slides[index].slide),
6702
6762
  onSlideStart: () => {
6703
6763
  // return Promise.resolve({currentTime: 0});
6704
6764
  this.cardLoadingStateController.onSetLoadEndState();
@@ -6797,11 +6857,7 @@ class CardApi {
6797
6857
  else if (index < 0) {
6798
6858
  index = this.slides.length - 1;
6799
6859
  }
6800
- this.slider.showByIndex(index).then(index => {
6801
- if (currentIndex === index)
6802
- return;
6803
- this.activeSlide = this.slides[index].slide;
6804
- });
6860
+ this.slider.showByIndex(index);
6805
6861
  }
6806
6862
  return result;
6807
6863
  }
@@ -18953,6 +19009,832 @@ class SwipeGestureDetector {
18953
19009
  static get [Symbol.for("___CTOR_ARGS___")]() { return [`HTMLElement`, `boolean`, `(e: MouseEvent | TouchEvent) => boolean`, `(e: MouseEvent | TouchEvent) => void`, `(e: MouseEvent | TouchEvent) => void`, `(e: MouseEvent | TouchEvent, gesture: SwipeGesture) => void`]; }
18954
19010
  }
18955
19011
 
19012
+ class RenderableComponent {
19013
+ _root = null;
19014
+ props;
19015
+ constructor(props) {
19016
+ this.props = (props ?? {});
19017
+ }
19018
+ render() {
19019
+ const newRoot = this.renderTemplate();
19020
+ const style = this.styleContent();
19021
+ if (style) {
19022
+ newRoot?.prepend(this.createStyleElement(style));
19023
+ }
19024
+ if (this._root) {
19025
+ this._root.replaceWith(newRoot ?? "");
19026
+ }
19027
+ this._root = newRoot;
19028
+ return this._root;
19029
+ }
19030
+ updateProps(props) {
19031
+ this.props = { ...this.props, ...props };
19032
+ this.render();
19033
+ }
19034
+ destroy() {
19035
+ this._root?.remove();
19036
+ this._root = null;
19037
+ }
19038
+ createStyleElement(css) {
19039
+ const styleEl = document.createElement("style");
19040
+ styleEl.textContent = css;
19041
+ return styleEl;
19042
+ }
19043
+ styleContent() {
19044
+ return "";
19045
+ }
19046
+ static get [Symbol.for("___CTOR_ARGS___")]() { return [`Props`]; }
19047
+ }
19048
+
19049
+ function h(tag, ...rest) {
19050
+ let props = {};
19051
+ let children = [];
19052
+ if (rest[0] && typeof rest[0] === "object" && !(rest[0] instanceof Node)) {
19053
+ props = rest.shift();
19054
+ }
19055
+ children = rest.flat();
19056
+ const el = document.createElement(tag);
19057
+ for (const [key, value] of Object.entries(props)) {
19058
+ if (value == null)
19059
+ continue;
19060
+ if (key === "class" || key === "className") {
19061
+ el.className = value;
19062
+ }
19063
+ else if (key === "textContent") {
19064
+ el.textContent = value;
19065
+ }
19066
+ else if (key === "html" || key === "innerHTML") {
19067
+ el.innerHTML = value;
19068
+ }
19069
+ else if (key === "ref" && typeof value === "function") {
19070
+ value(el);
19071
+ }
19072
+ else if (key.startsWith("data-")) {
19073
+ el.setAttribute(key, value);
19074
+ }
19075
+ else if (key.startsWith("on") && typeof value === "function") {
19076
+ const event = key.slice(2).toLowerCase();
19077
+ el.addEventListener(event, value);
19078
+ }
19079
+ else if (key in el) {
19080
+ // @ts-ignore — any valid DOM props
19081
+ el[key] = value;
19082
+ }
19083
+ else {
19084
+ el.setAttribute(key, value);
19085
+ }
19086
+ }
19087
+ for (const child of children) {
19088
+ if (child == null)
19089
+ continue;
19090
+ if (typeof child === "string") {
19091
+ el.appendChild(document.createTextNode(child));
19092
+ }
19093
+ else {
19094
+ el.appendChild(child);
19095
+ }
19096
+ }
19097
+ return el;
19098
+ }
19099
+
19100
+ class BottomSheet extends RenderableComponent {
19101
+ isClosing = false;
19102
+ _isOpened = false;
19103
+ constructor(props) {
19104
+ super(props ?? {});
19105
+ }
19106
+ get isOpened() {
19107
+ return this._isOpened;
19108
+ }
19109
+ renderTemplate() {
19110
+ return h("div", { class: `ias-bottom-sheet ${this._isOpened ? "ias-bottom-sheet--open" : ""}` }, h("div", {
19111
+ class: "ias-bottom-sheet__backdrop",
19112
+ onClick: this.handleBackdropClick,
19113
+ }), h("div", { class: "ias-bottom-sheet__container" }, h("div", { class: "ias-bottom-sheet__content" },
19114
+ /* h("div", { class: "ias-bottom-sheet__header" }), */
19115
+ h("div", { class: "ias-bottom-sheet__body" }, ...(this.props?.children?.map(c => c.render()) ?? [])))));
19116
+ }
19117
+ setHeight(height) {
19118
+ if (!this._root)
19119
+ return;
19120
+ const container = this._root.querySelector(".ias-bottom-sheet__container");
19121
+ if (!container)
19122
+ return;
19123
+ container.style.height = height;
19124
+ }
19125
+ open() {
19126
+ if (this.isOpened)
19127
+ return;
19128
+ this._isOpened = true;
19129
+ requestAnimationFrame(() => {
19130
+ requestAnimationFrame(() => {
19131
+ this._root?.classList.add("ias-bottom-sheet--open");
19132
+ });
19133
+ });
19134
+ }
19135
+ async close() {
19136
+ if (!this._root || this.isClosing)
19137
+ return;
19138
+ const root = this._root;
19139
+ root.classList.remove("ias-bottom-sheet--open");
19140
+ this.isClosing = true;
19141
+ await new Promise(resolve => {
19142
+ root.addEventListener("transitionend", () => resolve(), { once: true });
19143
+ });
19144
+ this.isClosing = false;
19145
+ this.props?.onClose?.();
19146
+ }
19147
+ handleBackdropClick = (e) => {
19148
+ e.preventDefault();
19149
+ e.stopPropagation();
19150
+ this.close();
19151
+ };
19152
+ static get [Symbol.for("___CTOR_ARGS___")]() { return [`BottomSheetProps`]; }
19153
+ }
19154
+
19155
+ class ProductDetailsDescription extends RenderableComponent {
19156
+ constructor(props) {
19157
+ super(props);
19158
+ }
19159
+ renderTemplate() {
19160
+ const { name, description } = this.props;
19161
+ return h("div", { class: "ias-product-details__description" }, name ? h("h6", { class: "ias-product-details__name", textContent: name }) : null, description ? h("p", { class: "ias-product-details__text", textContent: description }) : null);
19162
+ }
19163
+ static get [Symbol.for("___CTOR_ARGS___")]() { return [`ProductDetailsDescriptionProps`]; }
19164
+ }
19165
+
19166
+ class ProductDetailsGallery extends RenderableComponent {
19167
+ constructor(props) {
19168
+ super(props);
19169
+ }
19170
+ renderTemplate() {
19171
+ const { imageUrls = [] } = this.props;
19172
+ return h("div", { class: "ias-product-details__gallery" }, imageUrls.map(url => h("figure", { class: "ias-product-details__image" }, h("img", { src: url /* , loading: "lazy" */ }))));
19173
+ }
19174
+ static get [Symbol.for("___CTOR_ARGS___")]() { return [`ProductDetailsGalleryProps`]; }
19175
+ }
19176
+
19177
+ const ADD_TO_CART_TIMEOUT = 60000;
19178
+
19179
+ class ProductDetailsPurchaseAction extends RenderableComponent {
19180
+ button;
19181
+ constructor(props) {
19182
+ super(props);
19183
+ }
19184
+ renderTemplate() {
19185
+ this.button = h("button", {
19186
+ class: "ias-product-details__action-button",
19187
+ textContent: this.props.translations.addToCart,
19188
+ onClick: this.handleClickAddToCart,
19189
+ });
19190
+ return this.button;
19191
+ }
19192
+ handleClickAddToCart = async () => {
19193
+ try {
19194
+ this.showLoader();
19195
+ await this.addToCart();
19196
+ }
19197
+ catch (error) {
19198
+ this.handleAddToCartError(error);
19199
+ }
19200
+ finally {
19201
+ this.hideLoader();
19202
+ }
19203
+ };
19204
+ showLoader() {
19205
+ this.button.classList.add("ias-product-details__action-button--loading");
19206
+ }
19207
+ hideLoader() {
19208
+ this.button.classList.remove("ias-product-details__action-button--loading");
19209
+ }
19210
+ handleAddToCartError(error) {
19211
+ this.props.onAddToCartError({ error });
19212
+ }
19213
+ async addToCart() {
19214
+ await Promise.race([this.props.onAddToCart(), new Promise((resolve, reject) => setTimeout(reject, ADD_TO_CART_TIMEOUT))]);
19215
+ }
19216
+ static get [Symbol.for("___CTOR_ARGS___")]() { return [`ProductDetailsPurchaseActionProps`]; }
19217
+ }
19218
+
19219
+ class ProductDetailsPurchasePrice extends RenderableComponent {
19220
+ constructor(props) {
19221
+ super(props);
19222
+ }
19223
+ renderTemplate() {
19224
+ const { price, oldPrice, currency } = this.props.product;
19225
+ const rootEl = h("div", { class: "ias-product-details__price" });
19226
+ if (price != null && currency) {
19227
+ const currentPriceEl = h("div", {
19228
+ class: "ias-product-details__current-price",
19229
+ html: formatter.asCurrency(price, currency),
19230
+ });
19231
+ rootEl.appendChild(currentPriceEl);
19232
+ }
19233
+ if (oldPrice != null && currency) {
19234
+ const oldPriceEl = h("div", {
19235
+ class: "ias-product-details__old-price",
19236
+ html: formatter.asCurrency(oldPrice, currency),
19237
+ });
19238
+ rootEl.appendChild(oldPriceEl);
19239
+ }
19240
+ return rootEl;
19241
+ }
19242
+ static get [Symbol.for("___CTOR_ARGS___")]() { return [`ProductDetailsPurchasePriceProps`]; }
19243
+ }
19244
+
19245
+ class ProductDetailsCounter extends RenderableComponent {
19246
+ _value = 1;
19247
+ countElement = null;
19248
+ get value() {
19249
+ return this._value;
19250
+ }
19251
+ updateProps() {
19252
+ this._value = 1;
19253
+ this.render();
19254
+ }
19255
+ renderTemplate() {
19256
+ return h("div", { class: "ias-product-details__counter" }, h("button", {
19257
+ class: "ias-product-details__counter-button",
19258
+ textContent: "−",
19259
+ onClick: this.handleClickOnMinusButton,
19260
+ }), h("span", {
19261
+ class: "ias-product-details__counter-count",
19262
+ textContent: this._value.toString(),
19263
+ ref: (el) => (this.countElement = el),
19264
+ }), h("button", {
19265
+ class: "ias-product-details__counter-button",
19266
+ textContent: "+",
19267
+ onClick: this.handleClickOnPlusButton,
19268
+ }));
19269
+ }
19270
+ handleClickOnMinusButton = () => {
19271
+ this._value = Math.max(this._value - 1, 1);
19272
+ this.updateCountValue();
19273
+ };
19274
+ handleClickOnPlusButton = () => {
19275
+ this._value++;
19276
+ this.updateCountValue();
19277
+ };
19278
+ updateCountValue() {
19279
+ if (this.countElement) {
19280
+ this.countElement.textContent = this._value.toString();
19281
+ }
19282
+ }
19283
+ }
19284
+
19285
+ class ProductDetailsPurchase extends RenderableComponent {
19286
+ price;
19287
+ action;
19288
+ counter = new ProductDetailsCounter();
19289
+ constructor(props) {
19290
+ super(props);
19291
+ }
19292
+ renderTemplate() {
19293
+ this.price = new ProductDetailsPurchasePrice(this.props);
19294
+ this.action = new ProductDetailsPurchaseAction({
19295
+ onAddToCart: this.handleOnAddToCart,
19296
+ onAddToCartError: this.props.onAddToCartError,
19297
+ translations: this.props.translations,
19298
+ });
19299
+ return h("div", { class: "ias-product-details__purchase" }, h("div", { class: "ias-product-details__price-box" }, this.price.render(), this.counter.render()), this.action.render());
19300
+ }
19301
+ updateProps(props) {
19302
+ this.props = { ...this.props, ...props };
19303
+ this.price.updateProps(this.props);
19304
+ this.counter.updateProps();
19305
+ }
19306
+ handleOnAddToCart = async () => {
19307
+ return this.props.onAddToCart({
19308
+ quantity: this.counter.value,
19309
+ product: this.props.product,
19310
+ });
19311
+ };
19312
+ static get [Symbol.for("___CTOR_ARGS___")]() { return [`ProductDetailsPurchaseProps`]; }
19313
+ }
19314
+
19315
+ class ProductOptionButton extends RenderableComponent {
19316
+ constructor(props) {
19317
+ super(props);
19318
+ }
19319
+ renderTemplate() {
19320
+ const params = {
19321
+ class: `ias-product-details__option-button ${this.props.selected ? "ias-product-details__option-button--active" : ""} ${this.props.disabled ? "ias-product-details__option-button--disabled" : ""}`,
19322
+ textContent: this.props.label,
19323
+ onclick: () => {
19324
+ this.props.onClick();
19325
+ },
19326
+ };
19327
+ return h("button", params);
19328
+ }
19329
+ setSelected(selected) {
19330
+ if (!this._root)
19331
+ return;
19332
+ if (selected)
19333
+ this._root.classList.add("ias-product-details__option-button--active");
19334
+ else
19335
+ this._root.classList.remove("ias-product-details__option-button--active");
19336
+ }
19337
+ setDisabled(disabled) {
19338
+ if (!this._root)
19339
+ return;
19340
+ if (disabled)
19341
+ this._root.classList.add("ias-product-details__option-button--disabled");
19342
+ else
19343
+ this._root.classList.remove("ias-product-details__option-button--disabled");
19344
+ }
19345
+ static get [Symbol.for("___CTOR_ARGS___")]() { return [`ProductOptionButtonProps`]; }
19346
+ }
19347
+
19348
+ class ProductOptionsManager {
19349
+ optionNames;
19350
+ productVariants;
19351
+ subscribers = [];
19352
+ selectedOptions = {};
19353
+ allOptionsByName = {};
19354
+ availableOptionsByName = {};
19355
+ constructor(optionNames, productVariants) {
19356
+ this.optionNames = optionNames;
19357
+ this.productVariants = productVariants;
19358
+ this.allOptionsByName = this.extractAllOptions();
19359
+ }
19360
+ get selected() {
19361
+ return { ...this.selectedOptions };
19362
+ }
19363
+ get availableOptions() {
19364
+ return this.availableOptionsByName;
19365
+ }
19366
+ selectOption(option) {
19367
+ const compatibleVariants = this.findCompatibleVariants(option);
19368
+ this.ensureVariantsExist(option, compatibleVariants);
19369
+ const matchingVariant = this.findMatchingVariant(compatibleVariants);
19370
+ this.selectVariant(matchingVariant);
19371
+ }
19372
+ selectVariant(variant) {
19373
+ this.optionNames.forEach(name => {
19374
+ const currentSelected = this.selectedOptions[name];
19375
+ const newOption = variant.options[name];
19376
+ if (currentSelected && newOption && currentSelected.value === newOption.value) {
19377
+ this.selectedOptions[name] = currentSelected;
19378
+ }
19379
+ else {
19380
+ this.selectedOptions[name] = newOption;
19381
+ }
19382
+ });
19383
+ this.availableOptionsByName = this.extractAvailableOptions();
19384
+ this.notifySubscribers(variant);
19385
+ }
19386
+ onChange(callback) {
19387
+ this.subscribers.push(callback);
19388
+ }
19389
+ isOptionSelected(option) {
19390
+ return this.selected[option.name]?.value === option.value;
19391
+ }
19392
+ isOptionDisabled(option) {
19393
+ const options = this.availableOptions[option.name];
19394
+ return !options?.some(o => o.value === option.value);
19395
+ }
19396
+ getOptionsFor(name) {
19397
+ return this.allOptionsByName[name] ?? [];
19398
+ }
19399
+ findCompatibleVariants(option) {
19400
+ return this.productVariants.filter(variant => variant.options[option.name]?.value === option.value);
19401
+ }
19402
+ ensureVariantsExist(option, variants) {
19403
+ if (variants.length === 0) {
19404
+ throw new Error(`[IAS]: No compatible variant for option <${option.name}:${option.value}>`);
19405
+ }
19406
+ }
19407
+ findMatchingVariant(variants) {
19408
+ return (variants.find(variant => this.optionNames.every(name => !this.selectedOptions[name] || variant.options[name]?.value === this.selectedOptions[name]?.value)) ?? variants[0]);
19409
+ }
19410
+ extractAvailableOptions() {
19411
+ const result = {};
19412
+ for (const name of this.optionNames) {
19413
+ const filteredVariants = this.filterVariantsExcludingOption(name);
19414
+ const available = filteredVariants.filter(v => v.available && v.options[name]).map(v => v.options[name]);
19415
+ result[name] = this.getUniqueByKey(available, o => o.value);
19416
+ }
19417
+ return result;
19418
+ }
19419
+ filterVariantsExcludingOption(excludedName) {
19420
+ const filters = { ...this.selectedOptions };
19421
+ delete filters[excludedName];
19422
+ return this.productVariants.filter(variant => Object.entries(filters).every(([name, selected]) => variant.options[name]?.value === selected?.value));
19423
+ }
19424
+ extractAllOptions() {
19425
+ const all = {};
19426
+ for (const name of this.optionNames) {
19427
+ const options = this.productVariants.map(v => v.options[name]).filter(Boolean);
19428
+ all[name] = this.getUniqueByKey(options, o => o.value);
19429
+ }
19430
+ return all;
19431
+ }
19432
+ getUniqueByKey(items, getKey) {
19433
+ return items.filter((item, index, self) => index === self.findIndex(i => getKey(i) === getKey(item)));
19434
+ }
19435
+ notifySubscribers(variant) {
19436
+ this.subscribers.forEach(cb => cb(variant));
19437
+ }
19438
+ static get [Symbol.for("___CTOR_ARGS___")]() { return [`ProductOptionName[]`, `ProductVariant[]`]; }
19439
+ }
19440
+
19441
+ class ProductOptions extends RenderableComponent {
19442
+ optionsManager;
19443
+ optionsContainer;
19444
+ optionButtonsMap = new Map();
19445
+ constructor(props) {
19446
+ super(props);
19447
+ this.optionsManager = new ProductOptionsManager(props.optionNames, props.products);
19448
+ this.init(props.products);
19449
+ }
19450
+ renderTemplate() {
19451
+ this.optionsContainer = h("div", { class: "ias-product-details__options" }, this.renderOptionSelectors());
19452
+ return this.optionsContainer;
19453
+ }
19454
+ init(products) {
19455
+ this.optionsManager.selectVariant(products[0]);
19456
+ this.optionsManager.onChange(variant => {
19457
+ this.updateButtonsState();
19458
+ this.props.onChange(variant);
19459
+ });
19460
+ }
19461
+ renderOptionSelectors() {
19462
+ return this.props.optionNames.map(optionName => this.optionsManager.getOptionsFor(optionName).length > 0
19463
+ ? h("div", { class: "ias-product-details__selector" }, h("div", { class: "ias-product-details__selector-name", textContent: this.getOptionLabelByName(optionName) }), h("div", { class: "ias-product-details__option-selector" }, this.renderOptionsBySelector(optionName)))
19464
+ : null);
19465
+ }
19466
+ getOptionLabelByName(optionName) {
19467
+ switch (optionName) {
19468
+ case "color":
19469
+ return this.props.translations.color;
19470
+ case "size":
19471
+ return this.props.translations.size;
19472
+ }
19473
+ }
19474
+ renderOptionsBySelector(name) {
19475
+ const options = this.optionsManager.getOptionsFor(name);
19476
+ const buttons = [];
19477
+ const buttonElements = options.map(option => {
19478
+ const disabled = this.optionsManager.isOptionDisabled(option);
19479
+ const selected = this.optionsManager.isOptionSelected(option);
19480
+ const productOptionButton = new ProductOptionButton({
19481
+ selected,
19482
+ label: option.value,
19483
+ disabled,
19484
+ onClick: () => {
19485
+ this.optionsManager.selectOption(option);
19486
+ },
19487
+ });
19488
+ buttons.push(productOptionButton);
19489
+ return productOptionButton.render();
19490
+ });
19491
+ this.optionButtonsMap.set(name, buttons);
19492
+ return buttonElements;
19493
+ }
19494
+ updateButtonsState() {
19495
+ for (const [optionName, buttons] of this.optionButtonsMap.entries()) {
19496
+ const options = this.optionsManager.getOptionsFor(optionName);
19497
+ buttons.forEach((button, index) => {
19498
+ const option = options[index];
19499
+ const isSelected = this.optionsManager.isOptionSelected(option);
19500
+ const isDisabled = this.optionsManager.isOptionDisabled(option);
19501
+ button.setSelected(isSelected);
19502
+ button.setDisabled(isDisabled);
19503
+ });
19504
+ }
19505
+ }
19506
+ static get [Symbol.for("___CTOR_ARGS___")]() { return [`ProductOptionsProps`]; }
19507
+ }
19508
+
19509
+ class ProductDetailsCover extends RenderableComponent {
19510
+ renderTemplate() {
19511
+ return h(`div`, { class: "ias-product-details__cover" }, h("img", { src: this.props.src }));
19512
+ }
19513
+ styleContent() {
19514
+ return `
19515
+ .ias-product-details__cover {
19516
+ position: absolute;
19517
+ z-index: -1;
19518
+ inset: 0;
19519
+ }
19520
+
19521
+ .ias-product-details__cover img {
19522
+ width: 100%;
19523
+ height: 100%;
19524
+ object-fit: cover;
19525
+ }
19526
+ `;
19527
+ }
19528
+ }
19529
+
19530
+ class ProductDetails extends RenderableComponent {
19531
+ constructor(props) {
19532
+ super(props);
19533
+ }
19534
+ renderTemplate() {
19535
+ const { props } = this;
19536
+ const purchase = new ProductDetailsPurchase(props);
19537
+ const cover = new ProductDetailsCover({
19538
+ src: this.props.product.coverUrl ?? "",
19539
+ });
19540
+ const gallery = new ProductDetailsGallery({
19541
+ imageUrls: this.props.product.imageUrls ?? [],
19542
+ });
19543
+ const description = new ProductDetailsDescription(props.product);
19544
+ const productOptions = this.createProductOptions({ purchase, gallery, description, cover });
19545
+ const relatedProductsLength = this.props.relatedProducts.length ?? 0;
19546
+ return h("div", { class: "ias-product-details" },
19547
+ /* this.props.product.coverUrl ? cover.render() : null, */
19548
+ h("div", { class: "ias-product-details__scrollable" }, gallery.render(), h("div", { class: "ias-product-details__content" }, description.render(), relatedProductsLength > 0 ? productOptions.render() : null)), this.createFooter(purchase));
19549
+ }
19550
+ createProductOptions({ purchase, gallery, description, cover, }) {
19551
+ return new ProductOptions({
19552
+ optionNames: ["color", "size"],
19553
+ products: [this.props.product, ...this.props.relatedProducts],
19554
+ onChange: (product) => {
19555
+ if (this.props.isCartSupported)
19556
+ purchase.updateProps({ product: product });
19557
+ gallery.updateProps(product);
19558
+ description.updateProps(product);
19559
+ cover.updateProps({
19560
+ src: product.coverUrl,
19561
+ });
19562
+ },
19563
+ translations: this.props.translations,
19564
+ });
19565
+ }
19566
+ createFooter(purchase) {
19567
+ if (this.props.isCartSupported) {
19568
+ return h("div", { class: "ias-product-details__footer" }, purchase.render());
19569
+ }
19570
+ else if (this.props.product.url) {
19571
+ return h("div", { class: "ias-product-details__footer" }, this.createOpenUrlButton());
19572
+ }
19573
+ return null;
19574
+ }
19575
+ createOpenUrlButton() {
19576
+ return h("button", {
19577
+ class: "ias-product-details__action-button ias-product-details__open-url-button",
19578
+ textContent: this.props.translations.openUrl,
19579
+ onclick: () => {
19580
+ this.props.onOpenUrl();
19581
+ },
19582
+ });
19583
+ }
19584
+ static get [Symbol.for("___CTOR_ARGS___")]() { return [`ProductDetailsProps`]; }
19585
+ }
19586
+
19587
+ class ProductOfferMapper {
19588
+ static fromOfferDtoToProductOffer(offerDto) {
19589
+ return {
19590
+ id: offerDto.id.toString(),
19591
+ offerId: offerDto.offerId,
19592
+ available: offerDto.availability !== 0,
19593
+ availability: offerDto.availability,
19594
+ options: {
19595
+ color: offerDto.color ? { name: "color", value: offerDto.color } : { name: "color", value: "Undefined" },
19596
+ size: offerDto.size ? { name: "size", value: offerDto.size } : { name: "size", value: "Undefined" },
19597
+ },
19598
+ name: offerDto.name,
19599
+ price: offerDto.price,
19600
+ oldPrice: offerDto.oldPrice,
19601
+ currency: offerDto.currency,
19602
+ description: offerDto.description,
19603
+ imageUrls: offerDto.images?.map(image => image.url) ?? [],
19604
+ adult: offerDto.adult,
19605
+ coverUrl: offerDto.coverUrl,
19606
+ groupId: offerDto.groupId,
19607
+ url: offerDto.url,
19608
+ };
19609
+ }
19610
+ static fromOfferDtoToProductCartOffer(offerDto, quantity) {
19611
+ return {
19612
+ offerId: offerDto.offerId,
19613
+ imageUrls: offerDto.images?.map(image => image.url) ?? [],
19614
+ availability: offerDto.availability,
19615
+ quantity,
19616
+ groupId: offerDto.groupId,
19617
+ name: offerDto.name,
19618
+ description: offerDto.description,
19619
+ url: offerDto.url,
19620
+ coverUrl: offerDto.coverUrl,
19621
+ currency: offerDto.currency,
19622
+ price: offerDto.price,
19623
+ oldPrice: offerDto.oldPrice,
19624
+ adult: offerDto.adult,
19625
+ size: offerDto.size,
19626
+ color: offerDto.color,
19627
+ };
19628
+ }
19629
+ }
19630
+
19631
+ const successSvg = `<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" fill="none"><path stroke="#212121" stroke-linecap="round" stroke-linejoin="round" stroke-width="4" d="M40 14 18 36 8 26"></path></svg>`;
19632
+ class ProductCheckout extends RenderableComponent {
19633
+ constructor(props) {
19634
+ super(props);
19635
+ }
19636
+ renderTemplate() {
19637
+ return h("div", { class: "ias-product-checkout" }, h("div", { class: "ias-product-checkout__box" }, h("div", {
19638
+ class: "ias-product-checkout__icon",
19639
+ html: successSvg,
19640
+ }), h("span", {
19641
+ class: "ias-product-checkout__text",
19642
+ textContent: this.props.translations.successAddToCart,
19643
+ }), h("span", {
19644
+ class: "ias-product-checkout__sub-text",
19645
+ textContent: this.props.translations.successSubAddToCart,
19646
+ })), h("div", {
19647
+ class: "ias-product-checkout__actions",
19648
+ }, h("button", {
19649
+ class: "ias-product-checkout__button ias-product-checkout__button--close",
19650
+ textContent: this.props.translations.continueBtn,
19651
+ onclick: () => {
19652
+ this.props.onClose();
19653
+ },
19654
+ }), h("button", {
19655
+ class: "ias-product-checkout__button ias-product-checkout__button--checkout",
19656
+ textContent: this.props.translations.goToCartBtn,
19657
+ onclick: () => {
19658
+ this.props.onCheckout();
19659
+ },
19660
+ })));
19661
+ }
19662
+ static get [Symbol.for("___CTOR_ARGS___")]() { return [`ProductCheckoutProps`]; }
19663
+ }
19664
+
19665
+ const cartSvg = `<svg xmlns="http://www.w3.org/2000/svg" width="30" height="30" viewBox="0 0 20 20" fill="none">
19666
+ <path stroke="rgba(255, 255, 255, 1)" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.333" d="M4 1.333 2 4v9.333a1.333 1.333 0 0 0 1.333 1.334h9.334A1.334 1.334 0 0 0 14 13.333V4l-2-2.667H4ZM2 4h12"></path>
19667
+ <path stroke="rgba(255, 255, 255, 1)" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.333" d="M10.667 6.667a2.667 2.667 0 1 1-5.333 0"></path>
19668
+ </svg>`;
19669
+ class ProductCartButton extends RenderableComponent {
19670
+ constructor(props) {
19671
+ super(props);
19672
+ }
19673
+ renderTemplate() {
19674
+ return h("div", { class: "ias-product-cart-button", onclick: () => this.props.onClick(), innerHTML: cartSvg });
19675
+ }
19676
+ styleContent() {
19677
+ return `
19678
+ .ias-product-cart-button {
19679
+ position: absolute;
19680
+ left: 0;
19681
+ top: 20%;
19682
+ padding: .25em;
19683
+ padding-left: .5em;
19684
+ background: black;
19685
+ border-top-right-radius: 0.69em;
19686
+ border-bottom-right-radius: 0.69em;
19687
+ display: flex;
19688
+ justify-content: center;
19689
+ align-items: center;
19690
+ cursor: pointer;
19691
+ transition: all 200ms ease-in;
19692
+ transform: translate3d(-.25em, 0, 0);
19693
+ }
19694
+
19695
+ .ias-product-cart-button:hover {
19696
+ transform: translate3d(0, 0, 0);
19697
+ }
19698
+ `;
19699
+ }
19700
+ static get [Symbol.for("___CTOR_ARGS___")]() { return [`ProductCartButtonProps`]; }
19701
+ }
19702
+
19703
+ class ProductComponentsFactory {
19704
+ widgetDeps;
19705
+ props;
19706
+ constructor(widgetDeps, props) {
19707
+ this.widgetDeps = widgetDeps;
19708
+ this.props = props;
19709
+ }
19710
+ createBottomSheet() {
19711
+ const bs = new BottomSheet({
19712
+ onClose: () => {
19713
+ bs.destroy();
19714
+ },
19715
+ children: [],
19716
+ });
19717
+ return bs;
19718
+ }
19719
+ createProductDetails(params) {
19720
+ return new ProductDetails({
19721
+ product: ProductOfferMapper.fromOfferDtoToProductOffer(params.offer),
19722
+ relatedProducts: params.offer.subOffersApi
19723
+ ? params.offer.subOffersApi.map(subOffer => ProductOfferMapper.fromOfferDtoToProductOffer(subOffer))
19724
+ : [],
19725
+ onAddToCart: params.onAddToCart,
19726
+ onAddToCartError: ({ error }) => {
19727
+ this.widgetDeps.slideApiDeps.showToast(error.message);
19728
+ },
19729
+ translations: this.props.translations,
19730
+ isCartSupported: params.isCartSupported,
19731
+ onOpenUrl: () => {
19732
+ if (params.offer.url)
19733
+ this.widgetDeps.slideApiDeps.openUrl({ type: "link", link: { type: "url", target: params.offer.url } });
19734
+ },
19735
+ });
19736
+ }
19737
+ createProductCheckout(bottomSheet, offers) {
19738
+ const offersByIds = {};
19739
+ for (const offer of offers)
19740
+ offersByIds[offer.offerId] = offer;
19741
+ return new ProductCheckout({
19742
+ onClose: () => bottomSheet.close(),
19743
+ onCheckout: () => {
19744
+ this.widgetDeps.slideApiDeps.productCartClicked();
19745
+ },
19746
+ translations: this.props.translations,
19747
+ });
19748
+ }
19749
+ createProductCartButton() {
19750
+ return new ProductCartButton({
19751
+ onClick: async () => {
19752
+ try {
19753
+ const state = await this.widgetDeps.slideApiDeps.productCartGetState();
19754
+ console.log({ cart: state });
19755
+ this.widgetDeps.slideApiDeps.showToast(JSON.stringify(state.offers.map(({ offerId, name, quantity }) => ({
19756
+ offerId,
19757
+ name,
19758
+ quantity,
19759
+ }))));
19760
+ }
19761
+ catch (error) {
19762
+ this.widgetDeps.slideApiDeps.showToast(error.message);
19763
+ }
19764
+ },
19765
+ });
19766
+ }
19767
+ static get [Symbol.for("___CTOR_ARGS___")]() { return [`WidgetDeps`, `{
19768
+ translations: TranslationsMap;
19769
+ }`]; }
19770
+ }
19771
+
19772
+ class ProductDetailsBottomSheet extends RenderableComponent {
19773
+ widgetDeps;
19774
+ factory;
19775
+ bottomSheet;
19776
+ constructor(widgetDeps, props) {
19777
+ super(props);
19778
+ this.widgetDeps = widgetDeps;
19779
+ this.factory = new ProductComponentsFactory(this.widgetDeps, this.props);
19780
+ this.bottomSheet = this.factory.createBottomSheet();
19781
+ }
19782
+ renderTemplate() {
19783
+ return this.bottomSheet.render();
19784
+ }
19785
+ open(params) {
19786
+ this.showProductDetails(params);
19787
+ this.bottomSheet.open();
19788
+ }
19789
+ showProductDetails = ({ offer, isCartSupported }) => {
19790
+ const factory = new ProductComponentsFactory(this.widgetDeps, this.props);
19791
+ const offerDtos = [offer, ...(offer.subOffersApi ?? [])];
19792
+ this.renderProductDetails({ factory, offer, offerDtos, isCartSupported });
19793
+ };
19794
+ renderProductDetails({ factory, offer, offerDtos, isCartSupported, }) {
19795
+ const productDetails = factory.createProductDetails({
19796
+ offer,
19797
+ onAddToCart: async (payload) => {
19798
+ await this.productCartUpdate({
19799
+ offerDtos,
19800
+ product: payload.product,
19801
+ quantity: payload.quantity,
19802
+ });
19803
+ this.showProductCheckout({ offerDtos });
19804
+ },
19805
+ isCartSupported,
19806
+ });
19807
+ this.updateBottomSheetContent(productDetails);
19808
+ }
19809
+ showProductCheckout({ offerDtos }) {
19810
+ const productCheckout = this.factory.createProductCheckout(this.bottomSheet, offerDtos);
19811
+ this.updateBottomSheetContent(productCheckout);
19812
+ this.bottomSheet.setHeight("auto");
19813
+ }
19814
+ updateBottomSheetContent(content) {
19815
+ const cartButton = this.factory.createProductCartButton();
19816
+ const children = process.env.NODE_ENV === "staging" ? [cartButton, content] : [content];
19817
+ this.bottomSheet.updateProps({
19818
+ children,
19819
+ });
19820
+ }
19821
+ async productCartUpdate({ offerDtos, product, quantity }) {
19822
+ const offerDto = offerDtos.find(offerDto => product.offerId === offerDto.offerId);
19823
+ if (!offerDto)
19824
+ throw new Error(`[IAS]: Not found offer for ID ${product.offerId}`);
19825
+ const cartOffer = ProductOfferMapper.fromOfferDtoToProductCartOffer(offerDto, quantity);
19826
+ const delay = async () => new Promise(resolve => setTimeout(resolve, 300));
19827
+ const [productCart] = await Promise.all([
19828
+ await await this.widgetDeps.slideApiDeps.productCartUpdate({
19829
+ offer: cartOffer,
19830
+ }),
19831
+ delay(),
19832
+ ]);
19833
+ return productCart.offers;
19834
+ }
19835
+ static get [Symbol.for("___CTOR_ARGS___")]() { return [`WidgetDeps`, `ProductDetailsBottomSheetProps`]; }
19836
+ }
19837
+
18956
19838
  /**
18957
19839
  * adult: null
18958
19840
  * availability: 1
@@ -19107,7 +19989,7 @@ class WidgetProducts extends WidgetBase {
19107
19989
  if (!this.linkTarget.length) {
19108
19990
  return { message: this.msgServiceError ?? "", models: [] };
19109
19991
  }
19110
- let qs = `id=${this.linkTarget.join(",")}`;
19992
+ let qs = `id=${this.linkTarget.join(",")}&expand=images,subOffersApi`;
19111
19993
  const sdkClientVariables = this.widgetDeps.getSdkClientVariables();
19112
19994
  if (sdkClientVariables != null && sdkClientVariables.pos != null) {
19113
19995
  qs += `&pos=${String(sdkClientVariables.pos)}`;
@@ -19330,9 +20212,7 @@ class WidgetProducts extends WidgetBase {
19330
20212
  e.stopPropagation();
19331
20213
  e.preventDefault();
19332
20214
  this._statEventWidgetCardClick(offer);
19333
- if (offer.url) {
19334
- this.widgetDeps.slideApiDeps.openUrl({ type: "link", link: { type: "url", target: offer.url } });
19335
- }
20215
+ this.showProductDetails({ offer, card });
19336
20216
  };
19337
20217
  card.appendChild(figure);
19338
20218
  // card.appendChild(subTitle);
@@ -19340,6 +20220,27 @@ class WidgetProducts extends WidgetBase {
19340
20220
  card.appendChild(title);
19341
20221
  return card;
19342
20222
  }
20223
+ showProductDetails = ({ card, offer }) => {
20224
+ if (!this.productsView)
20225
+ return;
20226
+ const bs = new ProductDetailsBottomSheet(this.widgetDeps, {
20227
+ translations: {
20228
+ color: getTagData(this.element, "msgColor") ?? "",
20229
+ size: getTagData(this.element, "msgSize") ?? "",
20230
+ addToCart: getTagData(this.element, "msgAddToCart") ?? "",
20231
+ successAddToCart: getTagData(this.element, "msgSuccess") ?? "",
20232
+ successSubAddToCart: getTagData(this.element, "msgSuccessSub") ?? "",
20233
+ errorAddToCart: getTagData(this.element, "msgError") ?? "",
20234
+ goToCartBtn: getTagData(this.element, "msgGoToCart") ?? "",
20235
+ continueBtn: getTagData(this.element, "msgContinue") ?? "",
20236
+ openUrl: getTagData(this.element, "msgOpenUrl") ?? "",
20237
+ },
20238
+ });
20239
+ const isCartEnabled = getTagData(this.element, "isCartEnabled") === "true";
20240
+ const isCartSupported = this.widgetDeps.slideApiDeps.isSdkSupportProductCart && isCartEnabled;
20241
+ this.productsView.appendChild(bs.render());
20242
+ bs.open({ offer, isCartSupported });
20243
+ };
19343
20244
  createScrollView(offers) {
19344
20245
  const scrollViewGroup = document.createElement("div");
19345
20246
  scrollViewGroup.classList.add("ias-products-scroll-view-group");