@salla.sa/twilight-components 2.14.365 → 2.14.366

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 (253) hide show
  1. package/dist/cjs/{filepond-5FseaYGO.js → filepond-iKAI8_Ua.js} +1 -1
  2. package/dist/cjs/{filepond-plugin-file-poster-B6jRMST8.js → filepond-plugin-file-poster-DBOuyuqE.js} +1 -1
  3. package/dist/cjs/{filepond-plugin-file-validate-size-B5KYrf7Q.js → filepond-plugin-file-validate-size-3OjivJWc.js} +1 -1
  4. package/dist/cjs/{filepond-plugin-file-validate-type-D6zZbyEw.js → filepond-plugin-file-validate-type-C4wPNa1h.js} +1 -1
  5. package/dist/cjs/{filepond-plugin-image-edit-D9sIYJpS.js → filepond-plugin-image-edit-D06RnDWS.js} +1 -1
  6. package/dist/cjs/{filepond-plugin-image-exif-orientation-DCPv8T5a.js → filepond-plugin-image-exif-orientation-CbwYrnuw.js} +1 -1
  7. package/dist/cjs/{filepond-plugin-image-preview-B6ya_UMz.js → filepond-plugin-image-preview-mOmpKkFJ.js} +1 -1
  8. package/dist/cjs/{index-DaB0o62I.js → index-DL9nqubd.js} +6 -6
  9. package/dist/cjs/{index-DsLCYojB.js → index-TmWujwmX.js} +1 -1
  10. package/dist/cjs/loader.cjs.js +2 -2
  11. package/dist/cjs/salla-accordion-body_3.cjs.entry.js +1 -1
  12. package/dist/cjs/salla-accordion_6.cjs.entry.js +1 -1
  13. package/dist/cjs/salla-add-product-button_4.cjs.entry.js +1 -1
  14. package/dist/cjs/salla-advertisement.cjs.entry.js +1 -1
  15. package/dist/cjs/salla-alert_2.cjs.entry.js +1 -1
  16. package/dist/cjs/salla-app-install-alert.cjs.entry.js +1 -1
  17. package/dist/cjs/salla-apps-icons.cjs.entry.js +1 -1
  18. package/dist/cjs/salla-booking-field_7.cjs.entry.js +10 -10
  19. package/dist/cjs/salla-cart-item-offers_2.cjs.entry.js +1 -1
  20. package/dist/cjs/salla-comment-form_8.cjs.entry.js +1 -1
  21. package/dist/cjs/salla-conditional-offer.cjs.entry.js +1 -1
  22. package/dist/cjs/salla-contacts.cjs.entry.js +1 -1
  23. package/dist/cjs/salla-cookies-bar.cjs.entry.js +1 -1
  24. package/dist/cjs/salla-count-down_2.cjs.entry.js +11 -8
  25. package/dist/cjs/salla-custom-fields.cjs.entry.js +1 -1
  26. package/dist/cjs/salla-filters-widget.cjs.entry.js +1 -1
  27. package/dist/cjs/salla-filters.cjs.entry.js +1 -1
  28. package/dist/cjs/salla-gifting.cjs.entry.js +1 -1
  29. package/dist/cjs/salla-hook.cjs.entry.js +1 -1
  30. package/dist/cjs/salla-infinite-scroll.cjs.entry.js +1 -1
  31. package/dist/cjs/salla-installment.cjs.entry.js +1 -1
  32. package/dist/cjs/salla-list-tile.cjs.entry.js +1 -1
  33. package/dist/cjs/salla-localization-modal.cjs.entry.js +1 -1
  34. package/dist/cjs/salla-login-modal.cjs.entry.js +1 -1
  35. package/dist/cjs/salla-loyalty-prize-item.cjs.entry.js +1 -1
  36. package/dist/cjs/salla-loyalty-program.cjs.entry.js +1 -1
  37. package/dist/cjs/salla-loyalty.cjs.entry.js +1 -1
  38. package/dist/cjs/salla-maintenance-alert.cjs.entry.js +1 -1
  39. package/dist/cjs/salla-menu.cjs.entry.js +1 -1
  40. package/dist/cjs/salla-metadata.cjs.entry.js +1 -1
  41. package/dist/cjs/salla-multiple-bundle-product-cart_2.cjs.entry.js +1 -1
  42. package/dist/cjs/salla-multiple-bundle-product-options-modal_2.cjs.entry.js +1 -1
  43. package/dist/cjs/salla-multiple-bundle-product.cjs.entry.js +1 -1
  44. package/dist/cjs/salla-notification-item.cjs.entry.js +1 -1
  45. package/dist/cjs/salla-notifications.cjs.entry.js +1 -1
  46. package/dist/cjs/salla-offer-modal.cjs.entry.js +1 -1
  47. package/dist/cjs/salla-offer.cjs.entry.js +248 -177
  48. package/dist/cjs/salla-order-details-multiple-bundle-product.cjs.entry.js +1 -1
  49. package/dist/cjs/salla-order-details-options.cjs.entry.js +1 -1
  50. package/dist/cjs/salla-order-details.cjs.entry.js +1 -1
  51. package/dist/cjs/salla-order-summary.cjs.entry.js +1 -1
  52. package/dist/cjs/salla-order-totals-card.cjs.entry.js +1 -1
  53. package/dist/cjs/salla-orders.cjs.entry.js +1 -1
  54. package/dist/cjs/salla-payments.cjs.entry.js +1 -1
  55. package/dist/cjs/salla-placeholder.cjs.entry.js +1 -1
  56. package/dist/cjs/salla-price-range.cjs.entry.js +1 -1
  57. package/dist/cjs/salla-product-size-guide.cjs.entry.js +1 -1
  58. package/dist/cjs/salla-products-list.cjs.entry.js +9 -3
  59. package/dist/cjs/salla-products-slider.cjs.entry.js +1 -1
  60. package/dist/cjs/salla-progress-bar.cjs.entry.js +1 -1
  61. package/dist/cjs/salla-quick-order.cjs.entry.js +1 -1
  62. package/dist/cjs/salla-rating-modal.cjs.entry.js +1 -1
  63. package/dist/cjs/salla-scopes.cjs.entry.js +1 -1
  64. package/dist/cjs/salla-search.cjs.entry.js +1 -1
  65. package/dist/cjs/salla-skeleton.cjs.entry.js +1 -1
  66. package/dist/cjs/salla-slider.cjs.entry.js +1 -1
  67. package/dist/cjs/salla-social-share.cjs.entry.js +1 -1
  68. package/dist/cjs/salla-social.cjs.entry.js +1 -1
  69. package/dist/cjs/salla-tab-content_3.cjs.entry.js +1 -1
  70. package/dist/cjs/salla-tiered-offer.cjs.entry.js +1 -1
  71. package/dist/cjs/salla-tooltip.cjs.entry.js +1 -1
  72. package/dist/cjs/salla-trust-badges.cjs.entry.js +1 -1
  73. package/dist/cjs/salla-user-menu.cjs.entry.js +1 -1
  74. package/dist/cjs/salla-user-profile.cjs.entry.js +1 -1
  75. package/dist/cjs/salla-user-settings.cjs.entry.js +1 -1
  76. package/dist/cjs/salla-verify.cjs.entry.js +1 -1
  77. package/dist/cjs/salla-wallet.cjs.entry.js +1 -1
  78. package/dist/cjs/twilight.cjs.js +2 -2
  79. package/dist/cjs/{vanilla-picker-DE9NaT9j.js → vanilla-picker-DPu_Z0gW.js} +1 -1
  80. package/dist/collection/components/salla-offer/interfaces.js +2 -0
  81. package/dist/collection/components/salla-offer/salla-offer.css +2 -25
  82. package/dist/collection/components/salla-offer/salla-offer.js +256 -181
  83. package/dist/collection/components/salla-product-card/salla-product-card.js +29 -7
  84. package/dist/collection/components/salla-products-list/salla-products-list.js +27 -2
  85. package/dist/components/index.js +2 -2
  86. package/dist/components/salla-offer.js +273 -220
  87. package/dist/components/salla-product-card2.js +11 -7
  88. package/dist/components/salla-products-list2.js +9 -2
  89. package/dist/esm/{filepond-BGPYjCAA.js → filepond-OIAu6i0O.js} +1 -1
  90. package/dist/esm/{filepond-plugin-file-poster-sd-w_Hri.js → filepond-plugin-file-poster-BMvjO1cc.js} +1 -1
  91. package/dist/esm/{filepond-plugin-file-validate-size-CQkfT5sz.js → filepond-plugin-file-validate-size-CMCs88HU.js} +1 -1
  92. package/dist/esm/{filepond-plugin-file-validate-type-Cu8nOdXD.js → filepond-plugin-file-validate-type-Bjpeuqen.js} +1 -1
  93. package/dist/esm/{filepond-plugin-image-edit-CWpBhgby.js → filepond-plugin-image-edit-Fpoh6xBj.js} +1 -1
  94. package/dist/esm/{filepond-plugin-image-exif-orientation-DbSLLg4E.js → filepond-plugin-image-exif-orientation-CPChwYPW.js} +1 -1
  95. package/dist/esm/{filepond-plugin-image-preview-DXgOkLlG.js → filepond-plugin-image-preview-pLwEytag.js} +1 -1
  96. package/dist/esm/{index-DcD0Zbyk.js → index-CV1rqKQz.js} +6 -6
  97. package/dist/esm/{index-BNB-g4_5.js → index-Cs4XvAmW.js} +1 -1
  98. package/dist/esm/loader.js +3 -3
  99. package/dist/esm/salla-accordion-body_3.entry.js +1 -1
  100. package/dist/esm/salla-accordion_6.entry.js +1 -1
  101. package/dist/esm/salla-add-product-button_4.entry.js +1 -1
  102. package/dist/esm/salla-advertisement.entry.js +1 -1
  103. package/dist/esm/salla-alert_2.entry.js +1 -1
  104. package/dist/esm/salla-app-install-alert.entry.js +1 -1
  105. package/dist/esm/salla-apps-icons.entry.js +1 -1
  106. package/dist/esm/salla-booking-field_7.entry.js +10 -10
  107. package/dist/esm/salla-cart-item-offers_2.entry.js +1 -1
  108. package/dist/esm/salla-comment-form_8.entry.js +1 -1
  109. package/dist/esm/salla-conditional-offer.entry.js +1 -1
  110. package/dist/esm/salla-contacts.entry.js +1 -1
  111. package/dist/esm/salla-cookies-bar.entry.js +1 -1
  112. package/dist/esm/salla-count-down_2.entry.js +11 -8
  113. package/dist/esm/salla-custom-fields.entry.js +1 -1
  114. package/dist/esm/salla-filters-widget.entry.js +1 -1
  115. package/dist/esm/salla-filters.entry.js +1 -1
  116. package/dist/esm/salla-gifting.entry.js +1 -1
  117. package/dist/esm/salla-hook.entry.js +1 -1
  118. package/dist/esm/salla-infinite-scroll.entry.js +1 -1
  119. package/dist/esm/salla-installment.entry.js +1 -1
  120. package/dist/esm/salla-list-tile.entry.js +1 -1
  121. package/dist/esm/salla-localization-modal.entry.js +1 -1
  122. package/dist/esm/salla-login-modal.entry.js +1 -1
  123. package/dist/esm/salla-loyalty-prize-item.entry.js +1 -1
  124. package/dist/esm/salla-loyalty-program.entry.js +1 -1
  125. package/dist/esm/salla-loyalty.entry.js +1 -1
  126. package/dist/esm/salla-maintenance-alert.entry.js +1 -1
  127. package/dist/esm/salla-menu.entry.js +1 -1
  128. package/dist/esm/salla-metadata.entry.js +1 -1
  129. package/dist/esm/salla-multiple-bundle-product-cart_2.entry.js +1 -1
  130. package/dist/esm/salla-multiple-bundle-product-options-modal_2.entry.js +1 -1
  131. package/dist/esm/salla-multiple-bundle-product.entry.js +1 -1
  132. package/dist/esm/salla-notification-item.entry.js +1 -1
  133. package/dist/esm/salla-notifications.entry.js +1 -1
  134. package/dist/esm/salla-offer-modal.entry.js +1 -1
  135. package/dist/esm/salla-offer.entry.js +248 -177
  136. package/dist/esm/salla-order-details-multiple-bundle-product.entry.js +1 -1
  137. package/dist/esm/salla-order-details-options.entry.js +1 -1
  138. package/dist/esm/salla-order-details.entry.js +1 -1
  139. package/dist/esm/salla-order-summary.entry.js +1 -1
  140. package/dist/esm/salla-order-totals-card.entry.js +1 -1
  141. package/dist/esm/salla-orders.entry.js +1 -1
  142. package/dist/esm/salla-payments.entry.js +1 -1
  143. package/dist/esm/salla-placeholder.entry.js +1 -1
  144. package/dist/esm/salla-price-range.entry.js +1 -1
  145. package/dist/esm/salla-product-size-guide.entry.js +1 -1
  146. package/dist/esm/salla-products-list.entry.js +9 -3
  147. package/dist/esm/salla-products-slider.entry.js +1 -1
  148. package/dist/esm/salla-progress-bar.entry.js +1 -1
  149. package/dist/esm/salla-quick-order.entry.js +1 -1
  150. package/dist/esm/salla-rating-modal.entry.js +1 -1
  151. package/dist/esm/salla-scopes.entry.js +1 -1
  152. package/dist/esm/salla-search.entry.js +1 -1
  153. package/dist/esm/salla-skeleton.entry.js +1 -1
  154. package/dist/esm/salla-slider.entry.js +1 -1
  155. package/dist/esm/salla-social-share.entry.js +1 -1
  156. package/dist/esm/salla-social.entry.js +1 -1
  157. package/dist/esm/salla-tab-content_3.entry.js +1 -1
  158. package/dist/esm/salla-tiered-offer.entry.js +1 -1
  159. package/dist/esm/salla-tooltip.entry.js +1 -1
  160. package/dist/esm/salla-trust-badges.entry.js +1 -1
  161. package/dist/esm/salla-user-menu.entry.js +1 -1
  162. package/dist/esm/salla-user-profile.entry.js +1 -1
  163. package/dist/esm/salla-user-settings.entry.js +1 -1
  164. package/dist/esm/salla-verify.entry.js +1 -1
  165. package/dist/esm/salla-wallet.entry.js +1 -1
  166. package/dist/esm/twilight.js +3 -3
  167. package/dist/esm/{vanilla-picker-ErWyfb2S.js → vanilla-picker-BASTfXcg.js} +1 -1
  168. package/dist/twilight/{p-eaf91b32.entry.js → p-04664fcb.entry.js} +1 -1
  169. package/dist/twilight/{p-61b073fe.entry.js → p-0c385d73.entry.js} +1 -1
  170. package/dist/twilight/{p-05edd1ae.entry.js → p-0ede455c.entry.js} +1 -1
  171. package/dist/twilight/{p-90375d86.entry.js → p-0f1d7449.entry.js} +1 -1
  172. package/dist/twilight/{p-df475039.entry.js → p-134c9d22.entry.js} +1 -1
  173. package/dist/twilight/{p-37baa677.entry.js → p-15242c87.entry.js} +1 -1
  174. package/dist/twilight/{p-0a33368c.entry.js → p-1aead6d3.entry.js} +1 -1
  175. package/dist/twilight/{p-f0234135.entry.js → p-1f6ead7d.entry.js} +1 -1
  176. package/dist/twilight/{p-05b3f2ba.entry.js → p-215ed586.entry.js} +1 -1
  177. package/dist/twilight/{p-a3b90d18.entry.js → p-22b1bd15.entry.js} +1 -1
  178. package/dist/twilight/{p-e53c695d.entry.js → p-233b89ad.entry.js} +1 -1
  179. package/dist/twilight/{p-cf4c8fc8.entry.js → p-2405c0f7.entry.js} +1 -1
  180. package/dist/twilight/{p-3f99644a.entry.js → p-2c787ba0.entry.js} +1 -1
  181. package/dist/twilight/{p-ca43a3b7.entry.js → p-2dd98664.entry.js} +1 -1
  182. package/dist/twilight/{p-281ca90e.entry.js → p-3c09b198.entry.js} +1 -1
  183. package/dist/twilight/{p-f959adcd.entry.js → p-3c418ff7.entry.js} +1 -1
  184. package/dist/twilight/{p-a916b222.entry.js → p-3c6f9112.entry.js} +1 -1
  185. package/dist/twilight/{p-4b508998.entry.js → p-3f8b06b3.entry.js} +1 -1
  186. package/dist/twilight/{p-ec61d027.entry.js → p-40ec7a33.entry.js} +1 -1
  187. package/dist/twilight/{p-3e62ea6f.entry.js → p-4d35a32b.entry.js} +1 -1
  188. package/dist/twilight/{p-794141e7.entry.js → p-50f5e38d.entry.js} +1 -1
  189. package/dist/twilight/{p-1df500d5.entry.js → p-5485978c.entry.js} +1 -1
  190. package/dist/twilight/{p-eb1ee098.entry.js → p-585a349f.entry.js} +1 -1
  191. package/dist/twilight/{p-d4135be2.entry.js → p-58f562df.entry.js} +1 -1
  192. package/dist/twilight/{p-1db6e42a.entry.js → p-594d219c.entry.js} +1 -1
  193. package/dist/twilight/{p-D94qS2bu.js → p-5mQqqwMU.js} +1 -1
  194. package/dist/twilight/{p-f1865223.entry.js → p-64ac4c0c.entry.js} +1 -1
  195. package/dist/twilight/{p-28fa2261.entry.js → p-6aecc925.entry.js} +1 -1
  196. package/dist/twilight/{p-bac8dfc6.entry.js → p-6b6e2a52.entry.js} +1 -1
  197. package/dist/twilight/{p-5b221eda.entry.js → p-6daa8bd8.entry.js} +1 -1
  198. package/dist/twilight/{p-5ca44db4.entry.js → p-6dbcd99e.entry.js} +1 -1
  199. package/dist/twilight/{p-34690dc4.entry.js → p-6f09b53e.entry.js} +1 -1
  200. package/dist/twilight/{p-a12e53fb.entry.js → p-721bb258.entry.js} +1 -1
  201. package/dist/twilight/{p-43bed278.entry.js → p-75ab49a3.entry.js} +1 -1
  202. package/dist/twilight/{p-22b8f56b.entry.js → p-7bfb9d71.entry.js} +1 -1
  203. package/dist/twilight/{p-0f9b63f1.entry.js → p-7c8c6c47.entry.js} +1 -1
  204. package/dist/twilight/{p-50b01475.entry.js → p-8c2b148a.entry.js} +1 -1
  205. package/dist/twilight/{p-2a8e49ca.entry.js → p-907b40cd.entry.js} +1 -1
  206. package/dist/twilight/{p-7e971fde.entry.js → p-90eea1a9.entry.js} +1 -1
  207. package/dist/twilight/{p-ac4d4de4.entry.js → p-95db0124.entry.js} +1 -1
  208. package/dist/twilight/{p-31e390fc.entry.js → p-965fe2b3.entry.js} +1 -1
  209. package/dist/twilight/{p-3504a127.entry.js → p-9797a552.entry.js} +1 -1
  210. package/dist/twilight/{p-27198dfa.entry.js → p-9d937a82.entry.js} +1 -1
  211. package/dist/twilight/{p-BpwFfwom.js → p-BGB1zYFQ.js} +1 -1
  212. package/dist/twilight/{p-CMeOfINj.js → p-BLbGjdAU.js} +1 -1
  213. package/dist/twilight/{p-DcD0Zbyk.js → p-CV1rqKQz.js} +1 -1
  214. package/dist/twilight/{p-DI8hZjwW.js → p-CofhuO2Z.js} +1 -1
  215. package/dist/twilight/{p-DaQtMKKH.js → p-CvLPGpFQ.js} +1 -1
  216. package/dist/twilight/{p-CfS_Im-l.js → p-D5AsuzfF.js} +1 -1
  217. package/dist/twilight/{p-r4UR1cQJ.js → p-DbzHZVd1.js} +1 -1
  218. package/dist/twilight/p-a08f5eae.entry.js +4 -0
  219. package/dist/twilight/{p-5463603e.entry.js → p-a0a6a255.entry.js} +1 -1
  220. package/dist/twilight/{p-48b8702d.entry.js → p-a386b02a.entry.js} +1 -1
  221. package/dist/twilight/{p-62eecdc3.entry.js → p-a5df57f9.entry.js} +1 -1
  222. package/dist/twilight/{p-3fbb37fc.entry.js → p-ac7f094e.entry.js} +1 -1
  223. package/dist/twilight/{p-14d02ff1.entry.js → p-af3d4d0d.entry.js} +1 -1
  224. package/dist/twilight/{p-7472ce60.entry.js → p-bb0585cc.entry.js} +1 -1
  225. package/dist/twilight/{p-9a2691e8.entry.js → p-c0ab0fc6.entry.js} +1 -1
  226. package/dist/twilight/{p-4fcd9105.entry.js → p-c3f515ae.entry.js} +1 -1
  227. package/dist/twilight/{p-ea2ebd0c.entry.js → p-c7719ce9.entry.js} +1 -1
  228. package/dist/twilight/{p-38fb50ed.entry.js → p-c90a6440.entry.js} +1 -1
  229. package/dist/twilight/{p-eb21f677.entry.js → p-cf64bb24.entry.js} +1 -1
  230. package/dist/twilight/{p-0f733d50.entry.js → p-d64027b9.entry.js} +1 -1
  231. package/dist/twilight/{p-4afcc4e1.entry.js → p-db4f5b38.entry.js} +1 -1
  232. package/dist/twilight/p-de42ef8c.entry.js +4 -0
  233. package/dist/twilight/{p-cad7741c.entry.js → p-dfc75ce2.entry.js} +1 -1
  234. package/dist/twilight/{p-84920a03.entry.js → p-e0ce2c0d.entry.js} +1 -1
  235. package/dist/twilight/{p-bd15fbda.entry.js → p-e0e61f73.entry.js} +1 -1
  236. package/dist/twilight/{p-cacb3ce1.entry.js → p-e1bf6d23.entry.js} +1 -1
  237. package/dist/twilight/{p-3bd66c8c.entry.js → p-e2c6ed54.entry.js} +1 -1
  238. package/dist/twilight/{p-2e1418d2.entry.js → p-f1156ab8.entry.js} +1 -1
  239. package/dist/twilight/{p-d9e1559a.entry.js → p-f1be81ba.entry.js} +1 -1
  240. package/dist/twilight/{p-C6smOZtR.js → p-f2v0udIe.js} +1 -1
  241. package/dist/twilight/{p-049e7629.entry.js → p-f8fb3130.entry.js} +1 -1
  242. package/dist/twilight/{p-62ab3466.entry.js → p-f9fcf183.entry.js} +1 -1
  243. package/dist/twilight/{p-5286e950.entry.js → p-fc6ddedc.entry.js} +1 -1
  244. package/dist/twilight/{p-Ctf313G7.js → p-tacIS_Xg.js} +1 -1
  245. package/dist/twilight/twilight.esm.js +1 -1
  246. package/dist/types/components/salla-offer/interfaces.d.ts +9 -7
  247. package/dist/types/components/salla-offer/salla-offer.d.ts +35 -36
  248. package/dist/types/components/salla-product-card/salla-product-card.d.ts +4 -0
  249. package/dist/types/components/salla-products-list/salla-products-list.d.ts +4 -0
  250. package/dist/types/components.d.ts +18 -2
  251. package/package.json +5 -5
  252. package/dist/twilight/p-f94c1c9a.entry.js +0 -4
  253. package/dist/twilight/p-fbc08feb.entry.js +0 -4
