@salla.sa/twilight-components 2.14.500 → 2.14.501
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/cjs/catalog-recommendations-Bzt0HRy8.js +94 -0
- package/dist/cjs/{filepond-B9PtMjXt.js → filepond-YItpCyss.js} +1 -1
- package/dist/cjs/{filepond-plugin-file-poster-CMd-UUZx.js → filepond-plugin-file-poster-BAPK8RK2.js} +1 -1
- package/dist/cjs/{filepond-plugin-file-validate-size-DpJalosf.js → filepond-plugin-file-validate-size--RuyRQn1.js} +1 -1
- package/dist/cjs/{filepond-plugin-file-validate-type-CZjeYI0w.js → filepond-plugin-file-validate-type-CBvJsWh4.js} +1 -1
- package/dist/cjs/{filepond-plugin-image-edit-Bl6fwgrn.js → filepond-plugin-image-edit-CIZ-WDGk.js} +1 -1
- package/dist/cjs/{filepond-plugin-image-exif-orientation-BeQ8iCyg.js → filepond-plugin-image-exif-orientation-RE8rudTp.js} +1 -1
- package/dist/cjs/{filepond-plugin-image-preview-BkGKXzOB.js → filepond-plugin-image-preview-C17RG4r1.js} +1 -1
- package/dist/cjs/{functions-UaOjMOb2.js → functions-BYc4IT8l.js} +1 -1
- package/dist/cjs/{index-CQPk27Eg.js → index-CB_WYB8k.js} +1 -1
- package/dist/cjs/{index-Cd5xdrCT.js → index-CuQpJRcD.js} +6 -2
- package/dist/cjs/loader.cjs.js +2 -2
- package/dist/cjs/salla-accordion-body_2.cjs.entry.js +1 -1
- package/dist/cjs/salla-accordion_6.cjs.entry.js +1 -1
- package/dist/cjs/salla-add-product-button_5.cjs.entry.js +6 -18
- package/dist/cjs/salla-advertisement.cjs.entry.js +1 -1
- package/dist/cjs/salla-alert_2.cjs.entry.js +1 -1
- package/dist/cjs/salla-app-install-alert.cjs.entry.js +1 -1
- package/dist/cjs/salla-apps-icons.cjs.entry.js +1 -1
- package/dist/cjs/salla-badge.cjs.entry.js +1 -1
- package/dist/cjs/salla-basket-gap.cjs.entry.js +269 -0
- package/dist/cjs/salla-booking-field_7.cjs.entry.js +10 -10
- package/dist/cjs/salla-bullet-delivery_2.cjs.entry.js +1 -1
- package/dist/cjs/salla-cart-coupons.cjs.entry.js +1 -1
- package/dist/cjs/salla-cart-item-offers_2.cjs.entry.js +1 -1
- package/dist/cjs/salla-cart-summary-card.cjs.entry.js +1 -1
- package/dist/cjs/salla-cashback-banner.cjs.entry.js +1 -1
- package/dist/cjs/salla-comment-factors.cjs.entry.js +1 -1
- package/dist/cjs/salla-comment-form_8.cjs.entry.js +1 -1
- package/dist/cjs/salla-conditional-offer.cjs.entry.js +1 -1
- package/dist/cjs/salla-contacts.cjs.entry.js +1 -1
- package/dist/cjs/salla-cookies-bar.cjs.entry.js +1 -1
- package/dist/cjs/salla-count-down_2.cjs.entry.js +4 -3
- package/dist/cjs/salla-custom-fields.cjs.entry.js +1 -1
- package/dist/cjs/salla-delivery-promise.cjs.entry.js +1 -1
- package/dist/cjs/salla-edit-order-button.cjs.entry.js +1 -1
- package/dist/cjs/salla-filters-widget.cjs.entry.js +1 -1
- package/dist/cjs/salla-filters.cjs.entry.js +1 -1
- package/dist/cjs/salla-fulfillment-methods.cjs.entry.js +1 -1
- package/dist/cjs/salla-gifting.cjs.entry.js +1 -1
- package/dist/cjs/salla-hook.cjs.entry.js +1 -1
- package/dist/cjs/salla-infinite-scroll.cjs.entry.js +1 -1
- package/dist/cjs/salla-installment.cjs.entry.js +1 -1
- package/dist/cjs/salla-list-tile.cjs.entry.js +1 -1
- package/dist/cjs/salla-localization-modal.cjs.entry.js +1 -1
- package/dist/cjs/salla-login-modal.cjs.entry.js +1 -1
- package/dist/cjs/salla-loyalty-banner.cjs.entry.js +2 -2
- package/dist/cjs/salla-loyalty-exchange-product-card_5.cjs.entry.js +3 -3
- package/dist/cjs/salla-loyalty-hero_2.cjs.entry.js +2 -2
- package/dist/cjs/salla-loyalty-panel.cjs.entry.js +3 -3
- package/dist/cjs/salla-loyalty-points-banner.cjs.entry.js +1 -1
- package/dist/cjs/salla-loyalty-points-history.cjs.entry.js +1 -1
- package/dist/cjs/salla-loyalty-prize-item.cjs.entry.js +1 -1
- package/dist/cjs/salla-loyalty-program.cjs.entry.js +3 -3
- package/dist/cjs/salla-loyalty-reward.cjs.entry.js +2 -2
- package/dist/cjs/salla-loyalty.cjs.entry.js +1 -1
- package/dist/cjs/salla-maintenance-alert.cjs.entry.js +1 -1
- package/dist/cjs/salla-map_2.cjs.entry.js +1 -1
- package/dist/cjs/salla-menu.cjs.entry.js +1 -1
- package/dist/cjs/salla-metadata.cjs.entry.js +1 -1
- package/dist/cjs/salla-multiple-bundle-product-cart_2.cjs.entry.js +1 -1
- package/dist/cjs/salla-multiple-bundle-product-options-modal_2.cjs.entry.js +1 -1
- package/dist/cjs/salla-multiple-bundle-product.cjs.entry.js +1 -1
- package/dist/cjs/salla-next-order-coupon.cjs.entry.js +1 -1
- package/dist/cjs/salla-notification-item.cjs.entry.js +1 -1
- package/dist/cjs/salla-notifications.cjs.entry.js +1 -1
- package/dist/cjs/salla-offer-modal.cjs.entry.js +1 -1
- package/dist/cjs/salla-offer.cjs.entry.js +1 -1
- package/dist/cjs/salla-order-branch.cjs.entry.js +1 -1
- package/dist/cjs/salla-order-cancel.cjs.entry.js +1 -1
- package/dist/cjs/salla-order-details-multiple-bundle-product.cjs.entry.js +1 -1
- package/dist/cjs/salla-order-details-options.cjs.entry.js +1 -1
- package/dist/cjs/salla-order-details.cjs.entry.js +1 -1
- package/dist/cjs/salla-order-edit-item.cjs.entry.js +1 -1
- package/dist/cjs/salla-order-edit-product-card.cjs.entry.js +1 -1
- package/dist/cjs/salla-order-edit.cjs.entry.js +1 -1
- package/dist/cjs/salla-order-summary.cjs.entry.js +1 -1
- package/dist/cjs/salla-order-totals-card.cjs.entry.js +1 -1
- package/dist/cjs/salla-orders.cjs.entry.js +1 -1
- package/dist/cjs/salla-payments.cjs.entry.js +1 -1
- package/dist/cjs/salla-placeholder.cjs.entry.js +1 -1
- package/dist/cjs/salla-price-range.cjs.entry.js +1 -1
- package/dist/cjs/salla-product-card-embed.cjs.entry.js +1 -1
- package/dist/cjs/salla-product-card_2.cjs.entry.js +1 -1
- package/dist/cjs/salla-product-size-guide.cjs.entry.js +1 -1
- package/dist/cjs/salla-products-list.cjs.entry.js +1 -1
- package/dist/cjs/salla-quick-order.cjs.entry.js +1 -1
- package/dist/cjs/salla-rating-modal-v2.cjs.entry.js +1 -1
- package/dist/cjs/salla-rating-modal.cjs.entry.js +1 -1
- package/dist/cjs/salla-review-factors-tags.cjs.entry.js +1 -1
- package/dist/cjs/salla-scopes.cjs.entry.js +1 -1
- package/dist/cjs/salla-search.cjs.entry.js +1 -1
- package/dist/cjs/salla-skeleton.cjs.entry.js +1 -1
- package/dist/cjs/salla-slider.cjs.entry.js +1 -1
- package/dist/cjs/salla-social-share.cjs.entry.js +1 -1
- package/dist/cjs/salla-social.cjs.entry.js +1 -1
- package/dist/cjs/salla-tab-content_3.cjs.entry.js +1 -1
- package/dist/cjs/salla-tiered-offer.cjs.entry.js +1 -1
- package/dist/cjs/salla-tooltip.cjs.entry.js +1 -1
- package/dist/cjs/salla-trust-badges.cjs.entry.js +1 -1
- package/dist/cjs/salla-user-menu.cjs.entry.js +1 -1
- package/dist/cjs/salla-user-profile.cjs.entry.js +1 -1
- package/dist/cjs/salla-user-settings.cjs.entry.js +1 -1
- package/dist/cjs/salla-verify.cjs.entry.js +1 -1
- package/dist/cjs/salla-wallet.cjs.entry.js +1 -1
- package/dist/cjs/salla-wishlist-actions.cjs.entry.js +1 -1
- package/dist/cjs/{tracked-promise-DwUVHl1m.js → tracked-promise-XZchciB1.js} +1 -1
- package/dist/cjs/twilight.cjs.js +2 -2
- package/dist/cjs/{vanilla-picker-BTiOI13l.js → vanilla-picker-DcFuBceg.js} +1 -1
- package/dist/collection/collection-manifest.json +1 -0
- package/dist/collection/components/salla-basket-gap/salla-basket-gap.css +3 -0
- package/dist/collection/components/salla-basket-gap/salla-basket-gap.js +306 -0
- package/dist/collection/components/salla-bought-together/salla-bought-together.js +5 -17
- package/dist/collection/components/salla-count-down/salla-count-down.js +3 -2
- package/dist/collection/shared/catalog-recommendations.js +89 -0
- package/dist/components/catalog-recommendations.js +91 -0
- package/dist/components/index.js +2 -2
- package/dist/components/salla-basket-gap.d.ts +11 -0
- package/dist/components/salla-basket-gap.js +402 -0
- package/dist/components/salla-bought-together.js +5 -17
- package/dist/components/salla-count-down2.js +3 -2
- package/dist/esm/catalog-recommendations-9fzJJ_Ox.js +91 -0
- package/dist/esm/{filepond-DjtqIoeD.js → filepond-DQgEXp69.js} +1 -1
- package/dist/esm/{filepond-plugin-file-poster-CFxoEHLP.js → filepond-plugin-file-poster-BE5-JUQb.js} +1 -1
- package/dist/esm/{filepond-plugin-file-validate-size-BnBRYL0y.js → filepond-plugin-file-validate-size-CwWpBym0.js} +1 -1
- package/dist/esm/{filepond-plugin-file-validate-type-Dr5ofT9v.js → filepond-plugin-file-validate-type-CovRSsjJ.js} +1 -1
- package/dist/esm/{filepond-plugin-image-edit-DyMeCzTZ.js → filepond-plugin-image-edit-DY-5oWCU.js} +1 -1
- package/dist/esm/{filepond-plugin-image-exif-orientation-ngtve06j.js → filepond-plugin-image-exif-orientation-DQROYLkj.js} +1 -1
- package/dist/esm/{filepond-plugin-image-preview-aqxBqAYf.js → filepond-plugin-image-preview-CZCR-9d7.js} +1 -1
- package/dist/esm/{functions-Drikk4uf.js → functions-DWD7tnLk.js} +1 -1
- package/dist/esm/{index-DuoSRdS5.js → index-DW5RMC3M.js} +6 -2
- package/dist/esm/{index-CaZkz-p0.js → index-VUPjm0uj.js} +1 -1
- package/dist/esm/loader.js +3 -3
- package/dist/esm/salla-accordion-body_2.entry.js +1 -1
- package/dist/esm/salla-accordion_6.entry.js +1 -1
- package/dist/esm/salla-add-product-button_5.entry.js +6 -18
- package/dist/esm/salla-advertisement.entry.js +1 -1
- package/dist/esm/salla-alert_2.entry.js +1 -1
- package/dist/esm/salla-app-install-alert.entry.js +1 -1
- package/dist/esm/salla-apps-icons.entry.js +1 -1
- package/dist/esm/salla-badge.entry.js +1 -1
- package/dist/esm/salla-basket-gap.entry.js +267 -0
- package/dist/esm/salla-booking-field_7.entry.js +10 -10
- package/dist/esm/salla-bullet-delivery_2.entry.js +1 -1
- package/dist/esm/salla-cart-coupons.entry.js +1 -1
- package/dist/esm/salla-cart-item-offers_2.entry.js +1 -1
- package/dist/esm/salla-cart-summary-card.entry.js +1 -1
- package/dist/esm/salla-cashback-banner.entry.js +1 -1
- package/dist/esm/salla-comment-factors.entry.js +1 -1
- package/dist/esm/salla-comment-form_8.entry.js +1 -1
- package/dist/esm/salla-conditional-offer.entry.js +1 -1
- package/dist/esm/salla-contacts.entry.js +1 -1
- package/dist/esm/salla-cookies-bar.entry.js +1 -1
- package/dist/esm/salla-count-down_2.entry.js +4 -3
- package/dist/esm/salla-custom-fields.entry.js +1 -1
- package/dist/esm/salla-delivery-promise.entry.js +1 -1
- package/dist/esm/salla-edit-order-button.entry.js +1 -1
- package/dist/esm/salla-filters-widget.entry.js +1 -1
- package/dist/esm/salla-filters.entry.js +1 -1
- package/dist/esm/salla-fulfillment-methods.entry.js +1 -1
- package/dist/esm/salla-gifting.entry.js +1 -1
- package/dist/esm/salla-hook.entry.js +1 -1
- package/dist/esm/salla-infinite-scroll.entry.js +1 -1
- package/dist/esm/salla-installment.entry.js +1 -1
- package/dist/esm/salla-list-tile.entry.js +1 -1
- package/dist/esm/salla-localization-modal.entry.js +1 -1
- package/dist/esm/salla-login-modal.entry.js +1 -1
- package/dist/esm/salla-loyalty-banner.entry.js +2 -2
- package/dist/esm/salla-loyalty-exchange-product-card_5.entry.js +3 -3
- package/dist/esm/salla-loyalty-hero_2.entry.js +2 -2
- package/dist/esm/salla-loyalty-panel.entry.js +3 -3
- package/dist/esm/salla-loyalty-points-banner.entry.js +1 -1
- package/dist/esm/salla-loyalty-points-history.entry.js +1 -1
- package/dist/esm/salla-loyalty-prize-item.entry.js +1 -1
- package/dist/esm/salla-loyalty-program.entry.js +3 -3
- package/dist/esm/salla-loyalty-reward.entry.js +2 -2
- package/dist/esm/salla-loyalty.entry.js +1 -1
- package/dist/esm/salla-maintenance-alert.entry.js +1 -1
- package/dist/esm/salla-map_2.entry.js +1 -1
- package/dist/esm/salla-menu.entry.js +1 -1
- package/dist/esm/salla-metadata.entry.js +1 -1
- package/dist/esm/salla-multiple-bundle-product-cart_2.entry.js +1 -1
- package/dist/esm/salla-multiple-bundle-product-options-modal_2.entry.js +1 -1
- package/dist/esm/salla-multiple-bundle-product.entry.js +1 -1
- package/dist/esm/salla-next-order-coupon.entry.js +1 -1
- package/dist/esm/salla-notification-item.entry.js +1 -1
- package/dist/esm/salla-notifications.entry.js +1 -1
- package/dist/esm/salla-offer-modal.entry.js +1 -1
- package/dist/esm/salla-offer.entry.js +1 -1
- package/dist/esm/salla-order-branch.entry.js +1 -1
- package/dist/esm/salla-order-cancel.entry.js +1 -1
- package/dist/esm/salla-order-details-multiple-bundle-product.entry.js +1 -1
- package/dist/esm/salla-order-details-options.entry.js +1 -1
- package/dist/esm/salla-order-details.entry.js +1 -1
- package/dist/esm/salla-order-edit-item.entry.js +1 -1
- package/dist/esm/salla-order-edit-product-card.entry.js +1 -1
- package/dist/esm/salla-order-edit.entry.js +1 -1
- package/dist/esm/salla-order-summary.entry.js +1 -1
- package/dist/esm/salla-order-totals-card.entry.js +1 -1
- package/dist/esm/salla-orders.entry.js +1 -1
- package/dist/esm/salla-payments.entry.js +1 -1
- package/dist/esm/salla-placeholder.entry.js +1 -1
- package/dist/esm/salla-price-range.entry.js +1 -1
- package/dist/esm/salla-product-card-embed.entry.js +1 -1
- package/dist/esm/salla-product-card_2.entry.js +1 -1
- package/dist/esm/salla-product-size-guide.entry.js +1 -1
- package/dist/esm/salla-products-list.entry.js +1 -1
- package/dist/esm/salla-quick-order.entry.js +1 -1
- package/dist/esm/salla-rating-modal-v2.entry.js +1 -1
- package/dist/esm/salla-rating-modal.entry.js +1 -1
- package/dist/esm/salla-review-factors-tags.entry.js +1 -1
- package/dist/esm/salla-scopes.entry.js +1 -1
- package/dist/esm/salla-search.entry.js +1 -1
- package/dist/esm/salla-skeleton.entry.js +1 -1
- package/dist/esm/salla-slider.entry.js +1 -1
- package/dist/esm/salla-social-share.entry.js +1 -1
- package/dist/esm/salla-social.entry.js +1 -1
- package/dist/esm/salla-tab-content_3.entry.js +1 -1
- package/dist/esm/salla-tiered-offer.entry.js +1 -1
- package/dist/esm/salla-tooltip.entry.js +1 -1
- package/dist/esm/salla-trust-badges.entry.js +1 -1
- package/dist/esm/salla-user-menu.entry.js +1 -1
- package/dist/esm/salla-user-profile.entry.js +1 -1
- package/dist/esm/salla-user-settings.entry.js +1 -1
- package/dist/esm/salla-verify.entry.js +1 -1
- package/dist/esm/salla-wallet.entry.js +1 -1
- package/dist/esm/salla-wishlist-actions.entry.js +1 -1
- package/dist/esm/{tracked-promise-CUM6cNiF.js → tracked-promise-CZ98bqyM.js} +1 -1
- package/dist/esm/twilight.js +3 -3
- package/dist/esm/{vanilla-picker-kF8Cgi5q.js → vanilla-picker-DKozn4lm.js} +1 -1
- package/dist/twilight/{p-9cc2e54c.entry.js → p-015a4d45.entry.js} +1 -1
- package/dist/twilight/{p-a34c031b.entry.js → p-0708708b.entry.js} +1 -1
- package/dist/twilight/{p-03db477f.entry.js → p-0aea93dd.entry.js} +1 -1
- package/dist/twilight/{p-5cb10852.entry.js → p-0f2f8564.entry.js} +1 -1
- package/dist/twilight/{p-c3530e7a.entry.js → p-12f14fe5.entry.js} +1 -1
- package/dist/twilight/{p-d8c9d454.entry.js → p-1453e674.entry.js} +1 -1
- package/dist/twilight/{p-9a161a84.entry.js → p-17edd677.entry.js} +1 -1
- package/dist/twilight/{p-98186fb3.entry.js → p-18209070.entry.js} +1 -1
- package/dist/twilight/p-1decfdb8.entry.js +4 -0
- package/dist/twilight/{p-d54b75de.entry.js → p-210de87e.entry.js} +1 -1
- package/dist/twilight/{p-d3a9573e.entry.js → p-234752f4.entry.js} +1 -1
- package/dist/twilight/{p-0bc04e3f.entry.js → p-24f1c04b.entry.js} +1 -1
- package/dist/twilight/{p-2c9c0815.entry.js → p-254d24b3.entry.js} +1 -1
- package/dist/twilight/{p-f8d642b2.entry.js → p-29b848f7.entry.js} +1 -1
- package/dist/twilight/{p-d49130fc.entry.js → p-2abf736c.entry.js} +1 -1
- package/dist/twilight/{p-77d816b8.entry.js → p-2bc1991c.entry.js} +1 -1
- package/dist/twilight/{p-4fff03a8.entry.js → p-2fe13b65.entry.js} +1 -1
- package/dist/twilight/{p-0a1f28c9.entry.js → p-33710edf.entry.js} +1 -1
- package/dist/twilight/{p-1d75fdd9.entry.js → p-3f47b71b.entry.js} +1 -1
- package/dist/twilight/{p-72c9cd44.entry.js → p-41b9b2ef.entry.js} +1 -1
- package/dist/twilight/{p-9c798a1a.entry.js → p-42fb6aaa.entry.js} +1 -1
- package/dist/twilight/{p-e5c2df5a.entry.js → p-44403dab.entry.js} +1 -1
- package/dist/twilight/{p-56ba7f94.entry.js → p-47dd7a56.entry.js} +1 -1
- package/dist/twilight/{p-51bc9c4d.entry.js → p-485cd05f.entry.js} +1 -1
- package/dist/twilight/{p-99ff235e.entry.js → p-494f93d5.entry.js} +1 -1
- package/dist/twilight/{p-04fadfb3.entry.js → p-4aaba2ae.entry.js} +1 -1
- package/dist/twilight/{p-930ff69a.entry.js → p-4e60702f.entry.js} +1 -1
- package/dist/twilight/{p-0daa8221.entry.js → p-4ed58afc.entry.js} +1 -1
- package/dist/twilight/{p-c6d64b53.entry.js → p-4f1b17ce.entry.js} +1 -1
- package/dist/twilight/{p-54e43314.entry.js → p-4ff3fcc2.entry.js} +1 -1
- package/dist/twilight/{p-7df52f7b.entry.js → p-52465888.entry.js} +1 -1
- package/dist/twilight/{p-b0437615.entry.js → p-527c985e.entry.js} +1 -1
- package/dist/twilight/{p-bd2672ee.entry.js → p-5803461f.entry.js} +1 -1
- package/dist/twilight/{p-8658fefd.entry.js → p-5c81f957.entry.js} +1 -1
- package/dist/twilight/{p-953da0b5.entry.js → p-5f363172.entry.js} +1 -1
- package/dist/twilight/{p-be973f87.entry.js → p-60096faf.entry.js} +1 -1
- package/dist/twilight/{p-2c4f4539.entry.js → p-629b0300.entry.js} +1 -1
- package/dist/twilight/{p-c6b82041.entry.js → p-64bddbd4.entry.js} +1 -1
- package/dist/twilight/p-66b8ffe5.entry.js +4 -0
- package/dist/twilight/{p-74e009df.entry.js → p-686e0e20.entry.js} +1 -1
- package/dist/twilight/{p-01636f53.entry.js → p-693d1afd.entry.js} +1 -1
- package/dist/twilight/{p-cd65e560.entry.js → p-6c2bd4d3.entry.js} +1 -1
- package/dist/twilight/{p-9196b7a9.entry.js → p-6ea59d29.entry.js} +1 -1
- package/dist/twilight/{p-286d9ba3.entry.js → p-753c2036.entry.js} +1 -1
- package/dist/twilight/{p-0c1721e1.entry.js → p-7d4ea0b4.entry.js} +1 -1
- package/dist/twilight/{p-022343f3.entry.js → p-7d778acb.entry.js} +1 -1
- package/dist/twilight/{p-0b814320.entry.js → p-7fa1bb43.entry.js} +1 -1
- package/dist/twilight/{p-a2e8a9d1.entry.js → p-8091c1bb.entry.js} +1 -1
- package/dist/twilight/{p-15c3b0cc.entry.js → p-85238859.entry.js} +1 -1
- package/dist/twilight/{p-a96e5e06.entry.js → p-86b6bf59.entry.js} +1 -1
- package/dist/twilight/{p-eb2e3e67.entry.js → p-8a550a9b.entry.js} +1 -1
- package/dist/twilight/{p-7e730733.entry.js → p-8bd21221.entry.js} +1 -1
- package/dist/twilight/{p-67d7bd8b.entry.js → p-8c0b1195.entry.js} +1 -1
- package/dist/twilight/{p-f9a3f3f4.entry.js → p-8fded8e8.entry.js} +1 -1
- package/dist/twilight/{p-5fe29fcf.entry.js → p-90039201.entry.js} +1 -1
- package/dist/twilight/{p-DMHhYV48.js → p-9Gnw86AG.js} +1 -1
- package/dist/twilight/{p-168e3ad8.entry.js → p-9adcfb8f.entry.js} +1 -1
- package/dist/twilight/{p-a1d3a45f.entry.js → p-9b4a8482.entry.js} +1 -1
- package/dist/twilight/{p-39389b31.entry.js → p-9bfb9e67.entry.js} +1 -1
- package/dist/twilight/{p-19c6d83a.entry.js → p-9c7ed057.entry.js} +1 -1
- package/dist/twilight/{p-92d37b3e.entry.js → p-9ea31b28.entry.js} +1 -1
- package/dist/twilight/p-9fzJJ_Ox.js +4 -0
- package/dist/twilight/{p-lYj74H1f.js → p-BEd1gsDo.js} +1 -1
- package/dist/twilight/p-BOGl7WKm.js +4 -0
- package/dist/twilight/{p-CHOv1Smw.js → p-BOsr_t6U.js} +1 -1
- package/dist/twilight/{p-DYcV7UW8.js → p-Bk7FtCRB.js} +1 -1
- package/dist/twilight/{p-DYgnIxqR.js → p-BmLFLdi9.js} +1 -1
- package/dist/twilight/{p-DQXp-sN5.js → p-CTz-tTY_.js} +1 -1
- package/dist/twilight/{p-Ca84RIBI.js → p-D6IFHeYy.js} +1 -1
- package/dist/twilight/{p-kflOqry6.js → p-DKReyChR.js} +1 -1
- package/dist/twilight/{p-DuoSRdS5.js → p-DW5RMC3M.js} +1 -1
- package/dist/twilight/{p-KZ7SFw0C.js → p-Dha9oJHi.js} +1 -1
- package/dist/twilight/{p-BYpv9A8D.js → p-MxH_-y8s.js} +1 -1
- package/dist/twilight/{p-5a215130.entry.js → p-a7da83e9.entry.js} +1 -1
- package/dist/twilight/{p-2104f800.entry.js → p-a9d1a6ab.entry.js} +1 -1
- package/dist/twilight/{p-bdda14f6.entry.js → p-abffebe7.entry.js} +1 -1
- package/dist/twilight/{p-f4eba1d1.entry.js → p-b9babfe5.entry.js} +1 -1
- package/dist/twilight/{p-0604eb27.entry.js → p-bc890bf3.entry.js} +1 -1
- package/dist/twilight/{p-404d3645.entry.js → p-bc935da0.entry.js} +1 -1
- package/dist/twilight/{p-ecdf7027.entry.js → p-bd2359a7.entry.js} +1 -1
- package/dist/twilight/{p-92ec265b.entry.js → p-bd7ba620.entry.js} +1 -1
- package/dist/twilight/{p-7b9ed1e4.entry.js → p-bdfb4b2b.entry.js} +1 -1
- package/dist/twilight/{p-47c9e882.entry.js → p-be13f6cf.entry.js} +1 -1
- package/dist/twilight/{p-5f47eb12.entry.js → p-c0373e93.entry.js} +1 -1
- package/dist/twilight/{p-3c96d5af.entry.js → p-c2019c1f.entry.js} +1 -1
- package/dist/twilight/{p-dc6b3dfb.entry.js → p-c66582de.entry.js} +1 -1
- package/dist/twilight/{p-9e27778a.entry.js → p-cb675f91.entry.js} +1 -1
- package/dist/twilight/{p-ca0a62f9.entry.js → p-cc0b8dec.entry.js} +1 -1
- package/dist/twilight/{p-6e535738.entry.js → p-ce06372f.entry.js} +1 -1
- package/dist/twilight/{p-ae83c325.entry.js → p-ceb44ad7.entry.js} +1 -1
- package/dist/twilight/{p-0e6a0989.entry.js → p-cfe4f808.entry.js} +1 -1
- package/dist/twilight/{p-00d73870.entry.js → p-d047a409.entry.js} +1 -1
- package/dist/twilight/p-d63533f2.entry.js +4 -0
- package/dist/twilight/{p-a5eeb082.entry.js → p-d649f426.entry.js} +1 -1
- package/dist/twilight/{p-4fb48be8.entry.js → p-d89e140a.entry.js} +1 -1
- package/dist/twilight/{p-95d8a11b.entry.js → p-daaa9ef7.entry.js} +1 -1
- package/dist/twilight/{p-f060a3dd.entry.js → p-dbc38d79.entry.js} +1 -1
- package/dist/twilight/{p-74cac8a8.entry.js → p-dd7a835b.entry.js} +1 -1
- package/dist/twilight/{p-f9912293.entry.js → p-ddbaca65.entry.js} +1 -1
- package/dist/twilight/{p-90d53c9b.entry.js → p-e47540e1.entry.js} +1 -1
- package/dist/twilight/{p-f5ac65b4.entry.js → p-e8ada41e.entry.js} +1 -1
- package/dist/twilight/{p-061fdc55.entry.js → p-e9a35a7f.entry.js} +1 -1
- package/dist/twilight/{p-ca52add5.entry.js → p-ef77963a.entry.js} +1 -1
- package/dist/twilight/{p-d39bf8b5.entry.js → p-f2416b6d.entry.js} +1 -1
- package/dist/twilight/{p-aed6d4eb.entry.js → p-f9c12172.entry.js} +1 -1
- package/dist/twilight/{p-72291ad7.entry.js → p-fbc91885.entry.js} +1 -1
- package/dist/twilight/p-ff5a82a3.entry.js +4 -0
- package/dist/twilight/twilight.esm.js +1 -1
- package/dist/types/components/salla-basket-gap/salla-basket-gap.d.ts +52 -0
- package/dist/types/components.d.ts +23 -0
- package/dist/types/shared/catalog-recommendations.d.ts +2 -0
- package/package.json +5 -5
- package/dist/twilight/p-25ZR4Fc8.js +0 -4
- package/dist/twilight/p-2985e01e.entry.js +0 -4
- package/dist/twilight/p-931c44fb.entry.js +0 -4
- package/dist/twilight/p-982ccb80.entry.js +0 -4
|
@@ -0,0 +1,306 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* Crafted with ❤ by Salla
|
|
3
|
+
*/
|
|
4
|
+
import { Host, h } from "@stencil/core";
|
|
5
|
+
import { fetchCartBoughtTogether } from "../../shared/catalog-recommendations";
|
|
6
|
+
export class SallaBasketGap {
|
|
7
|
+
constructor() {
|
|
8
|
+
/**
|
|
9
|
+
* Maximum number of recommendations to fetch.
|
|
10
|
+
*/
|
|
11
|
+
this.limit = 10;
|
|
12
|
+
this.products = [];
|
|
13
|
+
this.isLoading = true;
|
|
14
|
+
this.canRender = true;
|
|
15
|
+
this.title = '';
|
|
16
|
+
this.addToCartLabel = '';
|
|
17
|
+
this.weightLabel = '';
|
|
18
|
+
this.discountLabel = '';
|
|
19
|
+
this.placeholder = '';
|
|
20
|
+
this.fetchGeneration = 0;
|
|
21
|
+
this.isSyncingCart = false;
|
|
22
|
+
this.cartItemChangedHandler = (response) => {
|
|
23
|
+
const items = response?.data?.cart?.items ?? [];
|
|
24
|
+
const ids = items.map((i) => String(i.product_id)).filter(Boolean);
|
|
25
|
+
// Reflect a newly added product in the cart list without a full page refresh.
|
|
26
|
+
this.syncCartItemsDom(items);
|
|
27
|
+
this.fetchRecommendations(ids);
|
|
28
|
+
};
|
|
29
|
+
this.beforeAddItemHandler = (data) => {
|
|
30
|
+
const id = String(data?.id ?? '');
|
|
31
|
+
if (id && this.products.some((p) => String(p.id) === id) && salla.cart?.api) {
|
|
32
|
+
salla.cart.api.addToCartSource = 'basket_gap';
|
|
33
|
+
}
|
|
34
|
+
};
|
|
35
|
+
this.addButtonSuccessHandler = (event) => {
|
|
36
|
+
const productId = event?.target?.getAttribute?.('product-id');
|
|
37
|
+
if (!productId)
|
|
38
|
+
return;
|
|
39
|
+
const product = this.products.find((p) => String(p.id) === String(productId));
|
|
40
|
+
if (!product)
|
|
41
|
+
return;
|
|
42
|
+
const items = event?.detail?.data?.items ?? [];
|
|
43
|
+
const cartItem = items.find((i) => String(i.product_id) === String(product.id)) ?? items.slice(-1)[0];
|
|
44
|
+
salla.event.emit('salla-basket-gap::product.added', [{
|
|
45
|
+
product,
|
|
46
|
+
position: this.products.indexOf(product) + 1,
|
|
47
|
+
cartItem,
|
|
48
|
+
cartId: event?.detail?.data?.id,
|
|
49
|
+
source: 'basket_gap',
|
|
50
|
+
}]);
|
|
51
|
+
};
|
|
52
|
+
salla.lang.onLoaded(() => {
|
|
53
|
+
this.title = salla.lang.get('pages.cart.basket_gap_title');
|
|
54
|
+
this.addToCartLabel = salla.lang.get('pages.cart.add_to_cart');
|
|
55
|
+
this.weightLabel = salla.lang.get('pages.products.weight');
|
|
56
|
+
this.discountLabel = salla.lang.get('pages.products.discount');
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
componentWillLoad() {
|
|
60
|
+
salla.onReady().then(() => {
|
|
61
|
+
if (!salla.config.get('store.settings.cart.basket_gap')) {
|
|
62
|
+
this.canRender = false;
|
|
63
|
+
this.isLoading = false;
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
this.title = salla.lang.get('pages.cart.basket_gap_title');
|
|
67
|
+
this.addToCartLabel = salla.lang.get('pages.cart.add_to_cart');
|
|
68
|
+
this.weightLabel = salla.lang.get('pages.products.weight');
|
|
69
|
+
this.discountLabel = salla.lang.get('pages.products.discount');
|
|
70
|
+
this.placeholder = salla.url.asset(salla.config.get('theme.settings.placeholder'));
|
|
71
|
+
const cachedCart = salla.storage.get('cart');
|
|
72
|
+
const cachedIds = (cachedCart?.items ?? []).map((i) => String(i.product_id)).filter(Boolean);
|
|
73
|
+
if (cachedIds.length) {
|
|
74
|
+
return this.fetchRecommendations(cachedIds);
|
|
75
|
+
}
|
|
76
|
+
return salla.api.cart.details()
|
|
77
|
+
.then(({ data: { cart } }) => {
|
|
78
|
+
const objectIDs = (cart?.items ?? []).map((i) => String(i.product_id)).filter(Boolean);
|
|
79
|
+
return this.fetchRecommendations(objectIDs);
|
|
80
|
+
})
|
|
81
|
+
.catch(() => {
|
|
82
|
+
this.canRender = false;
|
|
83
|
+
this.isLoading = false;
|
|
84
|
+
});
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
componentDidLoad() {
|
|
88
|
+
this.positionUnderCartItems();
|
|
89
|
+
}
|
|
90
|
+
componentDidUpdate() {
|
|
91
|
+
document.lazyLoadInstance?.update(this.host.querySelectorAll('.lazy'));
|
|
92
|
+
this.positionUnderCartItems();
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Cart item rows on the storefront cart page (excluding the order-options block).
|
|
96
|
+
* Kept defensive: themes that don't use the `form[id^="item-"]` pattern return none.
|
|
97
|
+
*/
|
|
98
|
+
getCartItemForms(root = document) {
|
|
99
|
+
return Array.from(root.querySelectorAll('form[id^="item-"]'))
|
|
100
|
+
.filter((form) => !form.closest('.cart-options'));
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* The component is injected at the theme's `cart:items.end` hook, which may sit
|
|
104
|
+
* below the order options/offers. Move the host to render directly under the
|
|
105
|
+
* cart items. No-ops when the cart item pattern isn't present.
|
|
106
|
+
*/
|
|
107
|
+
positionUnderCartItems() {
|
|
108
|
+
const items = this.getCartItemForms();
|
|
109
|
+
const lastItem = items[items.length - 1];
|
|
110
|
+
if (lastItem && lastItem.nextElementSibling !== this.host) {
|
|
111
|
+
lastItem.after(this.host);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Reflect a newly added product in the cart list without a full page reload.
|
|
116
|
+
* The whole item list is replaced with the fresh server-rendered rows because
|
|
117
|
+
* Salla re-assigns cart line-item ids on add, so diffing by id would duplicate
|
|
118
|
+
* the existing rows. No-ops on themes without the cart item markup.
|
|
119
|
+
*/
|
|
120
|
+
syncCartItemsDom(cartItems) {
|
|
121
|
+
if (!cartItems?.length || this.isSyncingCart)
|
|
122
|
+
return;
|
|
123
|
+
const missing = cartItems.filter((item) => !document.getElementById('item-' + item.id));
|
|
124
|
+
if (!missing.length)
|
|
125
|
+
return;
|
|
126
|
+
this.isSyncingCart = true;
|
|
127
|
+
fetch(window.location.href, { headers: { 'X-Requested-With': 'XMLHttpRequest' }, credentials: 'same-origin' })
|
|
128
|
+
.then((res) => res.text())
|
|
129
|
+
.then((html) => {
|
|
130
|
+
const doc = new DOMParser().parseFromString(html, 'text/html');
|
|
131
|
+
const freshForms = this.getCartItemForms(doc);
|
|
132
|
+
const currentForms = this.getCartItemForms();
|
|
133
|
+
if (!freshForms.length || !currentForms.length)
|
|
134
|
+
return;
|
|
135
|
+
const firstCurrent = currentForms[0];
|
|
136
|
+
const parent = firstCurrent.parentElement;
|
|
137
|
+
if (!parent)
|
|
138
|
+
return;
|
|
139
|
+
// Insert the fresh rows in place of the current ones, then drop the old rows.
|
|
140
|
+
freshForms.forEach((form) => {
|
|
141
|
+
parent.insertBefore(document.importNode(form, true), firstCurrent);
|
|
142
|
+
});
|
|
143
|
+
currentForms.forEach((form) => form.remove());
|
|
144
|
+
document.lazyLoadInstance?.update?.();
|
|
145
|
+
this.positionUnderCartItems();
|
|
146
|
+
})
|
|
147
|
+
.catch(() => { })
|
|
148
|
+
.finally(() => { this.isSyncingCart = false; });
|
|
149
|
+
}
|
|
150
|
+
connectedCallback() {
|
|
151
|
+
salla.event.on('cart::item.added', this.cartItemChangedHandler);
|
|
152
|
+
salla.event.on('cart::item.deleted', this.cartItemChangedHandler);
|
|
153
|
+
// Tag adds originating from a basket-gap recommendation so the cart auto-track
|
|
154
|
+
// is suppressed in favour of our attributed `salla-basket-gap::product.added`.
|
|
155
|
+
salla.event.on('cart::before.add.item', this.beforeAddItemHandler);
|
|
156
|
+
this.host.addEventListener('success', this.addButtonSuccessHandler);
|
|
157
|
+
}
|
|
158
|
+
disconnectedCallback() {
|
|
159
|
+
salla.event.off('cart::item.added', this.cartItemChangedHandler);
|
|
160
|
+
salla.event.off('cart::item.deleted', this.cartItemChangedHandler);
|
|
161
|
+
salla.event.off('cart::before.add.item', this.beforeAddItemHandler);
|
|
162
|
+
this.host.removeEventListener('success', this.addButtonSuccessHandler);
|
|
163
|
+
}
|
|
164
|
+
// The recommendation API receives at most 5 cart product IDs, so it can return
|
|
165
|
+
// products that are already in the cart (those beyond the 5-item payload limit).
|
|
166
|
+
// We filter them out here to avoid showing items the customer already has.
|
|
167
|
+
// cartProductIds may be passed in directly from a live event payload; otherwise
|
|
168
|
+
// we fall back to storage (which can lag behind on the initial load path).
|
|
169
|
+
getCartProductIds(knownIds) {
|
|
170
|
+
if (knownIds?.length)
|
|
171
|
+
return new Set(knownIds);
|
|
172
|
+
const cart = salla.storage.get('cart');
|
|
173
|
+
return new Set((cart?.items ?? []).map((i) => String(i.product_id)).filter(Boolean));
|
|
174
|
+
}
|
|
175
|
+
fetchRecommendations(objectIDs) {
|
|
176
|
+
if (!objectIDs.length) {
|
|
177
|
+
this.canRender = false;
|
|
178
|
+
this.isLoading = false;
|
|
179
|
+
return Promise.resolve();
|
|
180
|
+
}
|
|
181
|
+
const generation = ++this.fetchGeneration;
|
|
182
|
+
return fetchCartBoughtTogether(objectIDs)
|
|
183
|
+
.then((ids) => {
|
|
184
|
+
if (generation !== this.fetchGeneration)
|
|
185
|
+
return;
|
|
186
|
+
// Pass objectIDs as the authoritative cart list so the filter is not
|
|
187
|
+
// affected by stale storage when called from a live cart event.
|
|
188
|
+
const cartIds = this.getCartProductIds(objectIDs);
|
|
189
|
+
const filteredIds = ids.filter(id => !cartIds.has(id));
|
|
190
|
+
if (!filteredIds.length) {
|
|
191
|
+
this.canRender = false;
|
|
192
|
+
return;
|
|
193
|
+
}
|
|
194
|
+
return this.fetchProducts(filteredIds.slice(0, this.limit), generation);
|
|
195
|
+
})
|
|
196
|
+
.catch(() => {
|
|
197
|
+
if (generation !== this.fetchGeneration)
|
|
198
|
+
return;
|
|
199
|
+
this.canRender = false;
|
|
200
|
+
})
|
|
201
|
+
.finally(() => {
|
|
202
|
+
if (generation !== this.fetchGeneration)
|
|
203
|
+
return;
|
|
204
|
+
this.isLoading = false;
|
|
205
|
+
});
|
|
206
|
+
}
|
|
207
|
+
fetchProducts(ids, generation) {
|
|
208
|
+
return salla.api.withoutNotifier(() => salla.product.api.fetch({
|
|
209
|
+
source: 'selected',
|
|
210
|
+
source_value: ids,
|
|
211
|
+
limit: this.limit,
|
|
212
|
+
})).then((response) => {
|
|
213
|
+
if (generation !== this.fetchGeneration)
|
|
214
|
+
return;
|
|
215
|
+
this.products = response?.data ?? [];
|
|
216
|
+
this.canRender = this.products.length > 0;
|
|
217
|
+
}).catch(() => {
|
|
218
|
+
if (generation !== this.fetchGeneration)
|
|
219
|
+
return;
|
|
220
|
+
this.canRender = false;
|
|
221
|
+
});
|
|
222
|
+
}
|
|
223
|
+
getDiscountLabel(product) {
|
|
224
|
+
if (product.promotion_title)
|
|
225
|
+
return product.promotion_title;
|
|
226
|
+
if (product.is_on_sale && product.regular_price > 0 && product.sale_price > 0) {
|
|
227
|
+
const percent = Math.round((1 - product.sale_price / product.regular_price) * 100);
|
|
228
|
+
return percent > 0 ? `${this.discountLabel} ${percent}%` : null;
|
|
229
|
+
}
|
|
230
|
+
return null;
|
|
231
|
+
}
|
|
232
|
+
formatDate(timestamp) {
|
|
233
|
+
const d = new Date(timestamp * 1000);
|
|
234
|
+
const mm = String(d.getMonth() + 1).padStart(2, '0');
|
|
235
|
+
const dd = String(d.getDate()).padStart(2, '0');
|
|
236
|
+
return `${d.getFullYear()}-${mm}-${dd}`;
|
|
237
|
+
}
|
|
238
|
+
getSkeletonView() {
|
|
239
|
+
return (h(Host, { class: "s-basket-gap-entry" }, h("div", { class: "s-basket-gap-skeleton" }, h("salla-skeleton", { height: "16px", width: "40%", style: { marginBottom: '16px' } }), Array(3).fill(null).map((_, i) => (h("div", { key: i, class: "s-basket-gap-skeleton-card" }, h("salla-skeleton", { height: "64px", width: "64px", style: { borderRadius: '8px', flexShrink: '0' } }), h("div", { class: "s-basket-gap-skeleton-info" }, h("salla-skeleton", { height: "14px", width: "50%" }), h("salla-skeleton", { height: "12px", width: "25%", style: { marginTop: '6px' } }), h("salla-skeleton", { height: "10px", width: "35%", style: { marginTop: '4px' } })), h("salla-skeleton", { height: "36px", width: "100px", style: { borderRadius: '6px', flexShrink: '0', marginInlineStart: 'auto' } })))))));
|
|
240
|
+
}
|
|
241
|
+
getProductCard(product) {
|
|
242
|
+
const discountLabel = this.getDiscountLabel(product);
|
|
243
|
+
return (h("div", { key: product.id, class: "s-basket-gap-card" }, h("a", { href: product.url, class: "s-basket-gap-card-image" }, h("img", { class: "lazy", src: this.placeholder, "data-src": product.image?.url, alt: product.image?.alt || product.name })), h("div", { class: "s-basket-gap-card-info" }, h("h3", { class: "s-basket-gap-card-name" }, h("a", { href: product.url }, product.name)), product.is_on_sale
|
|
244
|
+
? h("div", { class: "s-basket-gap-card-sale-price" }, h("span", { innerHTML: salla.money(product.sale_price) }), h("del", { innerHTML: salla.money(product.regular_price) }))
|
|
245
|
+
: h("span", { class: "s-basket-gap-card-price", innerHTML: salla.money(product.price) }), product.weight_label && (h("span", { class: "s-basket-gap-card-weight" }, this.weightLabel, " ", product.weight_label))), (product.promotion_title || product.discount_ends || product.is_on_sale) && (h("div", { class: "s-basket-gap-card-offer" }, h("i", { class: "sicon-gift" }), discountLabel && h("span", null, discountLabel), product.discount_ends && [
|
|
246
|
+
h("salla-count-down", { date: this.formatDate(product.discount_ends), "end-of-day": true, digits: "en" }),
|
|
247
|
+
h("i", { class: "sicon-alarm" }),
|
|
248
|
+
])), h("salla-add-product-button", { class: "s-basket-gap-card-btn", "product-id": product.id, "product-status": product.status, "product-type": product.type }, this.addToCartLabel)));
|
|
249
|
+
}
|
|
250
|
+
render() {
|
|
251
|
+
if (!this.canRender)
|
|
252
|
+
return null;
|
|
253
|
+
if (this.isLoading)
|
|
254
|
+
return this.getSkeletonView();
|
|
255
|
+
if (!this.products.length)
|
|
256
|
+
return null;
|
|
257
|
+
return (h(Host, { class: "s-basket-gap-entry" }, this.title && h("h2", { class: "s-basket-gap-title" }, this.title), h("div", { class: "s-basket-gap-list" }, this.products.map(product => this.getProductCard(product)))));
|
|
258
|
+
}
|
|
259
|
+
static get is() { return "salla-basket-gap"; }
|
|
260
|
+
static get originalStyleUrls() {
|
|
261
|
+
return {
|
|
262
|
+
"$": ["salla-basket-gap.scss"]
|
|
263
|
+
};
|
|
264
|
+
}
|
|
265
|
+
static get styleUrls() {
|
|
266
|
+
return {
|
|
267
|
+
"$": ["salla-basket-gap.css"]
|
|
268
|
+
};
|
|
269
|
+
}
|
|
270
|
+
static get properties() {
|
|
271
|
+
return {
|
|
272
|
+
"limit": {
|
|
273
|
+
"type": "number",
|
|
274
|
+
"attribute": "limit",
|
|
275
|
+
"mutable": false,
|
|
276
|
+
"complexType": {
|
|
277
|
+
"original": "number",
|
|
278
|
+
"resolved": "number",
|
|
279
|
+
"references": {}
|
|
280
|
+
},
|
|
281
|
+
"required": false,
|
|
282
|
+
"optional": false,
|
|
283
|
+
"docs": {
|
|
284
|
+
"tags": [],
|
|
285
|
+
"text": "Maximum number of recommendations to fetch."
|
|
286
|
+
},
|
|
287
|
+
"getter": false,
|
|
288
|
+
"setter": false,
|
|
289
|
+
"reflect": false,
|
|
290
|
+
"defaultValue": "10"
|
|
291
|
+
}
|
|
292
|
+
};
|
|
293
|
+
}
|
|
294
|
+
static get states() {
|
|
295
|
+
return {
|
|
296
|
+
"products": {},
|
|
297
|
+
"isLoading": {},
|
|
298
|
+
"canRender": {},
|
|
299
|
+
"title": {},
|
|
300
|
+
"addToCartLabel": {},
|
|
301
|
+
"weightLabel": {},
|
|
302
|
+
"discountLabel": {}
|
|
303
|
+
};
|
|
304
|
+
}
|
|
305
|
+
static get elementRef() { return "host"; }
|
|
306
|
+
}
|
|
@@ -2,8 +2,7 @@
|
|
|
2
2
|
* Crafted with ❤ by Salla
|
|
3
3
|
*/
|
|
4
4
|
import { Host, h } from "@stencil/core";
|
|
5
|
-
|
|
6
|
-
const XSELL_API_KEY = 'VOL5WaZu2YROp0RplCZAr1RplhL9FFGQ';
|
|
5
|
+
import { fetchProductCustomersAlsoBought } from "../../shared/catalog-recommendations";
|
|
7
6
|
export class SallaBoughtTogether {
|
|
8
7
|
constructor() {
|
|
9
8
|
/**
|
|
@@ -39,25 +38,14 @@ export class SallaBoughtTogether {
|
|
|
39
38
|
return;
|
|
40
39
|
}
|
|
41
40
|
this.resolvedProductId = id;
|
|
42
|
-
return
|
|
43
|
-
requests: [{
|
|
44
|
-
indexName: 'products',
|
|
45
|
-
model: 'xsell-v1',
|
|
46
|
-
priceThreshold: 2,
|
|
47
|
-
objectID: String(id),
|
|
48
|
-
maxRecommendations: this.limit,
|
|
49
|
-
}]
|
|
50
|
-
}, 'post', { headers: { 'X-Algolia-Api-Key': XSELL_API_KEY, 'X-Query-Enrichment': 'false', 'X-source': 'store' } });
|
|
41
|
+
return fetchProductCustomersAlsoBought(String(id));
|
|
51
42
|
})
|
|
52
|
-
.then((
|
|
53
|
-
if (!
|
|
54
|
-
return;
|
|
55
|
-
const hits = response?.results?.[0]?.hits ?? [];
|
|
56
|
-
if (!hits.length) {
|
|
43
|
+
.then((recommendedIds) => {
|
|
44
|
+
if (!recommendedIds?.length) {
|
|
57
45
|
this.canRender = false;
|
|
58
46
|
return;
|
|
59
47
|
}
|
|
60
|
-
const ids = [String(this.resolvedProductId), ...
|
|
48
|
+
const ids = [String(this.resolvedProductId), ...recommendedIds.slice(0, this.limit)];
|
|
61
49
|
return salla.product.fetch({ source: 'selected', source_value: ids });
|
|
62
50
|
})
|
|
63
51
|
.then((response) => {
|
|
@@ -125,7 +125,8 @@ export class SallaCountDown {
|
|
|
125
125
|
return !isNaN(Date.parse(testedDate));
|
|
126
126
|
}
|
|
127
127
|
number(digit) {
|
|
128
|
-
|
|
128
|
+
const value = String(Math.max(0, Math.floor(digit))).padStart(2, '0');
|
|
129
|
+
return salla.helpers.number(value, this.digits === 'en');
|
|
129
130
|
}
|
|
130
131
|
startCountDown() {
|
|
131
132
|
const normalized = this.normalizeDate(this.date);
|
|
@@ -228,7 +229,7 @@ export class SallaCountDown {
|
|
|
228
229
|
return this.renderCountDown();
|
|
229
230
|
}
|
|
230
231
|
render() {
|
|
231
|
-
return (h(Host, { key: '
|
|
232
|
+
return (h(Host, { key: 'e2805e528a52b71ad71f4f1f16a473947dafb5bc', class: `s-count-down-wrapper ${this.preOrder && this.isValidDate(this.date) ? 's-count-down-pre-order' : ''} ${this.horizontal ? 's-count-down-horizontal' : ''} ${this.withButton ? 's-count-down-with-button' : ''} ${this.offerEnded ? 's-count-down-ended' : ''}` }, this.renderPrefixText(), this.renderContent(), this.offerEnded && this.renderOfferEnded(), this.renderButton()));
|
|
232
233
|
}
|
|
233
234
|
static get is() { return "salla-count-down"; }
|
|
234
235
|
static get originalStyleUrls() {
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* Crafted with ❤ by Salla
|
|
3
|
+
*/
|
|
4
|
+
const RECOMMENDATIONS_BASE_PATH = '/recommendations/v1';
|
|
5
|
+
const CART_BOUGHT_TOGETHER_MAX_PRODUCT_IDS = 5;
|
|
6
|
+
const CATALOG_RECOMMENDATIONS_API = 'https://api.salla.dev';
|
|
7
|
+
function getRecommendationsBaseUrl() {
|
|
8
|
+
const storeApi = String(salla.config.get('store.api', '') || '').replace(/\/$/, '');
|
|
9
|
+
if (storeApi.includes('api.salla.dev')) {
|
|
10
|
+
return storeApi;
|
|
11
|
+
}
|
|
12
|
+
// Recommendations proxy is on the global catalog API host (prod-only for now),
|
|
13
|
+
// not on beta preview /api/v1 paths that store.api may point to.
|
|
14
|
+
return CATALOG_RECOMMENDATIONS_API;
|
|
15
|
+
}
|
|
16
|
+
function getRecommendationsUrl(path) {
|
|
17
|
+
return `${getRecommendationsBaseUrl()}${RECOMMENDATIONS_BASE_PATH}${path}`;
|
|
18
|
+
}
|
|
19
|
+
function parseHostname(value) {
|
|
20
|
+
if (!value) {
|
|
21
|
+
return null;
|
|
22
|
+
}
|
|
23
|
+
try {
|
|
24
|
+
const normalized = value.startsWith('http') ? value : `https://${value}`;
|
|
25
|
+
return new URL(normalized).hostname || null;
|
|
26
|
+
}
|
|
27
|
+
catch {
|
|
28
|
+
const hostname = String(value).replace(/^https?:\/\//i, '').split('/')[0];
|
|
29
|
+
return hostname || null;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
function getStoreOriginHostname() {
|
|
33
|
+
const trackUrl = salla.config.get('jitsu.track_url');
|
|
34
|
+
const trackHostname = trackUrl ? parseHostname(String(trackUrl)) : null;
|
|
35
|
+
if (trackHostname) {
|
|
36
|
+
return trackHostname;
|
|
37
|
+
}
|
|
38
|
+
for (const candidate of [salla.config.get('store.domain'), salla.config.get('store.url')]) {
|
|
39
|
+
const hostname = candidate ? parseHostname(String(candidate)) : null;
|
|
40
|
+
if (hostname && !hostname.includes('beta.salla.group')) {
|
|
41
|
+
return hostname;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
return window.location.hostname;
|
|
45
|
+
}
|
|
46
|
+
function getRecommendationsRequestConfig(params) {
|
|
47
|
+
const headers = {
|
|
48
|
+
's-store-id': String(salla.config.get('store.id')),
|
|
49
|
+
origin: getStoreOriginHostname(),
|
|
50
|
+
's-source': 'store',
|
|
51
|
+
lang: salla.lang.getLocale(),
|
|
52
|
+
};
|
|
53
|
+
const scopeId = salla.api.getHeader('s-scope-id');
|
|
54
|
+
if (scopeId) {
|
|
55
|
+
headers['s-scope-id'] = String(scopeId);
|
|
56
|
+
}
|
|
57
|
+
return { params, headers };
|
|
58
|
+
}
|
|
59
|
+
function extractRecommendationIds(response) {
|
|
60
|
+
return (response?.data ?? [])
|
|
61
|
+
.map(item => item?.id)
|
|
62
|
+
.filter((id) => Boolean(id));
|
|
63
|
+
}
|
|
64
|
+
function fetchRecommendations(path, params) {
|
|
65
|
+
const url = getRecommendationsUrl(path);
|
|
66
|
+
const config = getRecommendationsRequestConfig(params);
|
|
67
|
+
// Recommendations are a non-critical, best-effort feature; suppress the global
|
|
68
|
+
// API error notifier so transient failures stay invisible and the consuming
|
|
69
|
+
// component can silently hide its section via its own .catch().
|
|
70
|
+
return salla.api.withoutNotifier(() => salla.api.request(url, config, 'get'))
|
|
71
|
+
.then((response) => extractRecommendationIds(response));
|
|
72
|
+
}
|
|
73
|
+
export function fetchCartBoughtTogether(productIds) {
|
|
74
|
+
const ids = productIds.slice(0, CART_BOUGHT_TOGETHER_MAX_PRODUCT_IDS);
|
|
75
|
+
if (!ids.length) {
|
|
76
|
+
return Promise.resolve([]);
|
|
77
|
+
}
|
|
78
|
+
return fetchRecommendations('/carts/bought-together', {
|
|
79
|
+
product_ids: ids.join(','),
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
export function fetchProductCustomersAlsoBought(productId) {
|
|
83
|
+
if (!productId) {
|
|
84
|
+
return Promise.resolve([]);
|
|
85
|
+
}
|
|
86
|
+
return fetchRecommendations('/products/customers-also-bought', {
|
|
87
|
+
product_id: productId,
|
|
88
|
+
});
|
|
89
|
+
}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* Crafted with ❤ by Salla
|
|
3
|
+
*/
|
|
4
|
+
const RECOMMENDATIONS_BASE_PATH = '/recommendations/v1';
|
|
5
|
+
const CART_BOUGHT_TOGETHER_MAX_PRODUCT_IDS = 5;
|
|
6
|
+
const CATALOG_RECOMMENDATIONS_API = 'https://api.salla.dev';
|
|
7
|
+
function getRecommendationsBaseUrl() {
|
|
8
|
+
const storeApi = String(salla.config.get('store.api', '') || '').replace(/\/$/, '');
|
|
9
|
+
if (storeApi.includes('api.salla.dev')) {
|
|
10
|
+
return storeApi;
|
|
11
|
+
}
|
|
12
|
+
// Recommendations proxy is on the global catalog API host (prod-only for now),
|
|
13
|
+
// not on beta preview /api/v1 paths that store.api may point to.
|
|
14
|
+
return CATALOG_RECOMMENDATIONS_API;
|
|
15
|
+
}
|
|
16
|
+
function getRecommendationsUrl(path) {
|
|
17
|
+
return `${getRecommendationsBaseUrl()}${RECOMMENDATIONS_BASE_PATH}${path}`;
|
|
18
|
+
}
|
|
19
|
+
function parseHostname(value) {
|
|
20
|
+
if (!value) {
|
|
21
|
+
return null;
|
|
22
|
+
}
|
|
23
|
+
try {
|
|
24
|
+
const normalized = value.startsWith('http') ? value : `https://${value}`;
|
|
25
|
+
return new URL(normalized).hostname || null;
|
|
26
|
+
}
|
|
27
|
+
catch {
|
|
28
|
+
const hostname = String(value).replace(/^https?:\/\//i, '').split('/')[0];
|
|
29
|
+
return hostname || null;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
function getStoreOriginHostname() {
|
|
33
|
+
const trackUrl = salla.config.get('jitsu.track_url');
|
|
34
|
+
const trackHostname = trackUrl ? parseHostname(String(trackUrl)) : null;
|
|
35
|
+
if (trackHostname) {
|
|
36
|
+
return trackHostname;
|
|
37
|
+
}
|
|
38
|
+
for (const candidate of [salla.config.get('store.domain'), salla.config.get('store.url')]) {
|
|
39
|
+
const hostname = candidate ? parseHostname(String(candidate)) : null;
|
|
40
|
+
if (hostname && !hostname.includes('beta.salla.group')) {
|
|
41
|
+
return hostname;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
return window.location.hostname;
|
|
45
|
+
}
|
|
46
|
+
function getRecommendationsRequestConfig(params) {
|
|
47
|
+
const headers = {
|
|
48
|
+
's-store-id': String(salla.config.get('store.id')),
|
|
49
|
+
origin: getStoreOriginHostname(),
|
|
50
|
+
's-source': 'store',
|
|
51
|
+
lang: salla.lang.getLocale(),
|
|
52
|
+
};
|
|
53
|
+
const scopeId = salla.api.getHeader('s-scope-id');
|
|
54
|
+
if (scopeId) {
|
|
55
|
+
headers['s-scope-id'] = String(scopeId);
|
|
56
|
+
}
|
|
57
|
+
return { params, headers };
|
|
58
|
+
}
|
|
59
|
+
function extractRecommendationIds(response) {
|
|
60
|
+
return (response?.data ?? [])
|
|
61
|
+
.map(item => item?.id)
|
|
62
|
+
.filter((id) => Boolean(id));
|
|
63
|
+
}
|
|
64
|
+
function fetchRecommendations(path, params) {
|
|
65
|
+
const url = getRecommendationsUrl(path);
|
|
66
|
+
const config = getRecommendationsRequestConfig(params);
|
|
67
|
+
// Recommendations are a non-critical, best-effort feature; suppress the global
|
|
68
|
+
// API error notifier so transient failures stay invisible and the consuming
|
|
69
|
+
// component can silently hide its section via its own .catch().
|
|
70
|
+
return salla.api.withoutNotifier(() => salla.api.request(url, config, 'get'))
|
|
71
|
+
.then((response) => extractRecommendationIds(response));
|
|
72
|
+
}
|
|
73
|
+
function fetchCartBoughtTogether(productIds) {
|
|
74
|
+
const ids = productIds.slice(0, CART_BOUGHT_TOGETHER_MAX_PRODUCT_IDS);
|
|
75
|
+
if (!ids.length) {
|
|
76
|
+
return Promise.resolve([]);
|
|
77
|
+
}
|
|
78
|
+
return fetchRecommendations('/carts/bought-together', {
|
|
79
|
+
product_ids: ids.join(','),
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
function fetchProductCustomersAlsoBought(productId) {
|
|
83
|
+
if (!productId) {
|
|
84
|
+
return Promise.resolve([]);
|
|
85
|
+
}
|
|
86
|
+
return fetchRecommendations('/products/customers-also-bought', {
|
|
87
|
+
product_id: productId,
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
export { fetchProductCustomersAlsoBought as a, fetchCartBoughtTogether as f };
|