solidus_reviews 1.0.0 → 1.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/.rubocop.yml +322 -0
- data/.travis.yml +27 -14
- data/Gemfile +23 -8
- data/LICENSE.md +2 -2
- data/README.md +9 -11
- data/Rakefile +2 -0
- data/app/controllers/spree/admin/feedback_reviews_controller.rb +3 -1
- data/app/controllers/spree/admin/review_settings_controller.rb +3 -1
- data/app/controllers/spree/admin/reviews_controller.rb +9 -6
- data/app/controllers/spree/feedback_reviews_controller.rb +25 -19
- data/app/controllers/spree/products_controller_decorator.rb +2 -0
- data/app/controllers/spree/reviews_controller.rb +11 -7
- data/app/helpers/spree/api/api_helpers_decorator.rb +12 -0
- data/app/helpers/spree/reviews_helper.rb +15 -5
- data/app/models/spree/feedback_review.rb +5 -4
- data/app/models/spree/product_decorator.rb +5 -4
- data/app/models/spree/review.rb +28 -10
- data/app/models/spree/reviews_ability.rb +17 -3
- data/app/models/spree/reviews_configuration.rb +16 -8
- data/app/models/spree/user_decorator.rb +3 -0
- data/app/overrides/add_reviews_after_product_properties.rb +7 -5
- data/app/overrides/add_reviews_tab_to_admin.rb +12 -4
- data/app/overrides/add_reviews_to_admin_configuration_sidebar.rb +13 -5
- data/app/views/spree/admin/feedback_reviews/index.html.erb +9 -9
- data/app/views/spree/admin/review_settings/edit.html.erb +64 -35
- data/app/views/spree/admin/reviews/_form.html.erb +26 -5
- data/app/views/spree/admin/reviews/edit.html.erb +2 -2
- data/app/views/spree/admin/reviews/index.html.erb +100 -88
- data/app/views/spree/api/reviews/_review.json.jbuilder +8 -0
- data/app/views/spree/api/reviews/index.json.jbuilder +6 -0
- data/app/views/spree/api/reviews/show.json.jbuilder +3 -0
- data/app/views/spree/feedback_reviews/_form.html.erb +5 -5
- data/app/views/spree/feedback_reviews/_summary.html.erb +3 -3
- data/app/views/spree/feedback_reviews/create.js.erb +2 -2
- data/app/views/spree/reviews/_form.html.erb +15 -10
- data/app/views/spree/reviews/new.html.erb +2 -2
- data/app/views/spree/shared/_rating.html.erb +3 -3
- data/app/views/spree/shared/_review.html.erb +29 -19
- data/app/views/spree/shared/_review_summary.html.erb +3 -3
- data/app/views/spree/shared/_reviews.html.erb +6 -6
- data/app/views/spree/shared/_shortrating.html.erb +2 -2
- data/bin/rails +4 -2
- data/config/initializers/constants.rb +2 -0
- data/config/initializers/load_preferences.rb +2 -0
- data/config/locales/de-CH.yml +14 -1
- data/config/locales/de.yml +14 -1
- data/config/locales/en-GB.yml +14 -2
- data/config/locales/en.yml +14 -1
- data/config/locales/es.yml +14 -2
- data/config/locales/fr.yml +14 -2
- data/config/locales/it.yml +79 -0
- data/config/locales/pl.yml +14 -2
- data/config/locales/pt-BR.yml +14 -2
- data/config/locales/pt.yml +14 -2
- data/config/locales/ro.yml +15 -3
- data/config/locales/ru.yml +14 -2
- data/config/locales/sv.yml +14 -1
- data/config/locales/tr.yml +14 -2
- data/config/locales/uk.yml +14 -1
- data/config/locales/zh-CN.yml +14 -1
- data/config/locales/zh-TW.yml +14 -1
- data/config/routes.rb +18 -1
- data/db/migrate/20081020220724_create_reviews.rb +4 -2
- data/db/migrate/20101222083309_create_feedback_reviews.rb +5 -3
- data/db/migrate/20110406083603_add_rating_to_products.rb +7 -5
- data/db/migrate/20110606150524_add_user_to_reviews.rb +4 -2
- data/db/migrate/20110806093221_add_ip_address_to_reviews.rb +3 -1
- data/db/migrate/20120110172331_namespace_tables.rb +3 -1
- data/db/migrate/20120123141326_recalculate_ratings.rb +6 -5
- data/db/migrate/20120712182514_add_locale_to_reviews.rb +4 -2
- data/db/migrate/20120712182627_add_locale_to_feedback_reviews.rb +4 -2
- data/db/migrate/20140703200946_add_show_identifier_to_reviews.rb +3 -1
- data/db/migrate/20190613165528_add_verified_purchaser_to_reviews.rb +5 -0
- data/lib/controllers/spree/api/reviews_controller.rb +111 -0
- data/lib/generators/solidus_reviews/install/install_generator.rb +5 -4
- data/lib/solidus_reviews.rb +3 -1
- data/lib/solidus_reviews/factories.rb +3 -1
- data/lib/solidus_reviews/factories/feedback_review_factory.rb +6 -5
- data/lib/solidus_reviews/factories/review_factory.rb +19 -9
- data/lib/spree_reviews/engine.rb +7 -0
- data/solidus_reviews.gemspec +20 -18
- data/spec/controllers/admin/feedback_reviews_controller_spec.rb +9 -7
- data/spec/controllers/admin/review_settings_controller_spec.rb +18 -16
- data/spec/controllers/admin/reviews_controller_spec.rb +18 -16
- data/spec/controllers/feedback_reviews_controller_spec.rb +29 -25
- data/spec/controllers/products_controller_spec.rb +4 -2
- data/spec/controllers/reviews_controller_spec.rb +67 -40
- data/spec/controllers/spree/api/reviews_controller_spec.rb +233 -0
- data/spec/features/admin_spec.rb +3 -0
- data/spec/features/reviews_spec.rb +27 -11
- data/spec/helpers/review_helper_spec.rb +3 -2
- data/spec/models/feedback_review_spec.rb +19 -17
- data/spec/models/product_spec.rb +41 -19
- data/spec/models/review_spec.rb +100 -42
- data/spec/models/reviews_ability_spec.rb +10 -8
- data/spec/models/reviews_configuration_spec.rb +28 -19
- data/spec/spec_helper.rb +21 -35
- data/vendor/assets/javascripts/jquery.rating.js +389 -376
- metadata +108 -59
data/Rakefile
CHANGED
@@ -1,4 +1,6 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class Spree::Admin::FeedbackReviewsController < Spree::Admin::ResourceController
|
2
4
|
belongs_to 'spree/review'
|
3
5
|
def index
|
4
6
|
@collection = parent.feedback_reviews
|
@@ -1,5 +1,7 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
class Spree::Admin::ReviewSettingsController < Spree::Admin::BaseController
|
2
|
-
|
4
|
+
before_action :process_unset_checkboxes, only: [:update]
|
3
5
|
|
4
6
|
def update
|
5
7
|
Spree::Reviews::Config.set(params[:preferences])
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
class Spree::Admin::ReviewsController < Spree::Admin::ResourceController
|
2
4
|
helper Spree::ReviewsHelper
|
3
5
|
|
@@ -6,20 +8,21 @@ class Spree::Admin::ReviewsController < Spree::Admin::ResourceController
|
|
6
8
|
end
|
7
9
|
|
8
10
|
def approve
|
9
|
-
|
11
|
+
review = Spree::Review.find(params[:id])
|
10
12
|
|
11
|
-
if
|
12
|
-
|
13
|
+
if review.update_attribute(:approved, true)
|
14
|
+
flash[:success] = I18n.t('spree.info_approve_review')
|
13
15
|
else
|
14
|
-
|
16
|
+
flash[:error] = I18n.t('spree.error_approve_review')
|
15
17
|
end
|
18
|
+
|
16
19
|
redirect_to admin_reviews_path
|
17
20
|
end
|
18
21
|
|
19
22
|
def edit
|
20
23
|
if @review.product.nil?
|
21
|
-
flash[:error] =
|
22
|
-
redirect_to admin_reviews_path
|
24
|
+
flash[:error] = I18n.t('spree.error_no_product')
|
25
|
+
redirect_to admin_reviews_path
|
23
26
|
end
|
24
27
|
end
|
25
28
|
|
@@ -1,11 +1,12 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
class Spree::FeedbackReviewsController < Spree::StoreController
|
2
4
|
helper Spree::BaseHelper
|
3
5
|
|
4
|
-
|
5
|
-
|
6
|
+
before_action :sanitize_rating, only: [:create]
|
7
|
+
before_action :load_review, only: [:create]
|
6
8
|
|
7
9
|
def create
|
8
|
-
|
9
10
|
if @review.present?
|
10
11
|
@feedback_review = @review.feedback_reviews.new(feedback_review_params)
|
11
12
|
@feedback_review.user = spree_current_user
|
@@ -15,27 +16,32 @@ class Spree::FeedbackReviewsController < Spree::StoreController
|
|
15
16
|
end
|
16
17
|
|
17
18
|
respond_to do |format|
|
18
|
-
format.html {
|
19
|
-
|
19
|
+
format.html {
|
20
|
+
if SolidusSupport.solidus_gem_version < Gem::Version.new('2.0')
|
21
|
+
redirect_to(:back)
|
22
|
+
else
|
23
|
+
redirect_back(fallback_location: root_path)
|
24
|
+
end
|
25
|
+
}
|
26
|
+
format.js { render action: :create }
|
20
27
|
end
|
21
|
-
|
22
28
|
end
|
23
29
|
|
24
30
|
protected
|
25
|
-
def load_review
|
26
|
-
@review ||= Spree::Review.find_by_id!(params[:review_id])
|
27
|
-
end
|
28
31
|
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
+
def load_review
|
33
|
+
@review ||= Spree::Review.find_by_id!(params[:review_id])
|
34
|
+
end
|
32
35
|
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
+
def permitted_feedback_review_attributes
|
37
|
+
[:rating, :comment]
|
38
|
+
end
|
36
39
|
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
end
|
40
|
+
def feedback_review_params
|
41
|
+
params.require(:feedback_review).permit(permitted_feedback_review_attributes)
|
42
|
+
end
|
41
43
|
|
44
|
+
def sanitize_rating
|
45
|
+
params[:feedback_review][:rating].to_s.sub!(/\s*[^0-9]*\z/, '') unless params[:feedback_review] && params[:feedback_review][:rating].blank?
|
46
|
+
end
|
47
|
+
end
|
@@ -1,30 +1,35 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
class Spree::ReviewsController < Spree::StoreController
|
2
4
|
helper Spree::BaseHelper
|
3
|
-
|
4
|
-
rescue_from ActiveRecord::RecordNotFound, :with => :render_404
|
5
|
+
before_action :load_product, only: [:index, :new, :create]
|
5
6
|
|
6
7
|
def index
|
7
8
|
@approved_reviews = Spree::Review.approved.where(product: @product)
|
8
9
|
end
|
9
10
|
|
10
11
|
def new
|
11
|
-
@review = Spree::Review.new(:
|
12
|
+
@review = Spree::Review.new(product: @product)
|
12
13
|
authorize! :create, @review
|
13
14
|
end
|
14
15
|
|
15
16
|
# save if all ok
|
16
17
|
def create
|
17
|
-
params[:review][:rating].sub!(/\s*[^0-9]*\z/,'') unless params[:review][:rating].blank?
|
18
|
+
params[:review][:rating].sub!(/\s*[^0-9]*\z/, '') unless params[:review][:rating].blank?
|
18
19
|
|
19
20
|
@review = Spree::Review.new(review_params)
|
20
21
|
@review.product = @product
|
21
22
|
@review.user = spree_current_user if spree_user_signed_in?
|
22
23
|
@review.ip_address = request.remote_ip
|
23
24
|
@review.locale = I18n.locale.to_s if Spree::Reviews::Config[:track_locale]
|
25
|
+
# Handle images
|
26
|
+
params[:review][:images]&.each do |image|
|
27
|
+
@review.images.new(attachment: image)
|
28
|
+
end
|
24
29
|
|
25
30
|
authorize! :create, @review
|
26
31
|
if @review.save
|
27
|
-
flash[:notice] =
|
32
|
+
flash[:notice] = I18n.t('spree.review_successfully_submitted')
|
28
33
|
redirect_to spree.product_path(@product)
|
29
34
|
else
|
30
35
|
render :new
|
@@ -38,11 +43,10 @@ class Spree::ReviewsController < Spree::StoreController
|
|
38
43
|
end
|
39
44
|
|
40
45
|
def permitted_review_attributes
|
41
|
-
[:rating, :title, :review, :name, :show_identifier]
|
46
|
+
[:rating, :title, :review, :name, :show_identifier, :images]
|
42
47
|
end
|
43
48
|
|
44
49
|
def review_params
|
45
50
|
params.require(:review).permit(permitted_review_attributes)
|
46
51
|
end
|
47
|
-
|
48
52
|
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
Spree::Api::ApiHelpers.module_eval do
|
4
|
+
@@review_attributes = [
|
5
|
+
:id, :product_id, :name, :location, :rating, :title, :review, :approved,
|
6
|
+
:created_at, :updated_at, :user_id, :ip_address, :locale, :show_identifier
|
7
|
+
]
|
8
|
+
|
9
|
+
def review_attributes
|
10
|
+
@@review_attributes
|
11
|
+
end
|
12
|
+
end
|
@@ -1,17 +1,27 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
|
+
module Spree::ReviewsHelper
|
3
4
|
def star(the_class)
|
4
|
-
content_tag(:span, " ✮ ".html_safe, :
|
5
|
+
content_tag(:span, " ✮ ".html_safe, class: the_class)
|
5
6
|
end
|
6
7
|
|
7
8
|
def mk_stars(m)
|
8
|
-
(1..5).collect {|n| n <= m ? star("lit") : star("unlit") }.join
|
9
|
+
(1..5).collect { |n| n <= m ? star("lit") : star("unlit") }.join
|
9
10
|
end
|
10
11
|
|
11
12
|
def txt_stars(n, show_out_of = true)
|
12
|
-
res =
|
13
|
-
res += " #{
|
13
|
+
res = I18n.t('spree.star', count: n)
|
14
|
+
res += " #{I18n.t('spree.out_of_5')}" if show_out_of
|
14
15
|
res
|
15
16
|
end
|
16
17
|
|
18
|
+
def display_verified_purchaser?(review)
|
19
|
+
Spree::Reviews::Config[:show_verified_purchaser] && review.user &&
|
20
|
+
Spree::LineItem.joins(:order, :variant)
|
21
|
+
.where.not(spree_orders: { completed_at: nil })
|
22
|
+
.find_by(
|
23
|
+
spree_variants: { product_id: review.product_id },
|
24
|
+
spree_orders: { user_id: review.user_id }
|
25
|
+
).present?
|
26
|
+
end
|
17
27
|
end
|
@@ -1,17 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
class Spree::FeedbackReview < ActiveRecord::Base
|
2
|
-
belongs_to :user, :
|
4
|
+
belongs_to :user, class_name: Spree.user_class.to_s
|
3
5
|
|
4
6
|
belongs_to :review, dependent: :destroy
|
5
7
|
validates :review, presence: true
|
6
8
|
|
7
9
|
validates :rating, numericality: { only_integer: true,
|
8
|
-
greater_than_or_equal_to: 1,
|
10
|
+
greater_than_or_equal_to: 1,
|
9
11
|
less_than_or_equal_to: 5,
|
10
|
-
message:
|
12
|
+
message: :you_must_enter_value_for_rating }
|
11
13
|
|
12
14
|
scope :most_recent_first, -> { order("spree_feedback_reviews.created_at DESC") }
|
13
15
|
default_scope { most_recent_first }
|
14
16
|
|
15
17
|
scope :localized, lambda { |lc| where('spree_feedback_reviews.locale = ?', lc) }
|
16
|
-
|
17
18
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
# Add access to reviews/ratings to the product model
|
2
4
|
Spree::Product.class_eval do
|
3
5
|
has_many :reviews
|
@@ -7,15 +9,14 @@ Spree::Product.class_eval do
|
|
7
9
|
end
|
8
10
|
|
9
11
|
def recalculate_rating
|
10
|
-
reviews_count =
|
12
|
+
reviews_count = reviews.reload.default_approval_filter.count
|
11
13
|
|
12
14
|
self.reviews_count = reviews_count
|
13
15
|
if reviews_count > 0
|
14
|
-
self.avg_rating =
|
16
|
+
self.avg_rating = '%.1f' % (reviews.default_approval_filter.sum(:rating).to_f / reviews_count)
|
15
17
|
else
|
16
18
|
self.avg_rating = 0
|
17
19
|
end
|
18
|
-
|
20
|
+
save
|
19
21
|
end
|
20
|
-
|
21
22
|
end
|
data/app/models/spree/review.rb
CHANGED
@@ -1,22 +1,23 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
class Spree::Review < ActiveRecord::Base
|
2
4
|
belongs_to :product, touch: true
|
3
|
-
belongs_to :user, :
|
5
|
+
belongs_to :user, class_name: Spree.user_class.to_s
|
4
6
|
has_many :feedback_reviews
|
7
|
+
has_many :images, -> { order(:position) }, as: :viewable,
|
8
|
+
dependent: :destroy, class_name: "Spree::Image"
|
5
9
|
|
6
|
-
|
10
|
+
before_create :verify_purchaser
|
11
|
+
after_save :recalculate_product_rating, if: :approved?
|
7
12
|
after_destroy :recalculate_product_rating
|
8
13
|
|
9
|
-
validates :name, presence: true
|
10
|
-
validates :review, presence: true
|
11
|
-
|
12
14
|
validates :rating, numericality: { only_integer: true,
|
13
|
-
greater_than_or_equal_to: 1,
|
15
|
+
greater_than_or_equal_to: 1,
|
14
16
|
less_than_or_equal_to: 5,
|
15
|
-
message:
|
16
|
-
|
17
|
+
message: :you_must_enter_value_for_rating }
|
17
18
|
|
18
19
|
default_scope { order("spree_reviews.created_at DESC") }
|
19
|
-
|
20
|
+
|
20
21
|
scope :localized, ->(lc) { where('spree_reviews.locale = ?', lc) }
|
21
22
|
scope :most_recent_first, -> { order('spree_reviews.created_at DESC') }
|
22
23
|
scope :oldest_first, -> { reorder('spree_reviews.created_at ASC') }
|
@@ -31,6 +32,23 @@ class Spree::Review < ActiveRecord::Base
|
|
31
32
|
end
|
32
33
|
|
33
34
|
def recalculate_product_rating
|
34
|
-
|
35
|
+
product.recalculate_rating if product.present?
|
36
|
+
end
|
37
|
+
|
38
|
+
def email
|
39
|
+
user.try!(:email)
|
40
|
+
end
|
41
|
+
|
42
|
+
def verify_purchaser
|
43
|
+
return unless user_id && product_id
|
44
|
+
|
45
|
+
verified_purchase = Spree::LineItem.joins(:order, :variant)
|
46
|
+
.where.not(spree_orders: { completed_at: nil })
|
47
|
+
.find_by(
|
48
|
+
spree_variants: { product_id: product_id },
|
49
|
+
spree_orders: { user_id: user_id }
|
50
|
+
).present?
|
51
|
+
|
52
|
+
self.verified_purchaser = verified_purchase
|
35
53
|
end
|
36
54
|
end
|
@@ -1,14 +1,28 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
class Spree::ReviewsAbility
|
2
4
|
include CanCan::Ability
|
3
5
|
|
4
|
-
def initialize
|
6
|
+
def initialize(user)
|
5
7
|
review_ability_class = self.class
|
6
|
-
|
8
|
+
|
9
|
+
can :create, Spree::Review do |_review|
|
7
10
|
review_ability_class.allow_anonymous_reviews? || !user.email.blank?
|
8
11
|
end
|
9
|
-
|
12
|
+
|
13
|
+
can :create, Spree::FeedbackReview do |_review|
|
10
14
|
review_ability_class.allow_anonymous_reviews? || !user.email.blank?
|
11
15
|
end
|
16
|
+
|
17
|
+
# You can read your own reviews, and everyone can read approved ones
|
18
|
+
can :read, Spree::Review do |review|
|
19
|
+
review.user == user || review.approved?
|
20
|
+
end
|
21
|
+
|
22
|
+
# You can only change your own review
|
23
|
+
can [:update, :destroy], Spree::Review do |review|
|
24
|
+
review.user == user
|
25
|
+
end
|
12
26
|
end
|
13
27
|
|
14
28
|
def self.allow_anonymous_reviews?
|
@@ -1,26 +1,34 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
class Spree::ReviewsConfiguration < Spree::Preferences::Configuration
|
2
4
|
def self.boolean_preferences
|
3
|
-
%w(include_unapproved_reviews feedback_rating show_email require_login track_locale)
|
5
|
+
%w(display_unapproved_reviews include_unapproved_reviews feedback_rating show_email require_login track_locale)
|
4
6
|
end
|
5
7
|
|
6
8
|
# include non-approved reviews in (public) listings
|
7
|
-
preference :include_unapproved_reviews, :boolean, :
|
9
|
+
preference :include_unapproved_reviews, :boolean, default: false
|
10
|
+
|
11
|
+
# displays non-approved reviews in (public) listings
|
12
|
+
preference :display_unapproved_reviews, :boolean, default: false
|
8
13
|
|
9
14
|
# control how many reviews are shown in summaries etc.
|
10
|
-
preference :preview_size, :integer, :
|
15
|
+
preference :preview_size, :integer, default: 3
|
11
16
|
|
12
17
|
# show a reviewer's email address
|
13
|
-
preference :show_email, :boolean, :
|
18
|
+
preference :show_email, :boolean, default: false
|
19
|
+
|
20
|
+
# show if a reviewer actually purchased the product
|
21
|
+
preference :show_verified_purchaser, :boolean, default: false
|
14
22
|
|
15
23
|
# show helpfullness rating form elements
|
16
|
-
preference :feedback_rating, :boolean, :
|
24
|
+
preference :feedback_rating, :boolean, default: false
|
17
25
|
|
18
26
|
# require login to post reviews
|
19
|
-
preference :require_login, :boolean, :
|
27
|
+
preference :require_login, :boolean, default: true
|
20
28
|
|
21
29
|
# whether to keep track of the reviewer's locale
|
22
|
-
preference :track_locale, :boolean, :
|
30
|
+
preference :track_locale, :boolean, default: false
|
23
31
|
|
24
32
|
# render checkbox for a user to approve to show their identifier (name or email) on their review
|
25
|
-
preference :render_show_identifier_checkbox, :boolean, :
|
33
|
+
preference :render_show_identifier_checkbox, :boolean, default: false
|
26
34
|
end
|
@@ -1,5 +1,7 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
:
|
5
|
-
:
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
Deface::Override.new(virtual_path: "spree/products/show",
|
4
|
+
name: "converted_product_properties_767643482",
|
5
|
+
insert_after: "[data-hook='product_properties']",
|
6
|
+
partial: "spree/shared/reviews",
|
7
|
+
disabled: false)
|
@@ -1,4 +1,12 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
Spree::Backend::Config.configure do |config|
|
4
|
+
config.menu_items.detect { |menu_item|
|
5
|
+
menu_item.label == :products
|
6
|
+
}.sections << :reviews
|
7
|
+
end
|
8
|
+
|
9
|
+
Deface::Override.new(virtual_path: "spree/admin/shared/_product_sub_menu",
|
10
|
+
name: "reviews_admin_tab",
|
11
|
+
insert_bottom: "[data-hook='admin_product_sub_tabs']",
|
12
|
+
text: "<%= tab(:reviews, label: 'review_management') %>")
|