@salla.sa/twilight-components 3.0.18 → 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.
Files changed (376) hide show
  1. package/dist/cjs/{Helper-D2VNt6eb.js → Helper-DqKJCL8G.js} +1 -1
  2. package/dist/cjs/{filepond-DkCudLhG.js → filepond-Byu0lc8z.js} +1 -1
  3. package/dist/cjs/{filepond-plugin-file-poster-C-uxFWfW.js → filepond-plugin-file-poster-qwx7lYZ-.js} +1 -1
  4. package/dist/cjs/{filepond-plugin-file-validate-size-BikXTQW2.js → filepond-plugin-file-validate-size-C-n0P4TT.js} +1 -1
  5. package/dist/cjs/{filepond-plugin-file-validate-type-Drs7PouU.js → filepond-plugin-file-validate-type-C8VOOXdT.js} +1 -1
  6. package/dist/cjs/{filepond-plugin-image-edit-hxr0h9kt.js → filepond-plugin-image-edit-B9KG763Y.js} +1 -1
  7. package/dist/cjs/{filepond-plugin-image-exif-orientation-CVZmWU_4.js → filepond-plugin-image-exif-orientation-Czt4pYzU.js} +1 -1
  8. package/dist/cjs/{filepond-plugin-image-preview-CBjPKx-d.js → filepond-plugin-image-preview-BFm1Zl0o.js} +1 -1
  9. package/dist/cjs/helpers-NV7wgP50.js +602 -0
  10. package/dist/cjs/{index-CTYg2zC6.js → index-CFW798jX.js} +2 -2
  11. package/dist/cjs/{intlTelInput-C9X0hKXV.js → intlTelInput-CLa2B89b.js} +1 -1
  12. package/dist/cjs/loader.cjs.js +2 -2
  13. package/dist/cjs/salla-accordion-body_2.cjs.entry.js +1 -1
  14. package/dist/cjs/salla-accordion_6.cjs.entry.js +2 -2
  15. package/dist/cjs/salla-add-product-button_5.cjs.entry.js +46 -3
  16. package/dist/cjs/salla-advertisement.cjs.entry.js +1 -1
  17. package/dist/cjs/salla-alert_2.cjs.entry.js +1 -1
  18. package/dist/cjs/salla-app-install-alert.cjs.entry.js +1 -1
  19. package/dist/cjs/salla-applied-filters.cjs.entry.js +2 -2
  20. package/dist/cjs/salla-apps-icons.cjs.entry.js +1 -1
  21. package/dist/cjs/salla-attachment-view_9.cjs.entry.js +11 -11
  22. package/dist/cjs/salla-badge.cjs.entry.js +1 -1
  23. package/dist/cjs/salla-basket-gap.cjs.entry.js +1 -1
  24. package/dist/cjs/salla-bullet-delivery_3.cjs.entry.js +425 -119
  25. package/dist/cjs/salla-cart-coupons.cjs.entry.js +1 -1
  26. package/dist/cjs/salla-cart-item-offers_2.cjs.entry.js +1 -1
  27. package/dist/cjs/salla-cart-summary-card.cjs.entry.js +1 -1
  28. package/dist/cjs/salla-cashback-banner.cjs.entry.js +1 -1
  29. package/dist/cjs/salla-comment-factors.cjs.entry.js +1 -1
  30. package/dist/cjs/salla-comment-form_9.cjs.entry.js +2 -2
  31. package/dist/cjs/salla-conditional-offer.cjs.entry.js +1 -1
  32. package/dist/cjs/salla-contacts.cjs.entry.js +1 -1
  33. package/dist/cjs/salla-cookies-bar.cjs.entry.js +1 -1
  34. package/dist/cjs/salla-count-down.cjs.entry.js +1 -1
  35. package/dist/cjs/salla-custom-fields.cjs.entry.js +1 -1
  36. package/dist/cjs/salla-delivery-promise.cjs.entry.js +2 -2
  37. package/dist/cjs/salla-edit-order-button.cjs.entry.js +1 -1
  38. package/dist/cjs/salla-filters-widget.cjs.entry.js +2 -2
  39. package/dist/cjs/salla-filters.cjs.entry.js +2 -2
  40. package/dist/cjs/salla-free-shipping-banner.cjs.entry.js +1 -1
  41. package/dist/cjs/salla-free-shipping-tag.cjs.entry.js +1 -1
  42. package/dist/cjs/salla-fulfillment-methods.cjs.entry.js +1 -1
  43. package/dist/cjs/salla-gift-card-redeem_2.cjs.entry.js +1 -1
  44. package/dist/cjs/salla-gifting.cjs.entry.js +1 -1
  45. package/dist/cjs/salla-hook.cjs.entry.js +1 -1
  46. package/dist/cjs/salla-infinite-scroll.cjs.entry.js +2 -2
  47. package/dist/cjs/salla-installment.cjs.entry.js +1 -1
  48. package/dist/cjs/salla-list-tile.cjs.entry.js +1 -1
  49. package/dist/cjs/salla-localization-modal.cjs.entry.js +1 -1
  50. package/dist/cjs/salla-login-modal.cjs.entry.js +7 -2
  51. package/dist/cjs/salla-loyalty-banner_10.cjs.entry.js +1 -1
  52. package/dist/cjs/salla-loyalty-exchange-product-card.cjs.entry.js +1 -1
  53. package/dist/cjs/salla-loyalty-points-banner.cjs.entry.js +1 -1
  54. package/dist/cjs/salla-loyalty-points-history.cjs.entry.js +1 -1
  55. package/dist/cjs/salla-loyalty-prize-item.cjs.entry.js +1 -1
  56. package/dist/cjs/salla-loyalty.cjs.entry.js +1 -1
  57. package/dist/cjs/salla-maintenance-alert.cjs.entry.js +1 -1
  58. package/dist/cjs/salla-map_3.cjs.entry.js +1 -1
  59. package/dist/cjs/salla-menu.cjs.entry.js +1 -1
  60. package/dist/cjs/salla-metadata.cjs.entry.js +1 -1
  61. package/dist/cjs/salla-multiple-bundle-product-cart_2.cjs.entry.js +1 -1
  62. package/dist/cjs/salla-multiple-bundle-product-options-modal_2.cjs.entry.js +1 -1
  63. package/dist/cjs/salla-multiple-bundle-product.cjs.entry.js +1 -1
  64. package/dist/cjs/salla-next-order-coupon.cjs.entry.js +1 -1
  65. package/dist/cjs/salla-notification-item_2.cjs.entry.js +2 -2
  66. package/dist/cjs/salla-offer-modal.cjs.entry.js +1 -1
  67. package/dist/cjs/salla-offer.cjs.entry.js +1 -1
  68. package/dist/cjs/salla-order-branch.cjs.entry.js +1 -1
  69. package/dist/cjs/salla-order-cancel.cjs.entry.js +1 -1
  70. package/dist/cjs/salla-order-details-multiple-bundle-product.cjs.entry.js +1 -1
  71. package/dist/cjs/salla-order-details-options.cjs.entry.js +1 -1
  72. package/dist/cjs/salla-order-details.cjs.entry.js +1 -1
  73. package/dist/cjs/salla-order-edit-item.cjs.entry.js +1 -1
  74. package/dist/cjs/salla-order-edit-product-card.cjs.entry.js +1 -1
  75. package/dist/cjs/salla-order-edit.cjs.entry.js +1 -1
  76. package/dist/cjs/salla-order-items.cjs.entry.js +1 -1
  77. package/dist/cjs/salla-order-options-modal.cjs.entry.js +1 -1
  78. package/dist/cjs/salla-order-payment.cjs.entry.js +1 -1
  79. package/dist/cjs/salla-order-rewards.cjs.entry.js +1 -1
  80. package/dist/cjs/salla-order-shipments.cjs.entry.js +1 -1
  81. package/dist/cjs/salla-order-summary.cjs.entry.js +1 -1
  82. package/dist/cjs/salla-order-totals-card.cjs.entry.js +1 -1
  83. package/dist/cjs/salla-orders.cjs.entry.js +2 -2
  84. package/dist/cjs/salla-payments.cjs.entry.js +1 -1
  85. package/dist/cjs/salla-placeholder.cjs.entry.js +1 -1
  86. package/dist/cjs/salla-price-range.cjs.entry.js +1 -1
  87. package/dist/cjs/salla-product-card-embed.cjs.entry.js +1 -1
  88. package/dist/cjs/salla-product-card.cjs.entry.js +1 -1
  89. package/dist/cjs/salla-product-size-guide.cjs.entry.js +1 -1
  90. package/dist/cjs/salla-products-list.cjs.entry.js +9 -2
  91. package/dist/cjs/salla-products-slider.cjs.entry.js +2 -2
  92. package/dist/cjs/salla-quick-order.cjs.entry.js +1 -1
  93. package/dist/cjs/salla-rating-modal-v2.cjs.entry.js +2 -2
  94. package/dist/cjs/salla-rating-modal.cjs.entry.js +2 -2
  95. package/dist/cjs/salla-review-factors-tags.cjs.entry.js +1 -1
  96. package/dist/cjs/salla-review-order-item.cjs.entry.js +1 -1
  97. package/dist/cjs/salla-scopes.cjs.entry.js +1 -1
  98. package/dist/cjs/salla-search-product-card.cjs.entry.js +1 -1
  99. package/dist/cjs/salla-search.cjs.entry.js +2 -2
  100. package/dist/cjs/salla-skeleton.cjs.entry.js +1 -1
  101. package/dist/cjs/salla-social-share.cjs.entry.js +1 -1
  102. package/dist/cjs/salla-social.cjs.entry.js +1 -1
  103. package/dist/cjs/salla-tab-content_3.cjs.entry.js +1 -1
  104. package/dist/cjs/salla-thank-you-header.cjs.entry.js +1 -1
  105. package/dist/cjs/salla-thank-you-page.cjs.entry.js +1 -1
  106. package/dist/cjs/salla-tiered-offer.cjs.entry.js +1 -1
  107. package/dist/cjs/salla-trust-badges.cjs.entry.js +1 -1
  108. package/dist/cjs/salla-user-menu.cjs.entry.js +1 -1
  109. package/dist/cjs/salla-user-profile.cjs.entry.js +1 -1
  110. package/dist/cjs/salla-user-settings.cjs.entry.js +1 -1
  111. package/dist/cjs/salla-verify.cjs.entry.js +1 -1
  112. package/dist/cjs/salla-wallet.cjs.entry.js +1 -1
  113. package/dist/cjs/salla-wishlist-actions.cjs.entry.js +1 -1
  114. package/dist/cjs/salla-wishlist-summary.cjs.entry.js +2 -2
  115. package/dist/cjs/twilight.cjs.js +2 -2
  116. package/dist/cjs/{vanilla-picker-BsLm8rHT.js → vanilla-picker-Vx_7G7bs.js} +1 -1
  117. package/dist/collection/components/salla-bullet-delivery/api-service.js +156 -25
  118. package/dist/collection/components/salla-bullet-delivery/helpers.js +143 -15
  119. package/dist/collection/components/salla-bullet-delivery/icons.js +17 -0
  120. package/dist/collection/components/salla-bullet-delivery/salla-bullet-delivery.css +490 -52
  121. package/dist/collection/components/salla-bullet-delivery/salla-bullet-delivery.js +417 -90
  122. package/dist/collection/components/salla-login-modal/salla-login-modal.js +6 -1
  123. package/dist/collection/components/salla-products-list/salla-products-list.js +7 -0
  124. package/dist/collection/components/salla-quick-buy/salla-quick-buy.js +44 -1
  125. package/dist/components/helpers.js +299 -40
  126. package/dist/components/index.js +2 -2
  127. package/dist/components/salla-bullet-delivery.js +430 -118
  128. package/dist/components/salla-login-modal2.js +6 -1
  129. package/dist/components/salla-products-list2.js +7 -0
  130. package/dist/components/salla-quick-buy2.js +44 -1
  131. package/dist/docs.json +1 -1
  132. package/dist/esm/{Helper-C1T-oD4J.js → Helper-I0CAizv1.js} +1 -1
  133. package/dist/esm/{filepond-BoWJzHeN.js → filepond-DTUYXV0J.js} +1 -1
  134. package/dist/esm/{filepond-plugin-file-poster-B6MkMtuC.js → filepond-plugin-file-poster-DydZjneT.js} +1 -1
  135. package/dist/esm/{filepond-plugin-file-validate-size-Dds_462B.js → filepond-plugin-file-validate-size-nbsCU2t9.js} +1 -1
  136. package/dist/esm/{filepond-plugin-file-validate-type-DrfGXNay.js → filepond-plugin-file-validate-type-Cl5B_DIy.js} +1 -1
  137. package/dist/esm/{filepond-plugin-image-edit-CN7eGg-7.js → filepond-plugin-image-edit-bzskFyFR.js} +1 -1
  138. package/dist/esm/{filepond-plugin-image-exif-orientation-CyhxK_6R.js → filepond-plugin-image-exif-orientation-MBDuxLaX.js} +1 -1
  139. package/dist/esm/{filepond-plugin-image-preview-DdKqAzT9.js → filepond-plugin-image-preview-N6wzEryW.js} +1 -1
  140. package/dist/esm/helpers-Cnh7Qptl.js +568 -0
  141. package/dist/esm/{index-DgUQRYr2.js → index-C9zdeQFI.js} +2 -2
  142. package/dist/esm/{intlTelInput-SwlavcFB.js → intlTelInput-B5L9nYtO.js} +1 -1
  143. package/dist/esm/loader.js +3 -3
  144. package/dist/esm/salla-accordion-body_2.entry.js +1 -1
  145. package/dist/esm/salla-accordion_6.entry.js +2 -2
  146. package/dist/esm/salla-add-product-button_5.entry.js +46 -3
  147. package/dist/esm/salla-advertisement.entry.js +1 -1
  148. package/dist/esm/salla-alert_2.entry.js +1 -1
  149. package/dist/esm/salla-app-install-alert.entry.js +1 -1
  150. package/dist/esm/salla-applied-filters.entry.js +2 -2
  151. package/dist/esm/salla-apps-icons.entry.js +1 -1
  152. package/dist/esm/salla-attachment-view_9.entry.js +11 -11
  153. package/dist/esm/salla-badge.entry.js +1 -1
  154. package/dist/esm/salla-basket-gap.entry.js +1 -1
  155. package/dist/esm/salla-bullet-delivery_3.entry.js +425 -119
  156. package/dist/esm/salla-cart-coupons.entry.js +1 -1
  157. package/dist/esm/salla-cart-item-offers_2.entry.js +1 -1
  158. package/dist/esm/salla-cart-summary-card.entry.js +1 -1
  159. package/dist/esm/salla-cashback-banner.entry.js +1 -1
  160. package/dist/esm/salla-comment-factors.entry.js +1 -1
  161. package/dist/esm/salla-comment-form_9.entry.js +2 -2
  162. package/dist/esm/salla-conditional-offer.entry.js +1 -1
  163. package/dist/esm/salla-contacts.entry.js +1 -1
  164. package/dist/esm/salla-cookies-bar.entry.js +1 -1
  165. package/dist/esm/salla-count-down.entry.js +1 -1
  166. package/dist/esm/salla-custom-fields.entry.js +1 -1
  167. package/dist/esm/salla-delivery-promise.entry.js +2 -2
  168. package/dist/esm/salla-edit-order-button.entry.js +1 -1
  169. package/dist/esm/salla-filters-widget.entry.js +2 -2
  170. package/dist/esm/salla-filters.entry.js +2 -2
  171. package/dist/esm/salla-free-shipping-banner.entry.js +1 -1
  172. package/dist/esm/salla-free-shipping-tag.entry.js +1 -1
  173. package/dist/esm/salla-fulfillment-methods.entry.js +1 -1
  174. package/dist/esm/salla-gift-card-redeem_2.entry.js +1 -1
  175. package/dist/esm/salla-gifting.entry.js +1 -1
  176. package/dist/esm/salla-hook.entry.js +1 -1
  177. package/dist/esm/salla-infinite-scroll.entry.js +2 -2
  178. package/dist/esm/salla-installment.entry.js +1 -1
  179. package/dist/esm/salla-list-tile.entry.js +1 -1
  180. package/dist/esm/salla-localization-modal.entry.js +1 -1
  181. package/dist/esm/salla-login-modal.entry.js +7 -2
  182. package/dist/esm/salla-loyalty-banner_10.entry.js +1 -1
  183. package/dist/esm/salla-loyalty-exchange-product-card.entry.js +1 -1
  184. package/dist/esm/salla-loyalty-points-banner.entry.js +1 -1
  185. package/dist/esm/salla-loyalty-points-history.entry.js +1 -1
  186. package/dist/esm/salla-loyalty-prize-item.entry.js +1 -1
  187. package/dist/esm/salla-loyalty.entry.js +1 -1
  188. package/dist/esm/salla-maintenance-alert.entry.js +1 -1
  189. package/dist/esm/salla-map_3.entry.js +1 -1
  190. package/dist/esm/salla-menu.entry.js +1 -1
  191. package/dist/esm/salla-metadata.entry.js +1 -1
  192. package/dist/esm/salla-multiple-bundle-product-cart_2.entry.js +1 -1
  193. package/dist/esm/salla-multiple-bundle-product-options-modal_2.entry.js +1 -1
  194. package/dist/esm/salla-multiple-bundle-product.entry.js +1 -1
  195. package/dist/esm/salla-next-order-coupon.entry.js +1 -1
  196. package/dist/esm/salla-notification-item_2.entry.js +2 -2
  197. package/dist/esm/salla-offer-modal.entry.js +1 -1
  198. package/dist/esm/salla-offer.entry.js +1 -1
  199. package/dist/esm/salla-order-branch.entry.js +1 -1
  200. package/dist/esm/salla-order-cancel.entry.js +1 -1
  201. package/dist/esm/salla-order-details-multiple-bundle-product.entry.js +1 -1
  202. package/dist/esm/salla-order-details-options.entry.js +1 -1
  203. package/dist/esm/salla-order-details.entry.js +1 -1
  204. package/dist/esm/salla-order-edit-item.entry.js +1 -1
  205. package/dist/esm/salla-order-edit-product-card.entry.js +1 -1
  206. package/dist/esm/salla-order-edit.entry.js +1 -1
  207. package/dist/esm/salla-order-items.entry.js +1 -1
  208. package/dist/esm/salla-order-options-modal.entry.js +1 -1
  209. package/dist/esm/salla-order-payment.entry.js +1 -1
  210. package/dist/esm/salla-order-rewards.entry.js +1 -1
  211. package/dist/esm/salla-order-shipments.entry.js +1 -1
  212. package/dist/esm/salla-order-summary.entry.js +1 -1
  213. package/dist/esm/salla-order-totals-card.entry.js +1 -1
  214. package/dist/esm/salla-orders.entry.js +2 -2
  215. package/dist/esm/salla-payments.entry.js +1 -1
  216. package/dist/esm/salla-placeholder.entry.js +1 -1
  217. package/dist/esm/salla-price-range.entry.js +1 -1
  218. package/dist/esm/salla-product-card-embed.entry.js +1 -1
  219. package/dist/esm/salla-product-card.entry.js +1 -1
  220. package/dist/esm/salla-product-size-guide.entry.js +1 -1
  221. package/dist/esm/salla-products-list.entry.js +9 -2
  222. package/dist/esm/salla-products-slider.entry.js +2 -2
  223. package/dist/esm/salla-quick-order.entry.js +1 -1
  224. package/dist/esm/salla-rating-modal-v2.entry.js +2 -2
  225. package/dist/esm/salla-rating-modal.entry.js +2 -2
  226. package/dist/esm/salla-review-factors-tags.entry.js +1 -1
  227. package/dist/esm/salla-review-order-item.entry.js +1 -1
  228. package/dist/esm/salla-scopes.entry.js +1 -1
  229. package/dist/esm/salla-search-product-card.entry.js +1 -1
  230. package/dist/esm/salla-search.entry.js +2 -2
  231. package/dist/esm/salla-skeleton.entry.js +1 -1
  232. package/dist/esm/salla-social-share.entry.js +1 -1
  233. package/dist/esm/salla-social.entry.js +1 -1
  234. package/dist/esm/salla-tab-content_3.entry.js +1 -1
  235. package/dist/esm/salla-thank-you-header.entry.js +1 -1
  236. package/dist/esm/salla-thank-you-page.entry.js +1 -1
  237. package/dist/esm/salla-tiered-offer.entry.js +1 -1
  238. package/dist/esm/salla-trust-badges.entry.js +1 -1
  239. package/dist/esm/salla-user-menu.entry.js +1 -1
  240. package/dist/esm/salla-user-profile.entry.js +1 -1
  241. package/dist/esm/salla-user-settings.entry.js +1 -1
  242. package/dist/esm/salla-verify.entry.js +1 -1
  243. package/dist/esm/salla-wallet.entry.js +1 -1
  244. package/dist/esm/salla-wishlist-actions.entry.js +1 -1
  245. package/dist/esm/salla-wishlist-summary.entry.js +2 -2
  246. package/dist/esm/twilight.js +3 -3
  247. package/dist/esm/{vanilla-picker-Buy50D7t.js → vanilla-picker-CAeu4f87.js} +1 -1
  248. package/dist/twilight/{p-bed54154.entry.js → p-01d5cd61.entry.js} +1 -1
  249. package/dist/twilight/{p-b3ada3d0.entry.js → p-0213fde4.entry.js} +1 -1
  250. package/dist/twilight/{p-d0ff9a3e.entry.js → p-036fbfc0.entry.js} +1 -1
  251. package/dist/twilight/{p-53735934.entry.js → p-0add41ce.entry.js} +1 -1
  252. package/dist/twilight/{p-bb8b2c85.entry.js → p-0b0d4942.entry.js} +1 -1
  253. package/dist/twilight/{p-d1121b3f.entry.js → p-17bcbf9b.entry.js} +1 -1
  254. package/dist/twilight/{p-6b5de500.entry.js → p-1867f7d4.entry.js} +1 -1
  255. package/dist/twilight/{p-ee65c489.entry.js → p-194ff38c.entry.js} +1 -1
  256. package/dist/twilight/{p-4ab5ee99.entry.js → p-20f9c62f.entry.js} +1 -1
  257. package/dist/twilight/{p-5e8d019e.entry.js → p-252748d9.entry.js} +1 -1
  258. package/dist/twilight/{p-6c3084c9.entry.js → p-290ce0bc.entry.js} +1 -1
  259. package/dist/twilight/{p-5694edf1.entry.js → p-2b930157.entry.js} +1 -1
  260. package/dist/twilight/{p-7fd9dc36.entry.js → p-2e4e15c5.entry.js} +1 -1
  261. package/dist/twilight/{p-b9d67694.entry.js → p-2e6537a3.entry.js} +1 -1
  262. package/dist/twilight/{p-7f97335a.entry.js → p-30d64bd1.entry.js} +1 -1
  263. package/dist/twilight/{p-516e4edc.entry.js → p-32495dd2.entry.js} +1 -1
  264. package/dist/twilight/{p-e9b03e9c.entry.js → p-32d9da31.entry.js} +1 -1
  265. package/dist/twilight/{p-9d15f22d.entry.js → p-32f100f8.entry.js} +1 -1
  266. package/dist/twilight/{p-6dccd40f.entry.js → p-386b3dcd.entry.js} +1 -1
  267. package/dist/twilight/{p-d1093a59.entry.js → p-3a4e86d1.entry.js} +1 -1
  268. package/dist/twilight/{p-f7a58656.entry.js → p-3b766a79.entry.js} +1 -1
  269. package/dist/twilight/{p-361f6033.entry.js → p-3b7a45ec.entry.js} +1 -1
  270. package/dist/twilight/{p-9cf1cfd4.entry.js → p-3bb0e184.entry.js} +1 -1
  271. package/dist/twilight/{p-b0d2e31f.entry.js → p-3cc6ca6c.entry.js} +1 -1
  272. package/dist/twilight/{p-d4fb9921.entry.js → p-4070f808.entry.js} +1 -1
  273. package/dist/twilight/{p-af49191f.entry.js → p-412fb721.entry.js} +1 -1
  274. package/dist/twilight/{p-5f6fee0e.entry.js → p-427c13b6.entry.js} +1 -1
  275. package/dist/twilight/{p-be6f8551.entry.js → p-45e0a5d0.entry.js} +1 -1
  276. package/dist/twilight/{p-c4cf0b4d.entry.js → p-4d615f9f.entry.js} +1 -1
  277. package/dist/twilight/{p-fddf1997.entry.js → p-4d7fc363.entry.js} +1 -1
  278. package/dist/twilight/{p-9e042cce.entry.js → p-5009f654.entry.js} +1 -1
  279. package/dist/twilight/{p-d9a1bf08.entry.js → p-50853b76.entry.js} +1 -1
  280. package/dist/twilight/{p-eaf0c514.entry.js → p-550ad1a6.entry.js} +1 -1
  281. package/dist/twilight/{p-3f842f32.entry.js → p-575014c4.entry.js} +1 -1
  282. package/dist/twilight/{p-66ad7a30.entry.js → p-5aee5e44.entry.js} +1 -1
  283. package/dist/twilight/{p-8c1d14f0.entry.js → p-619c709c.entry.js} +1 -1
  284. package/dist/twilight/{p-cdeb9bcc.entry.js → p-6d572fe0.entry.js} +1 -1
  285. package/dist/twilight/{p-12a25415.entry.js → p-6f84c662.entry.js} +1 -1
  286. package/dist/twilight/{p-b5a45f87.entry.js → p-703b9253.entry.js} +1 -1
  287. package/dist/twilight/{p-a5b732b3.entry.js → p-73dea22d.entry.js} +1 -1
  288. package/dist/twilight/{p-a44670a9.entry.js → p-74285af9.entry.js} +1 -1
  289. package/dist/twilight/{p-b1f808f5.entry.js → p-777d28f6.entry.js} +1 -1
  290. package/dist/twilight/{p-027cbda6.entry.js → p-7db6ccfe.entry.js} +1 -1
  291. package/dist/twilight/{p-0418c2df.entry.js → p-7db8d545.entry.js} +1 -1
  292. package/dist/twilight/{p-da0df10b.entry.js → p-7fa4d0b6.entry.js} +1 -1
  293. package/dist/twilight/{p-78a56dc6.entry.js → p-825c5b73.entry.js} +1 -1
  294. package/dist/twilight/{p-4b70e6c4.entry.js → p-8262e669.entry.js} +1 -1
  295. package/dist/twilight/p-86d55a6b.entry.js +4 -0
  296. package/dist/twilight/{p-259c995a.entry.js → p-8712f7c7.entry.js} +1 -1
  297. package/dist/twilight/{p-08a15c81.entry.js → p-8948b58c.entry.js} +1 -1
  298. package/dist/twilight/{p-aa35cf98.entry.js → p-8b8cf457.entry.js} +1 -1
  299. package/dist/twilight/{p-d0aeeb7f.entry.js → p-8c2992e7.entry.js} +1 -1
  300. package/dist/twilight/{p-79822d99.entry.js → p-8c548259.entry.js} +1 -1
  301. package/dist/twilight/{p-6af8a7b6.entry.js → p-8eb3fd92.entry.js} +1 -1
  302. package/dist/twilight/p-908716fb.entry.js +4 -0
  303. package/dist/twilight/{p-70dfb2b4.entry.js → p-90a59027.entry.js} +1 -1
  304. package/dist/twilight/{p-37192614.entry.js → p-9683535f.entry.js} +1 -1
  305. package/dist/twilight/{p-f9e5ed10.entry.js → p-982e9124.entry.js} +1 -1
  306. package/dist/twilight/{p-0d795b58.entry.js → p-995b898f.entry.js} +1 -1
  307. package/dist/twilight/{p-d1204965.entry.js → p-99cb3dba.entry.js} +1 -1
  308. package/dist/twilight/{p-071aa0e7.entry.js → p-9a0218a6.entry.js} +1 -1
  309. package/dist/twilight/{p-eefced26.entry.js → p-9cf31ff4.entry.js} +1 -1
  310. package/dist/twilight/{p-4891c565.entry.js → p-9d1a5007.entry.js} +1 -1
  311. package/dist/twilight/{p-f9587127.entry.js → p-9e429047.entry.js} +1 -1
  312. package/dist/twilight/p-9e542951.entry.js +4 -0
  313. package/dist/twilight/{p-BxQMWsr9.js → p-BcT9tEVW.js} +1 -1
  314. package/dist/twilight/{p-Y2ZIN9Ok.js → p-Bgu5gtOF.js} +1 -1
  315. package/dist/twilight/{p-DgUQRYr2.js → p-C9zdeQFI.js} +2 -2
  316. package/dist/twilight/{p-CCwsxMbZ.js → p-CSGj1pY-.js} +1 -1
  317. package/dist/twilight/{p-Ca_SZn0u.js → p-CWWgpQ8Q.js} +1 -1
  318. package/dist/twilight/{p-CgNJWeaK.js → p-Cfz9xit3.js} +1 -1
  319. package/dist/twilight/{p-BK9YeXWp.js → p-CmYSalnM.js} +1 -1
  320. package/dist/twilight/p-Cnh7Qptl.js +4 -0
  321. package/dist/twilight/{p-De1tLqQF.js → p-Dav_R_d2.js} +1 -1
  322. package/dist/twilight/{p-DMvhNbgN.js → p-JGEddAgs.js} +1 -1
  323. package/dist/twilight/{p-CBLWEyM9.js → p-RflSBQNB.js} +1 -1
  324. package/dist/twilight/{p-NqQdbGu6.js → p-Xgbueas7.js} +1 -1
  325. package/dist/twilight/{p-ba6dd59c.entry.js → p-a070cce0.entry.js} +1 -1
  326. package/dist/twilight/{p-1960020c.entry.js → p-a0bfedad.entry.js} +1 -1
  327. package/dist/twilight/{p-f7ab5825.entry.js → p-a22d9931.entry.js} +1 -1
  328. package/dist/twilight/{p-a95b0dc1.entry.js → p-a3959219.entry.js} +1 -1
  329. package/dist/twilight/p-a3ca61af.entry.js +4 -0
  330. package/dist/twilight/{p-e457e68f.entry.js → p-a55b5c44.entry.js} +1 -1
  331. package/dist/twilight/{p-23772523.entry.js → p-a5fc8358.entry.js} +1 -1
  332. package/dist/twilight/{p-3a632c69.entry.js → p-aabcd09f.entry.js} +1 -1
  333. package/dist/twilight/{p-d8955835.entry.js → p-ad00021e.entry.js} +1 -1
  334. package/dist/twilight/{p-481f52b1.entry.js → p-ade9a68c.entry.js} +1 -1
  335. package/dist/twilight/{p-4a3fa153.entry.js → p-b5e0065a.entry.js} +1 -1
  336. package/dist/twilight/{p-bed68e52.entry.js → p-bbb09d92.entry.js} +1 -1
  337. package/dist/twilight/{p-9e65451e.entry.js → p-c2df20f8.entry.js} +1 -1
  338. package/dist/twilight/{p-1af9db24.entry.js → p-c4274188.entry.js} +1 -1
  339. package/dist/twilight/{p-bfd5e263.entry.js → p-c5e2c781.entry.js} +1 -1
  340. package/dist/twilight/{p-e38a6793.entry.js → p-c64b2b22.entry.js} +1 -1
  341. package/dist/twilight/{p-3d8b77f7.entry.js → p-c92cc92f.entry.js} +1 -1
  342. package/dist/twilight/{p-ac736b30.entry.js → p-cb54adac.entry.js} +1 -1
  343. package/dist/twilight/{p-5bbf17dd.entry.js → p-ce1e45a3.entry.js} +1 -1
  344. package/dist/twilight/{p-fcb1009f.entry.js → p-d0acd7ff.entry.js} +1 -1
  345. package/dist/twilight/{p-92fd20a0.entry.js → p-d0f903ac.entry.js} +1 -1
  346. package/dist/twilight/{p-26d2b28a.entry.js → p-d57b49ff.entry.js} +1 -1
  347. package/dist/twilight/{p-8766e236.entry.js → p-db3efb27.entry.js} +1 -1
  348. package/dist/twilight/{p-0f25fedd.entry.js → p-db73d0bf.entry.js} +1 -1
  349. package/dist/twilight/{p-6e52b649.entry.js → p-e20d5e75.entry.js} +1 -1
  350. package/dist/twilight/{p-254cff9a.entry.js → p-e223beca.entry.js} +1 -1
  351. package/dist/twilight/{p-8c40278d.entry.js → p-e37da59f.entry.js} +1 -1
  352. package/dist/twilight/{p-84b0e7a9.entry.js → p-e3991836.entry.js} +1 -1
  353. package/dist/twilight/{p-cb48a5ef.entry.js → p-e455709f.entry.js} +1 -1
  354. package/dist/twilight/{p-9e0a9a5a.entry.js → p-e921b2d1.entry.js} +1 -1
  355. package/dist/twilight/{p-0ba159db.entry.js → p-ec356e5a.entry.js} +1 -1
  356. package/dist/twilight/{p-34148827.entry.js → p-eeefc285.entry.js} +1 -1
  357. package/dist/twilight/{p-6ba3808a.entry.js → p-f3b12754.entry.js} +1 -1
  358. package/dist/twilight/{p-419d6d71.entry.js → p-f6279a13.entry.js} +1 -1
  359. package/dist/twilight/{p-487b4411.entry.js → p-f83efc62.entry.js} +1 -1
  360. package/dist/twilight/{p-7b5f97e7.entry.js → p-fa622715.entry.js} +1 -1
  361. package/dist/twilight/{p-ee479819.entry.js → p-faf00404.entry.js} +1 -1
  362. package/dist/twilight/twilight.esm.js +1 -1
  363. package/dist/types/components/salla-bullet-delivery/api-service.d.ts +23 -7
  364. package/dist/types/components/salla-bullet-delivery/helpers.d.ts +61 -6
  365. package/dist/types/components/salla-bullet-delivery/icons.d.ts +14 -0
  366. package/dist/types/components/salla-bullet-delivery/interfaces.d.ts +36 -1
  367. package/dist/types/components/salla-bullet-delivery/salla-bullet-delivery.d.ts +73 -2
  368. package/dist/types/components/salla-quick-buy/salla-quick-buy.d.ts +6 -0
  369. package/package.json +5 -5
  370. package/dist/cjs/helpers-8bMfm_mm.js +0 -329
  371. package/dist/esm/helpers-DqzaeXrL.js +0 -309
  372. package/dist/twilight/p-76584a5b.entry.js +0 -4
  373. package/dist/twilight/p-DqzaeXrL.js +0 -4
  374. package/dist/twilight/p-bac25e34.entry.js +0 -4
  375. package/dist/twilight/p-d346dabd.entry.js +0 -4
  376. package/dist/twilight/p-e24fbbb4.entry.js +0 -4
