spree_core 4.10.1 → 5.0.0.rc1

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 (476) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/config/spree_core_manifest.js +4 -0
  3. data/app/assets/images/google_on_white_hdpi.png +0 -0
  4. data/app/controllers/spree/base_controller.rb +1 -4
  5. data/app/finders/spree/orders/find_complete.rb +14 -2
  6. data/app/finders/spree/products/find.rb +74 -23
  7. data/app/finders/spree/stores/find_current.rb +6 -2
  8. data/app/helpers/spree/addresses_helper.rb +106 -0
  9. data/app/helpers/spree/base_helper.rb +83 -55
  10. data/app/helpers/spree/currency_helper.rb +12 -0
  11. data/app/helpers/spree/images_helper.rb +18 -0
  12. data/app/helpers/spree/mail_helper.rb +24 -0
  13. data/app/helpers/spree/products_helper.rb +1 -20
  14. data/app/javascript/spree/core/controllers/address_autocomplete_controller.js +233 -0
  15. data/app/javascript/spree/core/controllers/address_form_controller.js +98 -0
  16. data/app/javascript/spree/core/controllers/enable_button_controller.js +29 -0
  17. data/app/javascript/spree/core/helpers/address_autocomplete/google_places_suggestions_provider.js +179 -0
  18. data/app/javascript/spree/core/helpers/debounce.js +9 -0
  19. data/app/javascript/spree/core/helpers/scroll_lock.js +25 -0
  20. data/app/jobs/spree/addresses/geocode_address_job.rb +31 -0
  21. data/app/jobs/spree/base_job.rb +1 -0
  22. data/app/jobs/spree/coupon_codes/bulk_generate_job.rb +17 -0
  23. data/app/jobs/spree/exports/generate_job.rb +12 -0
  24. data/app/jobs/spree/products/auto_match_taxons_job.rb +14 -0
  25. data/app/jobs/spree/products/touch_taxons_job.rb +12 -0
  26. data/app/jobs/spree/reports/generate_job.rb +12 -0
  27. data/app/jobs/spree/stock_locations/stock_items/create_job.rb +1 -1
  28. data/app/jobs/spree/themes/duplicate_components_job.rb +59 -0
  29. data/app/jobs/spree/themes/screenshot_job.rb +81 -0
  30. data/app/jobs/spree/variants/remove_from_incomplete_orders_job.rb +2 -0
  31. data/app/jobs/spree/variants/remove_line_item_job.rb +2 -0
  32. data/app/mailers/spree/base_mailer.rb +51 -0
  33. data/app/mailers/spree/export_mailer.rb +19 -0
  34. data/app/mailers/spree/report_mailer.rb +20 -0
  35. data/app/mailers/spree/test_mailer.rb +8 -0
  36. data/app/models/action_text/rich_text_decorator.rb +11 -0
  37. data/app/models/action_text/video_embed.rb +13 -0
  38. data/app/models/acts_as_taggable_on/tag_decorator.rb +10 -0
  39. data/app/models/concerns/spree/calculated_adjustments.rb +2 -0
  40. data/app/models/concerns/spree/display_on.rb +13 -0
  41. data/app/models/concerns/spree/has_one_link.rb +42 -0
  42. data/app/models/concerns/spree/has_page_links.rb +53 -0
  43. data/app/models/concerns/spree/metadata.rb +3 -7
  44. data/app/models/concerns/spree/multi_searchable.rb +21 -0
  45. data/app/models/concerns/spree/multi_store_resource.rb +9 -0
  46. data/app/models/concerns/spree/number_as_param.rb +4 -2
  47. data/app/models/concerns/spree/parameterizable_name.rb +21 -0
  48. data/app/models/concerns/spree/previewable.rb +17 -0
  49. data/app/models/concerns/spree/product_scopes.rb +7 -7
  50. data/app/models/concerns/spree/stores/setup.rb +52 -0
  51. data/app/models/concerns/spree/stores/socials.rb +68 -0
  52. data/app/models/concerns/spree/user_address.rb +4 -0
  53. data/app/models/concerns/spree/user_methods.rb +61 -11
  54. data/app/models/concerns/spree/user_reporting.rb +14 -6
  55. data/app/models/concerns/spree/user_roles.rb +1 -1
  56. data/app/models/spree/ability.rb +4 -2
  57. data/app/models/spree/address.rb +122 -28
  58. data/app/models/spree/adjustment.rb +4 -1
  59. data/app/models/spree/asset/support/active_storage.rb +1 -1
  60. data/app/models/spree/asset.rb +18 -6
  61. data/app/models/spree/base.rb +38 -7
  62. data/app/models/spree/base_analytics_event_handler.rb +49 -0
  63. data/app/models/spree/calculator.rb +1 -1
  64. data/app/models/spree/classification.rb +10 -1
  65. data/app/models/spree/country.rb +1 -1
  66. data/app/models/spree/coupon_code.rb +38 -0
  67. data/app/models/spree/credit_card.rb +4 -3
  68. data/app/models/spree/current.rb +9 -0
  69. data/app/models/spree/custom_domain.rb +53 -0
  70. data/app/models/spree/customer_return.rb +13 -1
  71. data/app/models/spree/data_feed.rb +1 -1
  72. data/app/models/spree/digital.rb +5 -6
  73. data/app/models/spree/digital_link.rb +11 -6
  74. data/app/models/spree/export.rb +172 -0
  75. data/app/models/spree/exports/orders.rb +23 -0
  76. data/app/models/spree/exports/products.rb +35 -0
  77. data/app/models/spree/gateway/bogus.rb +5 -0
  78. data/app/models/spree/gateway.rb +14 -4
  79. data/app/models/spree/gateway_customer.rb +13 -0
  80. data/app/models/spree/image/configuration/active_storage.rb +1 -1
  81. data/app/models/spree/inventory_unit.rb +1 -1
  82. data/app/models/spree/legacy_user.rb +3 -1
  83. data/app/models/spree/line_item.rb +37 -2
  84. data/app/models/spree/log_entry.rb +1 -1
  85. data/app/models/spree/option_type.rb +40 -6
  86. data/app/models/spree/option_type_prototype.rb +1 -1
  87. data/app/models/spree/option_value.rb +35 -5
  88. data/app/models/spree/option_value_variant.rb +2 -2
  89. data/app/models/spree/order/address_book.rb +34 -15
  90. data/app/models/spree/order/checkout.rb +12 -2
  91. data/app/models/spree/order/currency_updater.rb +1 -1
  92. data/app/models/spree/order/digital.rb +14 -3
  93. data/app/models/spree/order/emails.rb +1 -1
  94. data/app/models/spree/order/payments.rb +1 -13
  95. data/app/models/spree/order/store_credit.rb +17 -5
  96. data/app/models/spree/order/webhooks.rb +1 -1
  97. data/app/models/spree/order.rb +179 -49
  98. data/app/models/spree/order_promotion.rb +1 -1
  99. data/app/models/spree/order_updater.rb +9 -3
  100. data/app/models/spree/page.rb +184 -0
  101. data/app/models/spree/page_block.rb +69 -0
  102. data/app/models/spree/page_blocks/buttons.rb +29 -0
  103. data/app/models/spree/page_blocks/heading.rb +18 -0
  104. data/app/models/spree/page_blocks/image.rb +17 -0
  105. data/app/models/spree/page_blocks/link.rb +21 -0
  106. data/app/models/spree/page_blocks/mega_nav.rb +33 -0
  107. data/app/models/spree/page_blocks/mega_nav_with_subcategories.rb +32 -0
  108. data/app/models/spree/page_blocks/nav.rb +15 -0
  109. data/app/models/spree/page_blocks/newsletter_form.rb +18 -0
  110. data/app/models/spree/page_blocks/products/buy_buttons.rb +12 -0
  111. data/app/models/spree/page_blocks/products/price.rb +18 -0
  112. data/app/models/spree/page_blocks/products/quantity_selector.rb +12 -0
  113. data/app/models/spree/page_blocks/products/share.rb +8 -0
  114. data/app/models/spree/page_blocks/products/title.rb +15 -0
  115. data/app/models/spree/page_blocks/products/variant_picker.rb +9 -0
  116. data/app/models/spree/page_blocks/subheading.rb +17 -0
  117. data/app/models/spree/page_blocks/text.rb +16 -0
  118. data/app/models/spree/page_link.rb +59 -0
  119. data/app/models/spree/page_section.rb +215 -0
  120. data/app/models/spree/page_sections/announcement_bar.rb +30 -0
  121. data/app/models/spree/page_sections/collection_banner.rb +18 -0
  122. data/app/models/spree/page_sections/custom_code.rb +11 -0
  123. data/app/models/spree/page_sections/featured_posts.rb +43 -0
  124. data/app/models/spree/page_sections/featured_product.rb +46 -0
  125. data/app/models/spree/page_sections/featured_taxon.rb +88 -0
  126. data/app/models/spree/page_sections/featured_taxons.rb +45 -0
  127. data/app/models/spree/page_sections/footer.rb +94 -0
  128. data/app/models/spree/page_sections/header.rb +62 -0
  129. data/app/models/spree/page_sections/image_banner.rb +38 -0
  130. data/app/models/spree/page_sections/image_with_text.rb +48 -0
  131. data/app/models/spree/page_sections/main_password_footer.rb +18 -0
  132. data/app/models/spree/page_sections/main_password_header.rb +20 -0
  133. data/app/models/spree/page_sections/newsletter.rb +47 -0
  134. data/app/models/spree/page_sections/page_title.rb +19 -0
  135. data/app/models/spree/page_sections/post_details.rb +19 -0
  136. data/app/models/spree/page_sections/post_grid.rb +19 -0
  137. data/app/models/spree/page_sections/product_details.rb +16 -0
  138. data/app/models/spree/page_sections/product_grid.rb +13 -0
  139. data/app/models/spree/page_sections/related_products.rb +60 -0
  140. data/app/models/spree/page_sections/rich_text.rb +20 -0
  141. data/app/models/spree/page_sections/taxon_banner.rb +18 -0
  142. data/app/models/spree/page_sections/taxon_grid.rb +17 -0
  143. data/app/models/spree/page_sections/video.rb +99 -0
  144. data/app/models/spree/pages/account.rb +15 -0
  145. data/app/models/spree/pages/cart.rb +9 -0
  146. data/app/models/spree/pages/checkout.rb +9 -0
  147. data/app/models/spree/pages/custom.rb +34 -0
  148. data/app/models/spree/pages/homepage.rb +68 -0
  149. data/app/models/spree/pages/login.rb +15 -0
  150. data/app/models/spree/pages/password.rb +57 -0
  151. data/app/models/spree/pages/post.rb +27 -0
  152. data/app/models/spree/pages/post_list.rb +32 -0
  153. data/app/models/spree/pages/product_details.rb +29 -0
  154. data/app/models/spree/pages/search_results.rb +43 -0
  155. data/app/models/spree/pages/shop_all.rb +36 -0
  156. data/app/models/spree/pages/taxon.rb +29 -0
  157. data/app/models/spree/pages/taxon_list.rb +41 -0
  158. data/app/models/spree/pages/wishlist.rb +11 -0
  159. data/app/models/spree/payment/gateway_options.rb +13 -15
  160. data/app/models/spree/payment/processing.rb +1 -1
  161. data/app/models/spree/payment/webhooks.rb +1 -1
  162. data/app/models/spree/payment.rb +61 -12
  163. data/app/models/spree/payment_capture_event.rb +1 -1
  164. data/app/models/spree/payment_method/store_credit.rb +9 -1
  165. data/app/models/spree/payment_method.rb +26 -8
  166. data/app/models/spree/payment_source.rb +2 -2
  167. data/app/models/spree/post.rb +108 -0
  168. data/app/models/spree/post_category.rb +33 -0
  169. data/app/models/spree/preference.rb +1 -1
  170. data/app/models/spree/price.rb +10 -3
  171. data/app/models/spree/product/webhooks.rb +1 -1
  172. data/app/models/spree/product.rb +325 -54
  173. data/app/models/spree/product_option_type.rb +1 -1
  174. data/app/models/spree/product_promotion_rule.rb +1 -1
  175. data/app/models/spree/product_property.rb +4 -1
  176. data/app/models/spree/promotion/actions/create_line_items.rb +37 -2
  177. data/app/models/spree/promotion/rules/country.rb +22 -4
  178. data/app/models/spree/promotion/rules/currency.rb +21 -0
  179. data/app/models/spree/promotion/rules/item_total.rb +12 -3
  180. data/app/models/spree/promotion/rules/option_value.rb +5 -20
  181. data/app/models/spree/promotion/rules/product.rb +33 -1
  182. data/app/models/spree/promotion/rules/taxon.rb +31 -0
  183. data/app/models/spree/promotion/rules/user.rb +33 -4
  184. data/app/models/spree/promotion.rb +136 -15
  185. data/app/models/spree/promotion_action.rb +31 -1
  186. data/app/models/spree/promotion_action_line_item.rb +1 -1
  187. data/app/models/spree/promotion_category.rb +1 -1
  188. data/app/models/spree/promotion_handler/cart.rb +1 -1
  189. data/app/models/spree/promotion_handler/coupon.rb +46 -8
  190. data/app/models/spree/promotion_handler/free_shipping.rb +1 -1
  191. data/app/models/spree/promotion_handler/promotion_duplicator.rb +6 -5
  192. data/app/models/spree/promotion_rule.rb +23 -1
  193. data/app/models/spree/promotion_rule_taxon.rb +1 -1
  194. data/app/models/spree/promotion_rule_user.rb +1 -1
  195. data/app/models/spree/property.rb +11 -3
  196. data/app/models/spree/property_prototype.rb +1 -1
  197. data/app/models/spree/prototype.rb +1 -1
  198. data/app/models/spree/prototype_taxon.rb +1 -1
  199. data/app/models/spree/refund.rb +24 -4
  200. data/app/models/spree/refund_reason.rb +12 -2
  201. data/app/models/spree/reimbursement/credit.rb +1 -1
  202. data/app/models/spree/reimbursement/emails.rb +1 -1
  203. data/app/models/spree/reimbursement.rb +5 -3
  204. data/app/models/spree/reimbursement_type.rb +1 -1
  205. data/app/models/spree/report.rb +110 -0
  206. data/app/models/spree/report_line_item.rb +27 -0
  207. data/app/models/spree/report_line_items/products_performance.rb +76 -0
  208. data/app/models/spree/report_line_items/sales_total.rb +49 -0
  209. data/app/models/spree/reports/products_performance.rb +44 -0
  210. data/app/models/spree/reports/sales_total.rb +14 -0
  211. data/app/models/spree/return_authorization.rb +4 -1
  212. data/app/models/spree/return_authorization_reason.rb +1 -1
  213. data/app/models/spree/return_item.rb +2 -1
  214. data/app/models/spree/role.rb +5 -2
  215. data/app/models/spree/role_user.rb +2 -2
  216. data/app/models/spree/shipment/emails.rb +1 -1
  217. data/app/models/spree/shipment/webhooks.rb +1 -1
  218. data/app/models/spree/shipment.rb +14 -4
  219. data/app/models/spree/shipping_category.rb +1 -1
  220. data/app/models/spree/shipping_method.rb +48 -8
  221. data/app/models/spree/shipping_method_category.rb +1 -1
  222. data/app/models/spree/shipping_method_zone.rb +1 -1
  223. data/app/models/spree/shipping_rate.rb +21 -3
  224. data/app/models/spree/state.rb +1 -1
  225. data/app/models/spree/state_change.rb +1 -1
  226. data/app/models/spree/stock_item/webhooks.rb +1 -1
  227. data/app/models/spree/stock_item.rb +9 -6
  228. data/app/models/spree/stock_location.rb +35 -8
  229. data/app/models/spree/stock_movement/webhooks.rb +1 -1
  230. data/app/models/spree/stock_movement.rb +9 -3
  231. data/app/models/spree/stock_transfer.rb +41 -3
  232. data/app/models/spree/store.rb +345 -72
  233. data/app/models/spree/store_credit.rb +12 -4
  234. data/app/models/spree/store_credit_category.rb +1 -1
  235. data/app/models/spree/store_credit_event.rb +21 -1
  236. data/app/models/spree/store_credit_type.rb +1 -1
  237. data/app/models/spree/store_payment_method.rb +1 -1
  238. data/app/models/spree/store_product.rb +1 -1
  239. data/app/models/spree/store_promotion.rb +1 -1
  240. data/app/models/spree/tax_category.rb +15 -1
  241. data/app/models/spree/tax_rate.rb +1 -1
  242. data/app/models/spree/taxon.rb +210 -27
  243. data/app/models/spree/taxon_image/configuration/active_storage.rb +1 -1
  244. data/app/models/spree/taxon_rule.rb +25 -0
  245. data/app/models/spree/taxon_rules/available_on.rb +20 -0
  246. data/app/models/spree/taxon_rules/sale.rb +16 -0
  247. data/app/models/spree/taxon_rules/tag.rb +19 -0
  248. data/app/models/spree/taxonomy.rb +3 -2
  249. data/app/models/spree/theme.rb +200 -0
  250. data/app/models/spree/themes/default.rb +94 -0
  251. data/app/models/spree/variant/webhooks.rb +1 -1
  252. data/app/models/spree/variant.rb +211 -62
  253. data/app/models/spree/wished_item.rb +1 -1
  254. data/app/models/spree/wishlist.rb +1 -1
  255. data/app/models/spree/zone.rb +1 -1
  256. data/app/models/spree/zone_member.rb +1 -1
  257. data/app/presenters/spree/csv/order_line_item_presenter.rb +145 -0
  258. data/app/presenters/spree/csv/product_presenter.rb +63 -0
  259. data/app/presenters/spree/csv/product_variant_presenter.rb +130 -0
  260. data/app/services/spree/addresses/create.rb +31 -6
  261. data/app/services/spree/addresses/helper.rb +7 -4
  262. data/app/services/spree/addresses/update.rb +79 -12
  263. data/app/services/spree/cart/remove_out_of_stock_items.rb +56 -0
  264. data/app/services/spree/checkout/add_store_credit.rb +6 -1
  265. data/app/services/spree/checkout/advance.rb +44 -4
  266. data/app/services/spree/checkout/select_shipping_method.rb +2 -0
  267. data/app/services/spree/coupon_codes/bulk_generate.rb +37 -0
  268. data/app/services/spree/coupon_codes/coupon_codes_handler.rb +34 -0
  269. data/app/services/spree/orders/create_user_account.rb +70 -0
  270. data/app/services/spree/orders/update_contact_information.rb +19 -0
  271. data/app/services/spree/products/auto_match_taxons.rb +64 -0
  272. data/app/services/spree/products/duplicator.rb +121 -0
  273. data/app/services/spree/products/prepare_nested_attributes.rb +169 -0
  274. data/app/services/spree/seeds/admin_user.rb +22 -0
  275. data/app/services/spree/seeds/all.rb +1 -0
  276. data/app/services/spree/seeds/stores.rb +5 -10
  277. data/app/services/spree/seeds/zones.rb +2 -0
  278. data/app/services/spree/tags/bulk_add.rb +38 -0
  279. data/app/services/spree/tags/bulk_remove.rb +24 -0
  280. data/app/services/spree/taxons/add_products.rb +39 -0
  281. data/app/services/spree/taxons/regenerate_products.rb +53 -0
  282. data/app/services/spree/taxons/remove_products.rb +53 -0
  283. data/app/services/spree/taxons/touch_featured_sections.rb +21 -0
  284. data/app/services/spree/themes/duplicator.rb +40 -0
  285. data/app/services/spree/variants/remove_line_items.rb +1 -1
  286. data/app/sorters/spree/classifications/sort.rb +68 -0
  287. data/app/sorters/spree/products/sort.rb +2 -3
  288. data/app/views/action_text/video_embeds/_thumbnail.html.erb +1 -0
  289. data/app/views/action_text/video_embeds/_video_embed.html.erb +3 -0
  290. data/app/views/active_storage/blobs/_blob.html.erb +20 -0
  291. data/app/views/layouts/action_text/contents/_content.html.erb +3 -0
  292. data/app/views/layouts/spree/base_mailer.html.erb +46 -0
  293. data/app/views/spree/addresses/_form.html.erb +58 -0
  294. data/app/views/spree/addresses/_suggestions_box.erb +14 -0
  295. data/app/views/spree/export_mailer/export_done.html.erb +15 -0
  296. data/app/views/spree/report_mailer/report_done.html.erb +15 -0
  297. data/app/views/spree/shared/_base_mailer_footer.html.erb +12 -0
  298. data/app/views/spree/shared/_base_mailer_header.html.erb +6 -0
  299. data/app/views/spree/shared/_base_mailer_stylesheets.html.erb +456 -0
  300. data/app/views/spree/shared/_google_places_api_loader.html.erb +7 -0
  301. data/app/views/spree/shared/_mailer_line_item.html.erb +12 -0
  302. data/app/views/spree/shared/_mailer_logo.html.erb +41 -0
  303. data/app/views/spree/shared/_payment.html.erb +41 -0
  304. data/app/views/spree/test_mailer/test_email.html.erb +40 -0
  305. data/app/views/spree/test_mailer/test_email.text.erb +4 -0
  306. data/config/i18n-tasks.yml +178 -0
  307. data/config/importmap.rb +14 -0
  308. data/config/initializers/acts_as_taggable_on.rb +2 -0
  309. data/config/initializers/inflections.rb +2 -0
  310. data/config/initializers/mobility.rb +4 -0
  311. data/config/initializers/oembed.rb +1 -0
  312. data/config/locales/en.yml +823 -413
  313. data/config/routes.rb +6 -5
  314. data/db/migrate/20210914000000_spree_four_three.rb +0 -79
  315. data/db/migrate/20240913143518_change_default_value_of_spree_option_types_filterable.rb +5 -0
  316. data/db/migrate/20240914153106_add_display_on_to_spree_properties.rb +5 -0
  317. data/db/migrate/20240915144935_add_position_to_spree_properties.rb +6 -0
  318. data/db/migrate/20241004181911_create_spree_coupon_codes.rb +15 -0
  319. data/db/migrate/20241005093437_add_multi_code_to_spree_promotions.rb +14 -0
  320. data/db/migrate/20241014140140_translate_rich_texts.rb +17 -0
  321. data/db/migrate/20241030134309_create_spree_exports.rb +23 -0
  322. data/db/migrate/20241104083457_migrate_spree_promotion_rules_option_value_eligible_values.rb +16 -0
  323. data/db/migrate/20241123110646_add_estimated_transit_fields_to_spree_shipping_methods.rb +6 -0
  324. data/db/migrate/20241127193411_create_spree_taxon_rules.rb +13 -0
  325. data/db/migrate/20241127223627_add_rules_match_policy_and_sort_order_to_spree_taxons.rb +6 -0
  326. data/db/migrate/20241128103947_add_automatic_to_spree_taxons.rb +5 -0
  327. data/db/migrate/20241218183905_add_gateway_customer_profile_id_to_spree_payment_sources.rb +5 -0
  328. data/db/migrate/20250107220432_add_accept_marketing_and_signup_for_an_account_to_spree_orders.rb +6 -0
  329. data/db/migrate/20250110171203_add_quick_checkout_to_spree_addresses.rb +6 -0
  330. data/db/migrate/20250113180019_add_preferences_to_spree_stores.rb +5 -0
  331. data/db/migrate/20250114193857_add_metadata_to_spree_stores.rb +13 -0
  332. data/db/migrate/20250119165904_create_spree_custom_domains.rb +22 -0
  333. data/db/migrate/20250120094216_create_page_builder_models.rb +78 -0
  334. data/db/migrate/20250120152208_add_default_locale_to_action_text_rich_texts.rb +7 -0
  335. data/db/migrate/20250121160028_create_spree_posts_and_spree_post_categories.rb +33 -0
  336. data/db/migrate/20250122113708_add_first_and_last_name_to_spree_admin_class.rb +9 -0
  337. data/db/migrate/20250123135358_add_custom_code_fields_to_spree_store.rb +7 -0
  338. data/db/migrate/20250127083740_add_kind_to_spree_properties.rb +5 -0
  339. data/db/migrate/20250127112758_add_latitude_and_longitude_to_spree_addresses.rb +6 -0
  340. data/db/migrate/20250127151258_add_phone_to_spree_users.rb +5 -0
  341. data/db/migrate/20250204162453_create_spree_reports.rb +13 -0
  342. data/db/migrate/20250207084000_add_accepts_email_marketing_field_to_spree_users_table.rb +6 -0
  343. data/db/migrate/20250217171018_create_action_text_video_embeds.rb +11 -0
  344. data/db/migrate/20250304115943_add_performed_by_to_spree_reimbursements.rb +5 -0
  345. data/db/migrate/20250305121352_remove_page_builder_indices.rb +11 -0
  346. data/db/migrate/20250305121657_remove_spree_posts_indices.rb +7 -0
  347. data/db/migrate/20250311105934_create_spree_gateway_customers.rb +18 -0
  348. data/db/migrate/20250312202705_add_unique_index_on_promotion_rules_associations.rb +75 -0
  349. data/db/migrate/20250313104226_add_user_type_to_spree_role_users.rb +18 -0
  350. data/db/migrate/20250313175830_add_unique_index_on_promotion_action_line_items.rb +29 -0
  351. data/db/migrate/20250314144210_create_spree_taggings_and_spree_tags.rb +38 -0
  352. data/lib/generators/spree/authentication/custom/custom_generator.rb +49 -0
  353. data/lib/generators/spree/authentication/custom/templates/authentication_helpers.rb.tt +50 -0
  354. data/lib/generators/spree/authentication/devise/devise_generator.rb +57 -0
  355. data/lib/generators/spree/authentication/devise/templates/authentication_helpers.rb.tt +50 -0
  356. data/lib/generators/spree/dummy/dummy_generator.rb +1 -1
  357. data/lib/generators/spree/dummy/templates/rails/database.yml +1 -0
  358. data/lib/generators/spree/dummy/templates/rails/test.rb +1 -1
  359. data/lib/generators/spree/install/install_generator.rb +21 -36
  360. data/lib/generators/spree/install/templates/config/initializers/spree.rb +40 -6
  361. data/lib/normalize_string.rb +18 -0
  362. data/lib/spree/analytics.rb +11 -0
  363. data/lib/spree/core/components.rb +1 -1
  364. data/lib/spree/core/configuration.rb +14 -11
  365. data/lib/spree/core/controller_helpers/auth.rb +0 -26
  366. data/lib/spree/core/controller_helpers/order.rb +77 -12
  367. data/lib/spree/core/controller_helpers/search.rb +2 -0
  368. data/lib/spree/core/controller_helpers/store.rb +0 -5
  369. data/lib/spree/core/controller_helpers/strong_parameters.rb +4 -0
  370. data/lib/spree/core/controller_helpers/turbo.rb +19 -0
  371. data/lib/spree/core/dependencies.rb +3 -5
  372. data/lib/spree/core/engine.rb +158 -7
  373. data/lib/spree/core/preferences/configuration.rb +2 -44
  374. data/lib/spree/core/preferences/preferable.rb +9 -0
  375. data/lib/spree/core/preferences/preferable_class_methods.rb +11 -1
  376. data/lib/spree/core/preferences/runtime_configuration.rb +13 -2
  377. data/lib/spree/core/search/base.rb +2 -0
  378. data/lib/spree/core/version.rb +1 -1
  379. data/lib/spree/core.rb +61 -11
  380. data/lib/spree/i18n.rb +5 -8
  381. data/lib/spree/migrations.rb +1 -1
  382. data/lib/spree/permitted_attributes.rb +24 -15
  383. data/lib/spree/testing_support/authorization_helpers.rb +9 -6
  384. data/lib/spree/testing_support/capybara_config.rb +11 -0
  385. data/lib/spree/testing_support/common_rake.rb +20 -12
  386. data/lib/spree/testing_support/factories/calculator_factory.rb +16 -0
  387. data/lib/spree/testing_support/factories/country_factory.rb +8 -0
  388. data/lib/spree/testing_support/factories/coupon_code_factory.rb +7 -0
  389. data/lib/spree/testing_support/factories/custom_domain_factory.rb +7 -0
  390. data/lib/spree/testing_support/factories/export_factory.rb +32 -0
  391. data/lib/spree/testing_support/factories/gateway_customer_factory.rb +7 -0
  392. data/lib/spree/testing_support/factories/order_factory.rb +14 -3
  393. data/lib/spree/testing_support/factories/page_block_factory.rb +21 -0
  394. data/lib/spree/testing_support/factories/page_factory.rb +33 -0
  395. data/lib/spree/testing_support/factories/page_link_factory.rb +7 -0
  396. data/lib/spree/testing_support/factories/page_section_factory.rb +24 -0
  397. data/lib/spree/testing_support/factories/payment_factory.rb +2 -2
  398. data/lib/spree/testing_support/factories/post_category_factory.rb +7 -0
  399. data/lib/spree/testing_support/factories/post_factory.rb +10 -0
  400. data/lib/spree/testing_support/factories/product_factory.rb +3 -8
  401. data/lib/spree/testing_support/factories/product_property_factory.rb +1 -1
  402. data/lib/spree/testing_support/factories/promotion_action_factory.rb +5 -0
  403. data/lib/spree/testing_support/factories/promotion_factory.rb +7 -9
  404. data/lib/spree/testing_support/factories/promotion_rule_factory.rb +12 -0
  405. data/lib/spree/testing_support/factories/property_factory.rb +1 -1
  406. data/lib/spree/testing_support/factories/report_factory.rb +33 -0
  407. data/lib/spree/testing_support/factories/role_user_factory.rb +7 -0
  408. data/lib/spree/testing_support/factories/shipping_method_factory.rb +9 -0
  409. data/lib/spree/testing_support/factories/stock_transfer_factory.rb +5 -2
  410. data/lib/spree/testing_support/factories/store_factory.rb +6 -9
  411. data/lib/spree/testing_support/factories/taxon_factory.rb +13 -0
  412. data/lib/spree/testing_support/factories/taxon_rule_factory.rb +38 -0
  413. data/lib/spree/testing_support/factories/theme_factory.rb +14 -0
  414. data/lib/spree/testing_support/factories/user_factory.rb +13 -11
  415. data/lib/spree/testing_support/factories/variant_factory.rb +23 -5
  416. data/lib/spree/testing_support/jobs.rb +1 -7
  417. data/lib/spree/testing_support/metadata.rb +13 -1
  418. data/lib/spree/testing_support/order_walkthrough.rb +1 -7
  419. data/lib/spree/testing_support/preferences.rb +1 -4
  420. data/lib/spree/testing_support/store.rb +26 -0
  421. data/lib/spree_core.rb +1 -0
  422. data/vendor/javascript/@rails--request.js.js +4 -0
  423. data/vendor/javascript/@stimulus-components--auto-submit.js +4 -0
  424. data/vendor/javascript/stimulus-reveal-controller.js +4 -0
  425. data/vendor/javascript/tailwindcss-stimulus-components.js +4 -0
  426. metadata +340 -197
  427. data/Gemfile +0 -3
  428. data/app/finders/spree/cms_pages/find.rb +0 -41
  429. data/app/finders/spree/menus/find.rb +0 -11
  430. data/app/models/concerns/spree/display_link.rb +0 -30
  431. data/app/models/spree/cms/pages/feature_page.rb +0 -7
  432. data/app/models/spree/cms/pages/homepage.rb +0 -20
  433. data/app/models/spree/cms/pages/standard_page.rb +0 -4
  434. data/app/models/spree/cms/sections/featured_article.rb +0 -22
  435. data/app/models/spree/cms/sections/hero_image.rb +0 -38
  436. data/app/models/spree/cms/sections/image_gallery.rb +0 -97
  437. data/app/models/spree/cms/sections/product_carousel.rb +0 -14
  438. data/app/models/spree/cms/sections/rich_text_content.rb +0 -13
  439. data/app/models/spree/cms/sections/side_by_side_images.rb +0 -68
  440. data/app/models/spree/cms_page.rb +0 -70
  441. data/app/models/spree/cms_section.rb +0 -69
  442. data/app/models/spree/cms_section_image.rb +0 -9
  443. data/app/models/spree/cms_section_image_one.rb +0 -4
  444. data/app/models/spree/cms_section_image_three.rb +0 -4
  445. data/app/models/spree/cms_section_image_two.rb +0 -4
  446. data/app/models/spree/icon.rb +0 -7
  447. data/app/models/spree/linkable/homepage.rb +0 -3
  448. data/app/models/spree/linkable/uri.rb +0 -3
  449. data/app/models/spree/menu.rb +0 -66
  450. data/app/models/spree/menu_item.rb +0 -72
  451. data/brakeman.ignore +0 -328
  452. data/db/migrate/20211201202851_update_linkable_resource_types.rb +0 -10
  453. data/db/migrate/20220329113557_fix_cms_pages_unique_indexes.rb +0 -8
  454. data/lib/generators/spree/custom_authentication/custom_authentication_generator.rb +0 -23
  455. data/lib/generators/spree/custom_authentication/templates/authentication_helpers.rb.tt +0 -23
  456. data/lib/generators/spree/custom_user/custom_user_generator.rb +0 -46
  457. data/lib/generators/spree/custom_user/templates/current_user_helpers.rb.tt +0 -15
  458. data/lib/generators/spree/custom_user/templates/initializer.rb.tt +0 -1
  459. data/lib/generators/spree/custom_user/templates/migration.rb.tt +0 -7
  460. data/lib/generators/spree/dummy/templates/package.json +0 -12
  461. data/lib/spree/core/product_duplicator.rb +0 -85
  462. data/lib/spree/core/runtime_configuration.rb +0 -10
  463. data/lib/spree/testing_support/factories/cms_page_factory.rb +0 -20
  464. data/lib/spree/testing_support/factories/cms_section_factory.rb +0 -31
  465. data/lib/spree/testing_support/factories/icon_factory.rb +0 -9
  466. data/lib/spree/testing_support/factories/menu_factory.rb +0 -16
  467. data/lib/spree/testing_support/factories/menu_item_factory.rb +0 -10
  468. data/script/rails +0 -9
  469. data/spec/fixtures/favicon.ico +0 -0
  470. data/spec/fixtures/files/icon_256x256.gif +0 -0
  471. data/spec/fixtures/files/icon_256x256.png +0 -0
  472. data/spec/fixtures/files/icon_512x512.png +0 -0
  473. data/spec/fixtures/files/img_256x128.png +0 -0
  474. data/spec/fixtures/text-file.txt +0 -1
  475. data/spec/fixtures/thinking-cat.jpg +0 -0
  476. data/spree_core.gemspec +0 -62
