mirror of
https://github.com/openfoodfoundation/openfoodnetwork
synced 2026-03-01 02:03:22 +00:00
@@ -0,0 +1,2 @@
|
||||
Darkswarm.controller "CartFormCtrl", ($scope) ->
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
# Allows disabling of link buttons via disabled attribute.
|
||||
# This is normally ignored, ie the link appears disabled but is still clickable.
|
||||
|
||||
Darkswarm.directive "disableDynamically", ->
|
||||
restrict: 'A'
|
||||
|
||||
link: (scope, element, attrs) ->
|
||||
element.on 'click', (e) ->
|
||||
if attrs.disabled
|
||||
e.preventDefault()
|
||||
return
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
Darkswarm.directive "ofnOnHand", ->
|
||||
Darkswarm.directive "ofnOnHand", (StockQuantity) ->
|
||||
restrict: 'A'
|
||||
require: "ngModel"
|
||||
scope: true
|
||||
@@ -24,6 +24,4 @@ Darkswarm.directive "ofnOnHand", ->
|
||||
viewValue
|
||||
|
||||
scope.available_quantity = ->
|
||||
on_hand = parseInt(attr.ofnOnHand)
|
||||
finalized_quantity = parseInt(attr.finalizedquantity) || 0 # finalizedquantity is optional
|
||||
on_hand + finalized_quantity
|
||||
StockQuantity.available_quantity(attr.ofnOnHand, attr.finalizedquantity)
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
Darkswarm.directive "validateStockQuantity", (StockQuantity) ->
|
||||
restrict: 'A'
|
||||
require: "ngModel"
|
||||
scope: true
|
||||
|
||||
link: (scope, element, attr, ngModel) ->
|
||||
ngModel.$parsers.push (selectedQuantity) ->
|
||||
valid_number = parseInt(selectedQuantity) != NaN
|
||||
valid_quantity = parseInt(selectedQuantity) <= scope.available_quantity()
|
||||
|
||||
ngModel.$setValidity('stock', (valid_number && valid_quantity) );
|
||||
|
||||
selectedQuantity
|
||||
|
||||
scope.available_quantity = ->
|
||||
StockQuantity.available_quantity(attr.ofnOnHand, attr.finalizedquantity)
|
||||
@@ -0,0 +1,7 @@
|
||||
Darkswarm.factory "StockQuantity", ->
|
||||
new class StockQuantity
|
||||
available_quantity: (on_hand, finalized_quantity) ->
|
||||
on_hand = parseInt(on_hand)
|
||||
finalized_quantity = parseInt(finalized_quantity) || 0 # finalized_quantity is optional
|
||||
|
||||
on_hand + finalized_quantity
|
||||
@@ -72,6 +72,12 @@
|
||||
}
|
||||
|
||||
// Shopping cart
|
||||
#update-cart {
|
||||
#errorExplanation {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
#cart-detail {
|
||||
.cart-item-delete, .bought-item-delete {
|
||||
a {
|
||||
@@ -102,6 +108,12 @@
|
||||
float: right;
|
||||
}
|
||||
}
|
||||
|
||||
input {
|
||||
&.ng-invalid-stock, &.ng-invalid-number {
|
||||
border: 1px solid $clr-brick;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.item-thumb-image {
|
||||
|
||||
@@ -23,7 +23,11 @@
|
||||
= line_item.single_display_amount_with_adjustments.to_html
|
||||
%td.text-center.cart-item-quantity{"data-hook" => "cart_item_quantity"}
|
||||
- finalized_quantity = @order.completed? ? line_item.quantity : 0
|
||||
= item_form.number_field :quantity, :min => 0, "ofn-on-hand" => "#{variant.on_demand && 9999 || variant.on_hand}", "finalizedquantity" => finalized_quantity, "ng-model" => "line_item_#{line_item.id}", :class => "line_item_quantity", :size => 5
|
||||
= item_form.number_field :quantity,
|
||||
:min => 0, "ofn-on-hand" => "#{variant.on_demand && 9999 || variant.on_hand}",
|
||||
"finalizedquantity" => finalized_quantity, :class => "line_item_quantity", :size => 5,
|
||||
"ng-model" => "line_item_#{line_item.id}",
|
||||
"validate-stock-quantity" => true
|
||||
%td.cart-item-total.text-right{"data-hook" => "cart_item_total"}
|
||||
= line_item.display_amount_with_adjustments.to_html unless line_item.quantity.nil?
|
||||
|
||||
|
||||
@@ -33,7 +33,8 @@
|
||||
|
||||
- else
|
||||
%div{"data-hook" => "outside_cart_form"}
|
||||
= form_for @order, :url => main_app.update_cart_path, :html => {:id => 'update-cart'} do |order_form|
|
||||
= form_for @order, :url => main_app.update_cart_path,
|
||||
:html => {id: 'update-cart', name: "form", "ng-controller"=> 'CartFormCtrl'} do |order_form|
|
||||
%div{"data-hook" => "inside_cart_form"}
|
||||
%div{"data-hook" => "cart_items"}
|
||||
.row
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
%tr
|
||||
%td{colspan:"2"}
|
||||
%td
|
||||
= button_tag :class => 'secondary radius expand small', :id => 'update-button' do
|
||||
%button#update-button.secondary.radius.expand.small{"ng-class" => "{ alert: form.$dirty && form.$valid }"}
|
||||
%i.ofn-i_023-refresh
|
||||
= t(:update)
|
||||
%td
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
.row.links{'data-hook' => "cart_buttons"}
|
||||
%a.button.large.secondary{href: current_shop_products_path}
|
||||
%a.continue-shopping.button.large.secondary{href: current_shop_products_path, "ng-disabled" => "#{@insufficient_stock_lines.any?}", "disable-dynamically" => true}
|
||||
= t :orders_edit_continue
|
||||
%a#checkout-link.button.large.primary.right{href: main_app.checkout_path}
|
||||
%a#checkout-link.button.large.primary.right{href: main_app.checkout_path, "ng-disabled" => "#{@insufficient_stock_lines.any?}", "disable-dynamically" => true}
|
||||
= t :orders_edit_checkout
|
||||
|
||||
@@ -3406,7 +3406,7 @@ See the %{link} to find out more about %{sitename}'s features and to start using
|
||||
format: ! '%Y-%m-%d'
|
||||
js_format: 'yy-mm-dd'
|
||||
orders:
|
||||
error_flash_for_unavailable_items: "An item in your cart has become unavailable."
|
||||
error_flash_for_unavailable_items: "An item in your cart has become unavailable. Please update the selected quantities."
|
||||
edit:
|
||||
login_to_view_order: "Please log in to view your order."
|
||||
bought:
|
||||
|
||||
@@ -161,7 +161,7 @@ describe Spree::OrdersController, type: :controller do
|
||||
it "displays a flash message when we view the cart" do
|
||||
spree_get :edit
|
||||
expect(response.status).to eq 200
|
||||
expect(flash[:error]).to eq("An item in your cart has become unavailable.")
|
||||
expect(flash[:error]).to eq I18n.t('spree.orders.error_flash_for_unavailable_items')
|
||||
end
|
||||
end
|
||||
|
||||
@@ -173,7 +173,7 @@ describe Spree::OrdersController, type: :controller do
|
||||
it "displays a flash message when we view the cart" do
|
||||
spree_get :edit
|
||||
expect(response.status).to eq 200
|
||||
expect(flash[:error]).to eq("An item in your cart has become unavailable.")
|
||||
expect(flash[:error]).to eq I18n.t('spree.orders.error_flash_for_unavailable_items')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -213,6 +213,40 @@ feature "full-page cart", js: true do
|
||||
expect(page).to have_content "Insufficient stock available, only 2 remaining"
|
||||
expect(page).to have_field "order_line_items_attributes_0_quantity", with: '1'
|
||||
end
|
||||
|
||||
describe "full UX for correcting selected quantities with insufficient stock" do
|
||||
before do
|
||||
add_product_to_cart order, product_with_tax, quantity: 5
|
||||
variant.update_attributes! on_hand: 4, on_demand: false
|
||||
end
|
||||
|
||||
it "gives clear user feedback during the correcting process" do
|
||||
visit main_app.cart_path
|
||||
|
||||
# shows a relevant Flash message
|
||||
expect(page).to have_selector ".alert-box", text: I18n.t('spree.orders.error_flash_for_unavailable_items')
|
||||
|
||||
# "Continue Shopping" and "Checkout" buttons are disabled
|
||||
expect(page).to have_selector "a.continue-shopping[disabled=disabled]"
|
||||
expect(page).to have_selector "a#checkout-link[disabled=disabled]"
|
||||
|
||||
# Quantity field clearly marked as invalid and "Update" button is not highlighted
|
||||
expect(page).to have_selector "#order_line_items_attributes_0_quantity.ng-invalid-stock"
|
||||
expect(page).to_not have_selector "#update-button.alert"
|
||||
|
||||
fill_in "order_line_items_attributes_0_quantity", with: 4
|
||||
|
||||
# Quantity field not marked as invalid and "Update" button is highlighted after correction
|
||||
expect(page).to_not have_selector "#order_line_items_attributes_0_quantity.ng-invalid-stock"
|
||||
expect(page).to have_selector "#update-button.alert"
|
||||
|
||||
click_button I18n.t("update")
|
||||
|
||||
# "Continue Shopping" and "Checkout" buttons are not disabled after cart is updated
|
||||
expect(page).to_not have_selector "a.continue-shopping[disabled=disabled]"
|
||||
expect(page).to_not have_selector "a#checkout-link[disabled=disabled]"
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
Reference in New Issue
Block a user