@@ -343,9 +343,14 @@ export class SallaLoginModal {
343
343
  });
344
344
  }
345
345
  async handleGuestCheckout() {
346
+ // buy now resumes its own flow; emitted before closing so the dismissal doesn't race it
347
+ if (this.source === 'buy-now') {
348
+ Salla.event.emit('salla-login::guest-chosen', { source: this.source });
349
+ return this.modal.close();
350
+ }
346
351
  this.modal.close();
347
352
  if (salla.config.isGuest()) {
348
- return salla.cart.submit(false, true);
353
+ return salla.cart.submit(false, true, true);
349
354
  }
350
355
  }
351
356
  openModal() {
@@ -1181,6 +1181,13 @@ export class SallaProductsList {
1181
1181
  ?.find(filter => filter.key === 'category_id')
1182
1182
  // loose == : catId may be a number (auto-appended page.id) while API keys are strings
1183
1183
  ?.values?.find(cat => cat.key == catId)?.value ?? '';
1184
+ // without the filters feature the response has no `filters`, so the lookup above finds no name and the
1185
+ // theme would swap the page heading for a bare count; the page itself still names its own list.
1186
+ // page.title is raw text that themes drop into innerHTML, so it's escaped like the search term
1187
+ const pageId = salla.config.get('page.id');
1188
+ if (!title && catId != null && pageId != null && String(catId) === String(pageId)) {
1189
+ title = Helper.escapeHtml(salla.config.get('page.title'));
1190
+ }
1184
1191
  }
1185
1192
  title +=
1186
1193
  (title ? ' - ' : '') +
@@ -47,6 +47,9 @@ export class SallaQuickBuy {
47
47
  /** Session from the initial gesture; begun later when there are no order options. */
48
48
  this.pendingApplePaySession = null;
49
49
  this.quickBuy = salla.lang.get('pages.products.buy_now');
50
+ /** The guest picked "continue as guest" on the login step, so don't ask again. */
51
+ this.choseGuest = false;
52
+ this.cancelLoginAsk = null;
50
53
  /** Apple Pay onStartedSession: first call defers begin() to run the OO check; second (resolved) begins. */
51
54
  this.handleApplePaySessionStarted = (session) => {
52
55
  // Previously gated on `order_options.mandatory`, which is unrelated to CP-2836: a store with
@@ -114,6 +117,7 @@ export class SallaQuickBuy {
114
117
  salla?.event?.off?.('product-options::donation-changed', this.donationChangedListener);
115
118
  salla?.product?.event?.offPriceUpdated?.(this.priceUpdatedListener);
116
119
  this.langUnsubscribe?.();
120
+ this.cancelLoginAsk?.();
117
121
  }
118
122
  quickBuyHandler() {
119
123
  if (salla.config.isGuest() && !this.isGuestCheckout()) {
@@ -121,6 +125,10 @@ export class SallaQuickBuy {
121
125
  salla.api.auth.requireLoginThen('salla-quick-buy::user.logged-in', () => this.quickBuyHandler());
122
126
  return;
123
127
  }
128
+ if (this.shouldAskLoginFirst()) {
129
+ this.askLoginFirst();
130
+ return;
131
+ }
124
132
  // Sync validate — AP needs the gesture preserved for new ApplePaySession().
125
133
  if (!this.validatePdpOptionsSync())
126
134
  return;
@@ -188,7 +196,10 @@ export class SallaQuickBuy {
188
196
  injectFreeProductsIntoPayload(data, this.collectedFreeProducts);
189
197
  // if the store doesn't have Apple Pay , just create a cart and then redirect to check out page
190
198
  if (!this.isApplePayActive) {
191
- return salla.api.request('checkout/mini', data, 'post')
199
+ // tells checkout the guest already chose guest, so it opens on the guest form —
200
+ // re-check isGuest(): a login since the choice must not send guest params authenticated
201
+ const options = this.choseGuest && salla.config.isGuest() ? { params: { guest_checkout: 1, chose_guest: 1 } } : {};
202
+ return salla.api.request('checkout/mini', data, 'post', options)
192
203
  .catch(err => this.legacyQuickPurchaseFallback(err, data))
193
204
  .then(resp => {
194
205
  // mini-checkout answers {to, url}; legacy quick-purchase answered {redirect}
@@ -313,6 +324,38 @@ export class SallaQuickBuy {
313
324
  salla.logger.warn('quick-buy: falling back to quick-purchase because of token_not_provided');
314
325
  return salla.api.request('checkout/quick-purchase/' + this.productId, data, 'post');
315
326
  }
327
+ /** login-before-checkout variant: offer login or guest before buy now. Not for Apple Pay, which must open on the tap. */
328
+ shouldAskLoginFirst() {
329
+ return salla.config.isGuest()
330
+ && !this.choseGuest
331
+ && !this.isApplePayActive
332
+ && salla.cart.loginBeforeCheckoutGroup?.() === 'variant';
333
+ }
334
+ askLoginFirst() {
335
+ // a second click before the popup settles must replace the pending ask, not stack a listener
336
+ this.cancelLoginAsk?.();
337
+ const stop = () => {
338
+ salla.event.off('salla-login::guest-chosen', onGuest);
339
+ salla.event.off('salla-login::dismissed', stop);
340
+ this.cancelLoginAsk = null;
341
+ };
342
+ this.cancelLoginAsk = stop;
343
+ const onGuest = (detail) => {
344
+ if (detail?.source !== 'buy-now')
345
+ return;
346
+ stop();
347
+ this.choseGuest = true;
348
+ this.quickBuyHandler();
349
+ };
350
+ salla.event.on('salla-login::guest-chosen', onGuest);
351
+ salla.event.on('salla-login::dismissed', stop);
352
+ this.requireLogin.emit({ productId: this.productId });
353
+ salla.api.auth.requireLoginThen('salla-quick-buy::user.logged-in', () => {
354
+ stop();
355
+ this.choseGuest = false;
356
+ this.quickBuyHandler();
357
+ }, null, 'buy-now');
358
+ }
316
359
  isGuestCheckout() {
317
360
  return salla.config.isGuest() && this.isGuestCheckoutAllowed() && this.isPhysicalProduct();
318
361
  }
@@ -21,6 +21,8 @@ async function withApiErrorHandling(fn, fallback, logLabel) {
21
21
  }
22
22
  const apiCache = new Map();
23
23
  const CACHE_TTL = 5 * 60 * 1000;
24
+ let branchCacheGeneration = 0;
25
+ const resolvedBranchPages = new WeakMap();
24
26
  function getCached(key) {
25
27
  const entry = apiCache.get(key);
26
28
  if (!entry || Date.now() - entry.timestamp > CACHE_TTL) {
@@ -32,6 +34,47 @@ function getCached(key) {
32
34
  function setCache(key, data) {
33
35
  apiCache.set(key, { data, timestamp: Date.now() });
34
36
  }
37
+ function getCountryBranches(branches, countryId) {
38
+ if (!branches || countryId == null)
39
+ return branches;
40
+ if (branches.some(branch => branch.country?.id == null))
41
+ return null;
42
+ const matches = branches.filter(branch => String(branch.country?.id) === String(countryId));
43
+ return matches.length ? matches : null;
44
+ }
45
+ function getBranchPage({ query, lat, lng, country_id, city_id, page, per_page = 20 }, cachePage = true) {
46
+ const params = { per_page };
47
+ if (query && query.trim().length >= 2)
48
+ params.query = query;
49
+ if (lat)
50
+ params.lat = Number(lat).toFixed(6);
51
+ if (lng)
52
+ params.lng = Number(lng).toFixed(6);
53
+ if (country_id)
54
+ params.country_id = country_id;
55
+ if (city_id)
56
+ params.city_id = city_id;
57
+ if (page && page > 1)
58
+ params.page = page;
59
+ const cacheKey = `branches_${JSON.stringify(params)}`;
60
+ const cached = cachePage ? getCached(cacheKey) : null;
61
+ if (cached)
62
+ return cached;
63
+ const request = (async () => {
64
+ const res = await salla.api.request('branches', { params });
65
+ if (!Array.isArray(res?.data))
66
+ throw new Error('Invalid branches response');
67
+ return { branches: res.data, perPage: per_page, pagination: res.pagination };
68
+ })();
69
+ if (cachePage)
70
+ setCache(cacheKey, request);
71
+ void request.then(page => { resolvedBranchPages.set(request, page); }, () => { });
72
+ void request.catch(() => {
73
+ if (apiCache.get(cacheKey)?.data === request)
74
+ apiCache.delete(cacheKey);
75
+ });
76
+ return request;
77
+ }
35
78
  /** Uses country code from API (e.g. 'SA'). */
36
79
  const isSaudiArabia = (countryCode) => String(countryCode).toUpperCase() === 'SA';
37
80
  /**
@@ -141,30 +184,105 @@ const bulletDeliveryAPI = {
141
184
  return Array.isArray(data) ? data : [];
142
185
  }, [], 'Error fetching user addresses');
143
186
  },
144
- async getBranches({ query, lat, lng, country_id, per_page = 20 } = {}) {
145
- const hasSearchParams = query?.trim()?.length >= 2 || lat || lng;
146
- const cacheKey = !hasSearchParams && country_id ? `branches_${country_id}` : null;
147
- if (cacheKey) {
148
- const cached = getCached(cacheKey);
149
- if (cached)
150
- return cached;
187
+ /** Complete country rows for the city picker; incomplete reads remain retryable. */
188
+ async getAllBranches(country_id, per_page = 20) {
189
+ const collection = await this.getBranchCollection(country_id, per_page, { maxPages: Number.POSITIVE_INFINITY });
190
+ if (!collection.complete)
191
+ throw Object.assign(new Error('Incomplete branch city collection'), { branches: collection.branches });
192
+ return collection.branches;
193
+ },
194
+ /** Keeps loaded branches separate from whether the collection is complete. */
195
+ async getBranchCollection(country_id, per_page = 20, { maxPages = 10, requireComplete = false } = {}) {
196
+ const generation = branchCacheGeneration;
197
+ const cacheKey = `branches_all_${JSON.stringify([country_id ?? null, per_page, maxPages, requireComplete])}`;
198
+ const cached = Number.isFinite(maxPages) ? getCached(cacheKey) : null;
199
+ if (cached)
200
+ return cached;
201
+ const storeBranches = country_id != null ? getCached('branches_all') : null;
202
+ if (country_id == null)
203
+ setCache('branches_first', getBranchPage({ per_page, page: 1 }));
204
+ const partial = { branches: [], complete: false };
205
+ const request = withApiErrorHandling(async () => {
206
+ const sharedFirstPage = storeBranches ? getCached('branches_first') : null;
207
+ const first = sharedFirstPage ? resolvedBranchPages.get(sharedFirstPage) : null;
208
+ if (storeBranches && getCountryBranches(first?.branches ?? null, country_id)) {
209
+ const collection = await storeBranches;
210
+ if (generation !== branchCacheGeneration)
211
+ return { branches: [], complete: false };
212
+ const branches = collection.complete ? getCountryBranches(collection.branches, country_id) : null;
213
+ if (branches)
214
+ return { branches, complete: true };
215
+ }
216
+ for (let page = 1; page <= maxPages; page++) {
217
+ const { branches, pagination } = await getBranchPage({ country_id, per_page, page }, Number.isFinite(maxPages) || page === 1);
218
+ if (generation !== branchCacheGeneration)
219
+ return { branches: [], complete: false };
220
+ const currentPage = Number(pagination?.currentPage ?? page);
221
+ const totalPages = Number(pagination?.totalPages);
222
+ if (page === 1 && totalPages === 0 && !branches.length)
223
+ return { branches: [], complete: true };
224
+ if (pagination && (currentPage !== page || !Number.isInteger(totalPages) || totalPages < page)) {
225
+ throw new Error('Invalid branches pagination');
226
+ }
227
+ partial.branches.push(...branches);
228
+ if (pagination) {
229
+ if (requireComplete && totalPages > maxPages)
230
+ return partial;
231
+ if (page === totalPages)
232
+ return { branches: partial.branches, complete: true };
233
+ if (!branches.length)
234
+ throw new Error('Incomplete branches response');
235
+ }
236
+ else if (branches.length < per_page) {
237
+ return { branches: partial.branches, complete: true };
238
+ }
239
+ }
240
+ return partial;
241
+ }, partial, 'Error fetching all branches');
242
+ setCache(cacheKey, request);
243
+ if (country_id == null)
244
+ setCache('branches_all', request);
245
+ void request.then(collection => {
246
+ if (collection.complete) {
247
+ if (generation === branchCacheGeneration && apiCache.get('branches_all')?.data === request) {
248
+ setCache('branches_complete', collection.branches);
249
+ }
250
+ return;
251
+ }
252
+ if (apiCache.get(cacheKey)?.data === request)
253
+ apiCache.delete(cacheKey);
254
+ if (apiCache.get('branches_all')?.data === request)
255
+ apiCache.delete('branches_all');
256
+ });
257
+ return request;
258
+ },
259
+ async getBranches(filters = {}) {
260
+ const generation = branchCacheGeneration;
261
+ const hasSearchParams = (filters.query && filters.query.trim().length >= 2) || filters.lat || filters.lng || filters.city_id;
262
+ const perPage = filters.per_page ?? 20;
263
+ const offset = ((filters.page ?? 1) - 1) * perPage;
264
+ if (!hasSearchParams) {
265
+ const branches = getCountryBranches(getCached('branches_complete'), filters.country_id);
266
+ if (branches) {
267
+ return branches.slice(offset, offset + perPage);
268
+ }
269
+ const firstPage = getCached('branches_first');
270
+ if (firstPage) {
271
+ const result = resolvedBranchPages.get(firstPage);
272
+ if (generation !== branchCacheGeneration)
273
+ return [];
274
+ if (result) {
275
+ const first = getCountryBranches(result.branches, filters.country_id);
276
+ const complete = result.pagination
277
+ ? Number(result.pagination.totalPages) === 1
278
+ : result.branches.length < result.perPage;
279
+ if (first && (first.length >= offset + perPage || complete)) {
280
+ return first.slice(offset, offset + perPage);
281
+ }
282
+ }
283
+ }
151
284
  }
152
- const result = await withApiErrorHandling(async () => {
153
- const params = { per_page };
154
- if (query?.trim().length >= 2)
155
- params.query = query;
156
- if (lat)
157
- params.lat = lat;
158
- if (lng)
159
- params.lng = lng;
160
- if (country_id)
161
- params.country_id = country_id;
162
- const res = await salla.api.request("branches", { params });
163
- return (Array.isArray(res?.data) ? res.data : []);
164
- }, [], 'Error fetching branches');
165
- if (cacheKey && result.length > 0)
166
- setCache(cacheKey, result);
167
- return result;
285
+ return withApiErrorHandling(async () => (await getBranchPage(filters)).branches, [], 'Error fetching branches');
168
286
  },
169
287
  async saveAddressLocation(payload) {
170
288
  return withApiErrorHandling(async () => {
@@ -182,7 +300,12 @@ const bulletDeliveryAPI = {
182
300
  }, false, 'Error setting delivery scope');
183
301
  },
184
302
  async allocateScope(payload) {
185
- const errMsg = (d) => d?.error?.message ?? d?.message ?? 'Failed to allocate scope';
303
+ // A field reason (e.g. branch_id "not accepting orders") is more useful than the generic "invalid fields" message.
304
+ const errMsg = (d) => {
305
+ const body = d;
306
+ const fieldReason = Object.values(body?.error?.fields ?? {}).flat().find((m) => typeof m === 'string' && m.trim());
307
+ return fieldReason ?? body?.error?.message ?? body?.message ?? 'Failed to allocate scope';
308
+ };
186
309
  try {
187
310
  const response = await salla.api.withoutNotifier(() => salla.api.request("scopes/allocation", payload, 'post'));
188
311
  // SDK resolves with { data } and throws on non-2xx; any resolved value is success
@@ -203,8 +326,16 @@ const bulletDeliveryAPI = {
203
326
  },
204
327
  };
205
328
  function clearApiCache() {
329
+ branchCacheGeneration++;
206
330
  apiCache.clear();
207
331
  }
332
+ function clearBranchCache() {
333
+ branchCacheGeneration++;
334
+ for (const key of apiCache.keys()) {
335
+ if (key.startsWith('branches_'))
336
+ apiCache.delete(key);
337
+ }
338
+ }
208
339
 
209
340
  /**
210
341
  * Helper functions for salla-bullet-delivery component
@@ -233,13 +364,153 @@ const isBranchSelectable = (branch) => {
233
364
  const selectable = branch.pickup_readiness?.selectable;
234
365
  return typeof selectable === 'boolean' ? selectable : branch.is_open !== false;
235
366
  };
236
- /** Nearest available branch by distance; single pass O(n). */
367
+ /** Backend readiness label ("استلمه غدًا", "جاهز {date}") when pickup is not today; null otherwise. */
368
+ const getBranchReadinessLabel = (branch) => {
369
+ const readiness = branch?.pickup_readiness;
370
+ return readiness?.label && ['tomorrow', 'later'].includes(readiness.state) ? readiness.label : null;
371
+ };
372
+ /** Branch-clock "HH:mm" a branch that is closed now becomes ready at later today; null otherwise. */
373
+ const getBranchReadyTodayTime = (branch) => {
374
+ const readiness = branch?.pickup_readiness;
375
+ if (readiness?.state !== 'same_day' || branch?.is_open !== false)
376
+ return null;
377
+ return readiness.ready_at?.match(/T(\d{2}:\d{2})/)?.[1] ?? null;
378
+ };
379
+ /** Busy branches (stock at the merchant's stop-orders threshold) stay listed but dimmed and unselectable. */
380
+ const isBranchBusy = (branch) => branch?.pickup_readiness?.state === 'orders_paused';
381
+ /** Distinct cities of a branch list, in first-seen order (the API lists nearest first). */
382
+ const getBranchCities = (branches) => {
383
+ const seen = new Set();
384
+ const cities = [];
385
+ for (const { city } of branches) {
386
+ if (!city?.id || seen.has(String(city.id)))
387
+ continue;
388
+ seen.add(String(city.id));
389
+ cities.push({ id: city.id, name: city.name });
390
+ }
391
+ return cities;
392
+ };
393
+ /** "3.52" / "12" — at most two decimals, as the checkout picker shows it; '' when the distance is unknown. */
394
+ const formatBranchDistance = (km) => {
395
+ if (km == null || Number.isNaN(Number(km)))
396
+ return '';
397
+ return String(Math.round(Number(km) * 100) / 100);
398
+ };
399
+ /**
400
+ * Readiness states the picker hides outright instead of showing as a disabled card: closed and not
401
+ * taking pickup orders at all. Busy/out-of-stock stay visible-but-disabled so the shopper sees why
402
+ * (same rule as the checkout picker, INV-1414).
403
+ */
404
+ const HIDDEN_READINESS_STATES = ['closed', 'unavailable'];
405
+ const isBranchVisible = (branch) => !!branch && !HIDDEN_READINESS_STATES.includes(branch.pickup_readiness?.state);
406
+ /** The branch's pickup offer (INV-1416); null when it has none, or a zero one, so "خصم 0%" never shows. */
407
+ const getBranchDiscount = (branch) => {
408
+ const type = branch?.discount?.type;
409
+ const amount = Number(branch?.discount?.amount);
410
+ if ((type !== 'percentage' && type !== 'fixed_amount') || !(amount > 0))
411
+ return null;
412
+ return { type, amount };
413
+ };
414
+ /**
415
+ * Min–max pickup offer across the listed branches, for the pickup tab badge; null when none has one.
416
+ * Branches the picker hides are left out so the tab never advertises an offer the shopper can't pick.
417
+ * A percentage and a fixed amount can't share one range, so percentages win when both are set.
418
+ */
419
+ const getBranchDiscountRange = (branches) => {
420
+ const discounts = branches.filter(isBranchVisible).map(getBranchDiscount).filter((d) => !!d);
421
+ if (!discounts.length)
422
+ return null;
423
+ const type = discounts.some(d => d.type === 'percentage') ? 'percentage' : 'fixed_amount';
424
+ const amounts = discounts.filter(d => d.type === type).map(d => d.amount);
425
+ return { type, min: Math.min(...amounts), max: Math.max(...amounts) };
426
+ };
427
+ /** The storefront's working_hours and ready_at use 24h "HH:mm"; null for anything else. */
428
+ const parseBranchTime = (time) => {
429
+ const match = String(time ?? '').trim().match(/^(\d{1,2}):(\d{2})(?::\d{2})?$/);
430
+ if (!match || Number(match[1]) > 24)
431
+ return null;
432
+ return { hours: Number(match[1]) % 24, minutes: Number(match[2]) };
433
+ };
434
+ /** Date#getDay() keys for the day names the storefront API may send (Arabic or English). */
435
+ const DAY_KEYS = {
436
+ sunday: 0, 'الاحد': 0,
437
+ monday: 1, 'الاثنين': 1,
438
+ tuesday: 2, 'الثلاثاء': 2,
439
+ wednesday: 3, 'الاربعاء': 3,
440
+ thursday: 4, 'الخميس': 4,
441
+ friday: 5, 'الجمعة': 5,
442
+ saturday: 6, 'السبت': 6,
443
+ };
444
+ const dayKeyFromName = (name) => DAY_KEYS[String(name ?? '').trim().toLowerCase().replace(/[أإآ]/g, 'ا')];
445
+ /**
446
+ * The storefront's `working_hours` (`{ name, times: [{ from, to }] }`, 24h times) as weekly
447
+ * schedule rows for the hours dropdown.
448
+ */
449
+ const getBranchWeekSchedule = (branch) => (branch.working_hours || [])
450
+ .filter(day => day?.name)
451
+ .map(day => ({
452
+ day_key: dayKeyFromName(day.name),
453
+ day: day.name,
454
+ times: (day.times || []).map(t => ({ start: t.from, end: t.to })),
455
+ }));
456
+ const isBranchAlwaysOpen = (branch) => !!branch.always_open;
457
+ /**
458
+ * "11:00 م" / "11:00 PM". ar-SA's ICU pattern puts the day period first, which the bidi algorithm
459
+ * scrambles inside RTL text, so the parts are joined in a fixed "h:mm period" order instead.
460
+ */
461
+ const formatBranchClockTime = (time, locale) => {
462
+ const parsed = parseBranchTime(time);
463
+ if (!parsed)
464
+ return '';
465
+ const date = new Date(Date.UTC(2000, 0, 1, parsed.hours, parsed.minutes));
466
+ const parts = new Intl.DateTimeFormat(locale === 'ar' ? 'ar-SA-u-nu-latn' : 'en', {
467
+ timeZone: 'UTC',
468
+ hour: '2-digit',
469
+ minute: '2-digit',
470
+ hour12: true,
471
+ }).formatToParts(date);
472
+ const get = (type) => parts.find(p => p.type === type)?.value ?? '';
473
+ return `${get('hour')}:${get('minute')} ${get('dayPeriod')}`;
474
+ };
475
+ const sameTimes = (a, b) => a.length === b.length && a.every((t, i) => t.start === b[i].start && t.end === b[i].end);
476
+ /** Consecutive days with identical hours collapse into one row; the largest groups come first. */
477
+ const groupBranchSchedule = (weekSchedule) => {
478
+ const groups = [];
479
+ const days = [...(weekSchedule || [])].filter(s => s.times?.length).sort((a, b) => (a.day_key ?? 0) - (b.day_key ?? 0));
480
+ for (const day of days) {
481
+ const last = groups[groups.length - 1];
482
+ if (last && day.day_key === last.lastDayKey + 1 && sameTimes(last.times, day.times)) {
483
+ last.days.push(day.day);
484
+ last.lastDayKey = day.day_key;
485
+ }
486
+ else {
487
+ groups.push({ days: [day.day], times: day.times, lastDayKey: day.day_key ?? 0 });
488
+ }
489
+ }
490
+ return groups.sort((a, b) => b.days.length - a.days.length).map(({ days, times }) => ({ days, times }));
491
+ };
492
+ /** Keeps the digits and a leading "+" the merchant typed; drops spaces, dashes and brackets. */
493
+ const cleanPhone = (value) => String(value ?? '').trim().replace(/[^\d+]/g, '');
494
+ const getBranchPhoneHref = (branch) => {
495
+ const phone = cleanPhone(branch.contacts?.phone);
496
+ return phone ? `tel:${phone}` : null;
497
+ };
498
+ /** wa.me wants the international number as bare digits ("+966…" / "00966…" → "966…"). */
499
+ const getBranchWhatsappHref = (branch) => {
500
+ const digits = cleanPhone(branch.contacts?.whatsapp).replace(/^\+/, '').replace(/^00/, '').replace(/\D/g, '');
501
+ return digits ? `https://wa.me/${digits}` : null;
502
+ };
503
+ const getBranchDirectionsHref = (branch) => branch.location?.lat != null && branch.location?.lng != null
504
+ ? `https://www.google.com/maps?q=${branch.location.lat},${branch.location.lng}`
505
+ : null;
506
+ /** Nearest selectable branch by distance; single pass O(n). */
237
507
  function findNearestBranch(branches, userLat, userLon) {
238
508
  let nearest = null;
239
509
  let minD = Number.POSITIVE_INFINITY;
240
510
  for (const b of branches) {
241
511
  const lat = b.location?.lat != null ? Number(b.location.lat) : Number.NaN;
242
512
  const lng = b.location?.lng != null ? Number(b.location.lng) : Number.NaN;
513
+ // Closed branches that still take orders are selectable too, so gate on selectability, not is_open.
243
514
  if (Number.isNaN(lat) || Number.isNaN(lng) || !isBranchSelectable(b))
244
515
  continue;
245
516
  const d = calculateDistance(userLat, userLon, lat, lng);
@@ -250,11 +521,12 @@ function findNearestBranch(branches, userLat, userLon) {
250
521
  }
251
522
  return nearest;
252
523
  }
524
+ /** Matches the fields the branches API searches: branch, city and country names (either language). */
253
525
  const filterBranches = (branches, searchQuery) => {
254
526
  if (!searchQuery)
255
527
  return branches;
256
528
  const q = searchQuery.toLowerCase();
257
- return branches.filter((b) => b.name.toLowerCase().includes(q) || b.city?.name?.toLowerCase().includes(q));
529
+ return branches.filter((b) => [b.name, b.city?.name, b.city?.name_en, b.country?.name, b.country?.name_en].some((name) => name?.toLowerCase().includes(q)));
258
530
  };
259
531
  const getIntentSubtitle = (intent, toAddress, fromBranch) => {
260
532
  if (intent.type === 'branch') {
@@ -274,9 +546,6 @@ const getIntentRegionId = (i) => idFrom(i?.address_details?.region?.id);
274
546
  const getIntentCityId = (i) => idFrom(i?.address_details?.city?.id);
275
547
  const getIntentDistrictId = (i) => idFrom(i?.address_details?.district?.id);
276
548
  const getIntentBranchId = (i) => i?.branch_details?.id;
277
- /** Intent coordinates (branch tab only; address flow no longer uses coordinates). */
278
- const getIntentLatitude = (i) => i?.branch_details?.latitude;
279
- const getIntentLongitude = (i) => i?.branch_details?.longitude;
280
549
  const isMapOriginIntent = (i) => !!i && i.type === 'address' && i.address_details?.lat != null && i.address_details?.lng != null;
281
550
  const hasSessionAddressIntent = (intent) => {
282
551
  if (!intent || intent.type !== 'address' || intent.address_id)
@@ -295,15 +564,5 @@ const hasSessionAddressIntent = (intent) => {
295
564
  const requireRegionAndDistrictForSA = (countryCode, regionId, districtIdOrName) => !countryCode || !isSaudiArabia(countryCode)
296
565
  ? true
297
566
  : (regionId != null && Number(regionId) !== 0) && (districtIdOrName != null && (typeof districtIdOrName === 'number' ? districtIdOrName !== 0 : String(districtIdOrName).trim().length > 0));
298
- // Geolocation error codes - fallback constants for non-browser environments
299
- const GEO_ERROR_PERMISSION_DENIED = typeof GeolocationPositionError !== 'undefined' ? GeolocationPositionError.PERMISSION_DENIED : 1;
300
- const GEO_ERROR_POSITION_UNAVAILABLE = typeof GeolocationPositionError !== 'undefined' ? GeolocationPositionError.POSITION_UNAVAILABLE : 2;
301
- const GEO_ERROR_TIMEOUT = typeof GeolocationPositionError !== 'undefined' ? GeolocationPositionError.TIMEOUT : 3;
302
- const GEO_ERROR_MESSAGES = {
303
- [GEO_ERROR_PERMISSION_DENIED]: 'Location permission denied',
304
- [GEO_ERROR_POSITION_UNAVAILABLE]: 'Location unavailable',
305
- [GEO_ERROR_TIMEOUT]: 'Location timeout',
306
- };
307
- const getGeolocationErrorMessage = (errorCode) => GEO_ERROR_MESSAGES[errorCode] ?? 'An error occurred while detecting location';
308
567
 
309
- export { getIntentLongitude as a, bulletDeliveryAPI as b, getIntentCityId as c, getIntentCountryId as d, getIntentRegionId as e, getIntentDistrictId as f, getIntentLatitude as g, hasSessionAddressIntent as h, isSaudiArabia as i, isBranchSelectable as j, filterBranches as k, getIntentBranchId as l, findNearestBranch as m, getGeolocationErrorMessage as n, clearApiCache as o, getIntentSubtitle as p, isMapOriginIntent as q, requireRegionAndDistrictForSA as r, getIntentCountryCode as s };
568
+ export { getBranchDirectionsHref as A, formatBranchClockTime as B, CACHE_TTL as C, getBranchReadyTodayTime as D, isBranchBusy as E, isBranchAlwaysOpen as F, getIntentCountryCode as G, getIntentCountryId as a, bulletDeliveryAPI as b, clearBranchCache as c, getIntentRegionId as d, getIntentDistrictId as e, getBranchCities as f, getIntentCityId as g, hasSessionAddressIntent as h, isSaudiArabia as i, isBranchSelectable as j, getBranchDiscountRange as k, filterBranches as l, getIntentBranchId as m, findNearestBranch as n, clearApiCache as o, getIntentSubtitle as p, isMapOriginIntent as q, requireRegionAndDistrictForSA as r, isBranchVisible as s, getBranchReadinessLabel as t, groupBranchSchedule as u, getBranchWeekSchedule as v, getBranchPhoneHref as w, getBranchWhatsappHref as x, getBranchDiscount as y, formatBranchDistance as z };