Commit d95632a4 by Tran Hoang Viet

VietTH: Implement validate add_to_cart

parent 91759019
......@@ -92,4 +92,6 @@ end
gem 'rubocop', '~> 0.32.1'
gem 'cartman', '~> 2.1.2'
\ No newline at end of file
gem 'cartman', '~> 2.1.2'
gem 'font-awesome-rails', '~> 4.3.0.0'
\ No newline at end of file
......@@ -112,6 +112,8 @@ GEM
i18n (~> 0.5)
figaro (1.1.1)
thor (~> 0.14)
font-awesome-rails (4.3.0.0)
railties (>= 3.2, < 5.0)
font-awesome-sass (4.3.2.1)
sass (~> 3.2)
globalid (0.3.5)
......@@ -334,6 +336,7 @@ DEPENDENCIES
factory_girl_rails (~> 4.5.0)
faker (~> 1.4.3)
figaro (~> 1.1.1)
font-awesome-rails (~> 4.3.0.0)
font-awesome-sass
haml-rails (~> 0.9)
jbuilder (~> 2.0)
......
......@@ -11,6 +11,7 @@
// about supported directives.
//
//= require jquery
//= require jquery.spinner.min
//= require jquery_ujs
//= require jquery.validate.min
//= require additional-methods
......
@orderLib = (->
@options = {}
self = @
@validateCheckoutForm = ->
$('#checkout-cart form').validate()
jQuery.validator.addClassRules 'input-quantity', {
jQuery.validator.addClassRules 'input-add-quantity', {
required: true
number: true
min: 1
}
$('.input-quantity').each ->
$('.input-add-quantity').each ->
$(this).rules 'add', {max: $(this).data('max')}
@setOptions = (options)-> @options = options
@setEventChangeQuantity = (element, max)->
@updateTotalPrice()
$('.customize-spinner').spinner 'changed', (e, newVal, oldVal)->
self.updateQuantity($(e.target).data('id'), newVal)
self.updateTotalPrice()
@updateQuantity = (id, quantity)->
index = null
$.each @options.items, (i, item)->
index = i if parseInt(item.data.id) == id
@options.items[index].data.quantity = quantity
@updateTotalPrice = ->
total = 0
$.each @options.items, (index, item)->
total += parseInt(item.data.quantity) * parseInt(item.data.unit_cost)
$('#total-price').text(total)
return @
)()
\ No newline at end of file
......@@ -12,6 +12,8 @@
*
*= require_self
*= require bootstrap_and_overrides
*= require font-awesome
*= require bootstrap-spinner
*= require layout
*= require product
*= require cart
......
#cart-info{
margin-bottom: 30px;
}
#checkout-cart{
table{
td.quantity{
width: 100px;
input{
width: 100%;
}
}
#total-price, #total-price-title{
font-size: 25px;
}
#total-price{
color: blue;
}
}
.input-group-addon{
padding: 7px 12px;
}
i.fa.fa-sort-down {
margin-top: -9px;
vertical-align: middle;
}
}
\ No newline at end of file
......@@ -125,4 +125,11 @@ footer{
margin: 11px 0;
font-size: 20px;
}
}
.no-border{
border-top: 0 !important;
border-bottom: 0 !important;
border-left: 0 !important;
border-right: 0 !important;
}
\ No newline at end of file
......@@ -2,4 +2,8 @@ module ApplicationHelper
def cart_valid?
user_signed_in? && !current_user.cart.count.zero?
end
def format_price(price, delimiter = '.', separator = ',')
number_with_delimiter(price.ceil, delimiter: delimiter, separator: separator)
end
end
......@@ -2,7 +2,7 @@ class OrderItem < ActiveRecord::Base
belongs_to :order
belongs_to :product
before_save :update_product_quantity
after_save :update_product_quantity
def update_product_quantity
self.product.decrement!(:stock, self.quantity)
......
%h3.title Checkout
- if cart_valid?
#checkout-cart
= form_for Order.new do |f|
......@@ -22,10 +24,25 @@
%td
= order_item.stock
%td.quantity
= text_field_tag "cart[items][#{index}][quantity]", order_item.quantity, class: 'form-control compare input-quantity', data: {max: order_item.stock}
.customize-spinner.input-group.spinner{"data-trigger" => "spinner"}
= text_field_tag "cart[items][#{index}][quantity]", order_item.quantity, data: {max: order_item.stock, min: 1, step: 1, id: order_item.id}, class: 'form-control'
.input-group-addon
%a.spin-up{"data-spin" => "up", href: "javascript:;"}
%i.fa.fa-sort-up
%a.spin-down{"data-spin" => "down", href: "javascript:;"}
%i.fa.fa-sort-down
%tfoot
%tr
%td.text-right{colspan: 5}
%td#total-price-title.text-right{colspan: 2} Total:
%td#total-price{colspan: 3}
= format_price(current_user.cart.total)
%tr
%td.no-border.text-right{colspan: 5}
= f.submit 'Checkout', class: 'btn btn-primary'
:javascript
var items = #{current_user.cart.items.to_json.html_safe}
window.orderLib.setOptions({items: items})
window.orderLib.setEventChangeQuantity()
\ No newline at end of file
/*! jQuery spinner - v0.1.6 - 2015-03-09
* https://github.com/xixilive/jquery-spinner
* Copyright (c) 2015 xixilive; Licensed MIT */
!function(a){"use strict";var b,c=function(b,d){return d=a.extend({},d),this.$el=b,this.options=a.extend({},c.rules.defaults,c.rules[d.rule]||{},d),this.min=parseFloat(this.options.min)||0,this.max=parseFloat(this.options.max)||0,this.$el.on("focus.spinner",a.proxy(function(b){b.preventDefault(),a(document).trigger("mouseup.spinner"),this.oldValue=this.value()},this)).on("change.spinner",a.proxy(function(a){a.preventDefault(),this.value(this.$el.val())},this)).on("keydown.spinner",a.proxy(function(a){var b={38:"up",40:"down"}[a.which];b&&(a.preventDefault(),this.spin(b))},this)),this.oldValue=this.value(),this.value(this.$el.val()),this};c.rules={defaults:{min:null,max:null,step:1,precision:0},currency:{min:0,max:null,step:.01,precision:2},quantity:{min:1,max:999,step:1,precision:0},percent:{min:1,max:100,step:1,precision:0},month:{min:1,max:12,step:1,precision:0},day:{min:1,max:31,step:1,precision:0},hour:{min:0,max:23,step:1,precision:0},minute:{min:1,max:59,step:1,precision:0},second:{min:1,max:59,step:1,precision:0}},c.prototype={spin:function(b){if("disabled"!==this.$el.attr("disabled")){this.oldValue=this.value();var c=a.isFunction(this.options.step)?this.options.step.call(this,b):this.options.step;switch(b){case"up":this.value(this.oldValue+Number(c,10));break;case"down":this.value(this.oldValue-Number(c,10))}}},value:function(c){if(null===c||void 0===c)return this.numeric(this.$el.val());c=this.numeric(c);var e=this.validate(c);0!==e&&(c=-1===e?this.min:this.max),this.$el.val(c.toFixed(this.options.precision)),this.oldValue!==this.value()&&(this.$el.trigger("changing.spinner",[this.value(),this.oldValue]),clearTimeout(b),b=setTimeout(a.proxy(function(){this.$el.trigger("changed.spinner",[this.value(),this.oldValue])},this),d.delay))},numeric:function(a){return a=this.options.precision>0?parseFloat(a,10):parseInt(a,10),!isNaN(parseFloat(a))&&isFinite(a)?a:a||this.options.min||0},validate:function(a){return null!==this.options.min&&a<this.min?-1:null!==this.options.max&&a>this.max?1:0}};var d=function(b,d){d=a.extend({},d),this.$el=b,this.$spinning=a("[data-spin='spinner']",this.$el),0===this.$spinning.length&&(this.$spinning=a(":input[type='text']",this.$el)),this.spinning=new c(this.$spinning,a.extend(this.$spinning.data(),d)),this.$el.on("click.spinner","[data-spin='up'],[data-spin='down']",a.proxy(this.spin,this)).on("mousedown.spinner","[data-spin='up'],[data-spin='down']",a.proxy(this.spin,this)),a(document).on("mouseup.spinner",a.proxy(function(){clearTimeout(this.spinTimeout),clearInterval(this.spinInterval)},this)),d.delay&&this.delay(d.delay),d.changed&&this.changed(d.changed),d.changing&&this.changing(d.changing)};d.delay=500,d.prototype={constructor:d,spin:function(b){var c=a(b.currentTarget).data("spin");switch(b.type){case"click":b.preventDefault(),this.spinning.spin(c);break;case"mousedown":1===b.which&&(this.spinTimeout=setTimeout(a.proxy(this.beginSpin,this,c),300))}},delay:function(a){var b=parseInt(a,10);b>=0&&(this.constructor.delay=b+100)},value:function(){return this.spinning.value()},changed:function(a){this.bindHandler("changed.spinner",a)},changing:function(a){this.bindHandler("changing.spinner",a)},bindHandler:function(b,c){a.isFunction(c)?this.$spinning.on(b,c):this.$spinning.off(b)},beginSpin:function(b){this.spinInterval=setInterval(a.proxy(this.spinning.spin,this.spinning,b),100)}},a.fn.spinner=function(b,c){return this.each(function(){var e=a(this),f=e.data("spinner");f||e.data("spinner",f=new d(e,a.extend({},e.data(),b))),("delay"===b||"changed"===b||"changing"===b)&&f[b](c),"step"===b&&c&&(f.spinning.step=c),"spin"===b&&c&&f.spinning.spin(c)})},a(function(){a('[data-trigger="spinner"]').spinner()})}(jQuery);
\ No newline at end of file
.spinner.input-group .input-group-addon a.spin-up,.spinner.input-group .input-group-addon a.spin-down{height:10px;width:10px;font-size:14px;overflow:hidden;display:block;text-align:center;text-decoration:none;position:relative;color:#999}.spinner.input-group .input-group-addon a.spin-up .icon-sort-down,.spinner.input-group .input-group-addon a.spin-down .icon-sort-down{position:relative;top:-6px}.spinner.input-group .input-group-addon a.spin-up:hover,.spinner.input-group .input-group-addon a.spin-down:hover{color:#555}.spinner.input-group input{text-align:center}.spinner.input-group.input-group-lg .input-group-addon a.spin-up,.spinner.input-group.input-group-lg .input-group-addon a.spin-down{font-size:16px;height:12px}.spinner.input-group.input-group-sm .input-group-addon a.spin-up,.spinner.input-group.input-group-sm .input-group-addon a.spin-down{font-size:12px;height:9px}
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment