spree_group_buy 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +22 -0
- data/.rspec +3 -0
- data/.rubocop.yml +24 -0
- data/.travis.yml +49 -0
- data/Appraisals +20 -0
- data/Gemfile +11 -0
- data/LICENSE +26 -0
- data/README.md +51 -0
- data/Rakefile +21 -0
- data/app/.gitkeep +0 -0
- data/app/controllers/.gitkeep +0 -0
- data/app/controllers/spree/admin/group_buys_controller.rb +15 -0
- data/app/controllers/spree/admin/orders_controller_decorator.rb +17 -0
- data/app/controllers/spree/api/v2/storefront/cart_controller_decorator.rb +9 -0
- data/app/controllers/spree/products_controller_decorator.rb +20 -0
- data/app/mailers/spree/order_mailer_decorator.rb +10 -0
- data/app/models/.gitkeep +0 -0
- data/app/models/spree/group_buy.rb +72 -0
- data/app/models/spree/line_item_decorator.rb +18 -0
- data/app/models/spree/order_decorator.rb +68 -0
- data/app/models/spree/product_decorator.rb +8 -0
- data/app/models/spree/stock/packer_decorator.rb +27 -0
- data/app/models/spree/stock/prioritizer_decorator.rb +18 -0
- data/app/services/.gitkeep +0 -0
- data/app/services/spree/cart/group_buy_add_item.rb +66 -0
- data/app/views/.gitkeep +0 -0
- data/app/views/spree/admin/group_buys/_form.html.erb +32 -0
- data/app/views/spree/admin/group_buys/edit.html.erb +13 -0
- data/app/views/spree/admin/group_buys/index.html.erb +49 -0
- data/app/views/spree/admin/group_buys/new.html.erb +15 -0
- data/app/views/spree/admin/orders/index.html.erb +271 -0
- data/app/views/spree/admin/shared/_main_menu.html.erb +49 -0
- data/app/views/spree/admin/shared/_product_tabs.html.erb +56 -0
- data/bin/rails +8 -0
- data/config/locales/en.yml +5 -0
- data/config/routes.rb +8 -0
- data/db/migrate/20200824192531_create_spree_group_buys.rb +15 -0
- data/db/migrate/20200826140754_add_group_buy_to_line_items.rb +5 -0
- data/db/migrate/20201005210530_add_group_buy_to_orders.rb +5 -0
- data/gemfiles/spree_3_7.gemfile +9 -0
- data/gemfiles/spree_4_0.gemfile +8 -0
- data/gemfiles/spree_4_1.gemfile +9 -0
- data/gemfiles/spree_master.gemfile +8 -0
- data/lib/generators/spree_group_buy/install/install_generator.rb +26 -0
- data/lib/generators/templates/vendor/assets/javascripts/spree/frontend/views/spree/products/cart_form.js +388 -0
- data/lib/generators/templates/vendor/assets/javascripts/spree/frontend/views/spree/shared/product_added_modal.js +28 -0
- data/lib/spree_group_buy.rb +4 -0
- data/lib/spree_group_buy/engine.rb +20 -0
- data/lib/spree_group_buy/factories.rb +6 -0
- data/lib/spree_group_buy/version.rb +17 -0
- data/spree_group_buy.gemspec +32 -0
- metadata +197 -0
@@ -0,0 +1,49 @@
|
|
1
|
+
<nav>
|
2
|
+
<% if can? :admin, Spree::Order %>
|
3
|
+
<ul class="nav nav-sidebar border-bottom">
|
4
|
+
<%= tab *Spree::BackendConfiguration::ORDER_TABS, icon: 'shopping-cart' %>
|
5
|
+
</ul>
|
6
|
+
<% end %>
|
7
|
+
|
8
|
+
<% if can? :admin, Spree::Order %>
|
9
|
+
<ul class="nav nav-sidebar border-bottom">
|
10
|
+
<%= tab :group_buy_orders, url: '/admin/orders?q[group_buy_eq]=1', icon: 'shopping-cart' %>
|
11
|
+
</ul>
|
12
|
+
<% end %>
|
13
|
+
|
14
|
+
<% if can?(:admin, Spree::ReturnAuthorization) || can?(:admin, Spree::CustomerReturn) %>
|
15
|
+
<ul class="nav nav-sidebar border-bottom">
|
16
|
+
<%= main_menu_tree Spree.t(:returns), icon: "transfer", sub_menu: "returns", url: "#sidebar-returns" %>
|
17
|
+
</ul>
|
18
|
+
<% end %>
|
19
|
+
|
20
|
+
<% if can? :admin, Spree::Product %>
|
21
|
+
<ul class="nav nav-sidebar border-bottom">
|
22
|
+
<%= main_menu_tree Spree.t(:products), icon: "th-large", sub_menu: "product", url: "#sidebar-product" %>
|
23
|
+
</ul>
|
24
|
+
<% end %>
|
25
|
+
|
26
|
+
<% if can? :admin, Spree::Admin::ReportsController %>
|
27
|
+
<ul class="nav nav-sidebar border-bottom">
|
28
|
+
<%= tab *Spree::BackendConfiguration::REPORT_TABS, icon: 'file' %>
|
29
|
+
</ul>
|
30
|
+
<% end %>
|
31
|
+
|
32
|
+
<% if can? :admin, Spree::Promotion %>
|
33
|
+
<ul class="nav nav-sidebar border-bottom">
|
34
|
+
<%= main_menu_tree Spree.t(:promotions), icon: "gift", sub_menu: "promotion", url: "#sidebar-promotions" %>
|
35
|
+
</ul>
|
36
|
+
<% end %>
|
37
|
+
|
38
|
+
<% if Spree.user_class && can?(:admin, Spree.user_class) %>
|
39
|
+
<ul class="nav nav-sidebar border-bottom">
|
40
|
+
<%= tab *Spree::BackendConfiguration::USER_TABS, url: spree.admin_users_path, icon: 'user' %>
|
41
|
+
</ul>
|
42
|
+
<% end %>
|
43
|
+
|
44
|
+
<% if can? :admin, current_store %>
|
45
|
+
<ul class="nav nav-sidebar border-bottom">
|
46
|
+
<%= main_menu_tree Spree.t(:configurations), icon: "wrench", sub_menu: "configuration", url: "#sidebar-configuration" %>
|
47
|
+
</ul>
|
48
|
+
<% end %>
|
49
|
+
</nav>
|
@@ -0,0 +1,56 @@
|
|
1
|
+
<% content_for :page_title do %>
|
2
|
+
<%= link_to Spree.t(:products), admin_products_path %> /
|
3
|
+
<%= @product.name %>
|
4
|
+
<% end %>
|
5
|
+
|
6
|
+
<% content_for :sidebar do %>
|
7
|
+
<ul class="nav flex-column nav-pills" data-hook="admin_product_tabs">
|
8
|
+
<%= content_tag :li do %>
|
9
|
+
<%= link_to_with_icon 'edit',
|
10
|
+
Spree.t(:details),
|
11
|
+
edit_admin_product_url(@product),
|
12
|
+
class: "nav-link #{'active' if current == :details}" %>
|
13
|
+
|
14
|
+
<% end if can?(:admin, Spree::Product) %>
|
15
|
+
|
16
|
+
<%= content_tag :li do %>
|
17
|
+
<%= link_to_with_icon 'picture',
|
18
|
+
Spree.t(:images),
|
19
|
+
spree.admin_product_images_url(@product),
|
20
|
+
class: "nav-link #{'active' if current == :images}" %>
|
21
|
+
|
22
|
+
<% end if can?(:admin, Spree::Image) && !@product.deleted? %>
|
23
|
+
|
24
|
+
<%= content_tag :li do %>
|
25
|
+
<%= link_to_with_icon 'th-large',
|
26
|
+
Spree.t(:variants),
|
27
|
+
spree.admin_product_variants_url(@product),
|
28
|
+
class: "nav-link #{'active' if current == :variants}" %>
|
29
|
+
|
30
|
+
<% end if can?(:admin, Spree::Variant) && !@product.deleted? %>
|
31
|
+
|
32
|
+
<%= content_tag :li do %>
|
33
|
+
<%= link_to_with_icon 'list-alt',
|
34
|
+
Spree.t(:properties),
|
35
|
+
spree.admin_product_product_properties_url(@product),
|
36
|
+
class: "nav-link #{'active' if current == :properties}" %>
|
37
|
+
|
38
|
+
<% end if can?(:admin, Spree::ProductProperty) && !@product.deleted? %>
|
39
|
+
|
40
|
+
<%= content_tag :li do %>
|
41
|
+
<%= link_to_with_icon 'home',
|
42
|
+
Spree.t(:stock),
|
43
|
+
stock_admin_product_url(@product),
|
44
|
+
class: "nav-link #{'active' if current == :stock}" %>
|
45
|
+
|
46
|
+
<% end if can?(:admin, Spree::StockItem) && !@product.deleted? %>
|
47
|
+
|
48
|
+
<%= content_tag :li do %>
|
49
|
+
<%= link_to_with_icon 'money',
|
50
|
+
Spree.t(:group_buys),
|
51
|
+
admin_product_group_buys_url(@product),
|
52
|
+
class: "nav-link #{'active' if current == :group_buys}" %>
|
53
|
+
|
54
|
+
<% end if can?(:admin, Spree::GroupBuy) && !@product.deleted? %>
|
55
|
+
</ul>
|
56
|
+
<% end %>
|
data/bin/rails
ADDED
@@ -0,0 +1,8 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# This command will automatically be run when you run "rails" from the root of your extension
|
3
|
+
|
4
|
+
ENGINE_ROOT = File.expand_path('../..', __FILE__)
|
5
|
+
ENGINE_PATH = File.expand_path('../../lib/spree_group_buy/engine', __FILE__)
|
6
|
+
|
7
|
+
require 'rails/all'
|
8
|
+
require 'rails/engine/commands'
|
data/config/routes.rb
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
class CreateSpreeGroupBuys < ActiveRecord::Migration[6.0]
|
2
|
+
def change
|
3
|
+
create_table :spree_group_buys do |t|
|
4
|
+
t.references :product
|
5
|
+
t.integer :quantity, null: false
|
6
|
+
t.decimal :price, precision: 8, scale: 2
|
7
|
+
t.string :currency
|
8
|
+
t.datetime :expires_at
|
9
|
+
t.integer :engaged_count, default: 0, null: false
|
10
|
+
t.string :state
|
11
|
+
t.timestamps
|
12
|
+
end
|
13
|
+
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module SpreeGroupBuy
|
2
|
+
module Generators
|
3
|
+
class InstallGenerator < Rails::Generators::Base
|
4
|
+
class_option :auto_run_migrations, type: :boolean, default: false
|
5
|
+
|
6
|
+
source_root File.expand_path('../../../templates', __FILE__)
|
7
|
+
|
8
|
+
def copy_javascripts
|
9
|
+
directory 'vendor'
|
10
|
+
end
|
11
|
+
|
12
|
+
def add_migrations
|
13
|
+
run 'bundle exec rake railties:install:migrations FROM=spree_group_buy'
|
14
|
+
end
|
15
|
+
|
16
|
+
def run_migrations
|
17
|
+
run_migrations = options[:auto_run_migrations] || ['', 'y', 'Y'].include?(ask('Would you like to run the migrations now? [Y/n]'))
|
18
|
+
if run_migrations
|
19
|
+
run 'bundle exec rails db:migrate'
|
20
|
+
else
|
21
|
+
puts 'Skipping rails db:migrate, don\'t forget to run it!'
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,388 @@
|
|
1
|
+
//= require spree/api/storefront/cart
|
2
|
+
|
3
|
+
var ADD_TO_CART_FORM_SELECTOR = '.add-to-cart-form'
|
4
|
+
var VARIANT_ID_SELECTOR = '[name="variant_id"]'
|
5
|
+
var OPTION_VALUE_SELECTOR = '.product-variants-variant-values-radio'
|
6
|
+
var ADD_TO_CART_SELECTOR = '.add-to-cart-button'
|
7
|
+
var ADD_TO_CART_DEAL_SELECTOR = '.add-to-cart-deal-button'
|
8
|
+
var GROUP_BUY_SELECTOR = '.group_buy_options_radio'
|
9
|
+
|
10
|
+
var AVAILABILITY_TEMPLATES = {
|
11
|
+
notAvailableInCurrency: '.availability-template-not-available-in-currency',
|
12
|
+
inStock: '.availability-template-in-stock',
|
13
|
+
backorderable: '.availability-template-backorderable',
|
14
|
+
outOfStock: '.availability-template-out-of-stock'
|
15
|
+
}
|
16
|
+
|
17
|
+
|
18
|
+
function CartForm($, $cartForm) {
|
19
|
+
this.constructor = function() {
|
20
|
+
this.initialize()
|
21
|
+
this.bindEventHandlers()
|
22
|
+
}
|
23
|
+
|
24
|
+
this.initialize = function() {
|
25
|
+
this.selectedOptionValueIds = []
|
26
|
+
this.variants = JSON.parse($cartForm.attr('data-variants'))
|
27
|
+
this.withOptionValues = Boolean($cartForm.find(OPTION_VALUE_SELECTOR).length)
|
28
|
+
|
29
|
+
this.$addToCart = $cartForm.find(ADD_TO_CART_SELECTOR)
|
30
|
+
this.$addToCartDeal = $cartForm.find(ADD_TO_CART_DEAL_SELECTOR)
|
31
|
+
this.$price = $cartForm.find('.price.selling')
|
32
|
+
this.$variantIdInput = $cartForm.find(VARIANT_ID_SELECTOR)
|
33
|
+
|
34
|
+
this.initializeForm()
|
35
|
+
}
|
36
|
+
|
37
|
+
this.initializeForm = function() {
|
38
|
+
if (this.withOptionValues) {
|
39
|
+
var $optionValue = this.firstCheckedOptionValue()
|
40
|
+
this.applyCheckedOptionValue($optionValue, true)
|
41
|
+
} else {
|
42
|
+
this.updateAddToCart()
|
43
|
+
this.triggerVariantImages()
|
44
|
+
}
|
45
|
+
}
|
46
|
+
|
47
|
+
this.bindEventHandlers = function() {
|
48
|
+
$cartForm.on('click', OPTION_VALUE_SELECTOR, this.handleOptionValueClick)
|
49
|
+
// $cartForm.on('click', GROUP_BUY_SELECTOR, this.handleGroupBuyClick)
|
50
|
+
}
|
51
|
+
|
52
|
+
this.handleOptionValueClick = function(event) {
|
53
|
+
this.applyCheckedOptionValue($(event.currentTarget))
|
54
|
+
}.bind(this)
|
55
|
+
|
56
|
+
this.handleGroupBuyClick = function(event) {
|
57
|
+
var checkboxes = $cartForm.find(GROUP_BUY_SELECTOR)
|
58
|
+
var current_val = parseInt($(event.currentTarget).val())
|
59
|
+
$cartForm.find(GROUP_BUY_SELECTOR)
|
60
|
+
.each(function(_index, ov) {
|
61
|
+
var $ov = $(ov)
|
62
|
+
var id = parseInt($ov.val())
|
63
|
+
if(id != current_val) {
|
64
|
+
$ov.prop('checked', false)
|
65
|
+
}
|
66
|
+
|
67
|
+
})
|
68
|
+
}.bind(this)
|
69
|
+
|
70
|
+
this.applyCheckedOptionValue = function($optionValue, initialUpdate) {
|
71
|
+
this.saveCheckedOptionValue($optionValue)
|
72
|
+
this.showAvailableVariants()
|
73
|
+
this.updateAddToCart()
|
74
|
+
// we don't want to remove availability status on initial page load
|
75
|
+
if (!initialUpdate) this.updateVariantAvailability()
|
76
|
+
this.updateVariantPrice()
|
77
|
+
this.updateVariantId()
|
78
|
+
|
79
|
+
if (this.shouldTriggerVariantImage($optionValue)) {
|
80
|
+
this.triggerVariantImages()
|
81
|
+
}
|
82
|
+
}
|
83
|
+
|
84
|
+
this.saveCheckedOptionValue = function($optionValue) {
|
85
|
+
var optionTypeIndex = $optionValue.data('option-type-index')
|
86
|
+
|
87
|
+
this.selectedOptionValueIds.splice(
|
88
|
+
optionTypeIndex,
|
89
|
+
this.selectedOptionValueIds.length,
|
90
|
+
parseInt($optionValue.val())
|
91
|
+
)
|
92
|
+
}
|
93
|
+
|
94
|
+
this.showAvailableVariants = function() {
|
95
|
+
var availableOptionValueIds = this.availableOptionValueIds()
|
96
|
+
var selectedOptionValueIdsCount = this.selectedOptionValueIds.length
|
97
|
+
|
98
|
+
this.optionTypes().each(function(index, optionType) {
|
99
|
+
if (index < selectedOptionValueIdsCount) return
|
100
|
+
|
101
|
+
$(optionType)
|
102
|
+
.find(OPTION_VALUE_SELECTOR)
|
103
|
+
.each(function(_index, ov) {
|
104
|
+
var $ov = $(ov)
|
105
|
+
var id = parseInt($ov.val())
|
106
|
+
|
107
|
+
$ov.prop('checked', false)
|
108
|
+
$ov.prop('disabled', !availableOptionValueIds.includes(id))
|
109
|
+
})
|
110
|
+
})
|
111
|
+
}
|
112
|
+
|
113
|
+
this.optionTypes = function() {
|
114
|
+
return $cartForm.find('.product-variants-variant')
|
115
|
+
}
|
116
|
+
|
117
|
+
this.availableOptionValueIds = function() {
|
118
|
+
var selectedOptionValueIds = this.selectedOptionValueIds
|
119
|
+
|
120
|
+
return this.variants.reduce(function(acc, variant) {
|
121
|
+
var optionValues = variant.option_values.map(function(ov) {
|
122
|
+
return ov.id
|
123
|
+
})
|
124
|
+
|
125
|
+
var isPossibleVariantFound = selectedOptionValueIds.every(function(ov) {
|
126
|
+
return optionValues.includes(ov)
|
127
|
+
})
|
128
|
+
|
129
|
+
if (isPossibleVariantFound) {
|
130
|
+
return acc.concat(optionValues)
|
131
|
+
}
|
132
|
+
|
133
|
+
return acc
|
134
|
+
}, [])
|
135
|
+
}
|
136
|
+
|
137
|
+
this.firstCheckedOptionValue = function() {
|
138
|
+
return $cartForm.find(OPTION_VALUE_SELECTOR + '[data-option-type-index=0]' + ':checked')
|
139
|
+
}
|
140
|
+
|
141
|
+
this.shouldTriggerVariantImage = function($optionValue) {
|
142
|
+
return $optionValue.data('is-color') || !this.firstCheckedOptionValue().data('is-color')
|
143
|
+
}
|
144
|
+
|
145
|
+
this.triggerVariantImages = function() {
|
146
|
+
var checkedVariantId
|
147
|
+
var variant = this.selectedVariant()
|
148
|
+
|
149
|
+
if (variant) {
|
150
|
+
checkedVariantId = variant.id
|
151
|
+
} else {
|
152
|
+
checkedVariantId = this.firstCheckedOptionValue().data('variant-id')
|
153
|
+
}
|
154
|
+
|
155
|
+
// Wait for listeners to attach.
|
156
|
+
setTimeout(function() {
|
157
|
+
$cartForm.trigger({
|
158
|
+
type: 'variant_id_change',
|
159
|
+
triggerId: $cartForm.attr('data-variant-change-trigger-identifier'),
|
160
|
+
variantId: checkedVariantId + ''
|
161
|
+
})
|
162
|
+
})
|
163
|
+
}
|
164
|
+
|
165
|
+
this.selectedVariant = function() {
|
166
|
+
var self = this
|
167
|
+
|
168
|
+
if (!this.withOptionValues) {
|
169
|
+
return this.variants.find(function(variant) {
|
170
|
+
return variant.id === parseInt(self.$variantIdInput.val())
|
171
|
+
})
|
172
|
+
}
|
173
|
+
|
174
|
+
if (this.variants.length === 1 && this.variants[0].is_master) {
|
175
|
+
return this.variants[0]
|
176
|
+
}
|
177
|
+
|
178
|
+
return this.variants.find(function(variant) {
|
179
|
+
var optionValueIds = variant.option_values.map(function(ov) {
|
180
|
+
return ov.id
|
181
|
+
})
|
182
|
+
|
183
|
+
return self.areArraysEqual(optionValueIds, self.selectedOptionValueIds)
|
184
|
+
})
|
185
|
+
}
|
186
|
+
|
187
|
+
this.areArraysEqual = function(array1, array2) {
|
188
|
+
return this.sortArray(array1).join(',') === this.sortArray(array2).join(',')
|
189
|
+
}
|
190
|
+
|
191
|
+
this.sortArray = function(array) {
|
192
|
+
return array.concat().sort(function(a, b) {
|
193
|
+
if (a < b) return -1
|
194
|
+
if (a > b) return 1
|
195
|
+
|
196
|
+
return 0
|
197
|
+
})
|
198
|
+
}
|
199
|
+
|
200
|
+
this.updateAddToCart = function() {
|
201
|
+
var variant = this.selectedVariant()
|
202
|
+
|
203
|
+
this.$addToCart.prop('disabled', variant ? !variant.purchasable : true)
|
204
|
+
this.$addToCartDeal.prop('disabled', variant ? !variant.purchasable : true)
|
205
|
+
}
|
206
|
+
|
207
|
+
this.availabilityMessage = function(variant) {
|
208
|
+
if (!variant.is_product_available_in_currency) {
|
209
|
+
return $(AVAILABILITY_TEMPLATES.notAvailableInCurrency).html()
|
210
|
+
}
|
211
|
+
|
212
|
+
if (variant.in_stock) {
|
213
|
+
return $(AVAILABILITY_TEMPLATES.inStock).html()
|
214
|
+
}
|
215
|
+
|
216
|
+
if (variant.backorderable) {
|
217
|
+
return $(AVAILABILITY_TEMPLATES.backorderable).html()
|
218
|
+
}
|
219
|
+
|
220
|
+
return $(AVAILABILITY_TEMPLATES.outOfStock).html()
|
221
|
+
}
|
222
|
+
|
223
|
+
this.updateVariantAvailability = function() {
|
224
|
+
var variant = this.selectedVariant()
|
225
|
+
|
226
|
+
if (!variant) {
|
227
|
+
return $cartForm
|
228
|
+
.find('.add-to-cart-form-general-availability .add-to-cart-form-general-availability-value')
|
229
|
+
.html('')
|
230
|
+
}
|
231
|
+
|
232
|
+
return $cartForm
|
233
|
+
.find('.add-to-cart-form-general-availability .add-to-cart-form-general-availability-value')
|
234
|
+
.html(this.availabilityMessage(variant))
|
235
|
+
}
|
236
|
+
|
237
|
+
this.updateVariantPrice = function() {
|
238
|
+
var variant = this.selectedVariant()
|
239
|
+
|
240
|
+
if (!variant) return
|
241
|
+
|
242
|
+
this.$price.html(variant.display_price)
|
243
|
+
}
|
244
|
+
|
245
|
+
this.updateVariantId = function() {
|
246
|
+
var variant = this.selectedVariant()
|
247
|
+
var variantId = (variant && variant.id) || ''
|
248
|
+
|
249
|
+
this.$variantIdInput.val(variantId)
|
250
|
+
}
|
251
|
+
|
252
|
+
this.constructor()
|
253
|
+
}
|
254
|
+
|
255
|
+
function countdown() {
|
256
|
+
var countdown = document.getElementById("countdown");
|
257
|
+
|
258
|
+
if(!countdown) { return }
|
259
|
+
|
260
|
+
var expireDate = $('#expires_at').text();
|
261
|
+
|
262
|
+
// Set the date we're counting down to
|
263
|
+
var countDownDate = new Date(expireDate).getTime();
|
264
|
+
|
265
|
+
// Update the count down every 1 second
|
266
|
+
var x = setInterval(function() {
|
267
|
+
|
268
|
+
// Get today's date and time
|
269
|
+
var now = new Date().getTime();
|
270
|
+
|
271
|
+
// Find the distance between now and the count down date
|
272
|
+
var distance = countDownDate - now;
|
273
|
+
|
274
|
+
// Time calculations for days, hours, minutes and seconds
|
275
|
+
var days = Math.floor(distance / (1000 * 60 * 60 * 24));
|
276
|
+
var hours = Math.floor((distance % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60));
|
277
|
+
var minutes = Math.floor((distance % (1000 * 60 * 60)) / (1000 * 60));
|
278
|
+
var seconds = Math.floor((distance % (1000 * 60)) / 1000);
|
279
|
+
|
280
|
+
// Display the result in the element with id="demo"
|
281
|
+
countdown.innerHTML = days + "d " + hours + "h "
|
282
|
+
+ minutes + "m " + seconds + "s ";
|
283
|
+
|
284
|
+
// If the count down is finished, write some text
|
285
|
+
if (distance < 0) {
|
286
|
+
clearInterval(x);
|
287
|
+
countdown.innerHTML = "EXPIRED";
|
288
|
+
}
|
289
|
+
}, 1000);
|
290
|
+
}
|
291
|
+
|
292
|
+
Spree.ready(function($) {
|
293
|
+
Spree.variantById = function($cartForm, variantId) {
|
294
|
+
var cartFormVariants = JSON.parse($cartForm.attr('data-variants'))
|
295
|
+
return (
|
296
|
+
cartFormVariants.find(function(variant) {
|
297
|
+
return variant.id.toString() === variantId
|
298
|
+
}) || null
|
299
|
+
)
|
300
|
+
}
|
301
|
+
|
302
|
+
countdown();
|
303
|
+
|
304
|
+
$('#add-to-cart-button').on('click', function(event) {
|
305
|
+
var $cartForm = $(ADD_TO_CART_FORM_SELECTOR);
|
306
|
+
var checkboxes = $cartForm.find(GROUP_BUY_SELECTOR);
|
307
|
+
if(checkboxes.length > 0) {
|
308
|
+
$(checkboxes[0]).prop('checked', false);
|
309
|
+
}
|
310
|
+
$(ADD_TO_CART_SELECTOR).prop('disabled', true);
|
311
|
+
$cartForm.submit();
|
312
|
+
})
|
313
|
+
|
314
|
+
$('#add-to-cart-deal-button').on('click', function(event) {
|
315
|
+
var $cartForm = $(ADD_TO_CART_FORM_SELECTOR);
|
316
|
+
var checkboxes = $cartForm.find(GROUP_BUY_SELECTOR);
|
317
|
+
if(checkboxes.length > 0) {
|
318
|
+
$(checkboxes[0]).prop('checked', true);
|
319
|
+
}
|
320
|
+
$(ADD_TO_CART_DEAL_SELECTOR).prop('disabled', true);
|
321
|
+
$cartForm.submit();
|
322
|
+
})
|
323
|
+
|
324
|
+
$('#product-details').on('submit', ADD_TO_CART_FORM_SELECTOR, function(event) {
|
325
|
+
var variantId
|
326
|
+
var quantity
|
327
|
+
var group_buy_id
|
328
|
+
var group_buy_price
|
329
|
+
var group_buy_display_price
|
330
|
+
var $cartForm = $(event.currentTarget)
|
331
|
+
var $addToCart = $cartForm.find(ADD_TO_CART_SELECTOR)
|
332
|
+
var $addToCartDeal = $cartForm.find(ADD_TO_CART_DEAL_SELECTOR)
|
333
|
+
var $groupBuyChecked = $cartForm.find(GROUP_BUY_SELECTOR+':checked')
|
334
|
+
|
335
|
+
event.preventDefault()
|
336
|
+
// $addToCart.prop('disabled', true)
|
337
|
+
variantId = $cartForm.find(VARIANT_ID_SELECTOR).val()
|
338
|
+
quantity = parseInt($cartForm.find('[name="quantity"]').val())
|
339
|
+
|
340
|
+
if($groupBuyChecked.length) {
|
341
|
+
group_buy_id = $groupBuyChecked.val()
|
342
|
+
group_buy_price = $groupBuyChecked.data('price')
|
343
|
+
group_buy_display_price = $groupBuyChecked.data('display-price')
|
344
|
+
} else {
|
345
|
+
group_buy_id = group_buy_price = group_buy_display_price = undefined
|
346
|
+
}
|
347
|
+
|
348
|
+
Spree.ensureCart(function() {
|
349
|
+
SpreeAPI.Storefront.addToCart(
|
350
|
+
variantId,
|
351
|
+
quantity,
|
352
|
+
{groupBuyId: group_buy_id, groupBuyPrice: group_buy_price}, // options hash - you can pass additional parameters here, your backend
|
353
|
+
// needs to be aware of those, see API docs:
|
354
|
+
// https://github.com/spree/spree/blob/master/api/docs/v2/storefront/index.yaml#L42
|
355
|
+
function(response) {
|
356
|
+
$addToCart.prop('disabled', false)
|
357
|
+
$addToCartDeal.prop('disabled', false)
|
358
|
+
Spree.fetchCart()
|
359
|
+
Spree.showProductAddedModal(JSON.parse(
|
360
|
+
$cartForm.attr('data-product-summary')
|
361
|
+
), Spree.variantById($cartForm, variantId), group_buy_display_price)
|
362
|
+
$cartForm.trigger({
|
363
|
+
type: 'product_add_to_cart',
|
364
|
+
variant: Spree.variantById($cartForm, variantId),
|
365
|
+
quantity_increment: quantity,
|
366
|
+
cart: response.attributes
|
367
|
+
})
|
368
|
+
},
|
369
|
+
function(error) {
|
370
|
+
if (typeof error === 'string' && error !== '') {
|
371
|
+
document.querySelector('#no-product-available .no-product-available-text').innerText = error
|
372
|
+
}
|
373
|
+
document.getElementById('overlay').classList.add('shown')
|
374
|
+
document.getElementById('no-product-available').classList.add('shown')
|
375
|
+
window.scrollTo(0, 0)
|
376
|
+
$addToCart.prop('disabled', false)
|
377
|
+
$addToCartDeal.prop('disabled', false)
|
378
|
+
} // failure callback for 422 and 50x errors
|
379
|
+
)
|
380
|
+
})
|
381
|
+
})
|
382
|
+
|
383
|
+
$(ADD_TO_CART_FORM_SELECTOR).each(function(_cartFormIndex, cartFormElement) {
|
384
|
+
var $cartForm = $(cartFormElement)
|
385
|
+
|
386
|
+
CartForm($, $cartForm)
|
387
|
+
})
|
388
|
+
})
|