@salla.sa/twilight-components 3.0.17 → 3.0.19
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/{Helper-DSYelC4c.js → Helper-DqKJCL8G.js} +1 -1
- package/dist/cjs/{filepond-l9D0Yv7b.js → filepond-Byu0lc8z.js} +1 -1
- package/dist/cjs/{filepond-plugin-file-poster-8SrbLptI.js → filepond-plugin-file-poster-qwx7lYZ-.js} +1 -1
- package/dist/cjs/{filepond-plugin-file-validate-size-DGD6oJy0.js → filepond-plugin-file-validate-size-C-n0P4TT.js} +1 -1
- package/dist/cjs/{filepond-plugin-file-validate-type-BIvrhp3w.js → filepond-plugin-file-validate-type-C8VOOXdT.js} +1 -1
- package/dist/cjs/{filepond-plugin-image-edit-4xKikdXG.js → filepond-plugin-image-edit-B9KG763Y.js} +1 -1
- package/dist/cjs/{filepond-plugin-image-exif-orientation-C3BvwxQh.js → filepond-plugin-image-exif-orientation-Czt4pYzU.js} +1 -1
- package/dist/cjs/{filepond-plugin-image-preview-CBq_GY0V.js → filepond-plugin-image-preview-BFm1Zl0o.js} +1 -1
- package/dist/cjs/free-shipping-timer-6QBe5BNS.js +156 -0
- package/dist/cjs/helpers-NV7wgP50.js +602 -0
- package/dist/cjs/{index-BAwxpXnB.js → index-CFW798jX.js} +2 -2
- package/dist/cjs/{intlTelInput-xw-HaAEN.js → intlTelInput-CLa2B89b.js} +1 -1
- 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 +2 -2
- package/dist/cjs/salla-add-product-button_5.cjs.entry.js +46 -3
- 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-applied-filters.cjs.entry.js +2 -2
- package/dist/cjs/salla-apps-icons.cjs.entry.js +1 -1
- package/dist/cjs/salla-attachment-view_9.cjs.entry.js +11 -11
- package/dist/cjs/salla-badge.cjs.entry.js +1 -1
- package/dist/cjs/salla-basket-gap.cjs.entry.js +1 -1
- package/dist/cjs/salla-bullet-delivery_3.cjs.entry.js +590 -134
- 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_9.cjs.entry.js +2 -2
- 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.cjs.entry.js +1 -1
- package/dist/cjs/salla-custom-fields.cjs.entry.js +1 -1
- package/dist/cjs/salla-delivery-promise.cjs.entry.js +2 -2
- package/dist/cjs/salla-edit-order-button.cjs.entry.js +1 -1
- package/dist/cjs/salla-filters-widget.cjs.entry.js +2 -2
- package/dist/cjs/salla-filters.cjs.entry.js +2 -2
- package/dist/cjs/salla-free-shipping-banner.cjs.entry.js +95 -9
- package/dist/cjs/salla-free-shipping-tag.cjs.entry.js +18 -5
- package/dist/cjs/salla-fulfillment-methods.cjs.entry.js +1 -1
- package/dist/cjs/salla-gift-card-redeem_2.cjs.entry.js +1 -1
- package/dist/cjs/salla-gifting.cjs.entry.js +13 -6
- package/dist/cjs/salla-hook.cjs.entry.js +1 -1
- package/dist/cjs/salla-infinite-scroll.cjs.entry.js +2 -2
- 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 +7 -2
- package/dist/cjs/salla-loyalty-banner_10.cjs.entry.js +1 -1
- package/dist/cjs/salla-loyalty-exchange-product-card.cjs.entry.js +1 -1
- 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.cjs.entry.js +1 -1
- package/dist/cjs/salla-maintenance-alert.cjs.entry.js +1 -1
- package/dist/cjs/salla-map_3.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_2.cjs.entry.js +2 -2
- 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-items.cjs.entry.js +1 -1
- package/dist/cjs/salla-order-options-modal.cjs.entry.js +1 -1
- package/dist/cjs/salla-order-payment.cjs.entry.js +1 -1
- package/dist/cjs/salla-order-rewards.cjs.entry.js +1 -1
- package/dist/cjs/salla-order-shipments.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 +2 -2
- 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.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 +13 -5
- package/dist/cjs/salla-products-slider.cjs.entry.js +2 -2
- package/dist/cjs/salla-quick-order.cjs.entry.js +1 -1
- package/dist/cjs/salla-rating-modal-v2.cjs.entry.js +7 -4
- package/dist/cjs/salla-rating-modal.cjs.entry.js +2 -2
- package/dist/cjs/salla-review-factors-tags.cjs.entry.js +1 -1
- package/dist/cjs/salla-review-order-item.cjs.entry.js +1 -1
- package/dist/cjs/salla-scopes.cjs.entry.js +1 -1
- package/dist/cjs/salla-search-product-card.cjs.entry.js +1 -1
- package/dist/cjs/salla-search.cjs.entry.js +2 -2
- package/dist/cjs/salla-skeleton.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-thank-you-header.cjs.entry.js +1 -1
- package/dist/cjs/salla-thank-you-page.cjs.entry.js +1 -1
- package/dist/cjs/salla-tiered-offer.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/salla-wishlist-summary.cjs.entry.js +2 -2
- package/dist/cjs/twilight.cjs.js +2 -2
- package/dist/cjs/{vanilla-picker-Cm_uNdps.js → vanilla-picker-Vx_7G7bs.js} +1 -1
- package/dist/collection/components/salla-bullet-delivery/api-service.js +156 -25
- package/dist/collection/components/salla-bullet-delivery/helpers.js +143 -15
- package/dist/collection/components/salla-bullet-delivery/icons.js +17 -0
- package/dist/collection/components/salla-bullet-delivery/salla-bullet-delivery.css +490 -52
- package/dist/collection/components/salla-bullet-delivery/salla-bullet-delivery.js +489 -106
- package/dist/collection/components/salla-bullet-delivery/selector-tracker.js +106 -0
- package/dist/collection/components/salla-free-shipping-banner/salla-free-shipping-banner.css +18 -4
- package/dist/collection/components/salla-free-shipping-banner/salla-free-shipping-banner.js +94 -11
- package/dist/collection/components/salla-free-shipping-tag/salla-free-shipping-tag.css +6 -0
- package/dist/collection/components/salla-free-shipping-tag/salla-free-shipping-tag.js +18 -2
- package/dist/collection/components/salla-gifting/salla-gifting.css +16 -1
- package/dist/collection/components/salla-gifting/salla-gifting.js +11 -4
- package/dist/collection/components/salla-login-modal/salla-login-modal.js +6 -1
- package/dist/collection/components/salla-products-list/salla-products-list.js +11 -3
- package/dist/collection/components/salla-quick-buy/salla-quick-buy.js +44 -1
- package/dist/collection/components/salla-rating-modal/salla-rating-modal-v2.js +5 -2
- package/dist/collection/shared/free-shipping-timer.js +130 -0
- package/dist/components/free-shipping-timer.js +150 -0
- package/dist/components/helpers.js +299 -40
- package/dist/components/index.js +2 -2
- package/dist/components/salla-bullet-delivery.js +595 -133
- package/dist/components/salla-free-shipping-banner.js +95 -8
- package/dist/components/salla-free-shipping-tag.js +17 -3
- package/dist/components/salla-gifting.js +12 -5
- package/dist/components/salla-login-modal2.js +6 -1
- package/dist/components/salla-products-list2.js +11 -3
- package/dist/components/salla-quick-buy2.js +44 -1
- package/dist/components/salla-rating-modal-v22.js +5 -2
- package/dist/docs.json +25 -5
- package/dist/esm/{Helper-POCi7J93.js → Helper-I0CAizv1.js} +1 -1
- package/dist/esm/{filepond-Ct76xW02.js → filepond-DTUYXV0J.js} +1 -1
- package/dist/esm/{filepond-plugin-file-poster-C1OkzGRs.js → filepond-plugin-file-poster-DydZjneT.js} +1 -1
- package/dist/esm/{filepond-plugin-file-validate-size-gdd-69cO.js → filepond-plugin-file-validate-size-nbsCU2t9.js} +1 -1
- package/dist/esm/{filepond-plugin-file-validate-type-BaZ2QTzl.js → filepond-plugin-file-validate-type-Cl5B_DIy.js} +1 -1
- package/dist/esm/{filepond-plugin-image-edit-CsoNvf0i.js → filepond-plugin-image-edit-bzskFyFR.js} +1 -1
- package/dist/esm/{filepond-plugin-image-exif-orientation-BHDSe3nH.js → filepond-plugin-image-exif-orientation-MBDuxLaX.js} +1 -1
- package/dist/esm/{filepond-plugin-image-preview-CD_S17z3.js → filepond-plugin-image-preview-N6wzEryW.js} +1 -1
- package/dist/esm/free-shipping-timer-CnTwkF6y.js +150 -0
- package/dist/esm/helpers-Cnh7Qptl.js +568 -0
- package/dist/esm/{index-DmGAR42j.js → index-C9zdeQFI.js} +2 -2
- package/dist/esm/{intlTelInput-D76Q4XFx.js → intlTelInput-B5L9nYtO.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 +2 -2
- package/dist/esm/salla-add-product-button_5.entry.js +46 -3
- 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-applied-filters.entry.js +2 -2
- package/dist/esm/salla-apps-icons.entry.js +1 -1
- package/dist/esm/salla-attachment-view_9.entry.js +11 -11
- package/dist/esm/salla-badge.entry.js +1 -1
- package/dist/esm/salla-basket-gap.entry.js +1 -1
- package/dist/esm/salla-bullet-delivery_3.entry.js +590 -134
- 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_9.entry.js +2 -2
- 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.entry.js +1 -1
- package/dist/esm/salla-custom-fields.entry.js +1 -1
- package/dist/esm/salla-delivery-promise.entry.js +2 -2
- package/dist/esm/salla-edit-order-button.entry.js +1 -1
- package/dist/esm/salla-filters-widget.entry.js +2 -2
- package/dist/esm/salla-filters.entry.js +2 -2
- package/dist/esm/salla-free-shipping-banner.entry.js +94 -8
- package/dist/esm/salla-free-shipping-tag.entry.js +17 -4
- package/dist/esm/salla-fulfillment-methods.entry.js +1 -1
- package/dist/esm/salla-gift-card-redeem_2.entry.js +1 -1
- package/dist/esm/salla-gifting.entry.js +13 -6
- package/dist/esm/salla-hook.entry.js +1 -1
- package/dist/esm/salla-infinite-scroll.entry.js +2 -2
- 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 +7 -2
- package/dist/esm/salla-loyalty-banner_10.entry.js +1 -1
- package/dist/esm/salla-loyalty-exchange-product-card.entry.js +1 -1
- 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.entry.js +1 -1
- package/dist/esm/salla-maintenance-alert.entry.js +1 -1
- package/dist/esm/salla-map_3.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_2.entry.js +2 -2
- 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-items.entry.js +1 -1
- package/dist/esm/salla-order-options-modal.entry.js +1 -1
- package/dist/esm/salla-order-payment.entry.js +1 -1
- package/dist/esm/salla-order-rewards.entry.js +1 -1
- package/dist/esm/salla-order-shipments.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 +2 -2
- 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.entry.js +1 -1
- package/dist/esm/salla-product-size-guide.entry.js +1 -1
- package/dist/esm/salla-products-list.entry.js +13 -5
- package/dist/esm/salla-products-slider.entry.js +2 -2
- package/dist/esm/salla-quick-order.entry.js +1 -1
- package/dist/esm/salla-rating-modal-v2.entry.js +7 -4
- package/dist/esm/salla-rating-modal.entry.js +2 -2
- package/dist/esm/salla-review-factors-tags.entry.js +1 -1
- package/dist/esm/salla-review-order-item.entry.js +1 -1
- package/dist/esm/salla-scopes.entry.js +1 -1
- package/dist/esm/salla-search-product-card.entry.js +1 -1
- package/dist/esm/salla-search.entry.js +2 -2
- package/dist/esm/salla-skeleton.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-thank-you-header.entry.js +1 -1
- package/dist/esm/salla-thank-you-page.entry.js +1 -1
- package/dist/esm/salla-tiered-offer.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/salla-wishlist-summary.entry.js +2 -2
- package/dist/esm/twilight.js +3 -3
- package/dist/esm/{vanilla-picker-BlIXJyvJ.js → vanilla-picker-CAeu4f87.js} +1 -1
- package/dist/twilight/{p-84d725d4.entry.js → p-01d5cd61.entry.js} +1 -1
- package/dist/twilight/{p-60f4357f.entry.js → p-0213fde4.entry.js} +1 -1
- package/dist/twilight/{p-8f0af317.entry.js → p-036fbfc0.entry.js} +1 -1
- package/dist/twilight/{p-90d4129f.entry.js → p-0add41ce.entry.js} +1 -1
- package/dist/twilight/{p-fed66bcb.entry.js → p-0b0d4942.entry.js} +1 -1
- package/dist/twilight/{p-86ca22d5.entry.js → p-17bcbf9b.entry.js} +1 -1
- package/dist/twilight/{p-b66df976.entry.js → p-1867f7d4.entry.js} +1 -1
- package/dist/twilight/p-194ff38c.entry.js +4 -0
- package/dist/twilight/{p-4057b692.entry.js → p-20f9c62f.entry.js} +1 -1
- package/dist/twilight/{p-783c6346.entry.js → p-252748d9.entry.js} +1 -1
- package/dist/twilight/{p-3d5e862c.entry.js → p-290ce0bc.entry.js} +1 -1
- package/dist/twilight/{p-d68625f7.entry.js → p-2b930157.entry.js} +1 -1
- package/dist/twilight/{p-184ea04c.entry.js → p-2e4e15c5.entry.js} +1 -1
- package/dist/twilight/p-2e6537a3.entry.js +4 -0
- package/dist/twilight/{p-2a3e2404.entry.js → p-30d64bd1.entry.js} +1 -1
- package/dist/twilight/{p-5d4fadd2.entry.js → p-32495dd2.entry.js} +1 -1
- package/dist/twilight/{p-cd7029fc.entry.js → p-32d9da31.entry.js} +1 -1
- package/dist/twilight/{p-7e854633.entry.js → p-32f100f8.entry.js} +1 -1
- package/dist/twilight/{p-dc3ff1f0.entry.js → p-386b3dcd.entry.js} +1 -1
- package/dist/twilight/{p-e8090773.entry.js → p-3a4e86d1.entry.js} +1 -1
- package/dist/twilight/{p-a0a57259.entry.js → p-3b766a79.entry.js} +1 -1
- package/dist/twilight/{p-a5d2ad5e.entry.js → p-3b7a45ec.entry.js} +1 -1
- package/dist/twilight/{p-33ff7967.entry.js → p-3bb0e184.entry.js} +1 -1
- package/dist/twilight/{p-8b39a9f7.entry.js → p-3cc6ca6c.entry.js} +1 -1
- package/dist/twilight/{p-0a794d6f.entry.js → p-4070f808.entry.js} +1 -1
- package/dist/twilight/{p-d2c1457e.entry.js → p-412fb721.entry.js} +1 -1
- package/dist/twilight/{p-fce39869.entry.js → p-427c13b6.entry.js} +1 -1
- package/dist/twilight/{p-49195cb6.entry.js → p-45e0a5d0.entry.js} +1 -1
- package/dist/twilight/{p-cd866be6.entry.js → p-4d615f9f.entry.js} +1 -1
- package/dist/twilight/{p-4f794057.entry.js → p-4d7fc363.entry.js} +1 -1
- package/dist/twilight/{p-9eb92980.entry.js → p-5009f654.entry.js} +1 -1
- package/dist/twilight/{p-f4411a04.entry.js → p-50853b76.entry.js} +1 -1
- package/dist/twilight/{p-b9695308.entry.js → p-550ad1a6.entry.js} +1 -1
- package/dist/twilight/{p-4839d408.entry.js → p-575014c4.entry.js} +1 -1
- package/dist/twilight/{p-f10b887a.entry.js → p-5aee5e44.entry.js} +1 -1
- package/dist/twilight/{p-622bfb21.entry.js → p-619c709c.entry.js} +1 -1
- package/dist/twilight/{p-74f206cf.entry.js → p-6d572fe0.entry.js} +1 -1
- package/dist/twilight/{p-26fec98c.entry.js → p-6f84c662.entry.js} +1 -1
- package/dist/twilight/{p-4a1aa85f.entry.js → p-703b9253.entry.js} +1 -1
- package/dist/twilight/{p-509ad773.entry.js → p-73dea22d.entry.js} +1 -1
- package/dist/twilight/{p-6c7cae8a.entry.js → p-74285af9.entry.js} +1 -1
- package/dist/twilight/{p-31260fae.entry.js → p-777d28f6.entry.js} +1 -1
- package/dist/twilight/{p-4702959a.entry.js → p-7db6ccfe.entry.js} +1 -1
- package/dist/twilight/{p-e89a1905.entry.js → p-7db8d545.entry.js} +1 -1
- package/dist/twilight/{p-0c6a024f.entry.js → p-7fa4d0b6.entry.js} +1 -1
- package/dist/twilight/{p-2e8f95d0.entry.js → p-825c5b73.entry.js} +1 -1
- package/dist/twilight/{p-e5545546.entry.js → p-8262e669.entry.js} +1 -1
- package/dist/twilight/{p-bab5d057.entry.js → p-86d55a6b.entry.js} +1 -1
- package/dist/twilight/{p-0225f396.entry.js → p-8712f7c7.entry.js} +1 -1
- package/dist/twilight/{p-a53e2c74.entry.js → p-8948b58c.entry.js} +1 -1
- package/dist/twilight/{p-37b68ef3.entry.js → p-8b8cf457.entry.js} +1 -1
- package/dist/twilight/{p-8e8e40bc.entry.js → p-8c2992e7.entry.js} +1 -1
- package/dist/twilight/{p-eb160c2e.entry.js → p-8c548259.entry.js} +1 -1
- package/dist/twilight/{p-5d775867.entry.js → p-8eb3fd92.entry.js} +1 -1
- package/dist/twilight/p-908716fb.entry.js +4 -0
- package/dist/twilight/{p-62ba0971.entry.js → p-90a59027.entry.js} +1 -1
- package/dist/twilight/{p-ae9c0abe.entry.js → p-9683535f.entry.js} +1 -1
- package/dist/twilight/{p-89cff0c8.entry.js → p-982e9124.entry.js} +1 -1
- package/dist/twilight/{p-a17784e6.entry.js → p-995b898f.entry.js} +1 -1
- package/dist/twilight/{p-3a3d4cb7.entry.js → p-99cb3dba.entry.js} +1 -1
- package/dist/twilight/{p-6757344a.entry.js → p-9a0218a6.entry.js} +1 -1
- package/dist/twilight/{p-7d337f25.entry.js → p-9cf31ff4.entry.js} +1 -1
- package/dist/twilight/{p-d495cce0.entry.js → p-9d1a5007.entry.js} +1 -1
- package/dist/twilight/{p-57b93850.entry.js → p-9e429047.entry.js} +1 -1
- package/dist/twilight/{p-40083f25.entry.js → p-9e542951.entry.js} +1 -1
- package/dist/twilight/{p-Dhq3oJAe.js → p-BcT9tEVW.js} +1 -1
- package/dist/twilight/{p-Dza6OBFg.js → p-Bgu5gtOF.js} +1 -1
- package/dist/twilight/p-C9zdeQFI.js +5 -0
- package/dist/twilight/{p-BbZqYBfp.js → p-CSGj1pY-.js} +1 -1
- package/dist/twilight/{p-Nyk6-1lq.js → p-CWWgpQ8Q.js} +1 -1
- package/dist/twilight/{p-BwzmoZpm.js → p-Cfz9xit3.js} +1 -1
- package/dist/twilight/{p-iCJI7qYe.js → p-CmYSalnM.js} +1 -1
- package/dist/twilight/p-CnTwkF6y.js +4 -0
- package/dist/twilight/p-Cnh7Qptl.js +4 -0
- package/dist/twilight/{p-DVWVl151.js → p-Dav_R_d2.js} +1 -1
- package/dist/twilight/{p-B7rn1taO.js → p-JGEddAgs.js} +1 -1
- package/dist/twilight/{p-CAc7tX2K.js → p-RflSBQNB.js} +1 -1
- package/dist/twilight/{p-De2wEjqS.js → p-Xgbueas7.js} +1 -1
- package/dist/twilight/{p-64d49f5d.entry.js → p-a070cce0.entry.js} +1 -1
- package/dist/twilight/p-a0bfedad.entry.js +4 -0
- package/dist/twilight/{p-bf29daf3.entry.js → p-a22d9931.entry.js} +1 -1
- package/dist/twilight/{p-2153c6fd.entry.js → p-a3959219.entry.js} +1 -1
- package/dist/twilight/p-a3ca61af.entry.js +4 -0
- package/dist/twilight/{p-0e1248c4.entry.js → p-a55b5c44.entry.js} +1 -1
- package/dist/twilight/{p-24423a8d.entry.js → p-a5fc8358.entry.js} +1 -1
- package/dist/twilight/{p-66f6d722.entry.js → p-aabcd09f.entry.js} +1 -1
- package/dist/twilight/{p-4c801f91.entry.js → p-ad00021e.entry.js} +1 -1
- package/dist/twilight/{p-fae2a8d0.entry.js → p-ade9a68c.entry.js} +1 -1
- package/dist/twilight/{p-83ccad19.entry.js → p-b5e0065a.entry.js} +1 -1
- package/dist/twilight/{p-2a8d6e7e.entry.js → p-bbb09d92.entry.js} +1 -1
- package/dist/twilight/{p-f034968b.entry.js → p-c2df20f8.entry.js} +1 -1
- package/dist/twilight/{p-b38c38fe.entry.js → p-c4274188.entry.js} +1 -1
- package/dist/twilight/{p-d63ce284.entry.js → p-c5e2c781.entry.js} +1 -1
- package/dist/twilight/{p-07450aed.entry.js → p-c64b2b22.entry.js} +1 -1
- package/dist/twilight/{p-14752d03.entry.js → p-c92cc92f.entry.js} +1 -1
- package/dist/twilight/{p-d6c5bf2a.entry.js → p-cb54adac.entry.js} +1 -1
- package/dist/twilight/{p-7750bace.entry.js → p-ce1e45a3.entry.js} +1 -1
- package/dist/twilight/{p-e4d90663.entry.js → p-d0acd7ff.entry.js} +1 -1
- package/dist/twilight/{p-f9b9af72.entry.js → p-d0f903ac.entry.js} +1 -1
- package/dist/twilight/{p-7df4ee74.entry.js → p-d57b49ff.entry.js} +1 -1
- package/dist/twilight/p-db3efb27.entry.js +4 -0
- package/dist/twilight/{p-e81c4521.entry.js → p-db73d0bf.entry.js} +1 -1
- package/dist/twilight/{p-bfb70998.entry.js → p-e20d5e75.entry.js} +1 -1
- package/dist/twilight/{p-1982520c.entry.js → p-e223beca.entry.js} +1 -1
- package/dist/twilight/{p-20939237.entry.js → p-e37da59f.entry.js} +1 -1
- package/dist/twilight/p-e3991836.entry.js +4 -0
- package/dist/twilight/{p-fe413496.entry.js → p-e455709f.entry.js} +1 -1
- package/dist/twilight/{p-cc2c52bb.entry.js → p-e921b2d1.entry.js} +1 -1
- package/dist/twilight/{p-acd48ae7.entry.js → p-ec356e5a.entry.js} +1 -1
- package/dist/twilight/{p-7a985c8c.entry.js → p-eeefc285.entry.js} +1 -1
- package/dist/twilight/{p-120b4694.entry.js → p-f3b12754.entry.js} +1 -1
- package/dist/twilight/{p-c3c99d9e.entry.js → p-f6279a13.entry.js} +1 -1
- package/dist/twilight/{p-b819de23.entry.js → p-f83efc62.entry.js} +1 -1
- package/dist/twilight/{p-8b43035f.entry.js → p-fa622715.entry.js} +1 -1
- package/dist/twilight/{p-b87ea253.entry.js → p-faf00404.entry.js} +1 -1
- package/dist/twilight/twilight.esm.js +1 -1
- package/dist/types/components/salla-bullet-delivery/api-service.d.ts +23 -7
- package/dist/types/components/salla-bullet-delivery/helpers.d.ts +61 -6
- package/dist/types/components/salla-bullet-delivery/icons.d.ts +14 -0
- package/dist/types/components/salla-bullet-delivery/interfaces.d.ts +36 -1
- package/dist/types/components/salla-bullet-delivery/salla-bullet-delivery.d.ts +82 -3
- package/dist/types/components/salla-bullet-delivery/selector-tracker.d.ts +30 -0
- package/dist/types/components/salla-free-shipping-banner/salla-free-shipping-banner.d.ts +19 -5
- package/dist/types/components/salla-free-shipping-tag/salla-free-shipping-tag.d.ts +6 -1
- package/dist/types/components/salla-gifting/salla-gifting.d.ts +1 -0
- package/dist/types/components/salla-quick-buy/salla-quick-buy.d.ts +6 -0
- package/dist/types/components/salla-rating-modal/salla-rating-modal-v2.d.ts +1 -0
- package/dist/types/components.d.ts +11 -25
- package/dist/types/shared/free-shipping-timer.d.ts +36 -0
- package/package.json +5 -5
- package/dist/cjs/free-shipping-DkIKD6ch.js +0 -31
- package/dist/cjs/helpers-8bMfm_mm.js +0 -329
- package/dist/components/free-shipping.js +0 -29
- package/dist/esm/free-shipping-Brg4wsgg.js +0 -29
- package/dist/esm/helpers-DqzaeXrL.js +0 -309
- package/dist/twilight/p-12a8aed8.entry.js +0 -4
- package/dist/twilight/p-4f443e36.entry.js +0 -4
- package/dist/twilight/p-5b81a3d9.entry.js +0 -4
- package/dist/twilight/p-93f26336.entry.js +0 -4
- package/dist/twilight/p-Brg4wsgg.js +0 -4
- package/dist/twilight/p-DmGAR42j.js +0 -5
- package/dist/twilight/p-DqzaeXrL.js +0 -4
- package/dist/twilight/p-c7c868b4.entry.js +0 -4
- package/dist/twilight/p-d5a2ba68.entry.js +0 -4
- package/dist/twilight/p-f8ff074f.entry.js +0 -4
|
@@ -2,21 +2,32 @@
|
|
|
2
2
|
* Crafted with ❤ by Salla
|
|
3
3
|
*/
|
|
4
4
|
import { h, Host, } from "@stencil/core";
|
|
5
|
-
import { bulletDeliveryAPI, clearApiCache, isSaudiArabia } from "./api-service";
|
|
6
|
-
import {
|
|
5
|
+
import { bulletDeliveryAPI, CACHE_TTL, clearApiCache, clearBranchCache, isSaudiArabia } from "./api-service";
|
|
6
|
+
import { SelectorTracker, allocatedBranchIds, toCloseReason, } from "./selector-tracker";
|
|
7
|
+
import { filterBranches, findNearestBranch, formatBranchClockTime, formatBranchDistance, getBranchWeekSchedule, getBranchCities, getBranchDirectionsHref, getBranchDiscount, getBranchDiscountRange, getBranchPhoneHref, getBranchReadinessLabel, getBranchReadyTodayTime, getBranchWhatsappHref, getIntentBranchId, getIntentCityId, getIntentCountryCode, getIntentCountryId, getIntentDistrictId, getIntentRegionId, getIntentSubtitle, groupBranchSchedule, hasSessionAddressIntent, isMapOriginIntent, isBranchAlwaysOpen, isBranchBusy, isBranchSelectable, isBranchVisible, requireRegionAndDistrictForSA, } from "./helpers";
|
|
7
8
|
/* Location permission notice */
|
|
8
9
|
import { isLocationPermissionMissing, LocationPermissionNotice, requestLocationPermission, watchLocationPermission, } from "./location-permission-notice";
|
|
9
10
|
import { calculateLocationDistanceKm, LocationDistanceWarning, } from "./location-distance-warning";
|
|
10
11
|
const BRANCH_SEARCH_DEBOUNCE_MS = 1000;
|
|
12
|
+
/** Shorter queries are filtered locally; the branches API ignores them. */
|
|
13
|
+
const BRANCH_SEARCH_MIN_LENGTH = 2;
|
|
11
14
|
const GEOLOCATION_TIMEOUT = 10000;
|
|
15
|
+
/** GeolocationPositionError.PERMISSION_DENIED — inlined; the class is absent on the server. */
|
|
16
|
+
const GEO_PERMISSION_DENIED = 1;
|
|
17
|
+
/** Silent read for branch distances: a short wait, and a recent cached fix is good enough. */
|
|
18
|
+
const SILENT_GEOLOCATION_TIMEOUT = 5000;
|
|
19
|
+
const SILENT_GEOLOCATION_MAX_AGE = 10 * 60 * 1000;
|
|
20
|
+
/** Longest the branch list waits for that read; a later fix still serves the next list request. */
|
|
21
|
+
const BRANCH_LIST_LOCATION_WAIT = 1500;
|
|
22
|
+
/** Matches the `per_page` default of `bulletDeliveryAPI.getBranches`. */
|
|
23
|
+
const BRANCH_PAGE_SIZE = 20;
|
|
12
24
|
/** Final fallback center used only if `user.default_geo_location` is absent (Riyadh — matches checkout map-page). */
|
|
13
25
|
const DEFAULT_MAP_CENTER = { lat: 24.7756042, lng: 46.7360729 };
|
|
14
26
|
import GetDirections from "../../assets/svg/get-directions.svg";
|
|
15
|
-
import GPS from "../../assets/svg/gps.svg";
|
|
16
27
|
import Location from "../../assets/svg/location.svg";
|
|
17
28
|
import MiniMap from "../../assets/svg/mini-map.svg";
|
|
18
29
|
import Search from "../../assets/svg/search.svg";
|
|
19
|
-
import
|
|
30
|
+
import { BranchLocationIcon, LightningIcon, NotesIcon, PickupAvailabilityIcon, WorkingHoursIcon } from "./icons";
|
|
20
31
|
const DEBUG_KEY = 'salla-bullet-delivery-debug';
|
|
21
32
|
const OVERRIDE_IP_KEY = 'salla-bullet-delivery-override-ip';
|
|
22
33
|
function log(message, data) {
|
|
@@ -32,6 +43,8 @@ export class SallaBulletDelivery {
|
|
|
32
43
|
this.pendingCartSubmitResolver = null;
|
|
33
44
|
this.pendingCartSubmitPromise = null;
|
|
34
45
|
this.cartSubmitConfirmationPending = false;
|
|
46
|
+
/** Query the current branch list was searched with server-side; its results are not re-filtered locally. */
|
|
47
|
+
this.branchesServerQuery = '';
|
|
35
48
|
this.branchSearchDebounceTimer = null;
|
|
36
49
|
this.countrySearchTimer = null;
|
|
37
50
|
this.regionSearchTimer = null;
|
|
@@ -63,6 +76,13 @@ export class SallaBulletDelivery {
|
|
|
63
76
|
this.open();
|
|
64
77
|
};
|
|
65
78
|
this.closeHandler = null;
|
|
79
|
+
this.selectorTracker = new SelectorTracker();
|
|
80
|
+
this.openTrigger = "customer_requested";
|
|
81
|
+
this.pendingDismissReason = null;
|
|
82
|
+
this.modalCloseHandler = (detail) => {
|
|
83
|
+
this.pendingDismissReason = toCloseReason(detail?.reason);
|
|
84
|
+
queueMicrotask(() => (this.pendingDismissReason = null));
|
|
85
|
+
};
|
|
66
86
|
this.bulletDeliveryMobileSelectHandler = null;
|
|
67
87
|
/** True after saved addresses have been loaded (lazy: only when address tab is shown). */
|
|
68
88
|
this.savedAddressesLoaded = false;
|
|
@@ -72,6 +92,8 @@ export class SallaBulletDelivery {
|
|
|
72
92
|
/** Identifies the latest reverse-geocode call so a resolved-but-superseded callback (same
|
|
73
93
|
* coordinates re-picked, or the map left) can be told apart from the current one. */
|
|
74
94
|
this.geocodeRequestId = 0;
|
|
95
|
+
/** Identifies the latest pickup-offer fetch so one from an earlier modal open is dropped. */
|
|
96
|
+
this.pickupDiscountRequestId = 0;
|
|
75
97
|
// Core state
|
|
76
98
|
this.activeTab = "address";
|
|
77
99
|
this.isLoggedIn = false;
|
|
@@ -94,9 +116,27 @@ export class SallaBulletDelivery {
|
|
|
94
116
|
this.selectedSessionAddress = false;
|
|
95
117
|
// Pickup state
|
|
96
118
|
this.branches = [];
|
|
119
|
+
/** Pickup offer range across the store's branches (INV-1416); null shows the default tab badge. */
|
|
120
|
+
this.pickupDiscountRange = null;
|
|
121
|
+
/** False until the offer lookup settles, so the tab never flashes the default badge before an offer. */
|
|
122
|
+
this.pickupDiscountResolved = false;
|
|
97
123
|
this.filteredBranches = [];
|
|
98
124
|
this.selectedBranch = null;
|
|
99
125
|
this.branchSearchQuery = "";
|
|
126
|
+
/** Cities that have branches in the selected country (from the unfiltered branch list). */
|
|
127
|
+
this.branchCities = [];
|
|
128
|
+
this.selectedBranchCity = null;
|
|
129
|
+
this.branchCitySearchQuery = '';
|
|
130
|
+
/** Branch whose weekly hours are expanded behind the chevron (one at a time). */
|
|
131
|
+
this.expandedScheduleBranchId = null;
|
|
132
|
+
/** Shopper's device location for branch distances (see getGrantedDeviceLocation). */
|
|
133
|
+
this.shopperLocation = null;
|
|
134
|
+
this.shopperLocationRequestId = 0;
|
|
135
|
+
this.nearestBranchRequestId = 0;
|
|
136
|
+
/** Bumped per branch-list request; overlapping city/search loads only apply the latest one. */
|
|
137
|
+
this.branchesRequestId = 0;
|
|
138
|
+
/** Shared country rows and city options expire with the API cache. */
|
|
139
|
+
this.allBranchCities = null;
|
|
100
140
|
// Loading states
|
|
101
141
|
this.loadingCountries = false;
|
|
102
142
|
this.loadingCities = false;
|
|
@@ -215,6 +255,13 @@ export class SallaBulletDelivery {
|
|
|
215
255
|
this.displayedDistricts = this.districts;
|
|
216
256
|
this.searchingDistricts = false;
|
|
217
257
|
};
|
|
258
|
+
this.handleBranchCitySelected = (item) => {
|
|
259
|
+
this.selectedBranchCity = item && item.id !== -1
|
|
260
|
+
? (this.branchCities.find((c) => String(c.id) === String(item.id)) ?? item)
|
|
261
|
+
: null;
|
|
262
|
+
this.selectedBranch = null;
|
|
263
|
+
void this.loadBranches();
|
|
264
|
+
};
|
|
218
265
|
this.handleMapLocationChanged = (event) => {
|
|
219
266
|
const detail = event.detail;
|
|
220
267
|
if (!detail?.position?.lat || !detail?.position?.lng)
|
|
@@ -329,6 +376,7 @@ export class SallaBulletDelivery {
|
|
|
329
376
|
const details = this.buildIntentAddress();
|
|
330
377
|
if (!details)
|
|
331
378
|
return;
|
|
379
|
+
const previousIntent = this.getStoredIntent();
|
|
332
380
|
this.setStoredIntent({
|
|
333
381
|
type: "address",
|
|
334
382
|
country_id: Number(this.selectedCountry?.id) || 0,
|
|
@@ -337,7 +385,7 @@ export class SallaBulletDelivery {
|
|
|
337
385
|
});
|
|
338
386
|
this.selectedSavedAddress = null;
|
|
339
387
|
this.selectedSessionAddress = true;
|
|
340
|
-
await this.handleConfirm();
|
|
388
|
+
await this.handleConfirm(previousIntent);
|
|
341
389
|
};
|
|
342
390
|
this.handleCountrySelected = (item) => {
|
|
343
391
|
const country = this.countries.find(c => String(c.id) === String(item.id)) || item;
|
|
@@ -422,9 +470,10 @@ export class SallaBulletDelivery {
|
|
|
422
470
|
* successful auto-confirm never flashes the saved-addresses list; the caller is
|
|
423
471
|
* responsible for revealing the modal itself if it still needs the customer's input.
|
|
424
472
|
*/
|
|
425
|
-
async open(silent = false) {
|
|
473
|
+
async open(silent = false, trigger = "customer_requested") {
|
|
426
474
|
if (!this.isEnabled)
|
|
427
475
|
return; // feature disabled — never open
|
|
476
|
+
this.openTrigger = trigger;
|
|
428
477
|
// If mobile app, open the sheet
|
|
429
478
|
if (this.isMobileApp) {
|
|
430
479
|
Salla.event.dispatch('salla::bullet-delivery.open-sheet');
|
|
@@ -437,6 +486,7 @@ export class SallaBulletDelivery {
|
|
|
437
486
|
}
|
|
438
487
|
// Reset state before opening
|
|
439
488
|
this.resetState();
|
|
489
|
+
void this.loadPickupDiscountRange();
|
|
440
490
|
if (!silent) {
|
|
441
491
|
// Open modal immediately — fields render right away with inline loading
|
|
442
492
|
this.modal.open();
|
|
@@ -488,20 +538,18 @@ export class SallaBulletDelivery {
|
|
|
488
538
|
}
|
|
489
539
|
}
|
|
490
540
|
// Load branches only when branch tab is active (lazy tab data)
|
|
491
|
-
// Use lat/lng from session storage if available for more accurate results
|
|
492
541
|
if (this.activeTab === "branch") {
|
|
493
|
-
const
|
|
494
|
-
const
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
else {
|
|
499
|
-
await this.loadBranches();
|
|
500
|
-
}
|
|
542
|
+
const loading = this.loadBranches();
|
|
543
|
+
const request = this.branchesRequestId;
|
|
544
|
+
await loading;
|
|
545
|
+
if (request !== this.branchesRequestId || this.activeTab !== 'branch' || this.branchSearchQuery.trim())
|
|
546
|
+
return;
|
|
501
547
|
// Auto-select preselected branch if provided
|
|
502
548
|
if (this.preselectedBranchId) {
|
|
503
|
-
this.preselectBranch(this.preselectedBranchId);
|
|
549
|
+
await this.preselectBranch(this.preselectedBranchId);
|
|
504
550
|
}
|
|
551
|
+
if (request !== this.branchesRequestId || this.activeTab !== 'branch' || this.branchSearchQuery.trim())
|
|
552
|
+
return;
|
|
505
553
|
}
|
|
506
554
|
// Prefill form data from session storage
|
|
507
555
|
await this.prefillFromSessionStorage();
|
|
@@ -526,7 +574,45 @@ export class SallaBulletDelivery {
|
|
|
526
574
|
this.bulletDeliveryClosed.emit();
|
|
527
575
|
return this.modal?.close();
|
|
528
576
|
}
|
|
577
|
+
selectorContext() {
|
|
578
|
+
return {
|
|
579
|
+
configured_required: this.isRequired,
|
|
580
|
+
effective_nonclosable: this.isRequired || this.shouldForceNonClosable(),
|
|
581
|
+
trigger_configured: this.openingType ?? null,
|
|
582
|
+
trigger_actual: this.openTrigger,
|
|
583
|
+
};
|
|
584
|
+
}
|
|
585
|
+
handleModalVisibility(visible) {
|
|
586
|
+
if (visible) {
|
|
587
|
+
this.selectorTracker.viewed(this.selectorContext());
|
|
588
|
+
return;
|
|
589
|
+
}
|
|
590
|
+
if (!this.pendingDismissReason)
|
|
591
|
+
return;
|
|
592
|
+
this.selectorTracker.dismissed(this.selectorContext(), this.pendingDismissReason, !!this.getStoredIntent()?.scope_allocated);
|
|
593
|
+
this.pendingDismissReason = null;
|
|
594
|
+
}
|
|
595
|
+
trackSelectorResult(outcome, previousIntent, newBranchIds, scopeId) {
|
|
596
|
+
this.selectorTracker.result(this.selectorContext(), {
|
|
597
|
+
outcome,
|
|
598
|
+
fulfilment_method: this.activeTab === "branch" ? "pickup" : "delivery",
|
|
599
|
+
previous_branch_ids: previousIntent?.scope_allocated ? allocatedBranchIds(previousIntent) : [],
|
|
600
|
+
new_branch_ids: newBranchIds,
|
|
601
|
+
scope_id: scopeId ?? null,
|
|
602
|
+
});
|
|
603
|
+
}
|
|
529
604
|
resetState() {
|
|
605
|
+
clearBranchCache();
|
|
606
|
+
this.allBranchCities = null;
|
|
607
|
+
this.pickupDiscountRequestId++;
|
|
608
|
+
if (this.branchSearchDebounceTimer)
|
|
609
|
+
clearTimeout(this.branchSearchDebounceTimer);
|
|
610
|
+
++this.branchesRequestId;
|
|
611
|
+
this.loadingBranches = false;
|
|
612
|
+
++this.shopperLocationRequestId;
|
|
613
|
+
++this.nearestBranchRequestId;
|
|
614
|
+
this.loadingNearestBranch = false;
|
|
615
|
+
this.shopperLocation = null;
|
|
530
616
|
this.viewMode = "main";
|
|
531
617
|
this.mapLocationData = null;
|
|
532
618
|
this.mapCountryCode = null;
|
|
@@ -543,11 +629,16 @@ export class SallaBulletDelivery {
|
|
|
543
629
|
this.selectedSessionAddress = false;
|
|
544
630
|
this.selectedBranch = null;
|
|
545
631
|
this.branchSearchQuery = "";
|
|
632
|
+
this.branchCities = [];
|
|
633
|
+
this.selectedBranchCity = null;
|
|
634
|
+
this.expandedScheduleBranchId = null;
|
|
546
635
|
this.regions = [];
|
|
547
636
|
this.cities = [];
|
|
548
637
|
this.districts = [];
|
|
549
638
|
this.branches = [];
|
|
550
639
|
this.filteredBranches = [];
|
|
640
|
+
this.pickupDiscountRange = null;
|
|
641
|
+
this.pickupDiscountResolved = false;
|
|
551
642
|
this.newAddressForm = { ...SallaBulletDelivery.INITIAL_ADDRESS_FORM };
|
|
552
643
|
this.showCartWillBeClearedBanner = false;
|
|
553
644
|
this.allocationOutOfCoverageMessage = null;
|
|
@@ -665,7 +756,7 @@ export class SallaBulletDelivery {
|
|
|
665
756
|
if (!wasVisible) {
|
|
666
757
|
// Load silently — a successful auto-confirm should never flash the
|
|
667
758
|
// saved-addresses list; only reveal the modal below if it can't finish on its own.
|
|
668
|
-
await this.open(true);
|
|
759
|
+
await this.open(true, "after_login");
|
|
669
760
|
}
|
|
670
761
|
// open() -> loadSavedAddresses() already sets selectedSessionAddress when a
|
|
671
762
|
// session intent exists; bail if that didn't happen (e.g. address_id already set).
|
|
@@ -951,16 +1042,63 @@ export class SallaBulletDelivery {
|
|
|
951
1042
|
});
|
|
952
1043
|
}
|
|
953
1044
|
async loadBranches() {
|
|
1045
|
+
const request = ++this.branchesRequestId;
|
|
1046
|
+
// A city change keeps the active search, so the server filters before picking the first page.
|
|
1047
|
+
const query = this.branchSearchQuery.trim();
|
|
954
1048
|
this.loadingBranches = true;
|
|
955
1049
|
try {
|
|
956
|
-
|
|
1050
|
+
const branches = await bulletDeliveryAPI.getBranches({
|
|
957
1051
|
country_id: this.selectedCountry?.id,
|
|
958
|
-
|
|
1052
|
+
city_id: this.selectedBranchCity?.id,
|
|
1053
|
+
query,
|
|
1054
|
+
...(await this.getListLocation()),
|
|
1055
|
+
});
|
|
1056
|
+
if (request !== this.branchesRequestId)
|
|
1057
|
+
return;
|
|
1058
|
+
this.branchesServerQuery = query.length >= BRANCH_SEARCH_MIN_LENGTH ? query : '';
|
|
1059
|
+
this.applyLoadedBranches(branches);
|
|
1060
|
+
// Search results hold only the matching branches, which would shrink the city options.
|
|
1061
|
+
if (query.length < BRANCH_SEARCH_MIN_LENGTH)
|
|
1062
|
+
void this.refreshBranchCities();
|
|
959
1063
|
}
|
|
960
1064
|
finally {
|
|
961
|
-
this.
|
|
1065
|
+
if (request === this.branchesRequestId)
|
|
1066
|
+
this.loadingBranches = false;
|
|
962
1067
|
}
|
|
963
1068
|
}
|
|
1069
|
+
/** Reuse the country's city collection while keeping visible choices usable during loading. */
|
|
1070
|
+
refreshBranchCities() {
|
|
1071
|
+
if (!this.selectedBranchCity)
|
|
1072
|
+
this.branchCities = getBranchCities(this.branches);
|
|
1073
|
+
const countryId = this.selectedCountry?.id;
|
|
1074
|
+
if (!this.allBranchCities || this.allBranchCities.countryId !== countryId || Date.now() - this.allBranchCities.timestamp > CACHE_TTL) {
|
|
1075
|
+
const branches = bulletDeliveryAPI.getAllBranches(countryId, BRANCH_PAGE_SIZE);
|
|
1076
|
+
this.allBranchCities = {
|
|
1077
|
+
countryId,
|
|
1078
|
+
timestamp: Date.now(),
|
|
1079
|
+
branches,
|
|
1080
|
+
cities: branches.then((all) => getBranchCities(all)),
|
|
1081
|
+
};
|
|
1082
|
+
}
|
|
1083
|
+
const pending = this.allBranchCities;
|
|
1084
|
+
return pending.cities.then((cities) => {
|
|
1085
|
+
if (this.allBranchCities !== pending || this.selectedCountry?.id !== countryId)
|
|
1086
|
+
return;
|
|
1087
|
+
if (!cities.length) {
|
|
1088
|
+
this.allBranchCities = null;
|
|
1089
|
+
return;
|
|
1090
|
+
}
|
|
1091
|
+
this.branchCities = cities;
|
|
1092
|
+
}).catch((error) => {
|
|
1093
|
+
if (this.allBranchCities === pending) {
|
|
1094
|
+
this.allBranchCities = null;
|
|
1095
|
+
if (this.selectedCountry?.id === countryId && Array.isArray(error?.branches)) {
|
|
1096
|
+
this.branchCities = getBranchCities([...this.branches, ...error.branches]);
|
|
1097
|
+
}
|
|
1098
|
+
}
|
|
1099
|
+
console.error('[BulletDelivery] Error fetching branch cities', error);
|
|
1100
|
+
});
|
|
1101
|
+
}
|
|
964
1102
|
/**
|
|
965
1103
|
* Store a freshly fetched branch list and reconcile the current selection with it.
|
|
966
1104
|
* `selectedBranch` is a snapshot from selection time: when the refreshed list carries the
|
|
@@ -977,8 +1115,33 @@ export class SallaBulletDelivery {
|
|
|
977
1115
|
}
|
|
978
1116
|
this.filterBranches();
|
|
979
1117
|
}
|
|
1118
|
+
/** Shares a fresh branch collection with the picker on each modal open. */
|
|
1119
|
+
async loadPickupDiscountRange() {
|
|
1120
|
+
if (!this.supportsPickup)
|
|
1121
|
+
return;
|
|
1122
|
+
const requestId = ++this.pickupDiscountRequestId;
|
|
1123
|
+
const { branches, complete } = await bulletDeliveryAPI.getBranchCollection(undefined, 60, { requireComplete: true });
|
|
1124
|
+
if (requestId !== this.pickupDiscountRequestId)
|
|
1125
|
+
return;
|
|
1126
|
+
this.pickupDiscountRange = complete ? getBranchDiscountRange(branches) : null;
|
|
1127
|
+
this.pickupDiscountResolved = true;
|
|
1128
|
+
}
|
|
1129
|
+
/**
|
|
1130
|
+
* ar: "خصم 25%" / "خصم 5 – 25%" / "خصم 10 ر.س"; en: "25% discount" / "5 – 25% discount" / "10 SAR discount".
|
|
1131
|
+
* Money may carry the riyal-symbol SVG, so it renders as HTML.
|
|
1132
|
+
*/
|
|
1133
|
+
getPickupDiscountLabel(type, min, max = min) {
|
|
1134
|
+
const format = (amount) => type === 'percentage' ? String(Math.round(amount * 100) / 100) : salla.money(amount);
|
|
1135
|
+
const value = min === max ? format(min) : `${format(min)} – ${format(max)}`;
|
|
1136
|
+
const amount = type === 'percentage' ? `${value}%` : `${value} `;
|
|
1137
|
+
const fallback = this.isArabic ? `خصم ${amount}` : ` ${amount} discount`;
|
|
1138
|
+
return Salla.lang.getWithDefault('pages.checkout.pickup_discount', fallback, { amount });
|
|
1139
|
+
}
|
|
980
1140
|
filterBranches() {
|
|
981
|
-
|
|
1141
|
+
const query = this.branchSearchQuery.trim();
|
|
1142
|
+
this.filteredBranches = query && query === this.branchesServerQuery
|
|
1143
|
+
? this.branches
|
|
1144
|
+
: filterBranches(this.branches, query);
|
|
982
1145
|
}
|
|
983
1146
|
/**
|
|
984
1147
|
* Prefill form fields from session storage
|
|
@@ -1003,7 +1166,7 @@ export class SallaBulletDelivery {
|
|
|
1003
1166
|
if (country) {
|
|
1004
1167
|
this.selectedCountry = country;
|
|
1005
1168
|
this.updateNewAddressForm({ country_id: Number(country.id) });
|
|
1006
|
-
this.preselectBranch(getIntentBranchId(intent));
|
|
1169
|
+
await this.preselectBranch(getIntentBranchId(intent));
|
|
1007
1170
|
}
|
|
1008
1171
|
}
|
|
1009
1172
|
}
|
|
@@ -1042,7 +1205,16 @@ export class SallaBulletDelivery {
|
|
|
1042
1205
|
}
|
|
1043
1206
|
}
|
|
1044
1207
|
applyCountryChange(newCountry) {
|
|
1208
|
+
++this.branchesRequestId;
|
|
1209
|
+
this.allBranchCities = null;
|
|
1210
|
+
this.loadingBranches = false;
|
|
1211
|
+
this.branches = [];
|
|
1212
|
+
this.filteredBranches = [];
|
|
1045
1213
|
this.selectedCountry = newCountry;
|
|
1214
|
+
this.selectedBranchCity = null;
|
|
1215
|
+
this.branchCities = [];
|
|
1216
|
+
this.branchCitySearchQuery = '';
|
|
1217
|
+
this.selectedBranch = null;
|
|
1046
1218
|
this.selectedRegion = null;
|
|
1047
1219
|
this.regions = [];
|
|
1048
1220
|
this.displayedRegions = [];
|
|
@@ -1162,19 +1334,11 @@ export class SallaBulletDelivery {
|
|
|
1162
1334
|
void this.loadBranches();
|
|
1163
1335
|
return;
|
|
1164
1336
|
}
|
|
1165
|
-
this.branchSearchDebounceTimer = setTimeout(
|
|
1166
|
-
|
|
1337
|
+
this.branchSearchDebounceTimer = setTimeout(() => {
|
|
1338
|
+
// Below the minimum, only reload when the list still holds an earlier server search.
|
|
1339
|
+
if (query.trim().length < BRANCH_SEARCH_MIN_LENGTH && !this.branchesServerQuery)
|
|
1167
1340
|
return;
|
|
1168
|
-
this.
|
|
1169
|
-
try {
|
|
1170
|
-
this.applyLoadedBranches(await bulletDeliveryAPI.getBranches({
|
|
1171
|
-
country_id: this.selectedCountry?.id,
|
|
1172
|
-
query,
|
|
1173
|
-
}));
|
|
1174
|
-
}
|
|
1175
|
-
finally {
|
|
1176
|
-
this.loadingBranches = false;
|
|
1177
|
-
}
|
|
1341
|
+
void this.loadBranches();
|
|
1178
1342
|
}, BRANCH_SEARCH_DEBOUNCE_MS);
|
|
1179
1343
|
}
|
|
1180
1344
|
clearSearchTimers() {
|
|
@@ -1201,13 +1365,23 @@ export class SallaBulletDelivery {
|
|
|
1201
1365
|
this.clearSearchTimers();
|
|
1202
1366
|
}
|
|
1203
1367
|
async loadBranchesWithLocation(lat, lng) {
|
|
1368
|
+
// Later list loads (city change, search) keep measuring from the device location.
|
|
1369
|
+
++this.shopperLocationRequestId;
|
|
1370
|
+
this.shopperLocation = { lat, lng };
|
|
1371
|
+
const request = ++this.branchesRequestId;
|
|
1204
1372
|
this.loadingBranches = true;
|
|
1205
1373
|
try {
|
|
1206
|
-
|
|
1374
|
+
const branches = await bulletDeliveryAPI.getBranches({
|
|
1207
1375
|
country_id: this.selectedCountry?.id,
|
|
1376
|
+
city_id: this.selectedBranchCity?.id,
|
|
1208
1377
|
lat,
|
|
1209
1378
|
lng,
|
|
1210
|
-
})
|
|
1379
|
+
});
|
|
1380
|
+
if (request !== this.branchesRequestId)
|
|
1381
|
+
return false;
|
|
1382
|
+
this.branchesServerQuery = '';
|
|
1383
|
+
this.applyLoadedBranches(branches);
|
|
1384
|
+
void this.refreshBranchCities();
|
|
1211
1385
|
// Auto-select country from first branch if no country is selected
|
|
1212
1386
|
if (!this.selectedCountry && this.branches.length > 0) {
|
|
1213
1387
|
const firstBranch = this.branches[0];
|
|
@@ -1221,9 +1395,11 @@ export class SallaBulletDelivery {
|
|
|
1221
1395
|
}
|
|
1222
1396
|
}
|
|
1223
1397
|
}
|
|
1398
|
+
return true;
|
|
1224
1399
|
}
|
|
1225
1400
|
finally {
|
|
1226
|
-
this.
|
|
1401
|
+
if (request === this.branchesRequestId)
|
|
1402
|
+
this.loadingBranches = false;
|
|
1227
1403
|
}
|
|
1228
1404
|
}
|
|
1229
1405
|
/** Locate nearest branch using device geolocation (branches tab only). */
|
|
@@ -1232,6 +1408,7 @@ export class SallaBulletDelivery {
|
|
|
1232
1408
|
this.locationError = Salla.lang.get("pages.checkout.current_location_not_supported");
|
|
1233
1409
|
return;
|
|
1234
1410
|
}
|
|
1411
|
+
const request = ++this.nearestBranchRequestId;
|
|
1235
1412
|
this.loadingNearestBranch = true;
|
|
1236
1413
|
this.locationError = "";
|
|
1237
1414
|
try {
|
|
@@ -1243,7 +1420,12 @@ export class SallaBulletDelivery {
|
|
|
1243
1420
|
});
|
|
1244
1421
|
});
|
|
1245
1422
|
const { latitude, longitude } = position.coords;
|
|
1246
|
-
|
|
1423
|
+
if (request !== this.nearestBranchRequestId)
|
|
1424
|
+
return;
|
|
1425
|
+
if (!await this.loadBranchesWithLocation(latitude, longitude))
|
|
1426
|
+
return;
|
|
1427
|
+
if (request !== this.nearestBranchRequestId)
|
|
1428
|
+
return;
|
|
1247
1429
|
const nearestBranch = findNearestBranch(this.branches, latitude, longitude);
|
|
1248
1430
|
if (nearestBranch) {
|
|
1249
1431
|
this.selectedBranch = nearestBranch;
|
|
@@ -1252,26 +1434,56 @@ export class SallaBulletDelivery {
|
|
|
1252
1434
|
}
|
|
1253
1435
|
}
|
|
1254
1436
|
catch (error) {
|
|
1437
|
+
if (request !== this.nearestBranchRequestId)
|
|
1438
|
+
return;
|
|
1255
1439
|
const geoError = error;
|
|
1256
1440
|
const code = typeof geoError?.code === "number" ? geoError.code : -1;
|
|
1257
|
-
this.locationError =
|
|
1441
|
+
this.locationError = this.geolocationErrorMessage(code);
|
|
1258
1442
|
}
|
|
1259
1443
|
finally {
|
|
1260
|
-
this.
|
|
1444
|
+
if (request === this.nearestBranchRequestId)
|
|
1445
|
+
this.loadingNearestBranch = false;
|
|
1261
1446
|
}
|
|
1262
1447
|
}
|
|
1448
|
+
geolocationErrorMessage(code) {
|
|
1449
|
+
if (code === GEO_PERMISSION_DENIED) {
|
|
1450
|
+
return Salla.lang.getWithDefault("pages.checkout.allow_location_permission_blocked_hint", this.isArabic
|
|
1451
|
+
? "مشاركة الموقع محجوبة لهذا المتجر في متصفحك. افتح إعدادات الموقع في المتصفح، اسمح بالوصول إلى الموقع، ثم أعد المحاولة."
|
|
1452
|
+
: "Location sharing is blocked for this store in your browser. Open your browser's location settings, allow location access, then try again.");
|
|
1453
|
+
}
|
|
1454
|
+
return Salla.lang.getWithDefault("pages.checkout.pickup_location_unavailable", this.isArabic ? "تعذَّر تحديد موقعك. حاول مرة أخرى." : "We couldn't detect your location. Try again.");
|
|
1455
|
+
}
|
|
1263
1456
|
handleBranchSelect(branch) {
|
|
1264
1457
|
this.selectedBranch = branch;
|
|
1265
1458
|
this.allocationOutOfCoverageMessage = null;
|
|
1266
1459
|
}
|
|
1460
|
+
toggleBranchSchedule(branchId) {
|
|
1461
|
+
this.expandedScheduleBranchId = this.expandedScheduleBranchId === branchId ? null : branchId;
|
|
1462
|
+
}
|
|
1267
1463
|
/**
|
|
1268
1464
|
* Restore a remembered / event-provided branch — but only one the list renders as selectable,
|
|
1269
1465
|
* so a branch that has closed since it was remembered is never silently preselected (INV-1407).
|
|
1270
1466
|
*/
|
|
1271
|
-
preselectBranch(branchId) {
|
|
1272
|
-
if (branchId == null)
|
|
1467
|
+
async preselectBranch(branchId) {
|
|
1468
|
+
if (branchId == null || this.selectedBranch)
|
|
1273
1469
|
return;
|
|
1274
|
-
|
|
1470
|
+
let branch = this.branches.find((b) => b.id === branchId);
|
|
1471
|
+
if (!branch && this.allBranchCities) {
|
|
1472
|
+
const pending = this.allBranchCities;
|
|
1473
|
+
const request = this.branchesRequestId;
|
|
1474
|
+
try {
|
|
1475
|
+
branch = (await pending.branches).find((b) => b.id === branchId);
|
|
1476
|
+
}
|
|
1477
|
+
catch {
|
|
1478
|
+
return;
|
|
1479
|
+
}
|
|
1480
|
+
if (request !== this.branchesRequestId || this.activeTab !== 'branch' || this.allBranchCities !== pending || pending.countryId !== this.selectedCountry?.id || this.selectedBranch || this.branchSearchQuery.trim())
|
|
1481
|
+
return;
|
|
1482
|
+
if (this.selectedBranchCity && String(branch?.city?.id) !== String(this.selectedBranchCity.id))
|
|
1483
|
+
return;
|
|
1484
|
+
if (branch && isBranchSelectable(branch))
|
|
1485
|
+
this.applyLoadedBranches([...this.branches, branch]);
|
|
1486
|
+
}
|
|
1275
1487
|
if (branch && isBranchSelectable(branch)) {
|
|
1276
1488
|
this.selectedBranch = branch;
|
|
1277
1489
|
}
|
|
@@ -1532,6 +1744,48 @@ export class SallaBulletDelivery {
|
|
|
1532
1744
|
}
|
|
1533
1745
|
/** Center shown before geolocation resolves — the customer's IP-based default (falls back to Riyadh). */
|
|
1534
1746
|
get mapInitialCenter() {
|
|
1747
|
+
return this.defaultGeoLocation ?? DEFAULT_MAP_CENTER;
|
|
1748
|
+
}
|
|
1749
|
+
/** Device location for a branch list request, waiting at most BRANCH_LIST_LOCATION_WAIT. */
|
|
1750
|
+
getListLocation() {
|
|
1751
|
+
const location = this.getGrantedDeviceLocation();
|
|
1752
|
+
if (this.shopperLocation || !navigator.geolocation || !navigator.permissions?.query)
|
|
1753
|
+
return location;
|
|
1754
|
+
return Promise.race([location, new Promise((resolve) => setTimeout(() => resolve({}), BRANCH_LIST_LOCATION_WAIT))]);
|
|
1755
|
+
}
|
|
1756
|
+
/**
|
|
1757
|
+
* Where branch distances (`distance_km`) are measured from: the shopper's real device location
|
|
1758
|
+
* only. It comes from "nearest to my location", or is read silently when location permission was
|
|
1759
|
+
* already granted (never prompting). Empty otherwise: `user.default_geo_location` and the Riyadh
|
|
1760
|
+
* map fallback are not where the shopper is, so they would show wrong distances.
|
|
1761
|
+
*/
|
|
1762
|
+
async getGrantedDeviceLocation() {
|
|
1763
|
+
if (this.shopperLocation)
|
|
1764
|
+
return this.shopperLocation;
|
|
1765
|
+
if (!navigator.geolocation || !navigator.permissions?.query)
|
|
1766
|
+
return {};
|
|
1767
|
+
const request = ++this.shopperLocationRequestId;
|
|
1768
|
+
try {
|
|
1769
|
+
const permission = await navigator.permissions.query({ name: 'geolocation' });
|
|
1770
|
+
if (request !== this.shopperLocationRequestId)
|
|
1771
|
+
return this.shopperLocation ?? {};
|
|
1772
|
+
if (permission.state !== 'granted')
|
|
1773
|
+
return {};
|
|
1774
|
+
const position = await new Promise((resolve, reject) => navigator.geolocation.getCurrentPosition(resolve, reject, {
|
|
1775
|
+
timeout: SILENT_GEOLOCATION_TIMEOUT,
|
|
1776
|
+
maximumAge: SILENT_GEOLOCATION_MAX_AGE,
|
|
1777
|
+
}));
|
|
1778
|
+
if (request !== this.shopperLocationRequestId)
|
|
1779
|
+
return this.shopperLocation ?? {};
|
|
1780
|
+
this.shopperLocation = { lat: position.coords.latitude, lng: position.coords.longitude };
|
|
1781
|
+
return this.shopperLocation;
|
|
1782
|
+
}
|
|
1783
|
+
catch {
|
|
1784
|
+
return {};
|
|
1785
|
+
}
|
|
1786
|
+
}
|
|
1787
|
+
/** The customer's IP-based `user.default_geo_location`, or null when it is missing or invalid. */
|
|
1788
|
+
get defaultGeoLocation() {
|
|
1535
1789
|
const geo = salla.config.get('user.default_geo_location');
|
|
1536
1790
|
// Coerce defensively: config may arrive as strings, blank/whitespace, NaN, or out-of-range
|
|
1537
1791
|
// values. Reject blanks before coercion (Number('') === 0) and validate lat/lng ranges so we
|
|
@@ -1540,7 +1794,7 @@ export class SallaBulletDelivery {
|
|
|
1540
1794
|
const lng = this.toCoordinate(geo?.lng);
|
|
1541
1795
|
const isValid = lat != null && lng != null &&
|
|
1542
1796
|
lat >= -90 && lat <= 90 && lng >= -180 && lng <= 180;
|
|
1543
|
-
return isValid ? { lat, lng } :
|
|
1797
|
+
return isValid ? { lat, lng } : null;
|
|
1544
1798
|
}
|
|
1545
1799
|
/** Parse a config coordinate to a finite number, treating blank/whitespace strings as missing. */
|
|
1546
1800
|
toCoordinate(value) {
|
|
@@ -1554,6 +1808,8 @@ export class SallaBulletDelivery {
|
|
|
1554
1808
|
async handleTabChange(tab) {
|
|
1555
1809
|
if (this.tabChanging)
|
|
1556
1810
|
return;
|
|
1811
|
+
++this.branchesRequestId;
|
|
1812
|
+
this.loadingBranches = false;
|
|
1557
1813
|
this.tabChanging = true;
|
|
1558
1814
|
try {
|
|
1559
1815
|
this.activeTab = tab;
|
|
@@ -1585,24 +1841,25 @@ export class SallaBulletDelivery {
|
|
|
1585
1841
|
this.selectedCountry = this.countries[0];
|
|
1586
1842
|
}
|
|
1587
1843
|
}
|
|
1844
|
+
if (String(previousCountryId ?? '') !== String(this.selectedCountry?.id ?? '')) {
|
|
1845
|
+
this.allBranchCities = null;
|
|
1846
|
+
this.selectedBranchCity = null;
|
|
1847
|
+
this.branchCities = [];
|
|
1848
|
+
this.branchCitySearchQuery = '';
|
|
1849
|
+
this.selectedBranch = null;
|
|
1850
|
+
this.branches = [];
|
|
1851
|
+
this.filteredBranches = [];
|
|
1852
|
+
}
|
|
1588
1853
|
if (tab === "address" && this.needsMap)
|
|
1589
1854
|
this.fetchAddressToken();
|
|
1590
1855
|
// Load appropriate data when switching tabs if country is selected
|
|
1591
1856
|
if (this.selectedCountry) {
|
|
1592
1857
|
if (tab === "branch") {
|
|
1593
1858
|
// Load branches when switching to branch tab
|
|
1594
|
-
// Check session storage for lat/lng to get nearby branches
|
|
1595
1859
|
const savedIntent = this.getStoredIntent();
|
|
1596
|
-
|
|
1597
|
-
const intentLng = getIntentLongitude(savedIntent);
|
|
1598
|
-
if (intentLat != null && intentLng != null) {
|
|
1599
|
-
await this.loadBranchesWithLocation(intentLat, intentLng);
|
|
1600
|
-
}
|
|
1601
|
-
else {
|
|
1602
|
-
await this.loadBranches();
|
|
1603
|
-
}
|
|
1860
|
+
await this.loadBranches();
|
|
1604
1861
|
// Preselect branch from session storage if available
|
|
1605
|
-
this.preselectBranch(getIntentBranchId(savedIntent));
|
|
1862
|
+
void this.preselectBranch(getIntentBranchId(savedIntent));
|
|
1606
1863
|
}
|
|
1607
1864
|
else if (tab === "address") {
|
|
1608
1865
|
// Lazy-load saved addresses when switching to address tab (if not loaded yet).
|
|
@@ -1728,7 +1985,7 @@ export class SallaBulletDelivery {
|
|
|
1728
1985
|
if (await this.tryAutoConfirmAfterLogin())
|
|
1729
1986
|
return;
|
|
1730
1987
|
if (!this.modal?.hasAttribute?.("visible") || !this.isLoggedIn) {
|
|
1731
|
-
this.open();
|
|
1988
|
+
this.open(false, "after_login");
|
|
1732
1989
|
}
|
|
1733
1990
|
}
|
|
1734
1991
|
buildIntentAddress() {
|
|
@@ -2007,13 +2264,14 @@ export class SallaBulletDelivery {
|
|
|
2007
2264
|
}
|
|
2008
2265
|
return raw;
|
|
2009
2266
|
}
|
|
2010
|
-
async handleConfirm() {
|
|
2267
|
+
async handleConfirm(intentBeforeDraft) {
|
|
2011
2268
|
if (this.isConfirmDisabled() || this.confirming)
|
|
2012
2269
|
return;
|
|
2013
2270
|
this.allocationOutOfCoverageMessage = null;
|
|
2014
2271
|
this.confirming = true;
|
|
2015
2272
|
this.confirmBtn?.load();
|
|
2016
2273
|
let scheduledRedirect = false;
|
|
2274
|
+
const previousIntent = intentBeforeDraft === undefined ? this.getStoredIntent() : intentBeforeDraft;
|
|
2017
2275
|
try {
|
|
2018
2276
|
// A guest map pin uses the pin's own country; the IP/selected country may differ from it.
|
|
2019
2277
|
const country = this.activeTab === "address" && this.isGuestMapPick
|
|
@@ -2031,6 +2289,7 @@ export class SallaBulletDelivery {
|
|
|
2031
2289
|
const savedAddress = await this.saveSessionAddressToProfile();
|
|
2032
2290
|
if (!savedAddress) {
|
|
2033
2291
|
Salla.notify?.error(Salla.lang.get("common.errors.error_occurred"));
|
|
2292
|
+
this.trackSelectorResult("failed", previousIntent, []);
|
|
2034
2293
|
this.confirmBtn?.stop();
|
|
2035
2294
|
return;
|
|
2036
2295
|
}
|
|
@@ -2104,9 +2363,17 @@ export class SallaBulletDelivery {
|
|
|
2104
2363
|
(this.activeTab === "address"
|
|
2105
2364
|
? Salla.lang.get("pages.checkout.address_out_of_coverage")
|
|
2106
2365
|
: Salla.lang.get("pages.checkout.failed_to_set_pickup"));
|
|
2107
|
-
this.allocationOutOfCoverageMessage = `${errorMessage}.`;
|
|
2366
|
+
this.allocationOutOfCoverageMessage = /[.!؟?]$/.test(errorMessage.trim()) ? errorMessage : `${errorMessage}.`;
|
|
2367
|
+
this.trackSelectorResult("failed", previousIntent, []);
|
|
2108
2368
|
this.confirmBtn?.stop();
|
|
2109
2369
|
this.confirming = false;
|
|
2370
|
+
// A rejected branch may have turned busy or closed: drop it (the reload may hide it) and
|
|
2371
|
+
// reload so the list shows its current state.
|
|
2372
|
+
if (this.activeTab === "branch") {
|
|
2373
|
+
this.selectedBranch = null;
|
|
2374
|
+
clearApiCache();
|
|
2375
|
+
void this.loadBranches();
|
|
2376
|
+
}
|
|
2110
2377
|
return;
|
|
2111
2378
|
}
|
|
2112
2379
|
// Process successful allocation response
|
|
@@ -2141,6 +2408,7 @@ export class SallaBulletDelivery {
|
|
|
2141
2408
|
const scopeApplied = await bulletDeliveryAPI.setDeliveryScope(allocatedScopeId);
|
|
2142
2409
|
if (!scopeApplied) {
|
|
2143
2410
|
this.allocationOutOfCoverageMessage = `${Salla.lang.get("common.errors.error_occurred")}.`;
|
|
2411
|
+
this.trackSelectorResult("failed", previousIntent, [], allocatedScopeId);
|
|
2144
2412
|
this.confirmBtn?.stop();
|
|
2145
2413
|
this.confirming = false;
|
|
2146
2414
|
return;
|
|
@@ -2160,6 +2428,7 @@ export class SallaBulletDelivery {
|
|
|
2160
2428
|
// After allocation success: persist latest intent so switch UI can always reflect
|
|
2161
2429
|
// the selected address/branch once confirmed.
|
|
2162
2430
|
this.setStoredIntent({ ...result, scope_allocated: true });
|
|
2431
|
+
this.trackSelectorResult("accepted", previousIntent, allocatedBranchIds(result), allocatedScopeId);
|
|
2163
2432
|
const allocationConfirmedPayload = {
|
|
2164
2433
|
...result,
|
|
2165
2434
|
address: this.buildAllocationConfirmedAddressData(selectedAddress),
|
|
@@ -2270,6 +2539,19 @@ export class SallaBulletDelivery {
|
|
|
2270
2539
|
wrapper.append(info, btn);
|
|
2271
2540
|
return wrapper;
|
|
2272
2541
|
}
|
|
2542
|
+
/**
|
|
2543
|
+
* A branch pickup offer (INV-1416) replaces the default "save delivery fees" badge; only one shows,
|
|
2544
|
+
* and neither until the offer lookup settles.
|
|
2545
|
+
*/
|
|
2546
|
+
renderPickupTabBadge() {
|
|
2547
|
+
if (!this.pickupDiscountResolved)
|
|
2548
|
+
return null;
|
|
2549
|
+
const range = this.pickupDiscountRange;
|
|
2550
|
+
if (range) {
|
|
2551
|
+
return (h("span", { class: "s-bullet-delivery-tab-badge s-bullet-delivery-discount-badge", dir: this.isArabic ? 'rtl' : 'ltr', innerHTML: this.getPickupDiscountLabel(range.type, range.min, range.max) }));
|
|
2552
|
+
}
|
|
2553
|
+
return (h("span", { class: "s-bullet-delivery-tab-badge" }, h("span", { class: "s-bullet-delivery-tab-badge-icon", innerHTML: LightningIcon, "aria-hidden": "true" }), Salla.lang.getWithDefault("pages.checkout.save_delivery_fees", "وفّر رسوم التوصيل")));
|
|
2554
|
+
}
|
|
2273
2555
|
renderTabs() {
|
|
2274
2556
|
// Show tabs only when pickup is supported; otherwise delivery-only view with no tabs.
|
|
2275
2557
|
// The pickup tab is gated by this same `supportsPickup` check, while the delivery
|
|
@@ -2279,10 +2561,10 @@ export class SallaBulletDelivery {
|
|
|
2279
2561
|
return (h("div", { class: "s-bullet-delivery-tabs" }, this.isSupportsDelivery && (h("button", { type: "button", class: {
|
|
2280
2562
|
"s-bullet-delivery-tab": true,
|
|
2281
2563
|
"s-bullet-delivery-tab--active": this.activeTab === "address",
|
|
2282
|
-
}, onClick: () => this.handleTabChange("address") }, h("span",
|
|
2564
|
+
}, onClick: () => this.handleTabChange("address") }, h("span", null, Salla.lang.get("mobile_app.strings.delivery")))), h("button", { type: "button", class: {
|
|
2283
2565
|
"s-bullet-delivery-tab": true,
|
|
2284
2566
|
"s-bullet-delivery-tab--active": this.activeTab === "branch",
|
|
2285
|
-
}, onClick: () => this.handleTabChange("branch") }, h("span",
|
|
2567
|
+
}, onClick: () => this.handleTabChange("branch") }, h("span", null, Salla.lang.get("mobile_app.strings.pickup")), this.renderPickupTabBadge())));
|
|
2286
2568
|
}
|
|
2287
2569
|
renderAlert(message) {
|
|
2288
2570
|
return (h("div", { class: "s-bullet-delivery-allocation-out-of-coverage", role: "alert" }, h("span", { class: "s-bullet-delivery-allocation-out-of-coverage-icon", "aria-hidden": "true" }, h("svg", { width: "20", height: "20", viewBox: "0 0 20 20", fill: "none", xmlns: "http://www.w3.org/2000/svg", role: "img", "aria-hidden": "true" }, h("title", null, "Information"), h("circle", { cx: "10", cy: "10", r: "9", stroke: "currentColor", "stroke-width": "1.5", fill: "currentColor" }), h("text", { x: "10", y: "14", "text-anchor": "middle", fill: "white", "font-size": "12", "font-weight": "bold" }, "i"))), h("span", { class: "s-bullet-delivery-allocation-out-of-coverage-text", style: { textAlign: this.isRTL ? 'right' : 'left' } }, message)));
|
|
@@ -2306,8 +2588,9 @@ export class SallaBulletDelivery {
|
|
|
2306
2588
|
}
|
|
2307
2589
|
return this.renderAlert(`${message} ${Salla.lang.getWithDefault('pages.cart.choose_another_address', 'Choose another address')}`);
|
|
2308
2590
|
}
|
|
2309
|
-
|
|
2310
|
-
|
|
2591
|
+
/** `showLabel` is off in the pickup filter panel, where the selects sit label-less side by side. */
|
|
2592
|
+
renderCountrySelect(showLabel = true) {
|
|
2593
|
+
return (h("div", { class: "s-bullet-delivery-field" }, h("salla-searchable-dropdown", { label: showLabel ? Salla.lang.get("blocks.buy_as_gift.receiver_country") : undefined, placeholder: Salla.lang.get("pages.checkout.select_country"), items: this.displayedCountries, selectedItem: this.selectedCountry, loading: this.loadingCountries, searching: this.searchingCountries, disabled: this.countries.length <= 1, required: true, inputId: "bullet-delivery-country", searchQuery: this.countrySearchQuery, clientSearch: true, onItemSelected: (e) => this.handleCountrySelected(e.detail), onSearchInput: (e) => this.handleCountrySearch(e.detail), onDropdownClosed: () => this.handleCountryDropdownClosed() })));
|
|
2311
2594
|
}
|
|
2312
2595
|
/** Region select (SA only): shown when SA is selected; city and district disabled until region selected. */
|
|
2313
2596
|
renderRegionSelect() {
|
|
@@ -2552,66 +2835,146 @@ export class SallaBulletDelivery {
|
|
|
2552
2835
|
return (h("form", { onSubmit: handleSubmit }, this.renderGuestDeliveryForm(), h("div", { class: "s-bullet-delivery-form-actions s-bullet-delivery-form-actions--single", style: { padding: '24px' } }, h("salla-button", { type: "submit", loading: this.confirming, disabled: !canSubmit || this.confirming, width: "wide" }, submitLabel), !this.isLoggedIn && (h("button", { type: "button", class: "s-bullet-delivery-login-prompt", onClick: () => this.handleLogin() }, Salla.lang.get('pages.checkout.login_to_use_saved_addresses'))))));
|
|
2553
2836
|
}
|
|
2554
2837
|
renderBranchSearch() {
|
|
2555
|
-
return (h("div", { class: "s-bullet-delivery-branch-search" }, h("div", { class: "s-bullet-delivery-search-row" }, h("div", { class: "s-bullet-delivery-search s-bullet-delivery-branch-search-wrap" }, h("span", { class: "s-bullet-delivery-search-icon s-bullet-delivery-branch-search-icon", innerHTML: Search, "aria-hidden": "true" }), h("input", { type: "text", class: "s-bullet-delivery-branch-search-input form-input", placeholder: Salla.lang.
|
|
2838
|
+
return (h("div", { class: "s-bullet-delivery-branch-search" }, h("div", { class: "s-bullet-delivery-search-row" }, h("div", { class: "s-bullet-delivery-search s-bullet-delivery-branch-search-wrap" }, h("span", { class: "s-bullet-delivery-search-icon s-bullet-delivery-branch-search-icon", innerHTML: Search, "aria-hidden": "true" }), h("input", { type: "text", class: "s-bullet-delivery-branch-search-input form-input", placeholder: Salla.lang.getWithDefault("pages.checkout.search_for_country_city_or_branch", this.isArabic ? "ابحث عن دولة أو مدينة أو فرع" : "Search for a country, city or branch"), value: this.branchSearchQuery, onInput: (e) => this.handleBranchSearch(e), autocomplete: "off" })), h("button", { type: "button", class: {
|
|
2556
2839
|
"s-bullet-delivery-location-btn": true,
|
|
2557
2840
|
"s-bullet-delivery-location-btn--full": true,
|
|
2558
2841
|
"s-bullet-delivery-location-btn--loading": this.loadingNearestBranch,
|
|
2559
|
-
}, onClick: () => this.handleFindNearestBranch(), disabled: this.loadingNearestBranch }, this.loadingNearestBranch ? (h("span", { class: "s-bullet-delivery-location-icon", "aria-hidden": "true" }, h("salla-skeleton", { height: "
|
|
2560
|
-
}
|
|
2561
|
-
/** Renders a branch's `preparation_time_range` as a localized "from - to <unit>" label. */
|
|
2562
|
-
getPreparationTimeLabel(range) {
|
|
2563
|
-
if (!range)
|
|
2564
|
-
return null;
|
|
2565
|
-
const unitKeys = {
|
|
2566
|
-
hour: 'pages.checkout.preparation_time_hours',
|
|
2567
|
-
minute: 'pages.checkout.preparation_time_minutes',
|
|
2568
|
-
day: 'pages.checkout.preparation_time_days',
|
|
2569
|
-
};
|
|
2570
|
-
const key = unitKeys[range.from.unit];
|
|
2571
|
-
if (!key)
|
|
2572
|
-
return null;
|
|
2573
|
-
return Salla.lang
|
|
2574
|
-
.getWithDefault(key, 'من {from} إلى {to} دقائق')
|
|
2575
|
-
?.replace('{from}', String(range.from.value))
|
|
2576
|
-
?.replace('{to}', String(range.to.value));
|
|
2842
|
+
}, onClick: () => this.handleFindNearestBranch(), disabled: this.loadingNearestBranch, "aria-label": Salla.lang.get("pages.checkout.nearest_to_my_location") }, this.loadingNearestBranch ? (h("span", { class: "s-bullet-delivery-location-icon", "aria-hidden": "true" }, h("salla-skeleton", { height: "16px", width: "16px" }))) : (h("span", { class: "s-bullet-delivery-location-icon", innerHTML: Location, "aria-hidden": "true" })), h("span", { class: "s-bullet-delivery-location-label" }, Salla.lang.get("pages.checkout.nearest_to_my_location")))), this.locationError && this.activeTab === "branch" && (h("span", { class: "s-bullet-delivery-error" }, this.locationError))));
|
|
2577
2843
|
}
|
|
2578
2844
|
renderBranchList() {
|
|
2579
2845
|
if (this.loadingBranches) {
|
|
2580
2846
|
return (h("div", { class: "s-bullet-delivery-branches-wrap" }, h("div", { class: "s-bullet-delivery-branches-loading" }, [1, 2, 3, 4].map((v) => (h("div", { key: v, class: "s-bullet-delivery-branch-skeleton" }, h("salla-skeleton", { class: "s-bullet-delivery-branch-skeleton-radio", type: "circle", height: "16px", width: "16px" }), h("div", { class: "s-bullet-delivery-branch-skeleton-icon" }, h("salla-skeleton", { height: "34px", width: "34px" })), h("div", { class: "s-bullet-delivery-branch-skeleton-content" }, h("salla-skeleton", { class: "s-bullet-delivery-branch-skeleton-title", height: "12px", width: "124px" })), h("salla-skeleton", { class: "s-bullet-delivery-branch-skeleton-time", height: "12px", width: "88px" }), h("div", { class: "s-bullet-delivery-branch-skeleton-map" }, h("salla-skeleton", { height: "32px", width: "32px" }))))))));
|
|
2581
2847
|
}
|
|
2582
|
-
|
|
2848
|
+
const branches = this.filteredBranches.filter(isBranchVisible);
|
|
2849
|
+
if (branches.length === 0) {
|
|
2583
2850
|
return (h("salla-placeholder", { alignment: "center", class: "s-bullet-delivery-placeholder" }, h("span", { slot: "title" }, Salla.lang.get("pages.checkout.no_pickup_branches_found"))));
|
|
2584
2851
|
}
|
|
2585
|
-
return (h("div", { class: "s-bullet-delivery-branches-wrap" }, h("ul", { class: "s-bullet-delivery-branches-list s-scrollbar" },
|
|
2852
|
+
return (h("div", { class: "s-bullet-delivery-branches-wrap" }, h("ul", { class: "s-bullet-delivery-branches-list s-scrollbar", role: "listbox" }, branches.map(branch => {
|
|
2586
2853
|
const selectable = isBranchSelectable(branch);
|
|
2587
|
-
const
|
|
2854
|
+
const isSelected = this.selectedBranch?.id === branch.id;
|
|
2588
2855
|
const locationText = [branch.country?.name, branch.city?.name, branch.district?.name]
|
|
2589
2856
|
.filter(Boolean)
|
|
2590
|
-
.join('
|
|
2591
|
-
const
|
|
2857
|
+
.join('، ');
|
|
2858
|
+
const distance = formatBranchDistance(branch.distance_km);
|
|
2859
|
+
// Closed but taking orders: the opening-time readiness replaces the range.
|
|
2860
|
+
const readinessLabel = getBranchReadinessLabel(branch) ?? this.getReadyTodayLabel(branch);
|
|
2861
|
+
const preparationLabel = readinessLabel ? null : this.getPreparationShortLabel(branch.preparation_time_range);
|
|
2862
|
+
const scheduleGroups = groupBranchSchedule(getBranchWeekSchedule(branch));
|
|
2863
|
+
// An always-open branch has no hours worth listing, so it gets no working-hours dropdown.
|
|
2864
|
+
const hasSchedule = scheduleGroups.length > 0 && !isBranchAlwaysOpen(branch);
|
|
2865
|
+
const scheduleOpen = hasSchedule && this.expandedScheduleBranchId === branch.id;
|
|
2866
|
+
const phoneHref = getBranchPhoneHref(branch);
|
|
2867
|
+
const whatsappHref = getBranchWhatsappHref(branch);
|
|
2868
|
+
const directionsHref = getBranchDirectionsHref(branch);
|
|
2869
|
+
const discount = getBranchDiscount(branch);
|
|
2592
2870
|
return (h("li", { key: branch.id, class: {
|
|
2593
2871
|
's-bullet-delivery-branch-item': true,
|
|
2594
|
-
's-bullet-delivery-branch-item--selected':
|
|
2872
|
+
's-bullet-delivery-branch-item--selected': isSelected,
|
|
2595
2873
|
's-bullet-delivery-branch-item--disabled': !selectable,
|
|
2596
|
-
}, tabIndex: selectable ? 0 : -1, role: "option", "aria-disabled": !selectable, onClick: () => selectable && this.handleBranchSelect(branch), onKeyDown: e => {
|
|
2874
|
+
}, tabIndex: selectable ? 0 : -1, role: "option", "aria-selected": isSelected, "aria-disabled": !selectable, onClick: () => selectable && this.handleBranchSelect(branch), onKeyDown: e => {
|
|
2875
|
+
if (e.target !== e.currentTarget)
|
|
2876
|
+
return;
|
|
2597
2877
|
if (e.key === 'Enter' || e.key === ' ') {
|
|
2598
2878
|
e.preventDefault();
|
|
2599
2879
|
if (selectable)
|
|
2600
2880
|
this.handleBranchSelect(branch);
|
|
2601
2881
|
}
|
|
2602
|
-
} }, h("input", { type: "radio", name: "branch", class: "s-bullet-delivery-radio", checked:
|
|
2603
|
-
|
|
2604
|
-
|
|
2605
|
-
|
|
2606
|
-
|
|
2882
|
+
} }, h("input", { type: "radio", name: "branch", class: "s-bullet-delivery-radio s-bullet-delivery-branch-radio", checked: isSelected, disabled: !selectable, tabIndex: -1 }), h("div", { class: "s-bullet-delivery-branch-body" }, h("p", { class: "s-bullet-delivery-branch-name" }, h("span", null, branch.name), discount ? (h("span", { class: "s-bullet-delivery-discount-badge", dir: this.isArabic ? 'rtl' : 'ltr', innerHTML: this.getPickupDiscountLabel(discount.type, discount.amount) })) : null), locationText ? (h("span", { class: "s-bullet-delivery-branch-meta s-bullet-delivery-branch-location" }, h("span", { class: "s-bullet-delivery-branch-meta-icon", innerHTML: BranchLocationIcon, "aria-hidden": "true" }), h("span", null, locationText))) : null, isSelected && branch.pickup_instructions ? (h("span", { class: "s-bullet-delivery-branch-meta s-bullet-delivery-branch-instructions" }, h("span", { class: "s-bullet-delivery-branch-meta-icon", innerHTML: NotesIcon, "aria-hidden": "true" }), h("span", null, branch.pickup_instructions))) : null, h("div", { class: "s-bullet-delivery-branch-meta-row" }, distance || readinessLabel || preparationLabel ? (h("div", { class: "s-bullet-delivery-branch-pills" }, distance ? (h("span", { class: "s-bullet-delivery-branch-meta s-bullet-delivery-branch-pill s-bullet-delivery-branch-distance" }, h("i", { class: "sicon-location" }), h("span", null, this.renderDistanceLabel(distance)))) : null, readinessLabel ? (h("span", { class: "s-bullet-delivery-branch-meta s-bullet-delivery-branch-pill s-bullet-delivery-branch-prep" }, h("span", { class: "s-bullet-delivery-branch-meta-icon", innerHTML: PickupAvailabilityIcon, "aria-hidden": "true" }), h("span", { class: "s-bullet-delivery-branch-meta-value" }, readinessLabel))) : preparationLabel ? (h("span", { class: "s-bullet-delivery-branch-meta s-bullet-delivery-branch-pill s-bullet-delivery-branch-prep" }, h("span", { class: "s-bullet-delivery-branch-meta-icon", innerHTML: PickupAvailabilityIcon, "aria-hidden": "true" }), h("span", null, h("span", { class: "s-bullet-delivery-branch-meta-label" }, Salla.lang.getWithDefault('pages.checkout.pickup_branch_ready_in', 'Pickup available after:'), ' '), h("span", { class: "s-bullet-delivery-branch-meta-value" }, preparationLabel)))) : null)) : null, h("hr", { class: "s-bullet-delivery-branch-divider" }), this.renderBranchOpenStatus(branch, hasSchedule, scheduleOpen)), scheduleOpen && (h("div", { class: "s-bullet-delivery-branch-schedule" }, scheduleGroups.map((group, index) => (h("div", { key: index, class: "s-bullet-delivery-branch-schedule-day" }, h("span", { class: "s-bullet-delivery-branch-schedule-days" }, group.days.length > 1
|
|
2883
|
+
? `${group.days[0]} - ${group.days[group.days.length - 1]}`
|
|
2884
|
+
: group.days[0]), h("span", { class: "s-bullet-delivery-branch-schedule-times" }, group.times
|
|
2885
|
+
.map(t => `${this.formatClock(t.start)} - ${this.formatClock(t.end)}`)
|
|
2886
|
+
.join(this.isArabic ? '، ' : ', ')))))))), h("div", { class: "s-bullet-delivery-branch-actions" }, phoneHref && (h("a", { href: phoneHref, class: "s-bullet-delivery-branch-action", title: Salla.lang.getWithDefault('pages.checkout.branch_call', 'اتصال'), onClick: e => e.stopPropagation() }, h("i", { class: "sicon-phone" }))), whatsappHref && (h("a", { href: whatsappHref, target: "_blank", rel: "noopener noreferrer", class: "s-bullet-delivery-branch-action", title: Salla.lang.getWithDefault('pages.checkout.branch_whatsapp', 'واتساب'), onClick: e => e.stopPropagation() }, h("i", { class: "sicon-whatsapp2" }))), directionsHref && (h("a", { href: directionsHref, target: "_blank", rel: "noopener noreferrer", class: "s-bullet-delivery-branch-action s-bullet-delivery-branch-map-link", title: Salla.lang.get('common.elements.open_in_google_maps'), onClick: e => e.stopPropagation() }, h("span", { class: "s-bullet-delivery-branch-map-link-icon", innerHTML: GetDirections.replace(/mask0_25437_34440/g, `mask0_branch_${branch.id}`), "aria-hidden": "true" }), h("span", { class: "sr-only" }, Salla.lang.get('common.elements.open_in_google_maps')))))));
|
|
2607
2887
|
}))));
|
|
2608
2888
|
}
|
|
2889
|
+
/** "يبعد عنك: ~" stays muted; the distance and its unit read as the value, as in checkout. */
|
|
2890
|
+
renderDistanceLabel(distance) {
|
|
2891
|
+
const template = Salla.lang.getWithDefault('pages.checkout.branch_distance_from_you', 'يبعد عنك: ~ {distance} كم');
|
|
2892
|
+
const index = template.indexOf('{distance}');
|
|
2893
|
+
if (index === -1)
|
|
2894
|
+
return template;
|
|
2895
|
+
return [
|
|
2896
|
+
h("span", { class: "s-bullet-delivery-branch-meta-label" }, template.slice(0, index)),
|
|
2897
|
+
h("span", { class: "s-bullet-delivery-branch-meta-value" }, template.slice(index).replace('{distance}', distance)),
|
|
2898
|
+
];
|
|
2899
|
+
}
|
|
2900
|
+
get isArabic() {
|
|
2901
|
+
return (Salla.lang.getLocale?.() ?? document.documentElement.lang) === 'ar';
|
|
2902
|
+
}
|
|
2903
|
+
formatClock(time) {
|
|
2904
|
+
return formatBranchClockTime(time, this.isArabic ? 'ar' : 'en');
|
|
2905
|
+
}
|
|
2906
|
+
/** "جاهز اليوم 10:00 ص" for a branch that is closed now and opens later today. */
|
|
2907
|
+
getReadyTodayLabel(branch) {
|
|
2908
|
+
const time = getBranchReadyTodayTime(branch);
|
|
2909
|
+
return time
|
|
2910
|
+
? `${Salla.lang.getWithDefault('pages.checkout.pickup_branch_ready_today_at', 'جاهز اليوم')} ${this.formatClock(time)}`
|
|
2911
|
+
: null;
|
|
2912
|
+
}
|
|
2913
|
+
/** "15-30 د" — compact preparation range for the card's meta row. */
|
|
2914
|
+
getPreparationShortLabel(range) {
|
|
2915
|
+
if (!range?.from || !range?.to)
|
|
2916
|
+
return null;
|
|
2917
|
+
const unitKeys = {
|
|
2918
|
+
minute: ['pages.checkout.preparation_time_minute_short', 'د'],
|
|
2919
|
+
hour: ['pages.checkout.preparation_time_hour_short', 'س'],
|
|
2920
|
+
day: ['pages.checkout.preparation_time_day_short', 'يوم'],
|
|
2921
|
+
};
|
|
2922
|
+
const unit = (u) => (unitKeys[u] ? Salla.lang.getWithDefault(unitKeys[u][0], unitKeys[u][1]) : null);
|
|
2923
|
+
const fromUnit = unit(range.from.unit);
|
|
2924
|
+
const toUnit = unit(range.to.unit);
|
|
2925
|
+
if (!fromUnit || !toUnit)
|
|
2926
|
+
return null;
|
|
2927
|
+
return range.from.unit === range.to.unit
|
|
2928
|
+
? `${range.from.value}-${range.to.value} ${toUnit}`
|
|
2929
|
+
: `${range.from.value} ${fromUnit} - ${range.to.value} ${toUnit}`;
|
|
2930
|
+
}
|
|
2931
|
+
/**
|
|
2932
|
+
* Busy, always-open, or the backend's `open_status_line` ("مفتوح - يغلق عند 11:00 م"), which reads
|
|
2933
|
+
* the hours on the branch's clock. Without that line, `is_open` gives a bare open/closed label.
|
|
2934
|
+
*/
|
|
2935
|
+
renderBranchOpenStatus(branch, hasSchedule, scheduleOpen) {
|
|
2936
|
+
const toggle = hasSchedule && (h("button", { type: "button", class: "s-bullet-delivery-branch-schedule-toggle", "aria-expanded": scheduleOpen ? 'true' : 'false', "aria-label": Salla.lang.getWithDefault('pages.checkout.pickup_show_weekly_hours', 'عرض ساعات العمل الأسبوعية'), onClick: e => {
|
|
2937
|
+
e.stopPropagation();
|
|
2938
|
+
this.toggleBranchSchedule(branch.id);
|
|
2939
|
+
} }, h("i", { class: { 'sicon-keyboard_arrow_down': true, 'is-expanded': scheduleOpen } })));
|
|
2940
|
+
if (isBranchBusy(branch)) {
|
|
2941
|
+
return (h("span", { class: "s-bullet-delivery-branch-meta s-bullet-delivery-branch-open-status" }, h("span", { class: "s-bullet-delivery-branch-meta-icon", innerHTML: WorkingHoursIcon, "aria-hidden": "true" }), h("span", { class: "s-bullet-delivery-pickup-status--busy" }, Salla.lang.getWithDefault('pages.checkout.pickup_branch_busy', 'مشغول، لا يستقبل طلبات')), toggle));
|
|
2942
|
+
}
|
|
2943
|
+
const alwaysOpen = isBranchAlwaysOpen(branch);
|
|
2944
|
+
const line = branch.pickup_readiness?.open_status_line;
|
|
2945
|
+
if (!alwaysOpen && line) {
|
|
2946
|
+
return (h("span", { class: "s-bullet-delivery-branch-meta s-bullet-delivery-branch-open-status" }, h("span", { class: "s-bullet-delivery-branch-meta-icon", innerHTML: WorkingHoursIcon, "aria-hidden": "true" }), h("span", null, line), toggle));
|
|
2947
|
+
}
|
|
2948
|
+
if (!alwaysOpen && !hasSchedule)
|
|
2949
|
+
return null;
|
|
2950
|
+
if (!alwaysOpen && typeof branch.is_open !== 'boolean') {
|
|
2951
|
+
return h("span", { class: "s-bullet-delivery-branch-meta s-bullet-delivery-branch-open-status" }, toggle);
|
|
2952
|
+
}
|
|
2953
|
+
const isOpen = alwaysOpen || branch.is_open;
|
|
2954
|
+
const label = alwaysOpen
|
|
2955
|
+
? Salla.lang.getWithDefault('pages.checkout.pickup_branch_always_open', 'مفتوح دائمًا 24/7')
|
|
2956
|
+
: isOpen
|
|
2957
|
+
? Salla.lang.getWithDefault('pages.checkout.pickup_branch_open', 'مفتوح')
|
|
2958
|
+
: Salla.lang.getWithDefault('pages.checkout.pickup_branch_closed', 'مغلق');
|
|
2959
|
+
return (h("span", { class: "s-bullet-delivery-branch-meta s-bullet-delivery-branch-open-status" }, h("span", { class: "s-bullet-delivery-branch-meta-icon", innerHTML: WorkingHoursIcon, "aria-hidden": "true" }), h("span", { class: isOpen ? 's-bullet-delivery-pickup-status--open' : 's-bullet-delivery-pickup-status--closed' }, label), toggle));
|
|
2960
|
+
}
|
|
2609
2961
|
renderPickupTab() {
|
|
2610
2962
|
return (h("div", { class: {
|
|
2611
2963
|
"s-bullet-delivery-content": true,
|
|
2612
2964
|
"s-bullet-delivery-content--active": this.activeTab === "branch",
|
|
2613
2965
|
"s-hidden": this.activeTab !== "branch",
|
|
2614
|
-
} }, this.renderCountrySelect(), this.renderBranchSearch(), this.renderBranchList()));
|
|
2966
|
+
} }, h("div", { class: "s-bullet-delivery-pickup-filters" }, h("div", { class: "s-bullet-delivery-pickup-filters-row" }, this.renderCountrySelect(false), this.renderBranchCitySelect()), this.renderBranchSearch()), this.renderBranchList()));
|
|
2967
|
+
}
|
|
2968
|
+
/** City filter for the pickup list; options come from the branches themselves, so none is empty. */
|
|
2969
|
+
renderBranchCitySelect() {
|
|
2970
|
+
return (h("div", { class: "s-bullet-delivery-field" }, h("salla-searchable-dropdown", { placeholder: Salla.lang.get("pages.checkout.select_city"), items: [{ id: -1, name: Salla.lang.getWithDefault('pages.checkout.all_cities', this.isArabic ? 'كل المدن' : 'All cities') }, ...this.branchCities], selectedItem: this.selectedBranchCity, loading: this.loadingBranches && this.branchCities.length === 0, disabled: this.branchCities.length === 0 && !this.selectedBranchCity, inputId: "bullet-delivery-branch-city", searchQuery: this.branchCitySearchQuery, clientSearch: true, onItemSelected: (e) => {
|
|
2971
|
+
this.branchCitySearchQuery = '';
|
|
2972
|
+
this.handleBranchCitySelected(e.detail);
|
|
2973
|
+
}, onSearchInput: (e) => {
|
|
2974
|
+
this.branchCitySearchQuery = e.detail;
|
|
2975
|
+
}, onDropdownClosed: () => {
|
|
2976
|
+
this.branchCitySearchQuery = '';
|
|
2977
|
+
} })));
|
|
2615
2978
|
}
|
|
2616
2979
|
/** Add-address form: map + confirm card in one screen, or dropdown fallback. */
|
|
2617
2980
|
renderAddAddressForm() {
|
|
@@ -2653,7 +3016,7 @@ export class SallaBulletDelivery {
|
|
|
2653
3016
|
return (h("div", { class: "s-bullet-delivery-footer" }, h("salla-button", { ref: (btn) => {
|
|
2654
3017
|
this.confirmBtn = btn;
|
|
2655
3018
|
}, disabled: this.isConfirmDisabled(), onClick: () => this.handleConfirm(), "loader-position": "center", width: "wide" }, this.activeTab === "branch"
|
|
2656
|
-
? Salla.lang.
|
|
3019
|
+
? Salla.lang.getWithDefault("pages.checkout.confirm_receipt_from_the_branch", "تأكيد الإستلام من الفرع")
|
|
2657
3020
|
: Salla.lang.get("pages.checkout.confirm_address")), showAddAddressInFooter && (h("salla-button", { onClick: () => this.handleAddNewAddress(), width: "wide", shape: "link" }, Salla.lang.get("pages.checkout.add_new_address"))), !this.isLoggedIn && (h("salla-button", { shape: "link", onClick: () => this.handleLogin() }, Salla.lang.get("pages.checkout.login_to_use_saved_addresses")))));
|
|
2658
3021
|
}
|
|
2659
3022
|
renderMainView() {
|
|
@@ -2679,7 +3042,7 @@ export class SallaBulletDelivery {
|
|
|
2679
3042
|
if (canOpenForIncompleteIntent) {
|
|
2680
3043
|
this.markIncompleteIntentPrompted();
|
|
2681
3044
|
}
|
|
2682
|
-
this.open();
|
|
3045
|
+
this.open(false, canOpenForIncompleteIntent ? "incomplete_intent" : "after_add_to_cart");
|
|
2683
3046
|
}
|
|
2684
3047
|
overrideScopeSwitchUI() {
|
|
2685
3048
|
const intent = this.getStoredIntent();
|
|
@@ -2732,7 +3095,7 @@ export class SallaBulletDelivery {
|
|
|
2732
3095
|
// silently awaiting with nothing visible.
|
|
2733
3096
|
if (!this.isGuestUser()) {
|
|
2734
3097
|
if (!this.modal?.hasAttribute?.("visible")) {
|
|
2735
|
-
this.open();
|
|
3098
|
+
this.open(false, "checkout_gate");
|
|
2736
3099
|
}
|
|
2737
3100
|
await this.pendingCartSubmitPromise;
|
|
2738
3101
|
return;
|
|
@@ -2761,7 +3124,7 @@ export class SallaBulletDelivery {
|
|
|
2761
3124
|
this.openGuestLogin();
|
|
2762
3125
|
return;
|
|
2763
3126
|
}
|
|
2764
|
-
this.open();
|
|
3127
|
+
this.open(false, "checkout_gate");
|
|
2765
3128
|
});
|
|
2766
3129
|
await this.pendingCartSubmitPromise;
|
|
2767
3130
|
};
|
|
@@ -2777,6 +3140,7 @@ export class SallaBulletDelivery {
|
|
|
2777
3140
|
Salla.event.on("salla::bullet-delivery.modal.open.requested", this.bulletDeliveryOpenHandler);
|
|
2778
3141
|
this.closeHandler = this.close.bind(this);
|
|
2779
3142
|
Salla.event.on("salla::bullet-delivery.modal.close.requested", this.closeHandler);
|
|
3143
|
+
Salla.event.on("modal::close", this.modalCloseHandler);
|
|
2780
3144
|
this.isRTL = Salla.config.get("theme.is_rtl");
|
|
2781
3145
|
// Reading the permission never prompts, so it's safe to watch from here — the map view then
|
|
2782
3146
|
// renders the notice (or not) on its first paint instead of a frame later.
|
|
@@ -2801,7 +3165,7 @@ export class SallaBulletDelivery {
|
|
|
2801
3165
|
return;
|
|
2802
3166
|
if (this.modal?.hasAttribute?.("visible"))
|
|
2803
3167
|
return;
|
|
2804
|
-
this.open();
|
|
3168
|
+
this.open(false, "after_login");
|
|
2805
3169
|
};
|
|
2806
3170
|
Salla.event.on("auth::logged.in", this.authLoggedInHandler);
|
|
2807
3171
|
this.authLoggedOutHandler = () => {
|
|
@@ -2833,9 +3197,12 @@ export class SallaBulletDelivery {
|
|
|
2833
3197
|
return null; // no-op when disabled
|
|
2834
3198
|
return (h(Host, { class: "s-bullet-delivery" }, h("salla-modal", { ref: modal => {
|
|
2835
3199
|
this.modal = modal;
|
|
2836
|
-
}, isClosable: !this.isRequired && !this.shouldForceNonClosable(),
|
|
3200
|
+
}, isClosable: !this.isRequired && !this.shouldForceNonClosable(), onModalVisibilityChanged: (event) => {
|
|
3201
|
+
if (event.target === this.modal)
|
|
3202
|
+
this.handleModalVisibility(Boolean(event.detail));
|
|
3203
|
+
}, class: "s-bullet-delivery-modal", width: "sm", "data-testid": "salla-bullet-delivery-modal" }, h("div", { class: "s-bullet-delivery-inner" }, h("div", { class: "s-bullet-delivery-header" }, h("h2", { class: "s-bullet-delivery-title" }, this.activeTab === 'address'
|
|
2837
3204
|
? Salla.lang.get('blocks.home.add_address_for_order_delivery')
|
|
2838
|
-
: Salla.lang.
|
|
3205
|
+
: Salla.lang.getWithDefault('blocks.home.choose_pickup_branch_title', this.isArabic ? 'اختر فرع استلام طلبك' : 'Choose your pickup branch')), h("p", { class: "s-bullet-delivery-subtitle" }, this.activeTab === 'address'
|
|
2839
3206
|
? Salla.lang.get('blocks.home.products_available_for_delivery_shown_while_shopping')
|
|
2840
3207
|
: Salla.lang.get('blocks.home.choose_branch_for_order_pickup_description'))), this.renderTabs(), this.viewMode === 'main' && this.renderMainView(), this.viewMode === 'add-address' && this.renderAddAddressForm()))));
|
|
2841
3208
|
}
|
|
@@ -2869,7 +3236,7 @@ export class SallaBulletDelivery {
|
|
|
2869
3236
|
// Handle pending open request (if event was emitted before component was ready)
|
|
2870
3237
|
if (this.pendingOpen) {
|
|
2871
3238
|
this.pendingOpen = false;
|
|
2872
|
-
this.open();
|
|
3239
|
+
this.open(false, this.openTrigger);
|
|
2873
3240
|
return;
|
|
2874
3241
|
}
|
|
2875
3242
|
// Strategy-based auto-open logic
|
|
@@ -2877,11 +3244,11 @@ export class SallaBulletDelivery {
|
|
|
2877
3244
|
case "first_visit":
|
|
2878
3245
|
// Open once per session when component mounts (per-session behaviour)
|
|
2879
3246
|
if (!this.hasBeenShownThisSession()) {
|
|
2880
|
-
this.open();
|
|
3247
|
+
this.open(false, "first_visit");
|
|
2881
3248
|
}
|
|
2882
3249
|
else if (this.shouldPromptIncompleteIntentThisSession()) {
|
|
2883
3250
|
this.markIncompleteIntentPrompted();
|
|
2884
|
-
this.open();
|
|
3251
|
+
this.open(false, "incomplete_intent");
|
|
2885
3252
|
}
|
|
2886
3253
|
break;
|
|
2887
3254
|
case "on_cart_click":
|
|
@@ -2889,11 +3256,11 @@ export class SallaBulletDelivery {
|
|
|
2889
3256
|
if (Salla.url.is_page("cart")) {
|
|
2890
3257
|
const shown = this.getShownStorage().get(this.sessionShownKey) === true;
|
|
2891
3258
|
if (!shown) {
|
|
2892
|
-
this.open();
|
|
3259
|
+
this.open(false, "on_cart_click");
|
|
2893
3260
|
}
|
|
2894
3261
|
else if (this.shouldPromptIncompleteIntentThisSession()) {
|
|
2895
3262
|
this.markIncompleteIntentPrompted();
|
|
2896
|
-
this.open();
|
|
3263
|
+
this.open(false, "incomplete_intent");
|
|
2897
3264
|
}
|
|
2898
3265
|
}
|
|
2899
3266
|
break;
|
|
@@ -2918,6 +3285,7 @@ export class SallaBulletDelivery {
|
|
|
2918
3285
|
this.stopWatchingLocationPermission = null;
|
|
2919
3286
|
}
|
|
2920
3287
|
Salla.event.off("salla::bullet-delivery.modal.open.requested", this.bulletDeliveryOpenHandler);
|
|
3288
|
+
Salla.event.off("modal::close", this.modalCloseHandler);
|
|
2921
3289
|
if (this.closeHandler) {
|
|
2922
3290
|
Salla.event.off("salla::bullet-delivery.modal.close.requested", this.closeHandler);
|
|
2923
3291
|
this.closeHandler = null;
|
|
@@ -2993,9 +3361,15 @@ export class SallaBulletDelivery {
|
|
|
2993
3361
|
"selectedSavedAddress": {},
|
|
2994
3362
|
"selectedSessionAddress": {},
|
|
2995
3363
|
"branches": {},
|
|
3364
|
+
"pickupDiscountRange": {},
|
|
3365
|
+
"pickupDiscountResolved": {},
|
|
2996
3366
|
"filteredBranches": {},
|
|
2997
3367
|
"selectedBranch": {},
|
|
2998
3368
|
"branchSearchQuery": {},
|
|
3369
|
+
"branchCities": {},
|
|
3370
|
+
"selectedBranchCity": {},
|
|
3371
|
+
"branchCitySearchQuery": {},
|
|
3372
|
+
"expandedScheduleBranchId": {},
|
|
2999
3373
|
"loadingCountries": {},
|
|
3000
3374
|
"loadingCities": {},
|
|
3001
3375
|
"loadingDistricts": {},
|
|
@@ -3116,16 +3490,25 @@ export class SallaBulletDelivery {
|
|
|
3116
3490
|
return {
|
|
3117
3491
|
"open": {
|
|
3118
3492
|
"complexType": {
|
|
3119
|
-
"signature": "(silent?: boolean) => Promise<void>",
|
|
3493
|
+
"signature": "(silent?: boolean, trigger?: SelectorTrigger) => Promise<void>",
|
|
3120
3494
|
"parameters": [{
|
|
3121
3495
|
"name": "silent",
|
|
3122
3496
|
"type": "boolean",
|
|
3123
3497
|
"docs": ""
|
|
3498
|
+
}, {
|
|
3499
|
+
"name": "trigger",
|
|
3500
|
+
"type": "\"first_visit\" | \"after_add_to_cart\" | \"on_cart_click\" | \"incomplete_intent\" | \"checkout_gate\" | \"after_login\" | \"customer_requested\"",
|
|
3501
|
+
"docs": ""
|
|
3124
3502
|
}],
|
|
3125
3503
|
"references": {
|
|
3126
3504
|
"Promise": {
|
|
3127
3505
|
"location": "global",
|
|
3128
3506
|
"id": "global::Promise"
|
|
3507
|
+
},
|
|
3508
|
+
"SelectorTrigger": {
|
|
3509
|
+
"location": "import",
|
|
3510
|
+
"path": "./selector-tracker",
|
|
3511
|
+
"id": "src/components/salla-bullet-delivery/selector-tracker.ts::SelectorTrigger"
|
|
3129
3512
|
}
|
|
3130
3513
|
},
|
|
3131
3514
|
"return": "Promise<void>"
|