@@ -25,36 +25,45 @@ export class SallaOffer {
25
25
  * <salla-products-list product-card-component="my-custom-card-style1" ...
26
26
  * <salla-products-list product-card-component="my-custom-card-style2" ...
27
27
  */
28
- this.productCardComponent = 'custom-salla-product-card';
28
+ this.productCardComponent = 'salla-product-card';
29
29
  // Declare component state variables
30
30
  this.offersList = [];
31
- this.isMultipleBank = false;
32
- this.isBankOffer = false;
33
31
  this.canRender = false;
34
32
  this.showOffer = salla.config.get('store.settings.product.show_special_offers');
33
+ this.showAllOffersModal = false;
34
+ this.showProductsModal = false;
35
+ this.selectedOfferProducts = [];
36
+ this.collapsedOffers = {};
37
+ this.expandedCategories = {};
38
+ this.productsLoaded = false;
35
39
  // Default translated texts
36
40
  this.offer_with_price_text = salla.lang.get('pages.offer.with_price', { price: '' });
37
41
  this.with_discount_text = salla.lang.get('pages.products.with_a_discount');
38
42
  this.product_discount_text = salla.lang.get('pages.products.discount');
39
43
  this.special_offer_text = salla.lang.get('pages.products.special_offer');
40
- this.multipleBankOfferTitleText = salla.lang.get('pages.offer.multiple_bank_offers_title');
41
- this.multipleBankOfferTitleDescription = salla.lang.get('pages.offer.multiple_bank_offers_message');
42
44
  this.buy_quantity_text = (quantity) => salla.lang.get('pages.offer.buy_quantity', { quantity });
45
+ this.products_link_text = salla.lang.get('pages.offer.included_products', 'المنتجات المشمولة');
46
+ this.min_spend_text = (amount, currency) => salla.lang.get('pages.offer.min_spend_amount', { amount, currency }, `بحد أدنى ${amount} ${currency} من مبلغ الشراء`);
47
+ this.min_items_text = (items) => salla.lang.get('pages.offer.min_items', { items }, `بحد أدنى ${items} منتجات`);
48
+ this.product_text = salla.lang.get('common.elements.product', 'منتج');
43
49
  // Language
44
50
  salla.lang.onLoaded(() => {
45
51
  this.offer_with_price_text = salla.lang.get('pages.offer.with_price');
46
52
  this.with_discount_text = salla.lang.get('pages.products.with_a_discount');
47
53
  this.product_discount_text = salla.lang.get('pages.products.discount');
48
54
  this.special_offer_text = salla.lang.get('pages.products.special_offer');
49
- this.multipleBankOfferTitleText = salla.lang.get('pages.offer.multiple_bank_offers_title');
50
- this.multipleBankOfferTitleDescription = salla.lang.get('pages.offer.multiple_bank_offers_message');
51
55
  this.buy_quantity_text(0);
56
+ this.products_link_text = salla.lang.get('pages.offer.included_products', 'المنتجات المشمولة');
57
+ this.min_spend_text = (amount, currency) => salla.lang.get('pages.offer.min_spend_amount', { amount, currency }, `بحد أدنى ${amount} ${currency} من مبلغ الشراء`);
58
+ this.min_items_text = (items) => salla.lang.get('pages.offer.min_items', { items }, `بحد أدنى ${items} منتجات`);
59
+ this.product_text = salla.lang.get('common.elements.product', 'منتج');
52
60
  });
53
61
  salla.onReady(() => {
54
62
  this.currentPage = salla.config.get('page.slug');
55
- this.userCurrency = salla.config.get('currencies')[salla.config.get('user.currency_code')].symbol;
63
+ const currencies = salla.config.get('currencies') || {};
64
+ const currencyCode = salla.config.get('user.currency_code');
65
+ this.userCurrency = currencies[currencyCode] || { symbol: '', code: currencyCode || 'SAR', name: '' };
56
66
  });
57
- this.categorySlot = this.host.querySelector('[slot="category"]')?.innerHTML || '<a href={url} class="s-offer-slide-cat-entry"><i class={icon}></i><h4>{name}</h4></a>';
58
67
  }
