ba_spree 1.0.0

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 (160) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +673 -0
  3. data/README.md +150 -0
  4. data/app/assets/config/manifest.js +1 -0
  5. data/app/assets/javascripts/ba_spree/admin_overrides/query_builder_controller.js +505 -0
  6. data/app/assets/javascripts/ba_spree/storefront/ba_spree_local_time.js +9 -0
  7. data/app/assets/stylesheets/spree/admin/custom.scss +40 -0
  8. data/app/controllers/ba_spree/checkout_controller_decorator.rb +111 -0
  9. data/app/controllers/ba_spree/store_controller_decorator.rb +55 -0
  10. data/app/controllers/concerns/ba_spree/theme_concern_decorator.rb +16 -0
  11. data/app/controllers/spree/admin/assets_controller_decorator.rb +48 -0
  12. data/app/controllers/spree/admin/products_controller_decorator.rb +25 -0
  13. data/app/controllers/spree/admin/promotion_rules_controller_decorator.rb +30 -0
  14. data/app/controllers/spree/admin/users_controller_decorator.rb +34 -0
  15. data/app/controllers/spree/contacts_controller_decorator.rb +23 -0
  16. data/app/controllers/spree/digital_links_controller.rb +61 -0
  17. data/app/controllers/spree/orders_controller_decorator.rb +24 -0
  18. data/app/decorators/ba_spree/product_pricing_decorator.rb +65 -0
  19. data/app/decorators/spree/current_decorator.rb +17 -0
  20. data/app/decorators/spree/money_decorator.rb +51 -0
  21. data/app/decorators/spree/order_email_subscriber_decorator.rb +64 -0
  22. data/app/decorators/spree/page_sections/featured_posts_decorator.rb +17 -0
  23. data/app/helpers/currency_rounding_helper.rb +10 -0
  24. data/app/helpers/spree/admin/filter_params_preservation.rb +130 -0
  25. data/app/helpers/spree/admin/navigation_helper_decorator.rb +23 -0
  26. data/app/helpers/spree/admin/promotion_rules_helper_decorator.rb +33 -0
  27. data/app/helpers/spree/admin/table_helper_decorator.rb +40 -0
  28. data/app/helpers/spree/base_helper_decorator.rb +63 -0
  29. data/app/helpers/spree/checkout_analytics_helper_decorator.rb +32 -0
  30. data/app/javascript/ba_spree/controllers/disable_when_hidden_controller.js +70 -0
  31. data/app/javascript/ba_spree/index.js +11 -0
  32. data/app/javascript/spree/admin/controllers/calendar_range_controller.js +61 -0
  33. data/app/javascript/spree/admin/controllers/slug_form_controller.js +17 -0
  34. data/app/models/ba_spree/address_decorator.rb +43 -0
  35. data/app/models/ba_spree/adjustment_decorator.rb +13 -0
  36. data/app/models/ba_spree/order_decorator.rb +95 -0
  37. data/app/models/ba_spree/order_updater_decorator.rb +33 -0
  38. data/app/models/ba_spree/payment_method_decorator.rb +10 -0
  39. data/app/models/ba_spree/product_decorator.rb +44 -0
  40. data/app/models/ba_spree/store_decorator.rb +23 -0
  41. data/app/models/ba_spree/variant_decorator.rb +49 -0
  42. data/app/models/concerns/spree/adjustment_source_decorator.rb +66 -0
  43. data/app/models/concerns/spree/product_property_metafields.rb +52 -0
  44. data/app/models/spree/adjustable/adjuster/promotion_decorator.rb +16 -0
  45. data/app/models/spree/admin/table/filter_decorator.rb +52 -0
  46. data/app/models/spree/admin/table/filter_group_decorator.rb +64 -0
  47. data/app/models/spree/asset_decorator.rb +102 -0
  48. data/app/models/spree/contact_decorator.rb +22 -0
  49. data/app/models/spree/digital_link_decorator.rb +9 -0
  50. data/app/models/spree/export_decorator.rb +34 -0
  51. data/app/models/spree/line_item_destroy_callback_decorator.rb +30 -0
  52. data/app/models/spree/metafield_definition_decorator.rb +34 -0
  53. data/app/models/spree/option_type_decorator.rb +22 -0
  54. data/app/models/spree/option_value_decorator.rb +19 -0
  55. data/app/models/spree/option_value_variant_decorator.rb +30 -0
  56. data/app/models/spree/order/address_book_decorator.rb +14 -0
  57. data/app/models/spree/order_merger_decorator.rb +29 -0
  58. data/app/models/spree/price_rules/customer_group_rule_decorator.rb +18 -0
  59. data/app/models/spree/price_rules/user_rule_decorator.rb +25 -0
  60. data/app/models/spree/price_rules/volume_rule_decorator.rb +25 -0
  61. data/app/models/spree/price_rules/zone_rule_decorator.rb +25 -0
  62. data/app/models/spree/pricing/batch_resolver.rb +96 -0
  63. data/app/models/spree/promotion_handler/cart_decorator.rb +51 -0
  64. data/app/models/spree/stock/packer_decorator.rb +61 -0
  65. data/app/models/spree/stock/prioritizer_decorator.rb +27 -0
  66. data/app/models/spree/tax_rate_decorator.rb +93 -0
  67. data/app/models/spree/taxon_decorator.rb +42 -0
  68. data/app/models/spree/user_bill_address_sync_decorator.rb +33 -0
  69. data/app/overrides/add_ba_spree_storefront_javascript_importmap_tags.rb +8 -0
  70. data/app/overrides/add_cache_to_product_listing_page.rb +41 -0
  71. data/app/overrides/add_class_to_login_link.rb +6 -0
  72. data/app/overrides/add_confirm_state_to_checkout_content_block.rb.rb +30 -0
  73. data/app/overrides/add_promotions_nav.rb +8 -0
  74. data/app/overrides/add_turbo_frame_to_admin_order_line_item_edit_link.rb +23 -0
  75. data/app/overrides/add_turbo_frame_to_promotion_action_edit_link.rb +20 -0
  76. data/app/overrides/add_turbo_stream_format_to_cart_path_in_cart_pane.rb +8 -0
  77. data/app/overrides/ba_spree_local_time_add_custom_javascript_import_map_tags.rb +8 -0
  78. data/app/overrides/disable_hidden_bill_address_fields_on_payment.rb +15 -0
  79. data/app/overrides/disable_turbo_on_user_registration_form.rb +18 -0
  80. data/app/overrides/fix_coupon_apply_button_layout.rb +7 -0
  81. data/app/overrides/hide_gift_cards_and_store_credits_from_account_nav.rb +11 -0
  82. data/app/overrides/hide_shipping_message_for_digital_only_orders.rb +15 -0
  83. data/app/overrides/localize_apply_button_text.rb +6 -0
  84. data/app/overrides/localize_newsletter_button_text.rb +6 -0
  85. data/app/overrides/replace_announcement_bar_text.rb +6 -0
  86. data/app/overrides/replace_button_edit_checkout.rb +10 -0
  87. data/app/overrides/replace_checkout_delivery_info.rb +6 -0
  88. data/app/overrides/replace_checkout_pay_button_with_dynamic_label.rb +14 -0
  89. data/app/overrides/replace_variant_not_available_button.rb +19 -0
  90. data/app/overrides/set_logo_width_height_in_admin_store_basic_form.rb +12 -0
  91. data/app/overrides/show_breadcrumbs_on_taxon_page.rb +30 -0
  92. data/app/overrides/show_individual_adjustments_in_order_details.rb +18 -0
  93. data/app/overrides/show_only_selected_payment_method_on_confirm.rb +29 -0
  94. data/app/overrides/spree/admin/preserve_filter_params_across_table_forms.rb +64 -0
  95. data/app/overrides/spree/admin/promotion_rules/_promotion_rule/set_turbo_frame_on_edit_link.html.erb.deface +11 -0
  96. data/app/overrides/spree/admin/stores/add_special_instruction_message_settings.rb +17 -0
  97. data/app/overrides/use_absolute_time_for_order_header_completed_at.rb +15 -0
  98. data/app/presenters/spree/mega_nav_presenter_decorator.rb +26 -0
  99. data/app/services/ba_spree/setup_service.rb +144 -0
  100. data/app/services/spree/assets/position_normalizer.rb +67 -0
  101. data/app/services/spree/products/duplicator_decorator.rb +39 -0
  102. data/app/services/spree/products/prepare_nested_attributes_decorator.rb +58 -0
  103. data/app/views/spree/addresses/edit.html.erb +64 -0
  104. data/app/views/spree/admin/orders/_order.html.erb +32 -0
  105. data/app/views/spree/admin/orders/_summary.html.erb +122 -0
  106. data/app/views/spree/admin/shared/_custom_head.html.erb +56 -0
  107. data/app/views/spree/admin/shared/sidebar/_promotions_nav.html.erb +55 -0
  108. data/app/views/spree/admin/stores/_special_instruction_message_settings.html.erb +14 -0
  109. data/app/views/spree/checkout/_accept_marketing_checkbox.html.erb +40 -0
  110. data/app/views/spree/checkout/_address.html.erb +135 -0
  111. data/app/views/spree/checkout/_confirm.html.erb +25 -0
  112. data/app/views/spree/checkout/_line_item.html.erb +26 -0
  113. data/app/views/spree/checkout/_payment_method_confirm.html.erb +8 -0
  114. data/app/views/spree/checkout/_payment_methods.html.erb +88 -0
  115. data/app/views/spree/checkout/_summary.html.erb +146 -0
  116. data/app/views/spree/shared/_purchased_items_table.html.erb +60 -0
  117. data/app/views/spree/shared/_purchased_items_table.text.erb +24 -0
  118. data/app/views/themes/default/spree/orders/_empty.html.erb +14 -0
  119. data/app/views/themes/default/spree/orders/_summary.html.erb +87 -0
  120. data/app/views/themes/default/spree/orders/edit.turbo_stream.erb +10 -0
  121. data/app/views/themes/default/spree/page_sections/_featured_taxons.html.erb +38 -0
  122. data/app/views/themes/default/spree/page_sections/_header.html.erb +124 -0
  123. data/app/views/themes/default/spree/page_sections/_newsletter.html.erb +4 -0
  124. data/app/views/themes/default/spree/page_sections/_post_details.html.erb +22 -0
  125. data/app/views/themes/default/spree/page_sections/_product_details.html.erb +88 -0
  126. data/app/views/themes/default/spree/page_sections/_product_grid.html.erb +58 -0
  127. data/app/views/themes/default/spree/page_sections/nav/_desktop.html.erb +94 -0
  128. data/app/views/themes/default/spree/page_sections/nav/_mobile.html.erb +148 -0
  129. data/app/views/themes/default/spree/posts/_post.html.erb +16 -0
  130. data/app/views/themes/default/spree/products/_description.html.erb +7 -0
  131. data/app/views/themes/default/spree/products/_details.html.erb +65 -0
  132. data/app/views/themes/default/spree/products/_json_ld_variant.html.erb +15 -0
  133. data/app/views/themes/default/spree/products/_price.html.erb +76 -0
  134. data/app/views/themes/default/spree/products/_swiper.html.erb +90 -0
  135. data/app/views/themes/default/spree/shared/_account_pane.html.erb +18 -0
  136. data/app/views/themes/default/spree/shared/_cart_icon.html.erb +19 -0
  137. data/app/views/themes/default/spree/shared/_line_item_options.html.erb +9 -0
  138. data/app/views/themes/default/spree/shared/_logo.html.erb +39 -0
  139. data/app/views/themes/default/spree/shared/_nav_taxon_square_image.html.erb +8 -0
  140. data/app/views/themes/default/spree/shared/_order_shipment.html.erb +79 -0
  141. data/app/views/themes/default/spree/shared/_search.html.erb +33 -0
  142. data/app/views/themes/default/spree/shared/icons/_cart.html.erb +6 -0
  143. data/app/views/themes/default/spree/shared/icons/_cart_48.html.erb +8 -0
  144. data/app/views/themes/default/spree/shared/icons/_heart.html.erb +15 -0
  145. data/config/importmap.rb +12 -0
  146. data/config/initializers/admin_navigation.rb +43 -0
  147. data/config/initializers/spree.rb +6 -0
  148. data/config/initializers/spree_admin_label_i18n_alias.rb +52 -0
  149. data/config/initializers/spree_admin_tables.rb +57 -0
  150. data/config/initializers/spree_permitted_attributes.rb +1 -0
  151. data/config/locales/en.yml +15 -0
  152. data/config/locales/ja.yml +18 -0
  153. data/config/locales/spree.en.yml +4 -0
  154. data/config/locales/spree.ja.yml +3493 -0
  155. data/lib/ba_spree/engine.rb +41 -0
  156. data/lib/ba_spree/spree_events_dedup_patch.rb +44 -0
  157. data/lib/ba_spree/version.rb +3 -0
  158. data/lib/ba_spree.rb +20 -0
  159. data/lib/generators/ba_spree/install/install_generator.rb +85 -0
  160. metadata +594 -0