@@ -0,0 +1,69 @@
1
+ module Spree
2
+ class PageBlock < Spree.base_class
3
+ include Spree::HasPageLinks
4
+
5
+ #
6
+ # Magic methods
7
+ #
8
+ acts_as_paranoid
9
+ acts_as_list scope: :section
10
+
11
+ #
12
+ # Associations
13
+ #
14
+ belongs_to :section, class_name: 'Spree::PageSection', inverse_of: :blocks, touch: true
15
+ delegate :store, :theme, to: :section
16
+
17
+ #
18
+ # Rich Text
19
+ #
20
+ has_rich_text :text
21
+
22
+ #
23
+ # Attachments
24
+ #
25
+ has_one_attached :asset, service: Spree.public_storage_service_name
26
+
27
+ #
28
+ # Validations
29
+ #
30
+ validates :section, :type, :name, presence: true
31
+ validates :asset, content_type: Rails.application.config.active_storage.web_image_content_types
32
+
33
+ #
34
+ # Callbacks
35
+ #
36
+ before_validation :set_name_from_type, on: :create
37
+
38
+ #
39
+ # Preferences
40
+ #
41
+ TEXT_ALIGNMENT_DEFAULT = 'left'
42
+ CONTAINER_ALIGNMENT_DEFAULT = 'left'
43
+ SIZE_DEFAULT = 'medium'
44
+ WIDTH_DESKTOP_DEFAULT = 100
45
+ TOP_PADDING_DEFAULT = 0
46
+ BOTTOM_PADDING_DEFAULT = 0
47
+
48
+ preference :text_alignment, :string, default: -> { self.class::TEXT_ALIGNMENT_DEFAULT if defined?(self.class::TEXT_ALIGNMENT_DEFAULT) }
49
+ preference :container_alignment, :string, default: -> { self.class::CONTAINER_ALIGNMENT_DEFAULT if defined?(self.class::CONTAINER_ALIGNMENT_DEFAULT) }
50
+ preference :size, :string, default: -> { self.class::SIZE_DEFAULT if defined?(self.class::SIZE_DEFAULT) }
51
+ preference :width_desktop, :integer, default: -> { self.class::WIDTH_DESKTOP_DEFAULT if defined?(self.class::WIDTH_DESKTOP_DEFAULT) }
52
+ preference :top_padding, :integer, default: -> { self.class::TOP_PADDING_DEFAULT if defined?(self.class::TOP_PADDING_DEFAULT) }
53
+ preference :bottom_padding, :integer, default: -> { self.class::BOTTOM_PADDING_DEFAULT if defined?(self.class::BOTTOM_PADDING_DEFAULT) }
54
+
55
+ def display_name
56
+ name
57
+ end
58
+
59
+ def icon_name
60
+ 'fullscreen'
61
+ end
62
+
63
+ private
64
+
65
+ def set_name_from_type
66
+ self.name ||= type.demodulize.titleize
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,29 @@
1
+ module Spree
2
+ module PageBlocks
3
+ class Buttons < Spree::PageBlock
4
+ include Spree::HasOneLink
5
+
6
+ TEXT_ALIGNMENT_DEFAULT = 'center'
7
+
8
+ preference :button_style_1, :string, default: 'primary'
9
+ preference :background_color, :string
10
+ preference :button_background_color, :string
11
+ preference :button_text_color, :string
12
+
13
+ # Without link there is no purpose of the button.
14
+ def link_destroyed(_link)
15
+ return unless page_links_count.zero?
16
+
17
+ destroy
18
+ end
19
+
20
+ def display_name
21
+ Spree.t('page_blocks.buttons.display_name')
22
+ end
23
+
24
+ def icon_name
25
+ 'click'
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,18 @@
1
+ module Spree
2
+ module PageBlocks
3
+ class Heading < Spree::PageBlock
4
+ SIZE_DEFAULT = 'large'
5
+
6
+ preference :text_color, :string
7
+ preference :background_color, :string
8
+
9
+ def icon_name
10
+ 'heading'
11
+ end
12
+
13
+ def display_name
14
+ text.to_plain_text.truncate(30)
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,17 @@
1
+ module Spree
2
+ module PageBlocks
3
+ class Image < Spree::PageBlock
4
+ alias image asset
5
+
6
+ TOP_PADDING_DEFAULT = 20
7
+ BOTTOM_PADDING_DEFAULT = 20
8
+
9
+ preference :height, :integer, default: 64
10
+ preference :mobile_height, :integer, default: 32
11
+
12
+ def icon_name
13
+ 'photo'
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,21 @@
1
+ module Spree
2
+ module PageBlocks
3
+ class Link < Spree::PageBlock
4
+ include Spree::HasOneLink
5
+
6
+ def icon_name
7
+ 'menu-2'
8
+ end
9
+
10
+ def display_name
11
+ link&.label || Spree.t('page_blocks.link.display_name')
12
+ end
13
+
14
+ def link_destroyed(_link)
15
+ return unless page_links_count.zero?
16
+
17
+ destroy
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,33 @@
1
+ module Spree
2
+ module PageBlocks
3
+ class MegaNav < Spree::PageBlock
4
+ include Spree::HasPageLinks
5
+
6
+ has_one :link, ->(ps) { ps.links.where(position: 1) }, class_name: 'Spree::PageLink', as: :parent, dependent: :destroy, inverse_of: :parent
7
+ accepts_nested_attributes_for :link
8
+
9
+ preference :featured_taxon_id, :string, default: ''
10
+
11
+ def featured_taxon
12
+ store.taxons.find_by(id: preferred_featured_taxon_id) if preferred_featured_taxon_id.present?
13
+ end
14
+
15
+ def icon_name
16
+ 'layout-navbar-expand'
17
+ end
18
+
19
+ def display_name
20
+ link&.label || Spree.t(:mega_nav)
21
+ end
22
+
23
+ def default_links
24
+ @default_links.presence || [
25
+ Spree::PageLink.new(
26
+ label: Spree.t(:shop_all),
27
+ linkable: theme_or_parent.pages.find_by(type: 'Spree::Pages::ShopAll')
28
+ ),
29
+ ]
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,32 @@
1
+ module Spree
2
+ module PageBlocks
3
+ class MegaNavWithSubcategories < Spree::PageBlock
4
+ preference :taxon_id, :string, default: ''
5
+ preference :featured_taxon_id, :string, default: ''
6
+
7
+ before_validation :make_taxon_id_valid
8
+
9
+ def taxon
10
+ store.taxons.find_by(id: preferred_taxon_id) if preferred_taxon_id.present?
11
+ end
12
+
13
+ def featured_taxon
14
+ store.taxons.find_by(id: preferred_featured_taxon_id) if preferred_featured_taxon_id.present?
15
+ end
16
+
17
+ def icon_name
18
+ 'category'
19
+ end
20
+
21
+ def display_name
22
+ taxon&.name || Spree.t(:mega_nav_with_subcategories)
23
+ end
24
+
25
+ private
26
+
27
+ def make_taxon_id_valid
28
+ self.preferred_taxon_id = preferred_taxon_id.presence || store.taxons.where(depth: 1).first&.id
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,15 @@
1
+ module Spree
2
+ module PageBlocks
3
+ class Nav < Spree::PageBlock
4
+ preference :label, :string, default: Spree.t('page_blocks.nav.label_default')
5
+
6
+ def icon_name
7
+ 'menu-2'
8
+ end
9
+
10
+ def display_name
11
+ preferred_label
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,18 @@
1
+ module Spree
2
+ module PageBlocks
3
+ class NewsletterForm < Spree::PageBlock
4
+ preference :button_text, :string, default: Spree.t('page_blocks.newsletter_form.button_text_default')
5
+ preference :button_text_color, :string
6
+ preference :button_background_color, :string
7
+ preference :button_style, :string, default: 'primary'
8
+ preference :placeholder, :string, default: Spree.t('page_blocks.newsletter_form.placeholder_default')
9
+ preference :justify, :string, default: 'center'
10
+
11
+ validates :preferred_button_style, inclusion: { in: ['primary', 'secondary'] }
12
+
13
+ def icon_name
14
+ 'forms'
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,12 @@
1
+ module Spree
2
+ module PageBlocks
3
+ module Products
4
+ class BuyButtons < Spree::PageBlock
5
+ TOP_PADDING_DEFAULT = 20
6
+ BOTTOM_PADDING_DEFAULT = 20
7
+
8
+ preference :text_color, :string
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,18 @@
1
+ module Spree
2
+ module PageBlocks
3
+ module Products
4
+ class Price < Spree::PageBlocks::Text
5
+ TOP_PADDING_DEFAULT = 16
6
+ BOTTOM_PADDING_DEFAULT = 16
7
+
8
+ def icon_name
9
+ 'cash'
10
+ end
11
+
12
+ def display_name
13
+ 'Price'
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,12 @@
1
+ module Spree
2
+ module PageBlocks
3
+ module Products
4
+ class QuantitySelector < Spree::PageBlock
5
+ TOP_PADDING_DEFAULT = 20
6
+ BOTTOM_PADDING_DEFAULT = 20
7
+
8
+ preference :text_color, :string
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,8 @@
1
+ module Spree
2
+ module PageBlocks
3
+ module Products
4
+ class Share < Spree::PageBlocks::Text
5
+ end
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,15 @@
1
+ module Spree
2
+ module PageBlocks
3
+ module Products
4
+ class Title < Spree::PageBlocks::Heading
5
+ TOP_PADDING_DEFAULT = 16
6
+
7
+ preference :text_color, :string
8
+
9
+ def display_name
10
+ section.product_name.presence || 'Title'
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,9 @@
1
+ module Spree
2
+ module PageBlocks
3
+ module Products
4
+ class VariantPicker < Spree::PageBlock
5
+ preference :text_color, :string
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,17 @@
1
+ module Spree
2
+ module PageBlocks
3
+ class Subheading < Spree::PageBlock
4
+ SIZE_DEFAULT = 'small'
5
+
6
+ preference :text_color, :string
7
+
8
+ def icon_name
9
+ 'h2'
10
+ end
11
+
12
+ def display_name
13
+ text.to_plain_text.truncate(30)
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,16 @@
1
+ module Spree
2
+ module PageBlocks
3
+ class Text < Spree::PageBlock
4
+ preference :text_color, :string
5
+ preference :background_color, :string
6
+
7
+ def icon_name
8
+ 'align-justified'
9
+ end
10
+
11
+ def display_name
12
+ text.to_plain_text.truncate(30)
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,59 @@
1
+ module Spree
2
+ class PageLink < Spree.base_class
3
+ #
4
+ # Magic methods
5
+ #
6
+ acts_as_list scope: :parent
7
+
8
+ #
9
+ # Associations
10
+ #
11
+ belongs_to :parent, polymorphic: true, touch: true, counter_cache: true # Block or Section
12
+ belongs_to :linkable, polymorphic: true, optional: true # Page, Product, etc.
13
+ has_one :theme, through: :parent
14
+
15
+ #
16
+ # Validations
17
+ #
18
+ validates :label, :parent, presence: true
19
+ validates :url, presence: true, unless: :linkable
20
+
21
+ #
22
+ # Callbacks
23
+ #
24
+ after_destroy :notify_parent
25
+ before_validation :set_label, on: [:create, :update]
26
+
27
+ def linkable_url
28
+ @linkable_url ||= linkable&.page_builder_url || formatted_url
29
+ end
30
+
31
+ def formatted_url
32
+ return if url.blank?
33
+
34
+ @formatted_url ||= url.match(/http:\/\/|https:\/\//) ? url : "http://#{url}"
35
+ end
36
+
37
+ private
38
+
39
+ def notify_parent
40
+ return unless parent.present?
41
+ return unless parent.respond_to?(:link_destroyed)
42
+
43
+ parent.link_destroyed(self)
44
+ end
45
+
46
+ def set_label
47
+ return if label.present? && new_record?
48
+ return unless linkable_id_changed?
49
+
50
+ if linkable.respond_to?(:title)
51
+ self.label = linkable.title
52
+ elsif linkable.respond_to?(:display_name)
53
+ self.label = linkable.display_name
54
+ elsif linkable.respond_to?(:name)
55
+ self.label = linkable.name
56
+ end
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,215 @@
1
+ module Spree
2
+ class PageSection < Spree.base_class
3
+ include Spree::HasPageLinks
4
+ #
5
+ # Magic methods
6
+ #
7
+ acts_as_paranoid
8
+ acts_as_list scope: [:pageable_id, { deleted_at: nil }]
9
+
10
+ #
11
+ # Associations
12
+ #
13
+ belongs_to :pageable, polymorphic: true, touch: true # this can be either Page or Theme
14
+ has_many :blocks, lambda {
15
+ order(position: :asc)
16
+ }, class_name: 'Spree::PageBlock', dependent: :destroy, inverse_of: :section, foreign_key: :section_id
17
+ alias page_blocks blocks
18
+ delegate :store, to: :pageable
19
+
20
+ #
21
+ # Attachments
22
+ #
23
+ has_one_attached :asset, service: Spree.public_storage_service_name
24
+ alias image asset
25
+
26
+ #
27
+ # Validations
28
+ #
29
+ validates :name, :pageable, presence: true
30
+ validates :asset, content_type: Rails.application.config.active_storage.web_image_content_types
31
+ #
32
+ # Callbacks
33
+ #
34
+ before_validation :set_name, on: :create
35
+ after_create :create_blocks, unless: :do_not_create_blocks
36
+
37
+ #
38
+ # Scopes
39
+ #
40
+ scope :published, -> { where(pageable_type: 'Spree::Page') }
41
+ scope :related_products, -> { where(type: 'Spree::PageSections::RelatedProducts') }
42
+
43
+ #
44
+ # Preferences
45
+ #
46
+ TEXT_COLOR_DEFAULT = nil
47
+ BACKGROUND_COLOR_DEFAULT = nil
48
+ BORDER_COLOR_DEFAULT = nil
49
+ TOP_PADDING_DEFAULT = 40
50
+ BOTTOM_PADDING_DEFAULT = 40
51
+ TOP_BORDER_WIDTH_DEFAULT = 1
52
+ BOTTOM_BORDER_WIDTH_DEFAULT = 0
53
+
54
+ preference :text_color, :string, default: -> { self.class::TEXT_COLOR_DEFAULT if defined?(self.class::TEXT_COLOR_DEFAULT) }
55
+ preference :background_color, :string, default: -> { self.class::BACKGROUND_COLOR_DEFAULT if defined?(self.class::BACKGROUND_COLOR_DEFAULT) }
56
+ preference :border_color, :string, default: -> { self.class::BORDER_COLOR_DEFAULT if defined?(self.class::BORDER_COLOR_DEFAULT) }
57
+ preference :top_padding, :integer, default: -> { self.class::TOP_PADDING_DEFAULT if defined?(self.class::TOP_PADDING_DEFAULT) }
58
+ preference :bottom_padding, :integer, default: -> { self.class::BOTTOM_PADDING_DEFAULT if defined?(self.class::BOTTOM_PADDING_DEFAULT) }
59
+ preference :top_border_width, :integer, default: -> { self.class::TOP_BORDER_WIDTH_DEFAULT if defined?(self.class::TOP_BORDER_WIDTH_DEFAULT) }
60
+ preference :bottom_border_width, :integer, default: -> { self.class::BOTTOM_BORDER_WIDTH_DEFAULT if defined?(self.class::BOTTOM_BORDER_WIDTH_DEFAULT) }
61
+
62
+ #
63
+ # Virtual attributes
64
+ #
65
+ attribute :do_not_create_blocks, :boolean, default: false
66
+ attr_accessor :default_blocks
67
+
68
+ def to_partial_path
69
+ "spree/page_sections/#{type.to_s.demodulize.underscore}"
70
+ end
71
+
72
+ # this should be overridden in subclasses
73
+ def default_blocks
74
+ @default_blocks.presence || []
75
+ end
76
+
77
+ def blocks_available?
78
+ false
79
+ end
80
+
81
+ def available_blocks_to_add
82
+ []
83
+ end
84
+
85
+ def can_sort_blocks?
86
+ false
87
+ end
88
+
89
+ # this should be overridden in subclasses
90
+ # content - can be managed by the user
91
+ # system - main parts of the page eg. product details, login form
92
+ # header - header section
93
+ # footer - footer section
94
+ def self.role
95
+ 'content'
96
+ end
97
+
98
+ def role
99
+ self.class.role
100
+ end
101
+
102
+ def theme
103
+ @theme ||= if pageable.is_a?(Spree::Theme)
104
+ pageable
105
+ else
106
+ pageable.theme
107
+ end
108
+ end
109
+
110
+ def icon_name
111
+ 'text-caption'
112
+ end
113
+
114
+ def can_be_deleted?
115
+ role == 'content'
116
+ end
117
+
118
+ def can_be_sorted?
119
+ role == 'content'
120
+ end
121
+
122
+ def lazy?
123
+ false
124
+ end
125
+
126
+ def lazy_path(variables)
127
+ url_options = variables[:url_options] || {}
128
+
129
+ Spree::Core::Engine.routes.url_helpers.page_section_path(self, **url_options)
130
+ end
131
+
132
+ def rich_text_fields
133
+ self.class.rich_text_association_names.map { |rt| rt.to_s.sub('rich_text_', '') }
134
+ end
135
+
136
+ def copy_rich_text_fields_from(other)
137
+ rich_text_fields.each do |field|
138
+ send(field).body = other.send(field).body
139
+ end
140
+ end
141
+
142
+ def deep_clone(target)
143
+ new_section = type.constantize.new(
144
+ preferences: preferences,
145
+ position: position,
146
+ pageable: target
147
+ )
148
+ new_section.copy_rich_text_fields_from(self)
149
+ new_section.do_not_create_blocks = true
150
+ new_section.do_not_create_links = true
151
+ new_section.save!
152
+
153
+ new_section.asset.attach(asset.blob) if asset.attached?
154
+
155
+ blocks.includes(:links, asset_attachment: :blob).each do |block|
156
+ new_block = block.type.constantize.new(
157
+ preferences: block.preferences,
158
+ position: block.position,
159
+ section: new_section
160
+ )
161
+ new_block.do_not_create_links = true
162
+ new_block.text = block.text if block.respond_to?(:text) # we need to copy ActionText content
163
+ new_block.save!
164
+
165
+ new_block.asset.attach(block.asset.blob) if block.asset.attached?
166
+
167
+ deep_clone_links(block, new_block)
168
+ end
169
+
170
+ deep_clone_links(self, new_section)
171
+ end
172
+
173
+ def deep_clone_links(section_or_block, new_section_or_block)
174
+ section_or_block.links.each do |link|
175
+ new_link = link.dup
176
+ new_link.parent = new_section_or_block
177
+ new_link.save!
178
+ end
179
+ end
180
+
181
+ # Turns out #dup doesn't not copy rich text content to the new record.
182
+ # https://github.com/rails/rails/issues/36683
183
+ def dup
184
+ super.tap do |object|
185
+ object.copy_rich_text_fields_from(self)
186
+ end
187
+ end
188
+
189
+ def restore_design_settings_to_defaults
190
+ restore_preferences_for(design_settings_to_restore)
191
+ save
192
+ end
193
+
194
+ def display_name
195
+ name
196
+ end
197
+
198
+ private
199
+
200
+ def design_settings_to_restore
201
+ [:text_color, :background_color, :border_color, :top_padding, :bottom_padding, :top_border_width, :bottom_border_width]
202
+ end
203
+
204
+ def create_blocks
205
+ default_blocks.each do |block|
206
+ block.section = self
207
+ block.save!
208
+ end
209
+ end
210
+
211
+ def set_name
212
+ self.name ||= type.to_s.demodulize.titleize
213
+ end
214
+ end
215
+ end
@@ -0,0 +1,30 @@
1
+ module Spree
2
+ module PageSections
3
+ class AnnouncementBar < Spree::PageSection
4
+ has_rich_text :text
5
+
6
+ before_validation :set_default_text, on: :create
7
+
8
+ BACKGROUND_COLOR_DEFAULT = '#F5F5F4'
9
+ TOP_PADDING_DEFAULT = 8
10
+ BOTTOM_PADDING_DEFAULT = 8
11
+ TOP_BORDER_WIDTH_DEFAULT = 0
12
+
13
+ def self.role
14
+ 'header'
15
+ end
16
+
17
+ def icon_name
18
+ 'speakerphone'
19
+ end
20
+
21
+ private
22
+
23
+ def set_default_text
24
+ return unless text.blank?
25
+
26
+ self.text = Spree.t('page_sections.announcement_bar.default_text')
27
+ end
28
+ end
29
+ end
30
+ end