solidus_favorites 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.
- checksums.yaml +7 -0
- data/LICENSE +26 -0
- data/README.md +53 -0
- data/Rakefile +23 -0
- data/app/assets/javascripts/spree/backend/solidus_favorites.js +2 -0
- data/app/assets/javascripts/spree/frontend/solidus_favorites.js +40 -0
- data/app/assets/stylesheets/spree/backend/solidus_favorites.css +4 -0
- data/app/assets/stylesheets/spree/frontend/solidus_favorites.css +28 -0
- data/app/controllers/spree/admin/favorites_controller.rb +16 -0
- data/app/controllers/spree/favorites_controller.rb +51 -0
- data/app/helpers/solidus_favorites/store_helper_decorator.rb +27 -0
- data/app/helpers/spree/store_helper_decorator.rb +1 -0
- data/app/models/solidus_favorites/product_decorator.rb +21 -0
- data/app/models/solidus_favorites/user_decorator.rb +17 -0
- data/app/models/spree/favorite.rb +21 -0
- data/app/models/spree/product_decorator.rb +1 -0
- data/app/models/spree/user_decorator.rb +1 -0
- data/app/overrides/add_favorite_link_to_product_show.rb +6 -0
- data/app/overrides/add_favorite_to_admin_product_sidebar.rb +6 -0
- data/app/views/spree/admin/favorites/index.html.erb +45 -0
- data/app/views/spree/admin/favorites/users.html.erb +35 -0
- data/app/views/spree/favorites/_product_link.html.erb +24 -0
- data/app/views/spree/favorites/create.js.erb +6 -0
- data/app/views/spree/favorites/destroy.js.erb +10 -0
- data/app/views/spree/favorites/index.html.erb +52 -0
- data/config/locales/en.yml +25 -0
- data/config/routes.rb +9 -0
- data/db/migrate/20190624204433_create_table_spree_favorites.rb +15 -0
- data/lib/generators/solidus_favorites/install/install_generator.rb +30 -0
- data/lib/solidus_favorites.rb +7 -0
- data/lib/solidus_favorites/configuration.rb +7 -0
- data/lib/solidus_favorites/engine.rb +27 -0
- data/lib/solidus_favorites/factories.rb +6 -0
- data/lib/solidus_favorites/version.rb +3 -0
- metadata +354 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 9ca056d414e6a414422b6bdc2db2b2b8b35b8546f3cac850334af16a622344d8
|
4
|
+
data.tar.gz: 35762cf6e3b11d9ff76ab143f9c361401faabb56c3f1c3bba4b01fe6bdd5761d
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 490e88878d3d1611aacdd588a208ec3451c1cab5a1d9733014c9a5f6c137ed55d83d2fabdb7473b013fba4a2e9675305980b401cdc71a8f2e837a68fcfc6efd6
|
7
|
+
data.tar.gz: 875dd5fa89544ed5f86d8bf4c3b37fad53cf34c08c77fcf09f971db4e7ec959df63fae1fcb036bd801b62f0635dd455d5efa988cb8995f43f7e673627f4bbdc0
|
data/LICENSE
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
Copyright (c) 2019 [name of plugin creator]
|
2
|
+
All rights reserved.
|
3
|
+
|
4
|
+
Redistribution and use in source and binary forms, with or without modification,
|
5
|
+
are permitted provided that the following conditions are met:
|
6
|
+
|
7
|
+
* Redistributions of source code must retain the above copyright notice,
|
8
|
+
this list of conditions and the following disclaimer.
|
9
|
+
* Redistributions in binary form must reproduce the above copyright notice,
|
10
|
+
this list of conditions and the following disclaimer in the documentation
|
11
|
+
and/or other materials provided with the distribution.
|
12
|
+
* Neither the name Spree nor the names of its contributors may be used to
|
13
|
+
endorse or promote products derived from this software without specific
|
14
|
+
prior written permission.
|
15
|
+
|
16
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
17
|
+
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
18
|
+
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
19
|
+
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
20
|
+
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
21
|
+
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
22
|
+
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
23
|
+
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
24
|
+
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
25
|
+
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
26
|
+
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
data/README.md
ADDED
@@ -0,0 +1,53 @@
|
|
1
|
+
SolidusFavorites
|
2
|
+
================
|
3
|
+
|
4
|
+
[](https://travis-ci.org/jtapia/solidus_favorites)
|
5
|
+
|
6
|
+
Solidus Favorite Products is an extension that allows the user to mark/unkmark a product as favorite from the product page.
|
7
|
+
|
8
|
+
- Admin can view which products have been marked as favorite, and by which users, on the Admin end.
|
9
|
+
- It gives user the ability to see all products marked as favorite by him/her.
|
10
|
+
- Allow user to add the products marked as favorite to cart.
|
11
|
+
|
12
|
+
Installation
|
13
|
+
------------
|
14
|
+
|
15
|
+
Add `solidus_favorites` to your Gemfile:
|
16
|
+
|
17
|
+
```ruby
|
18
|
+
gem 'solidus_favorites'
|
19
|
+
```
|
20
|
+
|
21
|
+
Bundle your dependencies and run the installation generator:
|
22
|
+
|
23
|
+
```shell
|
24
|
+
bundle
|
25
|
+
bundle exec rails g solidus_favorites:install
|
26
|
+
```
|
27
|
+
|
28
|
+
Preview
|
29
|
+
----------
|
30
|
+
|
31
|
+

|
32
|
+

|
33
|
+

|
34
|
+

|
35
|
+
|
36
|
+
Testing
|
37
|
+
-------
|
38
|
+
|
39
|
+
First bundle your dependencies, then run `rake`. `rake` will default to building the dummy app if it does not exist, then it will run specs, and [Rubocop](https://github.com/bbatsov/rubocop) static code analysis. The dummy app can be regenerated by using `rake test_app`.
|
40
|
+
|
41
|
+
```shell
|
42
|
+
bundle
|
43
|
+
bundle exec rake
|
44
|
+
```
|
45
|
+
|
46
|
+
When testing your applications integration with this extension you may use it's factories.
|
47
|
+
Simply add this require statement to your spec_helper:
|
48
|
+
|
49
|
+
```ruby
|
50
|
+
require 'solidus_favorites/factories'
|
51
|
+
```
|
52
|
+
|
53
|
+
Copyright (c) 2019 [name of extension creator], released under the New BSD License
|
data/Rakefile
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'bundler'
|
4
|
+
Bundler::GemHelper.install_tasks
|
5
|
+
|
6
|
+
require 'rspec/core/rake_task'
|
7
|
+
require 'spree/testing_support/extension_rake'
|
8
|
+
|
9
|
+
RSpec::Core::RakeTask.new
|
10
|
+
|
11
|
+
task :default do
|
12
|
+
if Dir["spec/dummy"].empty?
|
13
|
+
Rake::Task[:test_app].invoke
|
14
|
+
Dir.chdir("../../")
|
15
|
+
end
|
16
|
+
Rake::Task[:spec].invoke
|
17
|
+
end
|
18
|
+
|
19
|
+
desc 'Generates a dummy app for testing'
|
20
|
+
task :test_app do
|
21
|
+
ENV['LIB_NAME'] = 'solidus_favorites'
|
22
|
+
Rake::Task['extension:test_app'].invoke
|
23
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
Spree.ready(function() {
|
2
|
+
$('.favorite_product_link').on('click', function(e) {
|
3
|
+
e.preventDefault();
|
4
|
+
|
5
|
+
var $el = $(e.currentTarget);
|
6
|
+
|
7
|
+
if ($el.hasClass('fa-heart-o')) {
|
8
|
+
$el.removeClass('fa-heart-o').addClass('fa-heart');
|
9
|
+
} else {
|
10
|
+
$el.removeClass('fa-heart').addClass('fa-heart-o');
|
11
|
+
}
|
12
|
+
})
|
13
|
+
|
14
|
+
$('.favorite_add_to_cart_link').on('click', function(e) {
|
15
|
+
e.preventDefault();
|
16
|
+
|
17
|
+
var addToCartLink = $(e.currentTarget);
|
18
|
+
var removeFavoriteLink = $('.favorite_remove_link');
|
19
|
+
var el = $(e.currentTarget);
|
20
|
+
var variantID = $(e.currentTarget).parents('.favorite_item').data('variantId');
|
21
|
+
var actionsContent = $(e.currentTarget).parent();
|
22
|
+
var actionLinks = $(e.currentTarget).parents('.favorite-product-actions');
|
23
|
+
|
24
|
+
actionsContent.addClass('hidden');
|
25
|
+
actionLinks.append("<i class='fa fa-refresh fa-spin'></i>")
|
26
|
+
|
27
|
+
$.ajax({
|
28
|
+
method: 'POST',
|
29
|
+
url: '/orders/populate',
|
30
|
+
dataType: 'html',
|
31
|
+
data: 'variant_id=' + variantID + '&quantity=1',
|
32
|
+
success: function(data) { Spree.fetch_cart('/cart_link'); },
|
33
|
+
error: function(jqXHR, textStatus, errorThrown) {},
|
34
|
+
complete: function(data) {
|
35
|
+
actionsContent.removeClass('hidden');
|
36
|
+
actionLinks.find('.fa-refresh').remove();
|
37
|
+
}
|
38
|
+
})
|
39
|
+
})
|
40
|
+
})
|
@@ -0,0 +1,28 @@
|
|
1
|
+
table.favorite-products .favorite-product-name p,
|
2
|
+
table.favorite-products .favorite-product-name span {
|
3
|
+
display: block;
|
4
|
+
}
|
5
|
+
|
6
|
+
table.favorite-products .favorite-product-name span {
|
7
|
+
font-style: italic;
|
8
|
+
}
|
9
|
+
|
10
|
+
.account-my-favorite-products table .favorite_add_to_cart_link,
|
11
|
+
.account-my-favorite-products table .favorite_remove_link,
|
12
|
+
.account-my-favorite-products table .favorite_go_to_product_link {
|
13
|
+
display: inline-block;
|
14
|
+
margin: 0 5px;
|
15
|
+
}
|
16
|
+
|
17
|
+
.account-my-favorite-products table .favorite-product-actions .fa-refresh {
|
18
|
+
font-size: 18px;
|
19
|
+
}
|
20
|
+
|
21
|
+
#product-description [data-hook='favorite'] {
|
22
|
+
margin-top: 5px;
|
23
|
+
}
|
24
|
+
|
25
|
+
#product-description .favorite_product_link.fa-heart,
|
26
|
+
#product-description .favorite_product_link.fa-heart-o {
|
27
|
+
font-size: 18px;
|
28
|
+
}
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module Spree
|
2
|
+
module Admin
|
3
|
+
class FavoritesController < Spree::Admin::BaseController
|
4
|
+
def index
|
5
|
+
@favorites = Spree::Product.joins(:favorites).page(params[:page]).
|
6
|
+
per(SolidusFavorites::Config.favorites_per_page)
|
7
|
+
end
|
8
|
+
|
9
|
+
def users
|
10
|
+
@product = Spree::Product.where(id: params[:id]).first
|
11
|
+
@users = @product.favorite_users.page(params[:page]).
|
12
|
+
per(SolidusFavorites::Config.favorites_per_page)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
module Spree
|
2
|
+
class FavoritesController < Spree::StoreController
|
3
|
+
before_action :find_favorite, only: [:destroy]
|
4
|
+
|
5
|
+
respond_to :html, :js
|
6
|
+
|
7
|
+
def index
|
8
|
+
@favorites = try_spree_current_user.favorites.page(params[:page]).
|
9
|
+
per(SolidusFavorites::Config.favorites_per_page) || []
|
10
|
+
end
|
11
|
+
|
12
|
+
def create
|
13
|
+
@favorite = try_spree_current_user.favorites.new(favorite_params)
|
14
|
+
if @favorite.save
|
15
|
+
flash.now[:success] = t('spree.successfully_added_favorite')
|
16
|
+
else
|
17
|
+
flash.now[:error] = @favorite.errors.full_messages.to_sentence
|
18
|
+
end
|
19
|
+
|
20
|
+
respond_to do |format|
|
21
|
+
format.js
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def destroy
|
26
|
+
if @favorite&.destroy
|
27
|
+
flash.now[:success] = t('spree.favorite_successfully_removed')
|
28
|
+
else
|
29
|
+
flash.now[:error] = t('spree.favorite_unsuccessfully_removed')
|
30
|
+
end
|
31
|
+
|
32
|
+
respond_with do |format|
|
33
|
+
format.js
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
private
|
38
|
+
|
39
|
+
def find_favorite
|
40
|
+
@favorite ||= try_spree_current_user.favorites.find(params[:id])
|
41
|
+
end
|
42
|
+
|
43
|
+
def favorite_params
|
44
|
+
params.permit(:favorable_id, :favorable_type, :variant_id)
|
45
|
+
end
|
46
|
+
|
47
|
+
def model_class
|
48
|
+
Spree::Favorite
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module SolidusFavorites
|
2
|
+
module StoreHelperDecorator
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
|
5
|
+
included do
|
6
|
+
def favorite_image(product)
|
7
|
+
if product.respond_to?(:gallery)
|
8
|
+
product&.gallery&.images&.first
|
9
|
+
else
|
10
|
+
product&.variant_images&.first
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def favorite_count
|
15
|
+
try_spree_current_user.favorites.count || 0
|
16
|
+
end
|
17
|
+
|
18
|
+
def get_favorite(object)
|
19
|
+
try_spree_current_user.favorites.find_by_favorable_id_and_favorable_type(object.id, object.class.to_s)
|
20
|
+
end
|
21
|
+
|
22
|
+
def has_favorite?(object)
|
23
|
+
try_spree_current_user.has_favorite?(object) if try_spree_current_user
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
Spree::StoreHelper.include(SolidusFavorites::StoreHelperDecorator)
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module SolidusFavorites
|
2
|
+
module ProductDecorator
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
|
5
|
+
included do
|
6
|
+
prepend(InstanceMethods)
|
7
|
+
has_many :favorites, as: :favorable
|
8
|
+
has_many :favorite_users, through: :favorites, class_name: 'Spree::User', source: 'user'
|
9
|
+
|
10
|
+
def self.favorite
|
11
|
+
joins(:favorites).uniq
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
module InstanceMethods
|
16
|
+
def to_cart_params
|
17
|
+
{}
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module SolidusFavorites
|
2
|
+
module UserDecorator
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
|
5
|
+
included do
|
6
|
+
prepend(InstanceMethods)
|
7
|
+
has_many :favorites, class_name: 'Spree::Favorite'
|
8
|
+
has_many :favorite_products, through: :favorites, class_name: 'Spree::Product', source: :favorable, source_type: 'Spree::Product'
|
9
|
+
end
|
10
|
+
|
11
|
+
module InstanceMethods
|
12
|
+
def has_favorite?(object)
|
13
|
+
favorites.exists?(favorable_id: object.id, favorable_type: object.class.to_s)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Spree
|
2
|
+
class Favorite < ActiveRecord::Base
|
3
|
+
FAVORABLES_ALLOWED = [
|
4
|
+
'Spree::Product'
|
5
|
+
]
|
6
|
+
|
7
|
+
belongs_to :favorable, polymorphic: true
|
8
|
+
belongs_to :user, class_name: Spree.user_class.to_s
|
9
|
+
belongs_to :variant, class_name: 'Spree::Variant'
|
10
|
+
|
11
|
+
validates :favorable, presence: true
|
12
|
+
validates :favorable_type, presence: true, inclusion: { in: FAVORABLES_ALLOWED }
|
13
|
+
|
14
|
+
validates :user_id, uniqueness: { allow_blank: true, message: 'Already added as favorite.', scope: [:favorable_id, :favorable_type] }
|
15
|
+
validates :guest_token, uniqueness: { allow_blank: true, message: 'Already added as favorite.', scope: [:favorable_id, :favorable_type] }
|
16
|
+
|
17
|
+
scope :by_guest_token, -> (token) { where(guest_token: token) }
|
18
|
+
|
19
|
+
default_scope { order('created_at DESC') }
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
Spree::Product.include(SolidusFavorites::ProductDecorator)
|
@@ -0,0 +1 @@
|
|
1
|
+
Spree.user_class.include(SolidusFavorites::UserDecorator)
|
@@ -0,0 +1,45 @@
|
|
1
|
+
<% admin_breadcrumb(link_to(plural_resource_name(Spree::Product), spree.admin_products_path)) %>
|
2
|
+
<% admin_breadcrumb(plural_resource_name(Spree::Favorite)) %>
|
3
|
+
|
4
|
+
<%= paginate @favorites, theme: 'solidus_admin' %>
|
5
|
+
|
6
|
+
<% if @favorites.any? %>
|
7
|
+
<table class='index' id='listing_products'>
|
8
|
+
<colgroup>
|
9
|
+
<col style='width: 15%;'>
|
10
|
+
<col style='width: 5%;'>
|
11
|
+
<col style='width: 50%;'>
|
12
|
+
<col style='width: 15%;'>
|
13
|
+
<col style='width: 15%;'>
|
14
|
+
</colgroup>
|
15
|
+
|
16
|
+
<thead>
|
17
|
+
<tr data-hook='admin_products_index_headers'>
|
18
|
+
<th><%= t('spree.sku') %></th>
|
19
|
+
<th colspan='2'><%= t('spree.name') %></th>
|
20
|
+
<th class='align-center'><%= t('spree.master_price') %></th>
|
21
|
+
<th class='align-center'><%= t('spree.favorite_users') %></th>
|
22
|
+
</tr>
|
23
|
+
</thead>
|
24
|
+
|
25
|
+
<tbody>
|
26
|
+
<% @favorites.each do |favorite| %>
|
27
|
+
<tr <%== "style='color: red;'" if favorite.deleted? %> id='<%= spree_dom_id favorite %>' data-hook='admin_favorites_index_rows'>
|
28
|
+
<td><%= favorite.sku %></td>
|
29
|
+
<td class='align-center'>
|
30
|
+
<%= link_to(render('spree/shared/image', image: favorite_image(favorite), size: :small, itemprop: "image"), admin_product_path(favorite), itemprop: 'url') %>
|
31
|
+
</td>
|
32
|
+
<td><%= link_to(favorite.try(:name), admin_product_path(favorite)) %></td>
|
33
|
+
<td class='align-center'><%= favorite&.display_price.to_html %></td>
|
34
|
+
<td class='align-center'><%= link_to favorite&.favorite_users.count, users_admin_favorite_path(:id => favorite.id) %></td>
|
35
|
+
</tr>
|
36
|
+
<% end %>
|
37
|
+
</tbody>
|
38
|
+
</table>
|
39
|
+
<% else %>
|
40
|
+
<div class='no-objects-found'>
|
41
|
+
<%= t('spree.no_results') %>
|
42
|
+
</div>
|
43
|
+
<% end %>
|
44
|
+
|
45
|
+
<%= paginate @favorites, theme: 'solidus_admin' %>
|
@@ -0,0 +1,35 @@
|
|
1
|
+
<% admin_breadcrumb(link_to(plural_resource_name(Spree::Product), spree.admin_products_path)) %>
|
2
|
+
<% admin_breadcrumb(link_to(plural_resource_name(Spree::Favorite), spree.admin_favorites_path)) %>
|
3
|
+
<% admin_breadcrumb(t('spree.users')) %>
|
4
|
+
|
5
|
+
<% content_for :page_title do %>
|
6
|
+
<%= t('spree.favorite_users') %>
|
7
|
+
<% end %>
|
8
|
+
|
9
|
+
<%= paginate @users, theme: 'solidus_admin' %>
|
10
|
+
|
11
|
+
<% if @users.any? %>
|
12
|
+
<table class='index' id='listing_favorite_products_users'>
|
13
|
+
<thead>
|
14
|
+
<tr data-hook='admin_favorite_users_index_headers'>
|
15
|
+
<th><%= t('spree.email') %></th>
|
16
|
+
</tr>
|
17
|
+
</thead>
|
18
|
+
|
19
|
+
<tbody>
|
20
|
+
<% @users.each do |user| %>
|
21
|
+
<tr <%== "style='color: red;'" if user.deleted? %> id='<%= spree_dom_id user %>' data-hook='admin_favorite_users_index_rows'>
|
22
|
+
<td>
|
23
|
+
<%= user.email %>
|
24
|
+
</td>
|
25
|
+
</tr>
|
26
|
+
<% end %>
|
27
|
+
</tbody>
|
28
|
+
</table>
|
29
|
+
<% else %>
|
30
|
+
<div class='no-objects-found'>
|
31
|
+
<%= t('spree.no_results') %>
|
32
|
+
</div>
|
33
|
+
<% end %>
|
34
|
+
|
35
|
+
<%= paginate @users, theme: 'solidus_admin' %>
|
@@ -0,0 +1,24 @@
|
|
1
|
+
<div itemprop='favorite' data-hook='favorite'>
|
2
|
+
<% if has_favorite?(@product) %>
|
3
|
+
<%= link_to_with_icon '',
|
4
|
+
t('spree.remove_favorite'),
|
5
|
+
favorite_path(get_favorite(@product),
|
6
|
+
favorable_id: @product.id,
|
7
|
+
favorable_type: 'Spree::Product'),
|
8
|
+
method: :delete,
|
9
|
+
no_text: true,
|
10
|
+
remote: true,
|
11
|
+
id: "favorable_product_#{@product.id}",
|
12
|
+
class: 'favorite_product_link fa fa-heart no-text with-tip' %>
|
13
|
+
<% else %>
|
14
|
+
<%= link_to_with_icon '',
|
15
|
+
t('spree.add_favorite'),
|
16
|
+
favorites_path(favorable_id: @product.id,
|
17
|
+
favorable_type: 'Spree::Product'),
|
18
|
+
method: :post,
|
19
|
+
no_text: true,
|
20
|
+
remote: true,
|
21
|
+
id: "favorable_product_#{@product.id}",
|
22
|
+
class: 'favorite_product_link fa fa-heart-o no-text with-tip' %>
|
23
|
+
<% end %>
|
24
|
+
</div>
|
@@ -0,0 +1,6 @@
|
|
1
|
+
<% if @favorite.persisted? %>
|
2
|
+
var $el = document.querySelector("#favorable_<%= @favorite.favorable_type.demodulize.underscore %>_<%= @favorite.favorable_id %>");
|
3
|
+
|
4
|
+
$el.href = '<%= favorite_path(@favorite, favorable_id: @favorite.favorable_id, favorable_type: @favorite.favorable_type) %>';
|
5
|
+
$el.dataset.method = 'delete';
|
6
|
+
<% end %>
|
@@ -0,0 +1,10 @@
|
|
1
|
+
<% if @favorite.destroyed? %>
|
2
|
+
var $el = document.querySelector("#favorable_<%= @favorite.favorable_type.demodulize.underscore %>_<%= @favorite.favorable_id %>");
|
3
|
+
|
4
|
+
if ($el) {
|
5
|
+
$el.href = '<%= favorites_path(favorable_id: @favorite.favorable_id, favorable_type: @favorite.favorable_type) %>';
|
6
|
+
$el.dataset.method = 'post';
|
7
|
+
} else {
|
8
|
+
$("#favorite_<%= @favorite.id %>").remove();
|
9
|
+
}
|
10
|
+
<% end %>
|
@@ -0,0 +1,52 @@
|
|
1
|
+
<div data-hook='account_my_favorite_products' class='account-my-favorite-products'>
|
2
|
+
<h3><%= t('spree.my_favorites') %></h3>
|
3
|
+
|
4
|
+
<% if @favorites.present? %>
|
5
|
+
<table class='favorite-products order-summary'>
|
6
|
+
<thead>
|
7
|
+
<tr>
|
8
|
+
<th class='favorite-product-image'><%= t('spree.image') %></th>
|
9
|
+
<th class='favorite-product-name'><%= t('spree.name') %></th>
|
10
|
+
<th class='favorite-product-price'><%= t('spree.price') %></th>
|
11
|
+
<th class='favorite-product-action'><%= t('spree.action')%></th>
|
12
|
+
</tr>
|
13
|
+
</thead>
|
14
|
+
|
15
|
+
<tbody>
|
16
|
+
<% @favorites.each do |favorite| %>
|
17
|
+
<tr class="favorite_item <%= cycle('even', 'odd') %>" id='favorite_<%= favorite.id %>' data-product-id='<%= favorite&.favorable&.id %>' data-variant-id='<%= favorite&.favorable&.master&.id %>'>
|
18
|
+
<td class='favorite-product-image'>
|
19
|
+
<%= link_to(render('spree/shared/image', image: favorite_image(favorite&.favorable), size: :small, itemprop: 'image'), product_path(favorite&.favorable), itemprop: 'url') %>
|
20
|
+
</td>
|
21
|
+
<td class='favorite-product-name'>
|
22
|
+
<%= favorite&.favorable.name %>
|
23
|
+
</td>
|
24
|
+
<td class='favorite-product-price'>
|
25
|
+
<% if price = favorite&.favorable.price_for(current_pricing_options) %>
|
26
|
+
<span class="price selling" itemprop="price" content="<%= price.to_d %>">
|
27
|
+
<%= price.to_html %>
|
28
|
+
</span>
|
29
|
+
<span itemprop='priceCurrency' content='<%= current_pricing_options.currency %>'></span>
|
30
|
+
<% end %>
|
31
|
+
</td>
|
32
|
+
<td class='favorite-product-actions'>
|
33
|
+
<div class='favorite-product-actions-links'>
|
34
|
+
<% if favorite.favorable.has_variants? %>
|
35
|
+
<%= link_to t('spree.go_to_product'), product_path(favorite.favorable), class: 'favorite_go_to_product_link' %>
|
36
|
+
<% else %>
|
37
|
+
<%= link_to t('spree.add_to_cart'), '#', class: 'favorite_add_to_cart_link', remote: true %>
|
38
|
+
<% end %>
|
39
|
+
<%= link_to t('spree.remove'), favorite_path(favorite), class: 'favorite_remove_link', method: :delete, remote: true %>
|
40
|
+
</div>
|
41
|
+
</tr>
|
42
|
+
<% end %>
|
43
|
+
</tbody>
|
44
|
+
</table>
|
45
|
+
<% else %>
|
46
|
+
<div class='no-objects-found'>
|
47
|
+
<p><%= t('spree.you_have_no_favorites_yet') %></p>
|
48
|
+
</div>
|
49
|
+
<% end %>
|
50
|
+
|
51
|
+
<%= paginate @favorites %>
|
52
|
+
</div
|
@@ -0,0 +1,25 @@
|
|
1
|
+
en:
|
2
|
+
activerecord:
|
3
|
+
attributes:
|
4
|
+
spree/favorite:
|
5
|
+
favorable: Favorable
|
6
|
+
user: User
|
7
|
+
models:
|
8
|
+
spree/favorite:
|
9
|
+
one: Favorite
|
10
|
+
other: Favorites
|
11
|
+
spree:
|
12
|
+
admin:
|
13
|
+
tab:
|
14
|
+
favorites: Favorites
|
15
|
+
add_favorite: Add Favorite
|
16
|
+
favorites: Favorites
|
17
|
+
favorites_settings: Favorite Settings
|
18
|
+
favorites_per_page: Per Page
|
19
|
+
favorite_users: Favorite Users
|
20
|
+
favorite_products: Favorite Products
|
21
|
+
go_to_product: Visit product page
|
22
|
+
my_favorites: My Favorites
|
23
|
+
remove_favorite: Remove Favorite
|
24
|
+
successfully_added_favorite: Successfully added favorite.
|
25
|
+
you_have_no_favorites_yet: You have no favorites yet.
|
data/config/routes.rb
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class CreateTableSpreeFavorites < SolidusSupport::Migration[5.1]
|
4
|
+
def change
|
5
|
+
create_table :spree_favorites do |t|
|
6
|
+
t.belongs_to :favorable, polymorphic: true
|
7
|
+
t.belongs_to :user, index: true
|
8
|
+
t.string :guest_token
|
9
|
+
t.timestamps
|
10
|
+
end
|
11
|
+
|
12
|
+
add_index :spree_favorites, [:favorable_id, :favorable_type]
|
13
|
+
add_index :spree_favorites, :guest_token
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module SolidusFavorites
|
2
|
+
module Generators
|
3
|
+
class InstallGenerator < Rails::Generators::Base
|
4
|
+
class_option :auto_run_migrations, type: :boolean, default: false
|
5
|
+
|
6
|
+
def add_javascripts
|
7
|
+
append_file 'vendor/assets/javascripts/spree/frontend/all.js', "//= require spree/frontend/solidus_favorites\n"
|
8
|
+
append_file 'vendor/assets/javascripts/spree/backend/all.js', "//= require spree/backend/solidus_favorites\n"
|
9
|
+
end
|
10
|
+
|
11
|
+
def add_stylesheets
|
12
|
+
inject_into_file 'vendor/assets/stylesheets/spree/frontend/all.css', " *= require spree/frontend/solidus_favorites\n", before: /\*\//, verbose: true
|
13
|
+
inject_into_file 'vendor/assets/stylesheets/spree/backend/all.css', " *= require spree/backend/solidus_favorites\n", before: /\*\//, verbose: true
|
14
|
+
end
|
15
|
+
|
16
|
+
def add_migrations
|
17
|
+
run 'bundle exec rake railties:install:migrations FROM=solidus_favorites'
|
18
|
+
end
|
19
|
+
|
20
|
+
def run_migrations
|
21
|
+
run_migrations = options[:auto_run_migrations] || ['', 'y', 'Y'].include?(ask('Would you like to run the migrations now? [Y/n]'))
|
22
|
+
if run_migrations
|
23
|
+
run 'bundle exec rake db:migrate'
|
24
|
+
else
|
25
|
+
puts 'Skipping rake db:migrate, don\'t forget to run it!'
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module SolidusFavorites
|
4
|
+
class Engine < Rails::Engine
|
5
|
+
isolate_namespace Spree
|
6
|
+
engine_name 'solidus_favorites'
|
7
|
+
|
8
|
+
config.autoload_paths += %W(#{config.root}/lib)
|
9
|
+
|
10
|
+
# use rspec for tests
|
11
|
+
config.generators do |g|
|
12
|
+
g.test_framework :rspec
|
13
|
+
end
|
14
|
+
|
15
|
+
initializer 'solidus_favorites.environment', before: :load_config_initializers do
|
16
|
+
SolidusFavorites::Config = SolidusFavorites::Configuration.new
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.activate
|
20
|
+
Dir.glob(File.join(File.dirname(__FILE__), '../../app/**/*_decorator*.rb')) do |c|
|
21
|
+
Rails.configuration.cache_classes ? require(c) : load(c)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
config.to_prepare(&method(:activate).to_proc)
|
26
|
+
end
|
27
|
+
end
|
metadata
ADDED
@@ -0,0 +1,354 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: solidus_favorites
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Jonathan Tapia
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2019-06-26 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: solidus
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '2.0'
|
20
|
+
- - "<"
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: '3'
|
23
|
+
type: :runtime
|
24
|
+
prerelease: false
|
25
|
+
version_requirements: !ruby/object:Gem::Requirement
|
26
|
+
requirements:
|
27
|
+
- - ">="
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '2.0'
|
30
|
+
- - "<"
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: '3'
|
33
|
+
- !ruby/object:Gem::Dependency
|
34
|
+
name: solidus_auth_devise
|
35
|
+
requirement: !ruby/object:Gem::Requirement
|
36
|
+
requirements:
|
37
|
+
- - ">="
|
38
|
+
- !ruby/object:Gem::Version
|
39
|
+
version: '2.0'
|
40
|
+
- - "<"
|
41
|
+
- !ruby/object:Gem::Version
|
42
|
+
version: '3'
|
43
|
+
type: :runtime
|
44
|
+
prerelease: false
|
45
|
+
version_requirements: !ruby/object:Gem::Requirement
|
46
|
+
requirements:
|
47
|
+
- - ">="
|
48
|
+
- !ruby/object:Gem::Version
|
49
|
+
version: '2.0'
|
50
|
+
- - "<"
|
51
|
+
- !ruby/object:Gem::Version
|
52
|
+
version: '3'
|
53
|
+
- !ruby/object:Gem::Dependency
|
54
|
+
name: solidus_support
|
55
|
+
requirement: !ruby/object:Gem::Requirement
|
56
|
+
requirements:
|
57
|
+
- - ">="
|
58
|
+
- !ruby/object:Gem::Version
|
59
|
+
version: '0'
|
60
|
+
type: :runtime
|
61
|
+
prerelease: false
|
62
|
+
version_requirements: !ruby/object:Gem::Requirement
|
63
|
+
requirements:
|
64
|
+
- - ">="
|
65
|
+
- !ruby/object:Gem::Version
|
66
|
+
version: '0'
|
67
|
+
- !ruby/object:Gem::Dependency
|
68
|
+
name: deface
|
69
|
+
requirement: !ruby/object:Gem::Requirement
|
70
|
+
requirements:
|
71
|
+
- - "~>"
|
72
|
+
- !ruby/object:Gem::Version
|
73
|
+
version: '1.0'
|
74
|
+
type: :runtime
|
75
|
+
prerelease: false
|
76
|
+
version_requirements: !ruby/object:Gem::Requirement
|
77
|
+
requirements:
|
78
|
+
- - "~>"
|
79
|
+
- !ruby/object:Gem::Version
|
80
|
+
version: '1.0'
|
81
|
+
- !ruby/object:Gem::Dependency
|
82
|
+
name: capybara
|
83
|
+
requirement: !ruby/object:Gem::Requirement
|
84
|
+
requirements:
|
85
|
+
- - ">="
|
86
|
+
- !ruby/object:Gem::Version
|
87
|
+
version: '0'
|
88
|
+
type: :development
|
89
|
+
prerelease: false
|
90
|
+
version_requirements: !ruby/object:Gem::Requirement
|
91
|
+
requirements:
|
92
|
+
- - ">="
|
93
|
+
- !ruby/object:Gem::Version
|
94
|
+
version: '0'
|
95
|
+
- !ruby/object:Gem::Dependency
|
96
|
+
name: capybara-screenshot
|
97
|
+
requirement: !ruby/object:Gem::Requirement
|
98
|
+
requirements:
|
99
|
+
- - ">="
|
100
|
+
- !ruby/object:Gem::Version
|
101
|
+
version: '0'
|
102
|
+
type: :development
|
103
|
+
prerelease: false
|
104
|
+
version_requirements: !ruby/object:Gem::Requirement
|
105
|
+
requirements:
|
106
|
+
- - ">="
|
107
|
+
- !ruby/object:Gem::Version
|
108
|
+
version: '0'
|
109
|
+
- !ruby/object:Gem::Dependency
|
110
|
+
name: coffee-rails
|
111
|
+
requirement: !ruby/object:Gem::Requirement
|
112
|
+
requirements:
|
113
|
+
- - ">="
|
114
|
+
- !ruby/object:Gem::Version
|
115
|
+
version: '0'
|
116
|
+
type: :development
|
117
|
+
prerelease: false
|
118
|
+
version_requirements: !ruby/object:Gem::Requirement
|
119
|
+
requirements:
|
120
|
+
- - ">="
|
121
|
+
- !ruby/object:Gem::Version
|
122
|
+
version: '0'
|
123
|
+
- !ruby/object:Gem::Dependency
|
124
|
+
name: database_cleaner
|
125
|
+
requirement: !ruby/object:Gem::Requirement
|
126
|
+
requirements:
|
127
|
+
- - ">="
|
128
|
+
- !ruby/object:Gem::Version
|
129
|
+
version: '0'
|
130
|
+
type: :development
|
131
|
+
prerelease: false
|
132
|
+
version_requirements: !ruby/object:Gem::Requirement
|
133
|
+
requirements:
|
134
|
+
- - ">="
|
135
|
+
- !ruby/object:Gem::Version
|
136
|
+
version: '0'
|
137
|
+
- !ruby/object:Gem::Dependency
|
138
|
+
name: factory_bot
|
139
|
+
requirement: !ruby/object:Gem::Requirement
|
140
|
+
requirements:
|
141
|
+
- - ">="
|
142
|
+
- !ruby/object:Gem::Version
|
143
|
+
version: '0'
|
144
|
+
type: :development
|
145
|
+
prerelease: false
|
146
|
+
version_requirements: !ruby/object:Gem::Requirement
|
147
|
+
requirements:
|
148
|
+
- - ">="
|
149
|
+
- !ruby/object:Gem::Version
|
150
|
+
version: '0'
|
151
|
+
- !ruby/object:Gem::Dependency
|
152
|
+
name: ffaker
|
153
|
+
requirement: !ruby/object:Gem::Requirement
|
154
|
+
requirements:
|
155
|
+
- - ">="
|
156
|
+
- !ruby/object:Gem::Version
|
157
|
+
version: '0'
|
158
|
+
type: :development
|
159
|
+
prerelease: false
|
160
|
+
version_requirements: !ruby/object:Gem::Requirement
|
161
|
+
requirements:
|
162
|
+
- - ">="
|
163
|
+
- !ruby/object:Gem::Version
|
164
|
+
version: '0'
|
165
|
+
- !ruby/object:Gem::Dependency
|
166
|
+
name: poltergeist
|
167
|
+
requirement: !ruby/object:Gem::Requirement
|
168
|
+
requirements:
|
169
|
+
- - ">="
|
170
|
+
- !ruby/object:Gem::Version
|
171
|
+
version: '0'
|
172
|
+
type: :development
|
173
|
+
prerelease: false
|
174
|
+
version_requirements: !ruby/object:Gem::Requirement
|
175
|
+
requirements:
|
176
|
+
- - ">="
|
177
|
+
- !ruby/object:Gem::Version
|
178
|
+
version: '0'
|
179
|
+
- !ruby/object:Gem::Dependency
|
180
|
+
name: puma
|
181
|
+
requirement: !ruby/object:Gem::Requirement
|
182
|
+
requirements:
|
183
|
+
- - ">="
|
184
|
+
- !ruby/object:Gem::Version
|
185
|
+
version: '0'
|
186
|
+
type: :development
|
187
|
+
prerelease: false
|
188
|
+
version_requirements: !ruby/object:Gem::Requirement
|
189
|
+
requirements:
|
190
|
+
- - ">="
|
191
|
+
- !ruby/object:Gem::Version
|
192
|
+
version: '0'
|
193
|
+
- !ruby/object:Gem::Dependency
|
194
|
+
name: rspec-rails
|
195
|
+
requirement: !ruby/object:Gem::Requirement
|
196
|
+
requirements:
|
197
|
+
- - ">="
|
198
|
+
- !ruby/object:Gem::Version
|
199
|
+
version: '0'
|
200
|
+
type: :development
|
201
|
+
prerelease: false
|
202
|
+
version_requirements: !ruby/object:Gem::Requirement
|
203
|
+
requirements:
|
204
|
+
- - ">="
|
205
|
+
- !ruby/object:Gem::Version
|
206
|
+
version: '0'
|
207
|
+
- !ruby/object:Gem::Dependency
|
208
|
+
name: rubocop
|
209
|
+
requirement: !ruby/object:Gem::Requirement
|
210
|
+
requirements:
|
211
|
+
- - ">="
|
212
|
+
- !ruby/object:Gem::Version
|
213
|
+
version: '0'
|
214
|
+
type: :development
|
215
|
+
prerelease: false
|
216
|
+
version_requirements: !ruby/object:Gem::Requirement
|
217
|
+
requirements:
|
218
|
+
- - ">="
|
219
|
+
- !ruby/object:Gem::Version
|
220
|
+
version: '0'
|
221
|
+
- !ruby/object:Gem::Dependency
|
222
|
+
name: rubocop-rspec
|
223
|
+
requirement: !ruby/object:Gem::Requirement
|
224
|
+
requirements:
|
225
|
+
- - ">="
|
226
|
+
- !ruby/object:Gem::Version
|
227
|
+
version: '0'
|
228
|
+
type: :development
|
229
|
+
prerelease: false
|
230
|
+
version_requirements: !ruby/object:Gem::Requirement
|
231
|
+
requirements:
|
232
|
+
- - ">="
|
233
|
+
- !ruby/object:Gem::Version
|
234
|
+
version: '0'
|
235
|
+
- !ruby/object:Gem::Dependency
|
236
|
+
name: sass-rails
|
237
|
+
requirement: !ruby/object:Gem::Requirement
|
238
|
+
requirements:
|
239
|
+
- - ">="
|
240
|
+
- !ruby/object:Gem::Version
|
241
|
+
version: '0'
|
242
|
+
type: :development
|
243
|
+
prerelease: false
|
244
|
+
version_requirements: !ruby/object:Gem::Requirement
|
245
|
+
requirements:
|
246
|
+
- - ">="
|
247
|
+
- !ruby/object:Gem::Version
|
248
|
+
version: '0'
|
249
|
+
- !ruby/object:Gem::Dependency
|
250
|
+
name: shoulda-matchers
|
251
|
+
requirement: !ruby/object:Gem::Requirement
|
252
|
+
requirements:
|
253
|
+
- - ">="
|
254
|
+
- !ruby/object:Gem::Version
|
255
|
+
version: '0'
|
256
|
+
type: :development
|
257
|
+
prerelease: false
|
258
|
+
version_requirements: !ruby/object:Gem::Requirement
|
259
|
+
requirements:
|
260
|
+
- - ">="
|
261
|
+
- !ruby/object:Gem::Version
|
262
|
+
version: '0'
|
263
|
+
- !ruby/object:Gem::Dependency
|
264
|
+
name: simplecov
|
265
|
+
requirement: !ruby/object:Gem::Requirement
|
266
|
+
requirements:
|
267
|
+
- - ">="
|
268
|
+
- !ruby/object:Gem::Version
|
269
|
+
version: '0'
|
270
|
+
type: :development
|
271
|
+
prerelease: false
|
272
|
+
version_requirements: !ruby/object:Gem::Requirement
|
273
|
+
requirements:
|
274
|
+
- - ">="
|
275
|
+
- !ruby/object:Gem::Version
|
276
|
+
version: '0'
|
277
|
+
- !ruby/object:Gem::Dependency
|
278
|
+
name: sqlite3
|
279
|
+
requirement: !ruby/object:Gem::Requirement
|
280
|
+
requirements:
|
281
|
+
- - ">="
|
282
|
+
- !ruby/object:Gem::Version
|
283
|
+
version: '0'
|
284
|
+
type: :development
|
285
|
+
prerelease: false
|
286
|
+
version_requirements: !ruby/object:Gem::Requirement
|
287
|
+
requirements:
|
288
|
+
- - ">="
|
289
|
+
- !ruby/object:Gem::Version
|
290
|
+
version: '0'
|
291
|
+
description: Users can mark favorite products or anything else you want to allow
|
292
|
+
email: jonathan.tapia@magmalabs.io
|
293
|
+
executables: []
|
294
|
+
extensions: []
|
295
|
+
extra_rdoc_files: []
|
296
|
+
files:
|
297
|
+
- LICENSE
|
298
|
+
- README.md
|
299
|
+
- Rakefile
|
300
|
+
- app/assets/javascripts/spree/backend/solidus_favorites.js
|
301
|
+
- app/assets/javascripts/spree/frontend/solidus_favorites.js
|
302
|
+
- app/assets/stylesheets/spree/backend/solidus_favorites.css
|
303
|
+
- app/assets/stylesheets/spree/frontend/solidus_favorites.css
|
304
|
+
- app/controllers/spree/admin/favorites_controller.rb
|
305
|
+
- app/controllers/spree/favorites_controller.rb
|
306
|
+
- app/helpers/solidus_favorites/store_helper_decorator.rb
|
307
|
+
- app/helpers/spree/store_helper_decorator.rb
|
308
|
+
- app/models/solidus_favorites/product_decorator.rb
|
309
|
+
- app/models/solidus_favorites/user_decorator.rb
|
310
|
+
- app/models/spree/favorite.rb
|
311
|
+
- app/models/spree/product_decorator.rb
|
312
|
+
- app/models/spree/user_decorator.rb
|
313
|
+
- app/overrides/add_favorite_link_to_product_show.rb
|
314
|
+
- app/overrides/add_favorite_to_admin_product_sidebar.rb
|
315
|
+
- app/views/spree/admin/favorites/index.html.erb
|
316
|
+
- app/views/spree/admin/favorites/users.html.erb
|
317
|
+
- app/views/spree/favorites/_product_link.html.erb
|
318
|
+
- app/views/spree/favorites/create.js.erb
|
319
|
+
- app/views/spree/favorites/destroy.js.erb
|
320
|
+
- app/views/spree/favorites/index.html.erb
|
321
|
+
- config/locales/en.yml
|
322
|
+
- config/routes.rb
|
323
|
+
- db/migrate/20190624204433_create_table_spree_favorites.rb
|
324
|
+
- lib/generators/solidus_favorites/install/install_generator.rb
|
325
|
+
- lib/solidus_favorites.rb
|
326
|
+
- lib/solidus_favorites/configuration.rb
|
327
|
+
- lib/solidus_favorites/engine.rb
|
328
|
+
- lib/solidus_favorites/factories.rb
|
329
|
+
- lib/solidus_favorites/version.rb
|
330
|
+
homepage: http://github.com/jtapia/solidus_favorites
|
331
|
+
licenses:
|
332
|
+
- BSD-3-Clause
|
333
|
+
metadata: {}
|
334
|
+
post_install_message:
|
335
|
+
rdoc_options: []
|
336
|
+
require_paths:
|
337
|
+
- lib
|
338
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
339
|
+
requirements:
|
340
|
+
- - ">="
|
341
|
+
- !ruby/object:Gem::Version
|
342
|
+
version: '0'
|
343
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
344
|
+
requirements:
|
345
|
+
- - ">="
|
346
|
+
- !ruby/object:Gem::Version
|
347
|
+
version: '0'
|
348
|
+
requirements: []
|
349
|
+
rubyforge_project:
|
350
|
+
rubygems_version: 2.7.6
|
351
|
+
signing_key:
|
352
|
+
specification_version: 4
|
353
|
+
summary: Users can mark favorite products or anything else you want to allow
|
354
|
+
test_files: []
|