@@ -0,0 +1,42 @@
1
+ module Spree
2
+ module TaxonDecorator
3
+ def self.prepended(base)
4
+ base.after_create :update_temp_permalink_to_id
5
+ base.after_destroy :touch_parent_on_destroy
6
+ end
7
+
8
+ def set_permalink
9
+ self.permalink = generate_slug
10
+ end
11
+
12
+ private
13
+ def generate_slug
14
+ if new_record?
15
+ uuid_for_friendly_id
16
+ else
17
+ if parent.present?
18
+ [ parent.permalink, self.id.to_s ].join('/')
19
+ else
20
+ self.id.to_s
21
+ end
22
+ end
23
+ end
24
+
25
+ def update_temp_permalink_to_id
26
+ update_column(:permalink, self.id.to_s)
27
+ end
28
+
29
+ def touch_parent_on_destroy
30
+ # Touch parent and all ancestors when a taxon is destroyed to invalidate cache
31
+ if parent.present?
32
+ parent.touch
33
+ parent.ancestors.update_all(updated_at: Time.current)
34
+ end
35
+ # Also touch taxonomy
36
+ taxonomy.try!(:touch)
37
+ end
38
+ end
39
+ end
40
+
41
+ # Decoratorを適用
42
+ Spree::Taxon.prepend(Spree::TaxonDecorator)
@@ -0,0 +1,33 @@
1
+ module Spree
2
+ # User の bill_address(請求先)が確定したタイミングで、
3
+ # User の first_name / last_name / phone / company を bill_address から同期する。
4
+ #
5
+ # 配送先(ship_address)が「贈り先」であるケースを考慮し、
6
+ # 配送先からは User 情報を更新しないようにするための仕組み。
7
+ module UserBillAddressSyncDecorator
8
+ def self.prepended(base)
9
+ base.after_update :sync_attributes_from_bill_address,
10
+ if: :saved_change_to_bill_address_id?
11
+ end
12
+
13
+ private
14
+
15
+ def sync_attributes_from_bill_address
16
+ return unless bill_address
17
+
18
+ # 名前は未入力の場合のみコピー(既に入力済みの名前は上書きしない)
19
+ if name.blank?
20
+ self.first_name = bill_address.firstname
21
+ self.last_name = bill_address.lastname
22
+ end
23
+
24
+ # phone / company は User 側に値があれば守る(name と方針を揃える)
25
+ self.phone = phone.presence || bill_address.phone
26
+ self.company = company.presence || bill_address.company
27
+
28
+ save! if changed?
29
+ end
30
+ end
31
+ end
32
+
33
+ Spree.user_class.prepend(Spree::UserBillAddressSyncDecorator)
@@ -0,0 +1,8 @@
1
+ Deface::Override.new(
2
+ virtual_path: 'spree/shared/_head',
3
+ name: 'add_ba_spree_storefront_javascript_importmap_tags',
4
+ insert_after: "erb[loud]:contains('javascript_importmap_tags')",
5
+ text: <<-ERB
6
+ <%= javascript_import_module_tag 'ba_spree' %>
7
+ ERB
8
+ )
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Add fragment cache to product listing page to improve performance
4
+ # This prevents the expensive product query and filter UI from being executed on every request
5
+
6
+ # Cache for product_grid render (turbo_frame_request path)
7
+ Deface::Override.new(
8
+ virtual_path: 'spree/shared/_product_listing_page',
9
+ name: 'add_cache_to_product_grid_render',
10
+ surround: "erb[loud]:contains('product_grid')",
11
+ text: <<~ERB
12
+ <% cache spree_base_cache_scope.call([
13
+ @taxon, # Auto-invalidate when product/property/child category changes
14
+ current_page.sections.find_by(type: 'Spree::PageSections::ProductGrid'), # Section settings
15
+ params[:page], # Pagination support
16
+ params[:sort_by], # Sorting support
17
+ params[:filter], # Filter support (price, categories, options)
18
+ 'product-grid'
19
+ ].compact) do %>
20
+ <%= render_original %>
21
+ <% end %>
22
+ ERB
23
+ )
24
+
25
+ # Cache for render_page (normal page render path)
26
+ Deface::Override.new(
27
+ virtual_path: 'spree/shared/_product_listing_page',
28
+ name: 'add_cache_to_render_page',
29
+ surround: "erb[loud]:contains('render_page')",
30
+ text: <<~ERB
31
+ <% cache spree_base_cache_scope.call([
32
+ @taxon, # Auto-invalidate when product/property/child category changes
33
+ params[:page], # Pagination support
34
+ params[:sort_by], # Sorting support
35
+ params[:filter], # Filter support (price, categories, options)
36
+ 'render-page'
37
+ ].compact) do %>
38
+ <%= render_original %>
39
+ <% end %>
40
+ ERB
41
+ )
@@ -0,0 +1,6 @@
1
+ Deface::Override.new(
2
+ virtual_path: "devise/shared/_links",
3
+ name: "add_class_to_login_link",
4
+ replace: "erb[loud]:contains('link_to Spree.t(:login)')",
5
+ text: "<%= link_to Spree.t(:login), new_session_path(resource_name), class: 'btn btn-secondary' %>"
6
+ )
@@ -0,0 +1,30 @@
1
+ Deface::Override.new(
2
+ virtual_path: 'spree/checkout/edit',
3
+ name: 'replace_entire_checkout_content_block',
4
+ replace: "div#checkout_content",
5
+ text: <<~ERB
6
+ <div class="checkout-content mt-5" id="checkout_content">
7
+ <% if @order.address? %>
8
+ <%= render partial: 'spree/checkout/address', locals: { order: @order } %>
9
+ <% elsif @order.payment? %>
10
+ <%= render partial: 'spree/checkout/payment', locals: { order: @order } %>
11
+ <% elsif @order.confirm? %>
12
+ <%= render partial: 'spree/checkout/confirm', locals: { order: @order } %>
13
+ <% elsif @order.delivery? %>
14
+ <%= render partial: 'spree/checkout/delivery', locals: { order: @order } %>
15
+ <% else %>
16
+ <%= form_for @order, url: spree.update_checkout_path(@order.token, @order.state), html: { id: "checkout_form_\#{@order.state}" } do |form| %>
17
+ <div>
18
+ <%= form.hidden_field :state_lock_version unless @order.errors.any? %>
19
+ <%= render @order.state, form: form %>
20
+ </div>
21
+ <div>
22
+ <%= button_tag Spree.t(:save_and_continue),
23
+ class: 'btn btn-primary font-weight-bold w-full lg:w-48 float-right checkout-content-save-continue-button',
24
+ data: { 'turbo-submits-with': (render 'button_processing', is_hidden: false) } %>
25
+ </div>
26
+ <% end %>
27
+ <% end %>
28
+ </div>
29
+ ERB
30
+ )
@@ -0,0 +1,8 @@
1
+ Deface::Override.new(
2
+ virtual_path: 'spree/admin/shared/sidebar/_store_nav',
3
+ name: 'add_promotions_nav_to_store_nav',
4
+ replace: "erb[loud]:contains(\"render 'spree/admin/shared/sidebar/promotions_nav'\")",
5
+ text: <<-HTML
6
+ <%= render 'spree/admin/shared/sidebar/promotions_nav' %>
7
+ HTML
8
+ )
@@ -0,0 +1,23 @@
1
+ # @gem-override spree_admin-5.3.6/app/views/spree/admin/orders/_line_item.html.erb
2
+ # reason: 注文明細(line_item)の「編集」リンクに data-turbo-frame を付与する。
3
+ # 本家は各明細を turbo_frame_tag dom_id(line_item) で囲み、編集リンクはその frame 内クリックで
4
+ # インライン編集される想定だが、dropdown が Floating UI でメニューを body 直下へ portal するため、
5
+ # 編集リンクが frame の外に出てしまい、data-turbo-frame 無指定だとフルページ遷移になる。
6
+ # (同種の不具合をプロモーションのルール/アクション編集でも修正済み)
7
+ # 対象 frame を明示してインライン編集に戻す。
8
+ #
9
+ # Spree 5.3 追従: 本家は dropdown に portal: false を追加し、メニューを body 直下へ portal しなくなった。
10
+ # これにより本来の不具合は本家側で解消し得るが、selector(edit_admin_order_line_item_path を含む erb)は
11
+ # 5.3 でも存在しマッチするため、安全側に倒して override を維持する(turbo_frame 明示は無害)。
12
+ Deface::Override.new(
13
+ virtual_path: 'spree/admin/orders/_line_item',
14
+ name: 'add_turbo_frame_to_admin_order_line_item_edit_link',
15
+ replace: "erb[loud]:contains('edit_admin_order_line_item_path')",
16
+ text: <<-ERB
17
+ <%= link_to_with_icon "edit",
18
+ Spree.t(:edit),
19
+ spree.edit_admin_order_line_item_path(@order, line_item),
20
+ class: "dropdown-item",
21
+ data: { turbo_frame: dom_id(line_item) } %>
22
+ ERB
23
+ )
@@ -0,0 +1,20 @@
1
+ # @gem-override spree_admin-5.3.6/app/views/spree/admin/promotion_actions/_promotion_action.html.erb
2
+ # reason: プロモーションアクションの「編集」リンクに data-turbo-frame を付与する。
3
+ # 本家は各アクションを turbo_frame_tag promotion_action(=dom_id) で囲み、編集リンクは
4
+ # その frame 内クリックでインライン編集(モーダル相当)される想定だが、dropdown が
5
+ # Floating UI でメニューを body 直下へ portal するため、編集リンクが frame の外に出てしまい、
6
+ # data-turbo-frame 無指定だとフルページ遷移(/promotion_actions/:id/edit)になり、更新後も
7
+ # プロモーション画面へ戻らない。対象 frame を明示してインライン編集に戻す。
8
+ # (削除リンクは元から turbo_frame: '_top' 指定があり影響なし)
9
+ #
10
+ # Spree 5.3 追従: 本家は dropdown に portal: false を追加し、メニューを body 直下へ portal しなくなった。
11
+ # これにより本来の不具合は本家側で解消し得るが、selector(edit_admin_promotion_action_path を含む erb)は
12
+ # 5.3 でも存在しマッチするため、安全側に倒して override を維持する(turbo_frame 明示は無害)。
13
+ Deface::Override.new(
14
+ virtual_path: 'spree/admin/promotion_actions/_promotion_action',
15
+ name: 'add_turbo_frame_to_promotion_action_edit_link',
16
+ replace: "erb[loud]:contains('edit_admin_promotion_action_path')",
17
+ text: <<-ERB
18
+ <%= link_to_with_icon 'pencil', Spree.t('actions.edit'), spree.edit_admin_promotion_action_path(promotion_action.promotion, promotion_action), class: 'dropdown-item', data: { turbo_frame: dom_id(promotion_action) } if can?(:update, promotion_action) %>
19
+ ERB
20
+ )
@@ -0,0 +1,8 @@
1
+ Deface::Override.new(
2
+ virtual_path: 'spree/shared/_cart_pane',
3
+ name: 'add_turbo_stream_format_to_cart_path_in_cart_pane',
4
+ replace: "erb[loud]:contains('turbo_frame_tag cart_id(order)')",
5
+ text: <<-ERB
6
+ <%= turbo_frame_tag cart_id(order), class: 'cart-contents', src: spree.cart_path(format: :turbo_stream), loading: :lazy %>
7
+ ERB
8
+ )
@@ -0,0 +1,8 @@
1
+ Deface::Override.new(
2
+ virtual_path: 'spree/shared/_head',
3
+ name: 'ba_spree_loca_time_add_custom_javascript_importmap_tags',
4
+ insert_after: "erb[loud]:contains('javascript_importmap_tags')",
5
+ text: <<-ERB
6
+ <%= javascript_import_module_tag 'ba-spree-local-time' %>
7
+ ERB
8
+ )
@@ -0,0 +1,15 @@
1
+ # payment 画面の請求先住所(bill_address)フォームは「配送先と同じ(use_shipping)」のとき
2
+ # hidden クラスで隠されるが、中の firstname_kana / lastname_kana などには required が
3
+ # 付いたまま残る。空のまま「保存して続ける」を押すと HTML5 バリデーションが非表示の
4
+ # required フィールドを検証しようとし "An invalid form control ... is not focusable" で
5
+ # submit が完全に中止される(POST が一切飛ばない)。
6
+ #
7
+ # disable-when-hidden コントローラを付与し、非表示の間は中の入力欄を disabled にして
8
+ # 検証・送信の対象から外す。表示に戻れば disabled を解除して挙動を元に戻す。
9
+ # @see https://github.com/be-agile/giga-repeat/issues/1210
10
+ Deface::Override.new(
11
+ virtual_path: 'spree/checkout/_payment',
12
+ name: 'disable_hidden_bill_address_fields_on_payment',
13
+ add_to_attributes: "div[data-toggle-target='toggleable']",
14
+ attributes: { 'data-controller': 'disable-when-hidden' }
15
+ )
@@ -0,0 +1,18 @@
1
+ # 会員登録フォームのバリデーションエラーを画面に表示するためのオーバーライド。
2
+ #
3
+ # spree_storefront の devise/registrations/new はフォームを turbo_frame_tag :login で囲み、
4
+ # data: { turbo_frame: '_top' } で送信する。この状態でサーバが 422 を返すと、レスポンスは
5
+ # turbo-frame レイアウトで描画される(error_messages パーシャルは含まれる)が、フォームは
6
+ # _top を狙うため Turbo がフレーム応答を反映できず、エラーが画面に出ないまま再描画される。
7
+ #
8
+ # パスワード変更フォーム(edit)は data: { turbo: false } で通常の全画面再描画となりエラーが
9
+ # 表示されるため、それに合わせて登録フォームも Turbo を無効化し、エラーを表示できるようにする。
10
+ # @see https://github.com/be-agile/giga-repeat/issues/1216
11
+ Deface::Override.new(
12
+ virtual_path: "devise/registrations/new",
13
+ name: "disable_turbo_on_user_registration_form",
14
+ replace: "erb[loud]:contains('form_for(resource')",
15
+ text: <<~ERB
16
+ <%= form_for(resource, as: resource_name, url: registration_path(resource_name), data: { turbo: false }) do |f| %>
17
+ ERB
18
+ )
@@ -0,0 +1,7 @@
1
+ # Fix coupon code apply button layout to prevent text wrapping
2
+ Deface::Override.new(
3
+ virtual_path: 'spree/checkout/_coupon_code',
4
+ name: 'fix_coupon_apply_button_layout',
5
+ replace: 'erb[loud]:contains("button_tag Spree.t(:apply)"):contains("btn-primary")',
6
+ text: '<%= button_tag Spree.t(:apply), class: "ml-3 btn-primary !px-3 !py-2 text-sm whitespace-nowrap", data: { "enable-button-target": "button" }, disabled: true %>'
7
+ )
@@ -0,0 +1,11 @@
1
+ Deface::Override.new(
2
+ virtual_path: "spree/account/_account_nav",
3
+ name: "hide_gift_cards_menu_from_account_nav",
4
+ remove: "erb[loud]:contains('account_gift_cards_path')"
5
+ )
6
+
7
+ Deface::Override.new(
8
+ virtual_path: "spree/account/_account_nav",
9
+ name: "hide_store_credits_menu_from_account_nav",
10
+ remove: "erb[loud]:contains('account_store_credits_path')"
11
+ )
@@ -0,0 +1,15 @@
1
+ # Hide shipping confirmation message for digital-only orders
2
+ # For digital products, there is no physical shipment, so the message
3
+ # "When your order is ready, you will receive an email confirmation"
4
+ # should not be displayed.
5
+ # See: https://github.com/be-agile/giga-repeat/issues/1006
6
+ Deface::Override.new(
7
+ virtual_path: "spree/checkout/complete",
8
+ name: "hide_shipping_message_for_digital_only_orders",
9
+ replace: "erb[loud]:contains('order_success_message')",
10
+ text: <<~ERB
11
+ <% unless @order.digital? %>
12
+ <%= Spree.t('storefront.checkout.order_success_message') %>
13
+ <% end %>
14
+ ERB
15
+ )
@@ -0,0 +1,6 @@
1
+ Deface::Override.new(
2
+ virtual_path: "spree/checkout/_coupon_code",
3
+ name: "localize_apply_button_text",
4
+ replace: "erb[loud]:contains('button_tag Spree.t(:apply)')",
5
+ text: "<%= button_tag Spree.t(:apply), class: 'ml-3 btn-primary !px-4 !py-3 text-sm whitespace-nowrap', data: { 'enable-button-target': 'button' }, disabled: true %>"
6
+ )
@@ -0,0 +1,6 @@
1
+ Deface::Override.new(
2
+ virtual_path: "spree/account/newsletter/_newsletter_settings",
3
+ name: "localize_newsletter_button_text",
4
+ replace: "erb[loud]:contains('@user.accepts_email_marketing?')",
5
+ text: "<%= @user.accepts_email_marketing? ? Spree.t(:unsubscribe) : Spree.t(:subscribe) %>"
6
+ )
@@ -0,0 +1,6 @@
1
+ Deface::Override.new(
2
+ virtual_path: "spree/page_sections/_announcement_bar",
3
+ name: "replace_announcement_bar_text",
4
+ replace: "div.tracking-widest",
5
+ text: "<div class='tracking-widest w-full'><%= CGI.unescapeHTML(section.text.body.to_s).html_safe %></div>"
6
+ )
@@ -0,0 +1,10 @@
1
+ Deface::Override.new(
2
+ virtual_path: "spree/checkout/edit",
3
+ name: "replace_button_edit_checkout",
4
+ replace: "div.text-xs",
5
+ text: <<-HTML
6
+ <div class="text-xs text-end whitespace-nowrap">
7
+ <%= link_to Spree.t(:edit), spree.checkout_state_path(@order.token, 'address'), class: "btn-secondary !py-1 !font-normal-important !text-xs-important" %>
8
+ </div>
9
+ HTML
10
+ )
@@ -0,0 +1,6 @@
1
+ Deface::Override.new(
2
+ virtual_path: "spree/checkout/_delivery",
3
+ name: "replace_delivery_method_header_content",
4
+ replace_contents: "h5.checkout-content-header",
5
+ text: "<strong><%= Spree.t('storefront.checkout.delivery_method').capitalize %></strong>"
6
+ )
@@ -0,0 +1,14 @@
1
+ Deface::Override.new(
2
+ virtual_path: 'spree/checkout/_payment_methods',
3
+ name: 'replace_checkout_pay_button_with_dynamic_label',
4
+ replace: "#checkout-payment-submit erb[loud]:contains('Spree.t(:pay)')",
5
+ text: <<-ERB
6
+ <% if @order.confirm? %>
7
+ <%= Spree.t(:confirm_order).titleize %>
8
+ <% elsif @order.payment? %>
9
+ <%= Spree.t(:save_and_continue).titleize %>
10
+ <% else %>
11
+ <%= Spree.t(:pay).titleize %>
12
+ <% end %>
13
+ ERB
14
+ )
@@ -0,0 +1,19 @@
1
+ Deface::Override.new(
2
+ virtual_path: "spree/products/_add_to_cart_button",
3
+ name: "replace_variant_not_available_button",
4
+ replace: "erb[loud]:contains('notify_me_when_available')",
5
+ text: <<-ERB
6
+ <% if product&.discontinued? || selected_variant&.discontinued? %>
7
+ <%= Spree.t(:add_to_cart_discontinued) %>
8
+ <% elsif selected_variant.present? && !selected_variant.purchasable? %>
9
+ <%= Spree.t(:add_to_cart_not_purchasable) %>
10
+ <% else %>
11
+ <%= Spree.t(:add_to_cart_not_available) %>
12
+ <% end %>
13
+ ERB
14
+ )
15
+
16
+ Deface::Override.new(
17
+ virtual_path: "spree/products/_add_to_cart_button",
18
+ name: "remove_variant_not_available_button_bell_icon",
19
+ remove: "erb[loud]:contains('bell')")
@@ -0,0 +1,12 @@
1
+ Deface::Override.new(
2
+ virtual_path: "spree/admin/stores/form/_basic",
3
+ name: "set_logo_width_height_in_admin_store_basic_form",
4
+ replace: "erb[loud]:contains('f.spree_file_field :logo')",
5
+ text: <<~ERB
6
+ <% logo = f.object.logo %>
7
+ <% logo.analyze if logo.present? && !logo.analyzed? %>
8
+ <% width = logo.metadata&.dig('width') || 240 %>
9
+ <% height = logo.metadata&.dig('height') || 240 %>
10
+ <%= f.spree_file_field :logo, width: width, height: height, crop: true, help_bubble: Spree.t('admin.store.logo_help') %>
11
+ ERB
12
+ )
@@ -0,0 +1,30 @@
1
+ # カテゴリ(Taxon)ページの Breadcrumbs セクションにパンくずを表示する。
2
+ # upstream のセクション用パーシャルは @product があるときしか描画しないため、
3
+ # @taxon があるカテゴリページでは何も表示されなかった。
4
+ # nav#breadcrumbs の内側末尾に @taxon 分岐を追加し、祖先→現在カテゴリのパンくずを描画する。
5
+ # @product 側の既存出力には手を入れないため、商品詳細ページへの影響はない。
6
+ # See: https://github.com/be-agile/giga-repeat/issues/1256
7
+ Deface::Override.new(
8
+ virtual_path: "spree/page_sections/_breadcrumbs",
9
+ name: "show_breadcrumbs_on_taxon_page",
10
+ insert_bottom: "nav#breadcrumbs",
11
+ text: <<~ERB
12
+ <% if @product.blank? && @taxon.present? %>
13
+ <% taxons = @taxon.self_and_ancestors.includes(:translations).find_all { |taxon| taxon.depth != 0 } %>
14
+
15
+ <ul class="inline-flex gap-3 text-sm">
16
+ <% taxons.each_with_index do |taxon, index| %>
17
+ <% is_current = taxon == @taxon %>
18
+ <li class="<%= is_current ? 'text-text opacity-100 font-medium' : 'opacity-50' %>">
19
+ <% if is_current %>
20
+ <%= taxon.name %>
21
+ <% else %>
22
+ <%= link_to taxon.name, spree.nested_taxons_path(taxon), title: taxon.name %>
23
+ <% end %>
24
+ </li>
25
+ <div class="breadcrumb-square opacity-50 <%= 'hidden' if index == taxons.length - 1 %>"></div>
26
+ <% end %>
27
+ </ul>
28
+ <% end %>
29
+ ERB
30
+ )
@@ -0,0 +1,18 @@
1
+ Deface::Override.new(
2
+ virtual_path: 'spree/shared/_order_details',
3
+ name: 'show_individual_adjustments_in_order_details',
4
+ replace: "erb[silent]:contains('if order.promo_total != 0')",
5
+ closing_selector: "erb[silent]:contains('end'):first",
6
+ text: <<~ERB
7
+ <% sort_adjustments_with_flat_percent_last(order.adjustments.nonzero.non_tax.eligible).each do |adjustment| %>
8
+ <div class="flex items-center justify-between py-2">
9
+ <div>
10
+ <%= adjustment.label %>
11
+ </div>
12
+ <div>
13
+ <%= adjustment.display_amount.to_html %>
14
+ </div>
15
+ </div>
16
+ <% end %>
17
+ ERB
18
+ )
@@ -0,0 +1,29 @@
1
+ Deface::Override.new(
2
+ virtual_path: 'spree/checkout/_payment_method',
3
+ name: 'show_only_selected_payment_method_on_confirm',
4
+ replace: "erb[loud]:contains(\"link_to spree.checkout_state_path\")",
5
+ closing_selector: "erb[silent]:contains(\"end\")",
6
+ text: <<~ERB
7
+ <% if @order.state == 'confirm' %>
8
+ <% if selected_method == method %>
9
+ <%= link_to spree.checkout_state_path(token: @order.token, state: 'payment', payment_method_id: method.id),
10
+ class: 'custom-control custom-radio flex items-center px-5 py-4 cursor-pointer w-full' do %>
11
+ <%= radio_button_tag "order[payments_attributes][][payment_method_id]",
12
+ method.id,
13
+ selected_method == method,
14
+ class: 'mr-3' %>
15
+ <%= Spree.t(method.name, scope: :payment_methods, default: method.name) %>
16
+ <% end %>
17
+ <% end %>
18
+ <% else %>
19
+ <%= link_to spree.checkout_state_path(token: @order.token, state: 'payment', payment_method_id: method.id),
20
+ class: 'custom-control custom-radio flex items-center px-5 py-4 cursor-pointer w-full' do %>
21
+ <%= radio_button_tag "order[payments_attributes][][payment_method_id]",
22
+ method.id,
23
+ selected_method == method,
24
+ class: 'mr-3' %>
25
+ <%= Spree.t(method.name, scope: :payment_methods, default: method.name) %>
26
+ <% end %>
27
+ <% end %>
28
+ ERB
29
+ )
@@ -0,0 +1,64 @@
1
+ # frozen_string_literal: true
2
+
3
+ # 一覧テーブルのツールバーにある「検索」「期間」「フィルタービルダー」は独立した GET フォームで、
4
+ # 送信すると他のフォームの絞り込み条件が URL から消えてしまう。
5
+ # 各フォームに、自分が送信しないパラメータを hidden input として持たせて併用できるようにする。
6
+ # @see https://github.com/be-agile/giga-repeat/issues/1262
7
+
8
+ # 検索フォーム: 期間・フィルターを引き継ぐ
9
+ Deface::Override.new(
10
+ virtual_path: 'spree/admin/tables/_table',
11
+ name: 'preserve_filter_params_in_table_search_form',
12
+ insert_bottom: 'div.form-input',
13
+ text: <<~ERB
14
+ <%= preserved_filter_params_inputs(except_q: [search_param]) %>
15
+ ERB
16
+ )
17
+
18
+ # 期間フォーム: 検索・フィルターを引き継ぐ
19
+ Deface::Override.new(
20
+ virtual_path: 'spree/admin/tables/_table',
21
+ name: 'preserve_filter_params_in_table_date_range_form',
22
+ insert_after: "erb[loud]:contains('calendar_range_picker')",
23
+ text: <<~ERB
24
+ <%= preserved_filter_params_inputs(except_q: ["\#{date_range_param}_gt", "\#{date_range_param}_lt"]) %>
25
+ ERB
26
+ )
27
+
28
+ # フィルタービルダーのフォーム: 検索・期間を引き継ぐ
29
+ # (query_state 由来の q[...] は JS が生成し直すため、ここでは引き継がない)
30
+ Deface::Override.new(
31
+ virtual_path: 'spree/admin/tables/_query_builder',
32
+ name: 'preserve_filter_params_in_table_query_builder_form',
33
+ insert_after: 'input[name="query_state"]',
34
+ text: <<~ERB
35
+ <%= preserved_filter_params_inputs(owns_query_state: true, table: table) %>
36
+ ERB
37
+ )
38
+
39
+ # ページネーションのリンク: 壊れた ransack キー (OR グループ) を URL に載せない。
40
+ # 本家は url_for(request.query_parameters.merge(page: ...)) で、壊れたキーを名前を変質させながら
41
+ # 引き回してしまう。
42
+ Deface::Override.new(
43
+ virtual_path: 'spree/admin/shared/_index_table_options',
44
+ name: 'sanitize_ransack_params_in_pagination_previous_link',
45
+ replace: "erb[loud]:contains('@pagy.previous')",
46
+ text: <<~ERB
47
+ <%= link_to icon('chevron-left', class: 'text-gray-900 mr-0'),
48
+ url_for(preserved_pagination_params(@pagy.previous)),
49
+ class: "btn btn-light p-2",
50
+ 'aria-label': 'Previous page' %>
51
+ ERB
52
+ )
53
+
54
+ Deface::Override.new(
55
+ virtual_path: 'spree/admin/shared/_index_table_options',
56
+ name: 'sanitize_ransack_params_in_pagination_next_link',
57
+ replace: "erb[loud]:contains('@pagy.next')",
58
+ text: <<~ERB
59
+ <%= link_to icon('chevron-right', class: 'text-gray-900 mr-0'),
60
+ url_for(preserved_pagination_params(@pagy.next)),
61
+ class: "btn btn-light p-2",
62
+ 'aria-label': 'Next page' %>
63
+ ERB
64
+ )
@@ -0,0 +1,11 @@
1
+ <!-- replace 'erb[loud]:contains("edit_admin_promotion_rule_path")' -->
2
+ <%# @see https://github.com/be-agile/giga-repeat/issues/1075 %>
3
+ <%#
4
+ dropdown は Floating UI でメニューを body 直下へ portal するため、編集リンクが
5
+ turbo_frame_tag promotion_rule(=dom_id(promotion_rule))の外に出てしまい、
6
+ data-turbo-frame 無指定だとフルページ遷移になる(更新後にプロモ画面へ戻らない)。
7
+ 対象frameを明示してインライン編集(モーダル相当)に戻す。
8
+ (元は spree_promotion_rule_property の全面override に含まれていた汎用修正。
9
+ engine削除に伴い Deface 部分override として ba_spree へ退避。)
10
+ %>
11
+ <%= link_to_with_icon 'pencil', Spree.t('actions.edit'), spree.edit_admin_promotion_rule_path(promotion_rule.promotion, promotion_rule), class: 'dropdown-item', data: { turbo_frame: dom_id(promotion_rule) } if can?(:update, promotion_rule) %>
@@ -0,0 +1,17 @@
1
+ Deface::Override.new(
2
+ virtual_path: 'spree/admin/stores/form/_checkout',
3
+ name: 'add_special_instruction_message_settings',
4
+ insert_after: "erb[loud]:contains('preferred_special_instructions_enabled')",
5
+ partial: 'spree/admin/stores/special_instruction_message_settings'
6
+ )
7
+
8
+ Deface::Override.new(
9
+ virtual_path: 'spree/checkout/_special_instructions',
10
+ name: 'add_special_instruction_message_checkout',
11
+ insert_after: 'h5.font-body',
12
+ text: '
13
+ <div id="special-instruction-message">
14
+ <%= current_store.special_instruction_message if current_store.special_instruction_message.present? %>
15
+ </div>
16
+ '
17
+ )
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Spree 5.3 追従: 注文詳細ヘッダーの「完了日時」を日本語の絶対日時で表示する
4
+ #
5
+ # spree_admin 5.3 の orders/_header.html.erb は完了日時を spree_time_ago で描画するため、
6
+ # 「yesterday at 8:29am」のような英語相対表示+ホバーで絶対日時、となる。
7
+ # 日本語の絶対日時(例 2026年06月11日 08:29)を最初から表示するため spree_time に差し替える。
8
+ # (注文一覧テーブルの completed_at 列は config/initializers/spree_admin_orders_table.rb で
9
+ # format: :spree_time として同等の対応済み)
10
+ Deface::Override.new(
11
+ virtual_path: 'spree/admin/orders/_header',
12
+ name: 'use_absolute_time_for_order_header_completed_at',
13
+ replace: "erb[loud]:contains('spree_time_ago')",
14
+ text: '<%= spree_time(@order.completed_at) %>'
15
+ )
@@ -0,0 +1,26 @@
1
+ module Spree
2
+ module MegaNavPresenterDecorator
3
+ ColumnPresenter = Struct.new(:title, :links, :view_all_linkable, keyword_init: true)
4
+
5
+ # @gem-override spree_storefront-5.3.6/app/presenters/spree/mega_nav_presenter.rb#columns
6
+ # @see https://github.com/be-agile/giga-repeat/commit/3d8f8c44f9a0d119fb24f9b8b19001fd7be20c2c
7
+ def columns
8
+ @columns ||=
9
+ if mega_nav.is_a?(Spree::PageBlocks::MegaNavWithSubcategories)
10
+ grouped_by_parent = mega_nav.taxon&.self_and_descendants&.group_by(&:parent_id) || []
11
+ main_subcategories = grouped_by_parent[mega_nav.taxon.id].to_a.sort_by(&:position)
12
+
13
+ main_subcategories.first(max_columns).map do |child_category|
14
+ links = grouped_by_parent[child_category.id].to_a.sort_by(&:position).map(&method(:to_link))
15
+ ColumnPresenter.new(title: child_category.name, links: links, view_all_linkable: child_category)
16
+ end.compact_blank
17
+ elsif mega_nav.is_a?(Spree::PageBlocks::MegaNav)
18
+ [ ColumnPresenter.new(title: main_link.label, links: mega_nav.links.drop(1), view_all_linkable: main_link.linkable) ]
19
+ else
20
+ []
21
+ end
22
+ end
23
+ end
24
+ end
25
+
26
+ Spree::MegaNavPresenter.prepend Spree::MegaNavPresenterDecorator