mirror of
https://github.com/openfoodfoundation/openfoodnetwork
synced 2026-01-24 20:36:49 +00:00
Basics in place, about to rework karma config
This commit is contained in:
@@ -4,8 +4,10 @@
|
||||
#= require spin
|
||||
#
|
||||
#= require angular
|
||||
#= require angular-cookies
|
||||
#= require angular-resource
|
||||
#= require ../shared/mm-foundation-tpls-0.2.0-SNAPSHOT
|
||||
#= require ../shared/angular-local-storage.js
|
||||
#
|
||||
#= require ../shared/jquery.timeago
|
||||
#= require foundation
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
Darkswarm.controller "CheckoutCtrl", ($scope, $rootScope, Order) ->
|
||||
$scope.require_ship_address = false
|
||||
Darkswarm.controller "CheckoutCtrl", ($scope, $rootScope, Order, storage) ->
|
||||
$scope.order = $scope.Order = Order
|
||||
|
||||
$scope.shippingMethodChanged = ->
|
||||
Order.shippingMethodChanged()
|
||||
# Binding accordion panel states to local storage
|
||||
storage.bind $scope, "user"
|
||||
storage.bind $scope, "details"
|
||||
storage.bind $scope, "billing"
|
||||
storage.bind $scope, "shipping"
|
||||
storage.bind $scope, "payment"
|
||||
|
||||
$scope.purchase = (event)->
|
||||
event.preventDefault()
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
window.Darkswarm = angular.module("Darkswarm", ["ngResource", "filters", 'mm.foundation']).config ($httpProvider, $tooltipProvider) ->
|
||||
window.Darkswarm = angular.module("Darkswarm", ["ngResource", "filters", 'mm.foundation', 'angularLocalStorage']).config ($httpProvider, $tooltipProvider) ->
|
||||
$httpProvider.defaults.headers.post['X-CSRF-Token'] = $('meta[name="csrf-token"]').attr('content')
|
||||
$httpProvider.defaults.headers['common']['X-Requested-With'] = 'XMLHttpRequest'
|
||||
$httpProvider.defaults.headers.common.Accept = "application/json, text/javascript, */*"
|
||||
|
||||
@@ -1,24 +1,17 @@
|
||||
Darkswarm.factory 'Order', ($resource, Product, order)->
|
||||
|
||||
## I am being clever here
|
||||
## order is a JSON object generated in shop/checkout/order.rabl
|
||||
## We're extending this to add methods while retaining the data!
|
||||
|
||||
new class Order
|
||||
constructor: ->
|
||||
@[name] = method for name, method of order # Clone all data from the order JSON object
|
||||
|
||||
# Our shipping_methods comes through as a hash like so: {id: requires_shipping_address}
|
||||
# Here we default to the first shipping method if none is selected
|
||||
@shipping_method_id ||= Object.keys(@shipping_methods)[0]
|
||||
@ship_address_same_as_billing = true if @ship_address_same_as_billing == null
|
||||
@shippingMethodChanged()
|
||||
@shipping_method_id ||= parseInt(Object.keys(@shipping_methods)[0])
|
||||
@ship_address_same_as_billing ?= true
|
||||
|
||||
shippingMethod: ->
|
||||
@shipping_methods[@shipping_method_id]
|
||||
|
||||
shippingMethodChanged: =>
|
||||
@require_ship_address = @shippingMethod().require_ship_address if @shippingMethod()
|
||||
requireShipAddress: ->
|
||||
@shippingMethod().require_ship_address
|
||||
|
||||
shippingPrice: ->
|
||||
@shippingMethod().price
|
||||
@@ -26,7 +19,6 @@ Darkswarm.factory 'Order', ($resource, Product, order)->
|
||||
paymentMethod: ->
|
||||
@payment_methods[@payment_method_id]
|
||||
|
||||
|
||||
cartTotal: ->
|
||||
@shippingPrice() + @display_total
|
||||
|
||||
|
||||
@@ -1,14 +1,13 @@
|
||||
Darkswarm.factory 'OrderCycle', ($resource, Product, orderCycleData) ->
|
||||
class OrderCycle
|
||||
@order_cycle = orderCycleData || null
|
||||
@order_cycle = orderCycleData # Object or {} due to RABL
|
||||
@push_order_cycle: ->
|
||||
new $resource("/shop/order_cycle").save {order_cycle_id: @order_cycle.order_cycle_id}, (order_data)->
|
||||
OrderCycle.order_cycle.orders_close_at = order_data.orders_close_at
|
||||
Product.update()
|
||||
|
||||
@orders_close_at: ->
|
||||
if @selected()
|
||||
@order_cycle.orders_close_at
|
||||
@order_cycle.orders_close_at if @selected()
|
||||
|
||||
@selected: ->
|
||||
@order_cycle != null and !$.isEmptyObject(@order_cycle) and @order_cycle.orders_close_at != undefined
|
||||
!$.isEmptyObject(@order_cycle) and @order_cycle.orders_close_at?
|
||||
|
||||
170
app/assets/javascripts/shared/angular-local-storage.js
vendored
Normal file
170
app/assets/javascripts/shared/angular-local-storage.js
vendored
Normal file
@@ -0,0 +1,170 @@
|
||||
/*
|
||||
* Angular.js localStorage module
|
||||
* https://github.com/agrublev/angularLocalStorage
|
||||
*/
|
||||
|
||||
(function (window, angular, undefined) {
|
||||
'use strict';
|
||||
|
||||
angular.module('angularLocalStorage', ['ngCookies']).factory('storage', ['$parse', '$cookieStore', '$window', '$log', function ($parse, $cookieStore, $window, $log) {
|
||||
/**
|
||||
* Global Vars
|
||||
*/
|
||||
var storage = (typeof $window.localStorage === 'undefined') ? undefined : $window.localStorage;
|
||||
var supported = typeof storage !== 'undefined';
|
||||
|
||||
var privateMethods = {
|
||||
/**
|
||||
* Pass any type of a string from the localStorage to be parsed so it returns a usable version (like an Object)
|
||||
* @param res - a string that will be parsed for type
|
||||
* @returns {*} - whatever the real type of stored value was
|
||||
*/
|
||||
parseValue: function (res) {
|
||||
var val;
|
||||
try {
|
||||
val = angular.fromJson(res);
|
||||
if (typeof val === 'undefined') {
|
||||
val = res;
|
||||
}
|
||||
if (val === 'true') {
|
||||
val = true;
|
||||
}
|
||||
if (val === 'false') {
|
||||
val = false;
|
||||
}
|
||||
if ($window.parseFloat(val) === val && !angular.isObject(val)) {
|
||||
val = $window.parseFloat(val);
|
||||
}
|
||||
} catch (e) {
|
||||
val = res;
|
||||
}
|
||||
return val;
|
||||
}
|
||||
};
|
||||
|
||||
var publicMethods = {
|
||||
/**
|
||||
* Set - let's you set a new localStorage key pair set
|
||||
* @param key - a string that will be used as the accessor for the pair
|
||||
* @param value - the value of the localStorage item
|
||||
* @returns {*} - will return whatever it is you've stored in the local storage
|
||||
*/
|
||||
set: function (key, value) {
|
||||
if (!supported) {
|
||||
try {
|
||||
$cookieStore.put(key, value);
|
||||
return value;
|
||||
} catch(e) {
|
||||
$log.log('Local Storage not supported, make sure you have angular-cookies enabled.');
|
||||
}
|
||||
}
|
||||
var saver = angular.toJson(value);
|
||||
storage.setItem(key, saver);
|
||||
return privateMethods.parseValue(saver);
|
||||
},
|
||||
|
||||
/**
|
||||
* Get - let's you get the value of any pair you've stored
|
||||
* @param key - the string that you set as accessor for the pair
|
||||
* @returns {*} - Object,String,Float,Boolean depending on what you stored
|
||||
*/
|
||||
get: function (key) {
|
||||
if (!supported) {
|
||||
try {
|
||||
return privateMethods.parseValue($.cookie(key));
|
||||
} catch (e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
var item = storage.getItem(key);
|
||||
return privateMethods.parseValue(item);
|
||||
},
|
||||
|
||||
/**
|
||||
* Remove - let's you nuke a value from localStorage
|
||||
* @param key - the accessor value
|
||||
* @returns {boolean} - if everything went as planned
|
||||
*/
|
||||
remove: function (key) {
|
||||
if (!supported) {
|
||||
try {
|
||||
$cookieStore.remove(key);
|
||||
return true;
|
||||
} catch (e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
storage.removeItem(key);
|
||||
return true;
|
||||
},
|
||||
|
||||
/**
|
||||
* Bind - let's you directly bind a localStorage value to a $scope variable
|
||||
* @param {Angular $scope} $scope - the current scope you want the variable available in
|
||||
* @param {String} key - the name of the variable you are binding
|
||||
* @param {Object} opts - (optional) custom options like default value or unique store name
|
||||
* Here are the available options you can set:
|
||||
* * defaultValue: the default value
|
||||
* * storeName: add a custom store key value instead of using the scope variable name
|
||||
* @returns {*} - returns whatever the stored value is
|
||||
*/
|
||||
bind: function ($scope, key, opts) {
|
||||
var defaultOpts = {
|
||||
defaultValue: '',
|
||||
storeName: ''
|
||||
};
|
||||
// Backwards compatibility with old defaultValue string
|
||||
if (angular.isString(opts)) {
|
||||
opts = angular.extend({},defaultOpts,{defaultValue:opts});
|
||||
} else {
|
||||
// If no defined options we use defaults otherwise extend defaults
|
||||
opts = (angular.isUndefined(opts)) ? defaultOpts : angular.extend(defaultOpts,opts);
|
||||
}
|
||||
|
||||
// Set the storeName key for the localStorage entry
|
||||
// use user defined in specified
|
||||
var storeName = opts.storeName || key;
|
||||
|
||||
// If a value doesn't already exist store it as is
|
||||
if (!publicMethods.get(storeName)) {
|
||||
publicMethods.set(storeName, opts.defaultValue);
|
||||
}
|
||||
|
||||
// If it does exist assign it to the $scope value
|
||||
$parse(key).assign($scope, publicMethods.get(storeName));
|
||||
|
||||
// Register a listener for changes on the $scope value
|
||||
// to update the localStorage value
|
||||
$scope.$watch(key, function (val) {
|
||||
if (angular.isDefined(val)) {
|
||||
publicMethods.set(storeName, val);
|
||||
}
|
||||
}, true);
|
||||
|
||||
return publicMethods.get(storeName);
|
||||
},
|
||||
/**
|
||||
* Unbind - let's you unbind a variable from localStorage while removing the value from both
|
||||
* the localStorage and the local variable and sets it to null
|
||||
* @param $scope - the scope the variable was initially set in
|
||||
* @param key - the name of the variable you are unbinding
|
||||
* @param storeName - (optional) if you used a custom storeName you will have to specify it here as well
|
||||
*/
|
||||
unbind: function($scope,key,storeName) {
|
||||
storeName = storeName || key;
|
||||
$parse(key).assign($scope, null);
|
||||
$scope.$watch(key, function () { });
|
||||
publicMethods.remove(storeName);
|
||||
},
|
||||
/**
|
||||
* Clear All - let's you clear out ALL localStorage variables, use this carefully!
|
||||
*/
|
||||
clearAll: function() {
|
||||
storage.clear();
|
||||
}
|
||||
};
|
||||
|
||||
return publicMethods;
|
||||
}]);
|
||||
|
||||
})(window, window.angular);
|
||||
9
app/views/shop/checkout/_authentication.html.haml
Normal file
9
app/views/shop/checkout/_authentication.html.haml
Normal file
@@ -0,0 +1,9 @@
|
||||
%fieldset
|
||||
%accordion-group{heading: "User"}
|
||||
.row
|
||||
%section#checkout_login
|
||||
.large-6.columns
|
||||
= render partial: "shop/checkout/login"
|
||||
%section#checkout_signup
|
||||
.large-6.columns
|
||||
= render partial: "shop/checkout/signup"
|
||||
@@ -1,5 +1,5 @@
|
||||
%fieldset#details
|
||||
%accordion-group
|
||||
%accordion-group{"is-open" => "details"}
|
||||
%accordion-heading
|
||||
.row
|
||||
.large-6.columns
|
||||
|
||||
@@ -17,7 +17,6 @@ child current_order.ship_address => :ship_address do
|
||||
attributes :phone, :firstname, :lastname, :address1, :address2, :city, :country_id, :state_id, :zipcode
|
||||
end
|
||||
|
||||
# Format here is {id: require_ship_address}
|
||||
node :shipping_methods do
|
||||
Hash[current_order.distributor.shipping_methods.collect {
|
||||
|method| [method.id, {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
%fieldset#shipping
|
||||
%accordion-group
|
||||
%accordion-group{"is-open" => "shipping"}
|
||||
%accordion-heading
|
||||
.row
|
||||
.large-6.columns
|
||||
@@ -9,24 +9,19 @@
|
||||
- for ship_method, i in current_distributor.shipping_methods.uniq
|
||||
.row
|
||||
.large-12.columns
|
||||
-#= f.radio_button :shipping_method_id, ship_method.id,
|
||||
-#text: ship_method.name,
|
||||
-#"ng-change" => "shippingMethodChanged()",
|
||||
-#"ng-model" => "order.shipping_method_id"
|
||||
%label
|
||||
= radio_button_tag "order[shipping_method_id]", ship_method.id, false,
|
||||
"ng-change" => "order.shippingMethodChanged()",
|
||||
"ng-model" => "order.shipping_method_id"
|
||||
= ship_method.name
|
||||
|
||||
#distributor_address.panel{"ng-show" => "!order.require_ship_address"}
|
||||
#distributor_address.panel{"ng-show" => "!order.requireShipAddress()"}
|
||||
= @order.distributor.distributor_info.andand.html_safe
|
||||
= @order.order_cycle.pickup_time_for(@order.distributor)
|
||||
= @order.order_cycle.pickup_instructions_for(@order.distributor)
|
||||
|
||||
= f.fields_for :ship_address, @order.ship_address do |sa|
|
||||
|
||||
#ship_address{"ng-show" => "order.require_ship_address"}
|
||||
#ship_address{"ng-show" => "order.requireShipAddress()"}
|
||||
%label
|
||||
= hidden_field_tag "order[ship_address_same_as_billing]", "false"
|
||||
= check_box_tag "order[ship_address_same_as_billing]", true, @order.ship_address_same_as_billing,
|
||||
|
||||
@@ -10,15 +10,7 @@
|
||||
%accordion.row{"close-others" => "false"}
|
||||
.large-9.columns
|
||||
- unless spree_current_user
|
||||
%fieldset
|
||||
%accordion-group{heading: "User"}
|
||||
.row
|
||||
%section#checkout_login
|
||||
.large-6.columns
|
||||
= render partial: "shop/checkout/login"
|
||||
%section#checkout_signup
|
||||
.large-6.columns
|
||||
= render partial: "shop/checkout/signup"
|
||||
= render partial: "shop/checkout/authentication"
|
||||
.row
|
||||
= render partial: "shop/checkout/form"
|
||||
|
||||
|
||||
@@ -14,3 +14,5 @@
|
||||
- else
|
||||
%form.custom
|
||||
= yield :order_cycle_form
|
||||
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
%select.avenir#order_cycle_id{"ng-model" => "order_cycle.order_cycle_id",
|
||||
"ng-change" => "changeOrderCycle()",
|
||||
"ng-options" => "oc.id as oc.time for oc in #{@order_cycles.map {|oc| {time: pickup_time(oc), id: oc.id}}.to_json}",
|
||||
"popover-placement" => "bottom", "popover" => "testy", "popover-trigger" => "openTrigger"}
|
||||
"popover-placement" => "bottom", "popover" => "Please select an order cycle", "popover-trigger" => "openTrigger"}
|
||||
|
||||
%closing{"ng-if" => "OrderCycle.selected()"}
|
||||
Orders close
|
||||
|
||||
@@ -23,7 +23,6 @@ feature "As a consumer I want to check out my cart", js: true do
|
||||
add_product_to_cart
|
||||
end
|
||||
|
||||
|
||||
context "logged in" do
|
||||
before do
|
||||
login_to_consumer_section
|
||||
@@ -39,7 +38,6 @@ feature "As a consumer I want to check out my cart", js: true do
|
||||
context "logged out" do
|
||||
before do
|
||||
visit "/shop/checkout"
|
||||
save_and_open_page
|
||||
toggle_accordion "User"
|
||||
end
|
||||
|
||||
|
||||
@@ -5,30 +5,7 @@ describe "CheckoutCtrl", ->
|
||||
|
||||
beforeEach ->
|
||||
module("Darkswarm")
|
||||
order =
|
||||
id: 3102
|
||||
shipping_method_id: "7"
|
||||
ship_address_same_as_billing: true
|
||||
payment_method_id: null
|
||||
shipping_methods:
|
||||
7:
|
||||
require_ship_address: true
|
||||
price: 0.0
|
||||
|
||||
25:
|
||||
require_ship_address: false
|
||||
price: 13
|
||||
order = {}
|
||||
inject ($controller) ->
|
||||
scope = {}
|
||||
ctrl = $controller 'CheckoutCtrl', {$scope: scope, order: order}
|
||||
|
||||
|
||||
it 'Gets the ship address automatically', ->
|
||||
expect(scope.require_ship_address).toEqual true
|
||||
|
||||
it 'Gets the current shipping price', ->
|
||||
expect(scope.shippingPrice()).toEqual 0.0
|
||||
scope.order.shipping_method_id = 25
|
||||
expect(scope.shippingPrice()).toEqual 13
|
||||
|
||||
|
||||
ctrl = $controller 'CheckoutCtrl', {$scope: scope, Order: order}
|
||||
|
||||
@@ -39,6 +39,6 @@ describe 'OrderCycle service', ->
|
||||
it "tells us when no order cycle is selected", ->
|
||||
OrderCycle.order_cycle = null
|
||||
expect(OrderCycle.selected()).toEqual false
|
||||
OrderCycle.order_cycle = {test: "blah"}
|
||||
OrderCycle.order_cycle = {orders_close_at: "10 days ago"}
|
||||
expect(OrderCycle.selected()).toEqual true
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
describe 'Order service', ->
|
||||
Order = null
|
||||
orderData = null
|
||||
|
||||
beforeEach ->
|
||||
orderData = {
|
||||
id: 3102
|
||||
payment_method_id: null
|
||||
shipping_methods:
|
||||
7:
|
||||
require_ship_address: true
|
||||
price: 0.0
|
||||
|
||||
25:
|
||||
require_ship_address: false
|
||||
price: 13
|
||||
payment_methods:
|
||||
99:
|
||||
test: "foo"
|
||||
}
|
||||
angular.module('Darkswarm').value('order', orderData)
|
||||
module 'Darkswarm'
|
||||
inject ($injector)->
|
||||
Order = $injector.get("Order")
|
||||
|
||||
it "defaults the shipping method to the first", ->
|
||||
expect(Order.shipping_method_id).toEqual 7
|
||||
expect(Order.shippingMethod()).toEqual { require_ship_address : true, price : 0 }
|
||||
|
||||
it "defaults to 'same as billing' for address", ->
|
||||
expect(Order.ship_address_same_as_billing).toEqual true
|
||||
|
||||
it 'Tracks whether a ship address is required', ->
|
||||
expect(Order.requireShipAddress()).toEqual true
|
||||
Order.shipping_method_id = 25
|
||||
expect(Order.requireShipAddress()).toEqual false
|
||||
|
||||
it 'Gets the current shipping price', ->
|
||||
expect(Order.shippingPrice()).toEqual 0.0
|
||||
Order.shipping_method_id = 25
|
||||
expect(Order.shippingPrice()).toEqual 13
|
||||
|
||||
it 'Gets the current payment method', ->
|
||||
expect(Order.paymentMethod()).toEqual null
|
||||
Order.payment_method_id = 99
|
||||
expect(Order.paymentMethod()).toEqual {test: "foo"}
|
||||
|
||||
Reference in New Issue
Block a user