59
68
  async getEndpointByPageName() {
60
69
  if (this.currentPage == PageType.Cart) {
@@ -72,36 +81,34 @@ export class SallaOffer {
72
81
  emitPromotionViewed() {
73
82
  if (!(this.offersList.length && this.canRender && this.showOffer))
74
83
  return;
75
- // Transform offer data to match analytics expectations
76
- const promotionData = {
77
- id: this.offersList[0].id,
78
- name: this.offersList[0].title,
79
- creative: this.offersList[0].description || '',
80
- position: 1
81
- };
82
- salla.event.emit('promotion::viewed', [promotionData]);
84
+ // Emit analytics for all visible offers (first 5) with correct positions
85
+ const visibleOffers = this.offersList.slice(0, 5);
86
+ const promotionDataArray = visibleOffers.map((offer, index) => ({
87
+ id: offer.id,
88
+ name: offer.title,
89
+ creative: offer.description || '',
90
+ position: index + 1
91
+ }));
92
+ salla.event.emit('salla::offer.promotion.viewed', promotionDataArray);
83
93
  }
84
94
  /**
85
95
  * Emits a promotion clicked event
86
96
  */
87
- emitPromotionClicked(position = 1) {
97
+ emitPromotionClicked(offer, position = 1) {
88
98
  if (!(this.offersList.length && this.canRender && this.showOffer))
89
99
  return;
100
+ const targetOffer = offer || this.offersList[0];
90
101
  // Transform offer data to match analytics expectations
91
102
  const promotionData = {
92
- id: this.offersList[0].id,
93
- name: this.offersList[0].title,
94
- creative: this.offersList[0].description || '',
103
+ id: targetOffer.id,
104
+ name: targetOffer.title,
105
+ creative: targetOffer.description || '',
95
106
  position: position
96
107
  };
97
- salla.event.emit('promotion::clicked', [promotionData]);
108
+ salla.event.emit('salla::offer.promotion.clicked', [promotionData]);
98
109
  }
99
110
  componentWillLoad() {
100
111
  this.hasCustomComponent = !!customElements.get(this.productCardComponent);
101
- // let offers = this.getOffersFromStorage();
102
- // if (offers) {
103
- // return offers.then(offersFromStorage => this.offersList = offersFromStorage);
104
- // }
105
112
  return (new Promise(resolve => salla.onReady(resolve)))
106
113
  .then(() => {
107
114
  this.showOffer = !salla.url.is_page('product.single') || salla.config.get('store.settings.product.show_special_offers');
@@ -111,61 +118,86 @@ export class SallaOffer {
111
118
  throw new Error("Merchant disabled showing the offers on product page");
112
119
  })
113
120
  .then(async () => salla.api.request(await this.getEndpointByPageName()))
114
- .then((res) => {
121
+ .then(async (res) => {
115
122
  if (!(this.offersList = res.data).length) {
116
123
  throw new Error('salla-offers:: There is no offers!');
117
124
  }
118
- //we support these offers only
119
- const offer = this.offersList.find(offer => [OfferType.SpecialPrice, OfferType.Bank, OfferType.BuyXGetY, OfferType.DiscountsTable].includes(offer.type));
120
- if (!offer) {
121
- throw new Error('salla-offers:: Offer type not supported yet!');
122
- }
123
- //because there is no need for special handling for discounts table, just skip the other cases
124
- if (offer.type === OfferType.DiscountsTable) {
125
- return this.offersList = [offer];
125
+ // Filter to only supported offer types
126
+ this.offersList = this.offersList.filter(offer => [OfferType.SpecialPrice, OfferType.Bank, OfferType.BuyXGetY, OfferType.DiscountsTable, OfferType.PercentageOrFixed, OfferType.Percentage, OfferType.FixedAmount].includes(offer.type));
127
+ if (!this.offersList.length) {
128
+ throw new Error('salla-offers:: No supported offer types found!');
126
129
  }
127
- //if it's banks offer, we need to include the other banks overs
128
- if ((this.isBankOffer = offer.type === OfferType.Bank)) {
129
- this.offersList = this.offersList.filter(offer => offer.type === OfferType.Bank);
130
- this.isMultipleBank = this.offersList.length > 1;
131
- return this.offersList;
130
+ // Fetch all categories once if any offer needs them
131
+ let allCategories = null;
132
+ const needsCategories = this.offersList.some(offer => {
133
+ const details = offer.details;
134
+ return (details.apply_to === 'category' && details.targets) ||
135
+ (details.apply_to === 'categories' && details.targets) ||
136
+ (offer.type === OfferType.BuyXGetY && (details.get?.source === 'categories' || details.get?.source === 'category'));
137
+ });
138
+ if (needsCategories) {
139
+ const res = await salla.product.api.categories();
140
+ allCategories = res.data;
132
141
  }
133
- //if it's special price offer
134
- if (offer.type === OfferType.SpecialPrice) {
142
+ // Collect all unique product IDs to make single batched API call
143
+ const productIds = new Set();
144
+ for (const offer of this.offersList) {
135
145
  const details = offer.details;
136
- return details.apply_to === 'product'
137
- // Avoid additional requests; use `salla-products-slider` and pass the custom card
138
- ? salla.product.api.fetch({ source: "selected", source_value: details.targets })
139
- .then((response) => {
140
- offer.details.products = response.data; // Set the fetched products
141
- return this.offersList = [offer];
142
- })
143
- : salla.product.api.categories() // Fetch all categories in one query
144
- .then((res) => {
145
- const categoriesToRender = this.findCategories(res.data, details.targets); // Extract only the selected categories
146
- offer.details.categories = categoriesToRender;
147
- return this.offersList = [offer];
146
+ if ((details.apply_to === 'product' || details.apply_to === 'products') && details.targets) {
147
+ details.targets.forEach(id => productIds.add(id));
148
+ }
149
+ if (offer.type === OfferType.BuyXGetY && details.get?.source === 'products' && details.get?.source_value) {
150
+ details.get.source_value.forEach(id => productIds.add(id));
151
+ }
152
+ if (offer.type === OfferType.BuyXGetY && (details.buy?.source === 'products' || details.buy?.source === 'product') && details.buy?.source_value) {
153
+ details.buy.source_value.forEach(id => productIds.add(id));
154
+ }
155
+ }
156
+ // Single batched API call with source="selected" prevents redundant requests
157
+ let allProducts = {};
158
+ if (productIds.size > 0) {
159
+ try {
160
+ const response = await salla.product.api.fetch({
161
+ source: "selected",
162
+ source_value: Array.from(productIds)
148
163
  });
164
+ allProducts = Object.fromEntries(response.data.map(p => [p.id, p]));
165
+ }
166
+ catch (error) {
167
+ allProducts = {};
168
+ }
149
169
  }
150
- //BuyXGetY offers
151
- const getY = offer.details.get;
152
- return getY.source === 'products'
153
- //todo:: avoid this request, and the handling for the products, just use `salla-products-slider` and don't forget to pass the customcard
154
- ? salla.product.api.fetch({ source: "selected", source_value: getY.source_value })
155
- .then((response) => {
156
- getY.products = response.data;
157
- offer.details.get = getY;
158
- return this.offersList = [offer];
159
- }) //set the products
160
- : salla.product.api.categories() //get all categories in one query, then extract only the selected one, instead of sending multi requests
161
- .then((res) => {
162
- getY.categories = this.findCategories(res.data, getY.source_value);
163
- offer.details.get = getY;
164
- return this.offersList = [offer];
165
- });
170
+ // Process each offer using cached data
171
+ for (const offer of this.offersList) {
172
+ const details = offer.details;
173
+ const shouldFetchCategories = (details.apply_to === 'category' && details.targets) ||
174
+ (details.apply_to === 'categories' && details.targets);
175
+ if (shouldFetchCategories && allCategories) {
176
+ details.categories = this.findCategories(allCategories, details.targets);
177
+ }
178
+ if ((details.apply_to === 'product' || details.apply_to === 'products') && details.targets) {
179
+ details.products = details.targets.map(id => allProducts[id]).filter(Boolean);
180
+ }
181
+ if (offer.type === OfferType.BuyXGetY && details.get) {
182
+ const getY = details.get;
183
+ if (getY.source === 'products' && getY.source_value) {
184
+ getY.products = getY.source_value.map(id => allProducts[id]).filter(Boolean);
185
+ }
186
+ else if ((getY.source === 'categories' || getY.source === 'category') && allCategories && getY.source_value) {
187
+ getY.categories = this.findCategories(allCategories, getY.source_value);
188
+ details.categories = getY.categories;
189
+ }
190
+ }
191
+ if (offer.type === OfferType.BuyXGetY && details.buy) {
192
+ const buyX = details.buy;
193
+ if ((buyX.source === 'products' || buyX.source === 'product') && buyX.source_value) {
194
+ buyX.products = buyX.source_value.map(id => allProducts[id]).filter(Boolean);
195
+ }
196
+ }
197
+ }
198
+ return this.offersList;
166
199
  })
167
- .then((offers) => {
168
- salla.storage.set(this.getStorageKey(), { offers, stored_at: new Date().getTime() });
200
+ .then(() => {
169
201
  this.canRender = true;
170
202
  })
171
203
  .catch((error) => {
@@ -189,128 +221,165 @@ export class SallaOffer {
189
221
  }
190
222
  return found;
191
223
  }
192
- //todo::add to the key params, to make sure it will support multi offers in the same page if it's wanted
193
- getStorageKey() {
194
- try {
195
- const pageSlug = salla.config.get('page.slug').replace('.', '_');
196
- const locale = salla.lang.getLocale();
197
- const currencyCode = salla.config.currency().code;
198
- if (!pageSlug || !locale || !currencyCode) {
199
- throw new Error('Unable to get the storage key.');
200
- }
201
- return `s-offers-${pageSlug}-${salla.config.get('page.id')}-${locale}-${currencyCode}`;
202
- }
203
- catch (error) {
204
- return '';
205
- }
206
- }
207
- //@ts-ignore
208
- getOffersFromStorage() {
209
- let storageOffers = salla.storage.get(this.getStorageKey());
210
- //if the offers not existed, or it has been stored before 10 minutes from now, ignore it;
211
- if (!storageOffers || storageOffers.stored_at < (new Date().getTime() - 10 * 60 * 1000)) {
212
- salla.storage.remove(this.getStorageKey());
213
- return null;
214
- }
215
- this.canRender = true;
216
- //return it as resolve to support .then
217
- return Promise.resolve(storageOffers.offers);
218
- }
219
224
  render() {
220
225
  // Check if the offers list is empty or if the component is not ready to render
221
226
  if (!this.offersList.length || !this.canRender || !this.showOffer)
222
227
  return null;
223
- const offer = this.offersList[0];
224
- const blockTitle = this.isBankOffer ? (this.isMultipleBank ? this.multipleBankOfferTitleText : null) : offer.title;
225
- const blockSubTitle = this.isBankOffer ? (this.isMultipleBank ? this.multipleBankOfferTitleDescription : null) : offer.description;
228
+ const blockTitle = salla.lang.get('pages.offer.offers_title', 'عروض المنتج');
229
+ const blockSubTitle = salla.lang.get('pages.offer.offers_subtitle', 'احصل على المنتج بسعر مخفض مع أفضل العروض');
226
230
  const titles = {
227
231
  'block-title': blockTitle,
228
232
  'block-subTitle': blockSubTitle,
229
- 'show-controls': this.isMultipleBank
233
+ 'show-controls': this.offersList.length > 1
230
234
  };
231
- return (h("div", { class: "s-offer-wrapper", onClick: () => this.emitPromotionClicked() }, h("p", { class: "s-offer-corner-badge" }, this.special_offer_text), h("salla-slider", { type: "carousel", id: "offer-slider", ...titles }, h("div", { slot: 'items' }, this.renderSectionForOfferType(offer.type)))));
235
+ return [
236
+ h("div", { class: "s-offer-wrapper" }, h("salla-slider", { type: "carousel", id: "offers-slider", ...titles }, h("div", { slot: "items" }, this.offersList.slice(0, 5).map((offer, index) => this.renderOfferCard(offer, index + 1)), this.offersList.length > 5 && this.renderShowMoreCard()))),
237
+ // Always render drawers but control visibility through visible prop
238
+ this.renderAllOffersModal(),
239
+ this.renderProductsModal()
240
+ ];
241
+ }
242
+ renderShowMoreCard() {
243
+ return (h("div", { class: "s-offer-slide-one-fourth swiper-slide", onClick: (e) => {
244
+ e.preventDefault();
245
+ e.stopPropagation();
246
+ this.openAllOffersModal();
247
+ } }, h("div", { class: "s-offer-card s-offer-show-more-card" }, h("i", { class: "sicon-add s-offer-show-more-icon" }), h("h3", { class: "s-offer-show-more-title" }, salla.lang.get('pages.offer.show_more_offers', 'عرض المزيد من العروض')))));
248
+ }
249
+ openAllOffersModal() {
250
+ this.showAllOffersModal = true;
232
251
  }
233
- renderSectionForOfferType(offerType) {
234
- if (this.isBankOffer) {
235
- return this.renderBankSection();
252
+ closeAllOffersModal() {
253
+ this.showAllOffersModal = false;
254
+ }
255
+ closeProductsModal() {
256
+ this.showProductsModal = false;
257
+ this.selectedOfferProducts = [];
258
+ this.productsLoaded = false;
259
+ }
260
+ handleAccordionToggle(offerId, collapsed) {
261
+ this.collapsedOffers = {
262
+ ...this.collapsedOffers,
263
+ [offerId]: collapsed
264
+ };
265
+ }
266
+ getOfferProducts(offer) {
267
+ const details = offer.details;
268
+ // Handle products from any offer type
269
+ if (details.products && details.products.length > 0) {
270
+ return details.products;
236
271
  }
237
- if (offerType == OfferType.SpecialPrice) {
238
- return this.renderSpecialPriceSection();
272
+ // Handle BuyXGetY special case
273
+ if (offer.type === OfferType.BuyXGetY && details.get?.products) {
274
+ return details.get.products;
239
275
  }
240
- if (offerType == OfferType.BuyXGetY) {
241
- return this.renderBuyXGetYSection();
276
+ // For categories, we'll return empty array as we handle categories separately
277
+ return [];
278
+ }
279
+ renderProductsLinkForModalCard(offer, isInDrawer) {
280
+ const products = this.getOfferProducts(offer);
281
+ if (!products || products.length === 0) {
282
+ return null;
242
283
  }
243
- return this.renderDiscountTableSection();
284
+ const handleProductsClick = (e) => {
285
+ e.stopPropagation();
286
+ this.selectedOfferProducts = products;
287
+ this.showProductsModal = true;
288
+ };
289
+ return (h("div", { class: "s-offer-products-link", onClick: handleProductsClick }, h("span", { class: "s-offer-products-link-text" }, this.products_link_text), isInDrawer && h("i", { class: "sicon-keyboard_arrow_down s-offer-products-link-icon" })));
244
290
  }
245
- /**
246
- * Generates content for the categories section.
247
- *
248
- * @param offeredCategories - An array of Category objects.
249
- * @returns An array of HTML elements representing categories.
250
- */
251
- getCategoriesSection(category) {
252
- return h("div", { class: "s-offer-slide-one-sixth swiper-slide", innerHTML: this.categorySlot
253
- .replace(/\{url\}/g, category.url)
254
- .replace(/\{icon\}/g, category.icon || "sicon-store")
255
- .replace(/\{name\}/g, category.name) });
291
+ renderAllOffersModal() {
292
+ return (h("salla-drawer", { visible: this.showAllOffersModal, position: "right", width: "md", "no-padding": true, "drawer-title": salla.lang.get('pages.offer.all_offers_title', 'جميع العروض'), onDrawerVisibilityChanged: (e) => !e.detail && this.closeAllOffersModal() }, h("div", { class: "s-offer-drawer-content" }, this.offersList.map((offer, index) => this.renderModalOfferCard(offer, index + 1)))));
256
293
  }
257
- renderBuyXGetYSection() {
258
- const details = this.offersList[0].details;
259
- return [
260
- details.get.products?.map((product) => (h("div", { class: "s-offer-slide-one-fourth" }, this.hasCustomComponent
261
- ? h(this.productCardComponent, { product: product })
262
- : h("salla-product-card", { "shadow-on-hover": true, product: product })))),
263
- details.get.categories?.map((category) => this.getCategoriesSection(category))
264
- ];
294
+ renderProductsModal() {
295
+ return (h("salla-drawer", { visible: this.showProductsModal, width: "md", position: "right", "no-padding": true, "drawer-title": this.products_link_text, onDrawerVisibilityChanged: (e) => !e.detail && this.closeProductsModal() }, h("div", { class: "s-offer-products-drawer-content" }, this.selectedOfferProducts?.length > 0 ? (h("div", null, !this.productsLoaded && (h("div", { class: "flex items-center justify-center p-8" }, h("salla-loading", { size: "24" }))), h("salla-products-list", { source: "selected", "source-value": JSON.stringify(this.selectedOfferProducts.map(p => p.id)), "product-card-component": this.productCardComponent, "horizontal-cards": true, "compact-cards": true, includes: ["images"], onProductsFetched: () => this.productsLoaded = true }))) : (h("div", { class: "p-4 text-center text-gray-500" }, salla.lang.get('blocks.products.no_products_found', 'لا توجد منتجات'))))));
265
296
  }
266
- /**
267
- * Generates content for the bank section.
268
- *
269
- * @param offeredBank - An array of Bank objects.
270
- * @param name - The title of the current offer.
271
- * @param description - The description of the current offer.
272
- * @returns An array of HTML elements representing banks.
273
- *
274
- * TODO: loop over the list and filter bank types and pass it to this function
275
- */
276
- renderBankSection() {
277
- return this.offersList.map((bankOffer) => {
278
- return h("div", { class: { "s-offer-slide-one-sixth": this.isMultipleBank, "s-offer-bank-wrapper-sinlge-item": !this.isMultipleBank } }, h("div", { class: { "s-offer-bank-wrapper": true, "s-offer-slide-one-sixth": !this.isMultipleBank, "s-offer-bank-wrapper-multi-spacer": this.isMultipleBank } }, h("div", { class: "s-offer-bank-logo" }, h("img", { src: bankOffer.details.logo || salla.url.cdn('images/s-empty.png'), "data-src": bankOffer.details.logo, alt: bankOffer.title + " offer" })), h("ul", { class: "s-offer-bank-payment-wrapper" }, bankOffer.details.payments.map((payment) => {
279
- return h("li", { class: "s-offer-bank-payment-single" }, h("img", { src: salla.url.cdn('images/payment/' + payment + '.png') || salla.url.cdn('images/s-empty.png'), "data-src": salla.url.cdn('images/payment/' + payment + '.png'), alt: "payment" }));
280
- })), this.isMultipleBank ?
281
- h("p", { class: "s-offer-bank-payment-discount-percent" }, `${this.product_discount_text} ${bankOffer.details.discount_value}${bankOffer.details.discount_type === "percentage" && '%'}`)
282
- : ""), !this.isMultipleBank ?
283
- h("div", { class: "s-offer-bank-message s-offer-slide-one-fourth" }, h("h2", null, this.offersList[0].title), h("p", { innerHTML: this.generateBankDescription(this.offersList[0].description, bankOffer.details.discount_value) }))
284
- : "");
285
- });
297
+ renderModalOfferCard(offer, position = 1) {
298
+ const products = this.getOfferProducts(offer);
299
+ const hasProducts = products && products.length > 0;
300
+ const isCollapsed = this.collapsedOffers[offer.id] !== false; // Default to collapsed
301
+ return (h("div", { class: "s-offer-drawer-card" }, h("div", { class: "s-offer-card-main", onClick: () => this.emitPromotionClicked(offer, position) }, h("div", { class: "s-offer-card-icon" }, this.getOfferIcon(offer.type)), h("div", { class: "s-offer-card-content" }, h("h3", { class: "s-offer-card-title", title: offer.title }, offer.title), offer.description && h("p", { class: "s-offer-card-description" }, offer.description), offer.type === OfferType.DiscountsTable ? (h("div", { class: "s-offer-card-details" }, this.renderDiscountTableOfferContent(offer))) : (offer.type === OfferType.PercentageOrFixed || offer.type === OfferType.Percentage || offer.type === OfferType.FixedAmount) ? (h("div", { class: "s-offer-card-details" }, this.renderPercentageOrFixedOfferContent(offer), this.renderOfferCategories(offer))) : (h("div", { class: "s-offer-card-details" }, this.renderOfferCategories(offer))))), hasProducts && (h("salla-accordion", { collapsed: isCollapsed, collapsible: true, size: "sm", onClick: (e) => e.stopPropagation(), onAccordionToggle: (e) => this.handleAccordionToggle(offer.id, e.detail.payload.collapsed) }, h("salla-accordion-head", { collapsible: true, collapsed: isCollapsed }, h("div", { slot: "title", class: "s-offer-products-thumbnails" }, h("span", { class: "s-offer-products-title" }, this.products_link_text, h("i", { class: `sicon-keyboard_arrow_${isCollapsed ? 'down' : 'up'} s-offer-products-link-icon` })), h("div", { class: "s-offer-products-thumbnails-stack" }, products.slice(0, 3).map((product, index) => (h("div", { class: "s-offer-product-thumbnail", style: { zIndex: `${index + 1}` } }, h("img", { src: product.thumbnail || product.image?.url || salla.url.cdn('images/s-empty.png'), alt: product.name })))), products.length > 3 && (h("div", { class: "s-offer-products-more-count", style: { zIndex: '7' } }, "+", products.length - 3))))), h("salla-accordion-body", null, h("div", { class: "s-offer-products-content" }, h("salla-products-list", { source: "selected", "source-value": JSON.stringify(products.map(p => p.id)), "product-card-component": this.productCardComponent, "horizontal-cards": true, "compact-cards": true, includes: ["images"] })))))));
302
+ }
303
+ renderOfferCard(offer, position = 1) {
304
+ return (h("div", { class: "s-offer-slide-one-fourth swiper-slide", onClick: () => this.emitPromotionClicked(offer, position) }, h("div", { class: "s-offer-card" }, h("div", { class: "s-offer-card-icon" }, this.getOfferIcon(offer.type)), h("div", { class: "s-offer-card-content" }, h("h3", { class: "s-offer-card-title", title: offer.title }, offer.title), offer.description && h("p", { class: "s-offer-card-description" }, offer.description), h("div", { class: "s-offer-card-details" }, offer.type === OfferType.DiscountsTable
305
+ ? this.renderDiscountTableOfferContent(offer)
306
+ : (offer.type === OfferType.PercentageOrFixed || offer.type === OfferType.Percentage || offer.type === OfferType.FixedAmount)
307
+ ? [
308
+ this.renderPercentageOrFixedOfferContent(offer),
309
+ this.renderOfferCategories(offer)
310
+ ]
311
+ : this.renderOfferCategories(offer), this.renderProductsLinkForModalCard(offer, false))))));
312
+ }
313
+ getOfferIcon(offerType) {
314
+ const iconMap = {
315
+ [OfferType.DiscountsTable]: 'sicon-discount-calculator',
316
+ [OfferType.Bank]: 'sicon-bank',
317
+ [OfferType.SpecialPrice]: 'sicon-fire',
318
+ [OfferType.BuyXGetY]: 'sicon-gift',
319
+ [OfferType.PercentageOrFixed]: 'sicon-special-discount',
320
+ [OfferType.Percentage]: 'sicon-special-discount',
321
+ [OfferType.FixedAmount]: 'sicon-special-discount'
322
+ };
323
+ return h("i", { class: iconMap[offerType] || 'sicon-discount' });
324
+ }
325
+ renderDiscountTableOfferContent(offer) {
326
+ const details = offer.details;
327
+ const discounts = details.discounts || [];
328
+ if (!discounts.length)
329
+ return null;
330
+ return (h("div", null, h("div", { class: "s-offer-card-description" }, salla.lang.get('pages.offer.discount_table_subtitle', 'وفر اكتر بشراء منتجات أكثر')), h("table", { class: "s-offer-discount-table" }, h("tbody", null, this.groupDiscountsByRows(discounts, 3).map((row, rowIndex) => (h("tr", { key: rowIndex }, row.map((discount, colIndex) => (h("td", { key: colIndex }, h("div", { class: "s-offer-discount-percentage" }, discount.percentage, "%"), h("div", { class: "s-offer-discount-condition" }, this.formatDiscountCondition(discount))))))))))));
286
331
  }
287
- generateBankDescription(desc, value) {
288
- return desc.replace(new RegExp(`${value} %`), `<span class="s-offer-bank-message-amount">${value} %</span>`);
332
+ renderPercentageOrFixedOfferContent(offer) {
333
+ const details = offer.details;
334
+ if (!details.discount_value && !(details.min_spend > 0) && !(details.min_items > 0))
335
+ return null;
336
+ return (h("div", { class: "s-offer-percentage-fixed-content" }, details.min_spend > 0 && (h("div", { class: "s-offer-min-spend" }, this.min_spend_text(details.min_spend, this.userCurrency?.symbol || ''))), details.min_items > 0 && (h("div", { class: "s-offer-min-items" }, this.min_items_text(details.min_items)))));
337
+ }
338
+ groupDiscountsByRows(discounts, itemsPerRow) {
339
+ const rows = [];
340
+ for (let i = 0; i < discounts.length; i += itemsPerRow) {
341
+ rows.push(discounts.slice(i, i + itemsPerRow));
342
+ }
343
+ return rows;
344
+ }
345
+ formatDiscountCondition(discount) {
346
+ // Format the condition text based on discount amount or quantity
347
+ if (discount.discounted_amount) {
348
+ return `${discount.discounted_amount} ${this.userCurrency?.symbol || ''}`;
349
+ }
350
+ if (discount.quantity != null) {
351
+ return this.buy_quantity_text(discount.quantity);
352
+ }
353
+ return `1 ${this.product_text}`;
354
+ }
355
+ renderOfferCategories(offer) {
356
+ const details = offer.details;
357
+ // Get categories from different locations based on offer type
358
+ let categories = details.categories || [];
359
+ // For BuyXGetY offers, also check get.categories
360
+ if (offer.type === OfferType.BuyXGetY && details.get?.categories) {
361
+ categories = details.get.categories;
362
+ }
363
+ if (!categories.length)
364
+ return null;
365
+ const maxVisible = 3; // Show only first 3 categories initially
366
+ const isExpanded = this.expandedCategories[offer.id];
367
+ const shouldShowMore = categories.length > maxVisible;
368
+ const visibleCategories = isExpanded ? categories : categories.slice(0, maxVisible);
369
+ return (h("div", { class: "s-offer-categories" }, h("div", { class: "s-offer-categories-list" }, visibleCategories.map((category, index) => (h("a", { key: index, class: "s-offer-category-item", href: category.url || salla.url.create('categories', category.id || category.id_) }, category.name))), shouldShowMore && (h("span", { class: "s-offer-categories-toggle", onClick: (e) => {
370
+ e.preventDefault();
371
+ e.stopPropagation();
372
+ this.toggleCategoryExpansion(offer.id);
373
+ } }, isExpanded ? (h("span", null, h("i", { class: "sicon-keyboard_arrow_up" }), ' ', salla.lang.get('common.elements.hide', 'إخفاء'))) : (h("span", null, salla.lang.get('common.elements.show', 'عرض'), " ", `+${categories.length - maxVisible}`, ' ', h("i", { class: "sicon-keyboard_arrow_down" }))))))));
289
374
  }
290
375
  /**
291
- * Generates content for the discount table section.
292
- *
293
- * @param discountTable - An array of Discount objects.
294
- * @returns An array of HTML elements representing discounts_table.
376
+ * Toggle category expansion for a specific offer
295
377
  */
296
- renderDiscountTableSection() {
297
- const offer = this.offersList[0];
298
- let show_discounted_price = offer.details.show_price_after_discount;
299
- return this.offersList[0].details.discounts?.map((discount) => h("div", { class: "s-offer-slide-one-fourth" }, h("div", { class: "s-offer-slide-offer-entry" }, h("div", { class: "s-offer-slide-offer-entry-price-quantity-container" }, h("p", { class: "s-offer-slide-offer-entry-quantity" }, this.buy_quantity_text(discount.quantity)), show_discounted_price ?
300
- h("div", { class: "s-offer-slide-offer-entry-price" }, h("span", null, this.offer_with_price_text), h("span", { class: "s-offer-slide-offer-entry-price-amount" }, discount.discounted_amount), " ", h("span", null, this.userCurrency)) : ""), h("p", { class: "s-offer-slide-offer-entry-price-amount-percent" }, this.with_discount_text, "(", h("span", null, discount.percentage, !!discount.percentage && '%'), ")"))));
301
- }
302
- renderSpecialPriceSection() {
303
- const details = this.offersList[0].details;
304
- return [
305
- // Render products if `apply_to` is "product"
306
- details.apply_to === "product" &&
307
- details.products?.map((product) => (h("div", { class: "s-offer-slide-one-fourth" }, this.hasCustomComponent
308
- ? h(this.productCardComponent, { product: product })
309
- : h("salla-product-card", { "shadow-on-hover": true, product: product })))),
310
- // Render categories if `apply_to` is "category"
311
- details.apply_to === "category" &&
312
- details.categories?.map((category) => this.getCategoriesSection(category)),
313
- ];
378
+ toggleCategoryExpansion(offerId) {
379
+ this.expandedCategories = {
380
+ ...this.expandedCategories,
381
+ [offerId]: !this.expandedCategories[offerId]
382
+ };
314
383
  }
315
384
  static get is() { return "salla-offer"; }
316
385
  static get originalStyleUrls() {
@@ -346,7 +415,7 @@ export class SallaOffer {
346
415
  "getter": false,
347
416
  "setter": false,
348
417
  "reflect": false,
349
- "defaultValue": "'custom-salla-product-card'"
418
+ "defaultValue": "'salla-product-card'"
350
419
  }
351
420
  };
352
421
  }
@@ -354,20 +423,26 @@ export class SallaOffer {
354
423
  return {
355
424
  "offersList": {},
356
425
  "userCurrency": {},
357
- "isMultipleBank": {},
358
426
  "title": {},
359
427
  "currentPage": {},
360
428
  "hasCustomComponent": {},
361
- "isBankOffer": {},
362
429
  "canRender": {},
363
430
  "showOffer": {},
431
+ "showAllOffersModal": {},
432
+ "showProductsModal": {},
433
+ "selectedOfferProducts": {},
434
+ "collapsedOffers": {},
435
+ "expandedCategories": {},
436
+ "productsLoaded": {},
364
437
  "offer_with_price_text": {},
365
438
  "with_discount_text": {},
366
439
  "product_discount_text": {},
367
440
  "special_offer_text": {},
368
- "multipleBankOfferTitleText": {},
369
- "multipleBankOfferTitleDescription": {},
370
- "buy_quantity_text": {}
441
+ "buy_quantity_text": {},
442
+ "products_link_text": {},
443
+ "min_spend_text": {},
444
+ "min_items_text": {},
445
+ "product_text": {}
371
446
  };
372
447
  }
373
448
  static get elementRef() { return "host"; }