diff --git a/back-office/app/models/cart.rb b/back-office/app/models/cart.rb index a78e067..5322588 100644 --- a/back-office/app/models/cart.rb +++ b/back-office/app/models/cart.rb @@ -2,5 +2,6 @@ class Cart < ActiveRecord::Base has_many :item_in_carts belongs_to :user + belongs_to :delivery_destination end diff --git a/back-office/app/models/item_in_cart.rb b/back-office/app/models/item_in_cart.rb index c18c2ae..10e084e 100644 --- a/back-office/app/models/item_in_cart.rb +++ b/back-office/app/models/item_in_cart.rb @@ -6,7 +6,7 @@ class ItemInCart < ActiveRecord::Base validates :item_id, presence: true validates :cart_id, presence: true - def to_s + def name item.name + " " + count.to_s + " " + price.to_s end end diff --git a/front-api/controllers/cart.rb b/front-api/controllers/cart.rb index 17f36a4..cdcda8d 100644 --- a/front-api/controllers/cart.rb +++ b/front-api/controllers/cart.rb @@ -11,19 +11,26 @@ helpers do end end -get '/cart' do + +create_the_cart = -> () { # -1 is a placeholder for user id when we implement users # auid will still be used in case user is not logged in Cart.find_or_create(anonymous_id, -1).to_json +} +post '/cart', &create_the_cart +put '/cart', &create_the_cart + +get '/cart' do + Cart.just_find(anonymous_id, -1).to_json end # gets number of items in cart for every item get '/cart/item' do - Cart.find_or_create(anonymous_id, -1).item_in_carts.to_json + Cart.just_find(anonymous_id, -1).item_in_carts.to_json end update_cart_item = ->() { - cart_id = Cart.find_or_create(anonymous_id, -1).id + cart_id = Cart.just_find(anonymous_id, -1).id item_id = @json_params["item_id"].to_i count = @json_params["count"].to_i ItemInCart.update_state(cart_id, item_id, count).to_json @@ -34,7 +41,7 @@ post '/cart/item', &update_cart_item # gets list of items in cart without count get '/cart/item/display' do - cart = Cart.find_or_create(anonymous_id, -1) + cart = Cart.just_find(anonymous_id, -1) item_ids = cart.item_in_carts.map do |x| x.item_id end @@ -44,12 +51,12 @@ get '/cart/item/display' do end get '/cart/delivery_destination' do - cart = Cart.find_or_create(anonymous_id, -1) + cart = Cart.just_find(anonymous_id, -1) cart.delivery_destination.to_json(:except => [:created_at, :email_verification_code, :phone_verification_code]) end update_delivery_destination = ->() { - cart = Cart.find_or_create(anonymous_id, -1) + cart = Cart.just_find(anonymous_id, -1) allowed_keys = ["name", "address", "place", "postal_code", "phone", "email", "note"] params = @json_params.reject { |key,_| !allowed_keys.include?(key) } cart.delivery_destination.update_attributes(params) @@ -61,10 +68,14 @@ post '/cart/delivery_destination', &update_delivery_destination post '/cart/confirmation' do - cart = Cart.find_or_create(anonymous_id, -1) + anonymous = anonymous_id + cart = Cart.just_find(anonymous, -1) if cart.item_in_carts.length > 0 cart.ordered = true cart.save! end + # since there is no more ordered cart this needs to be done + # in order for next call of Cart#just_find to be ready + Cart.find_or_create(anonymous, -1) "OK".to_json end \ No newline at end of file diff --git a/front-api/models/cart.rb b/front-api/models/cart.rb index 5597e26..0b2adcb 100644 --- a/front-api/models/cart.rb +++ b/front-api/models/cart.rb @@ -7,7 +7,14 @@ class Cart < ActiveRecord::Base cart ||= Cart.where(anonymous_id_string: anonymous_id).where(ordered: false).first safe_user_id = (user_id > 0) ? user_id : nil cart ||= Cart.create!(anonymous_id_string: anonymous_id, user_id: safe_user_id, ordered: false ) - cart.delivery_destination ||= DeliveryDestination.find_or_create(anonymous_id, user_id); + cart.delivery_destination ||= DeliveryDestination.create_from_last(anonymous_id, safe_user_id); + cart.save! + return cart + end + + def self.just_find(anonymous_id,user_id) + cart = Cart.where(user_id: user_id).where(ordered: false).first + cart ||= Cart.where(anonymous_id_string: anonymous_id).where(ordered: false).first return cart end end \ No newline at end of file diff --git a/front-api/models/delivery_destination.rb b/front-api/models/delivery_destination.rb index 5d3bd6f..5a36183 100644 --- a/front-api/models/delivery_destination.rb +++ b/front-api/models/delivery_destination.rb @@ -2,10 +2,13 @@ class DeliveryDestination < ActiveRecord::Base has_one :cart belongs_to :user - def self.find_or_create(anonymous_id, user_id) + def self.create_from_last(anonymous_id, user_id) dd = DeliveryDestination.where(user_id: user_id).order("id desc").first dd ||= DeliveryDestination.where(anonymous_id_string: anonymous_id).order("id desc").first - dd ||= DeliveryDestination.create!({user_id: user_id, anonymous_id_string: anonymous_id }) - return dd + dd ||= DeliveryDestination.new({user_id: user_id, anonymous_id_string: anonymous_id }) + attributes = dd.as_json + attributes.delete("id") + result = DeliveryDestination.create!(attributes) + return result end end diff --git a/front-ui/app/actions/initializationActions.js b/front-ui/app/actions/initializationActions.js new file mode 100644 index 0000000..7aae628 --- /dev/null +++ b/front-ui/app/actions/initializationActions.js @@ -0,0 +1,11 @@ +var AppDispatcher = require('../dispatcher/appDispatcher'); +var InitializationConstants = require('../constants/initializationConstants'); + +var IntializationActions = { + initialize: function() { + AppDispatcher.handleAction({ + actionType : InitializationConstants.INITIALIZE, + }); + } +}; +module.exports = IntializationActions; diff --git a/front-ui/app/components/rootApp.js b/front-ui/app/components/rootApp.js index 6552d7c..36f41ce 100644 --- a/front-ui/app/components/rootApp.js +++ b/front-ui/app/components/rootApp.js @@ -3,14 +3,42 @@ var React = require('react'), Router = require('react-router'), Link = Router.Link, RouteHandler = Router.RouteHandler, - LoginStatus = require('./shared/loginStatus'); + LoginStatus = require('./shared/loginStatus'), + InitializationStore = require('../stores/initializationStore'), + InitializationActions = require('../actions/initializationActions'); var CartIcon = require('./cart/cartIcon'); var RootApp = React.createClass({ + // Add change listeners to stores + componentDidMount: function() { + InitializationStore.addChangeListener(this._onChange); + InitializationActions.initialize(); + }, + + + getInitialState: function() { + return InitializationStore.getState(); + }, + + + _onChange: function () { + if (this.isMounted()) { + this.setState(InitializationStore.getState()); + } + }, + + componentWillUnmount: function () { + InitializationStore.removeChangeListener(this._onChange); + }, + render: function() { + if (!this.state.isEverythingReadyToStartTheShow) { + return (
loading...
); + } + return (
diff --git a/front-ui/app/constants/initializationConstants.js b/front-ui/app/constants/initializationConstants.js new file mode 100644 index 0000000..124ec2a --- /dev/null +++ b/front-ui/app/constants/initializationConstants.js @@ -0,0 +1,6 @@ +var keyMirror = require('react/lib/keyMirror'); + +// Define action constants +module.exports = keyMirror({ + INITIALIZE: null +}); \ No newline at end of file diff --git a/front-ui/app/models/cart.js b/front-ui/app/models/cart.js new file mode 100644 index 0000000..2037bfc --- /dev/null +++ b/front-ui/app/models/cart.js @@ -0,0 +1,22 @@ +var Backbone = require('backbone'); +var Globals = require('../globals'); + +var Cart = Backbone.Model.extend({ + + initialize: function() { + $.ajaxPrefilter( + function(options, originalOptions, jqXHR) { + options.xhrFields = { + withCredentials: true + } + } + ); + }, + urlRoot : Globals.ApiUrl + '/cart', + defaults : { + 'yes': 'yes' + } +}); + + +module.exports = Cart; diff --git a/front-ui/app/stores/cartStore.js b/front-ui/app/stores/cartStore.js index dbd2b6f..af61827 100644 --- a/front-ui/app/stores/cartStore.js +++ b/front-ui/app/stores/cartStore.js @@ -9,6 +9,7 @@ var ItemCollection = require('../models/itemCollection'); var DeliveryDestination = require('../models/deliveryDestination'); var OrderConfirmation = require('../models/orderConfirmation'); var Place = require('../models/place'); +var Validation = require('../utils/validation'); var _ = require('underscore'); @@ -141,27 +142,27 @@ var validateDeliveryDestinationForm = function() { _deliveryDestinationErrors = {}; var nameRegex = /.+\s+.+/i; - if (_deliveryDestination.get('name').search(nameRegex) < 0) { + if (Validation.safeString(_deliveryDestination.get('name')).search(nameRegex) < 0) { _deliveryDestinationErrors['name'] = "I prezime i ime su obavezni"; } var addressRegex = /.+\s+.+/i; - if (_deliveryDestination.get('address').search(addressRegex) < 0) { + if (Validation.safeString(_deliveryDestination.get('address')).search(addressRegex) < 0) { _deliveryDestinationErrors['address'] = "Adresa mora biti ispravna"; } var emailRegex = /^[a-zA-Z0-9._-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,6}$/i; - if (_deliveryDestination.get('email').search(emailRegex) < 0) { + if (Validation.safeString(_deliveryDestination.get('email')).search(emailRegex) < 0) { _deliveryDestinationErrors['email'] = "Email mora biti ispravno upisan"; } var phoneRegex = /[\d\s-]{7,8}/i; - if (_deliveryDestination.get('phone').search(phoneRegex) < 0) { + if (Validation.safeString(_deliveryDestination.get('phone')).search(phoneRegex) < 0) { _deliveryDestinationErrors['phone'] = "Telefon mora biti ispravan"; } var placeRegex = /^\s{0,1}\d{5}$/i; - if (_deliveryDestination.get('place').search(placeRegex) < 0) { + if (Validation.safeString(_deliveryDestination.get('place')).search(placeRegex) < 0){ _deliveryDestinationErrors['place'] = "Mjesto mora biti izabrano"; } diff --git a/front-ui/app/stores/initializationStore.js b/front-ui/app/stores/initializationStore.js new file mode 100644 index 0000000..3f54bad --- /dev/null +++ b/front-ui/app/stores/initializationStore.js @@ -0,0 +1,69 @@ +var AppDispatcher = require('../dispatcher/appDispatcher'); +var EventEmitter = require('events').EventEmitter; +var Cart = require('../models/cart'); + +var InitializationConstants = require('../constants/initializationConstants') +var _ = require('underscore'); + + +var state = { + isEverythingReadyToStartTheShow: false +} + +var initializeTheShop = function () { + // for now only guarantee that cart is created + var cart = new Cart(); + cart.save(null, { + success: function () { + state.isEverythingReadyToStartTheShow = true; + InitializationStore.emitChange(); + } + }) +} + +// Extend ItemStore with EventEmitter to add eventing capabilities +var InitializationStore = _.extend({}, EventEmitter.prototype, { + + getState: function() { + return state; + }, + + // Emit Change event + emitChange: function() { + console.log("InitializationStore change!"); + this.emit('change'); + }, + + // Add change listener + addChangeListener: function(callback) { + this.on('change', callback); + }, + + // Remove change listener + removeChangeListener: function(callback) { + this.removeListener('change', callback); + } + +}); + + +// Register callback with AppDispatcher +InitializationStore.dispatchToken = AppDispatcher.register(function(payload) { + var action = payload.action; + + switch (action.actionType) { + + case InitializationConstants.INITIALIZE: + initializeTheShop(); + break; + default: + return true; + } + + // If action was responded to, emit change event + InitializationStore.emitChange(); + return true; + +}); + +module.exports = InitializationStore; \ No newline at end of file diff --git a/front-ui/app/utils/validation.js b/front-ui/app/utils/validation.js index a73536f..4601cd6 100644 --- a/front-ui/app/utils/validation.js +++ b/front-ui/app/utils/validation.js @@ -1,17 +1,28 @@ -var Validations = { -_emailRe: /^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/, -isValidEmail: function(value) { - return this._emailRe.test(value); +var _ = require('underscore'); -}, +var Validations = { + _emailRe: /^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/, + isValidEmail: function(value) { + return this._emailRe.test(value); + + }, isValidRequired: function(value) { - if(value === undefined || value === "") { + if (value === undefined || value === "") { return false; } return true; + }, + + safeString: function(item) { + if (!_.isString(item)) { + return ""; + } else { + return item; + } + } }; -module.exports = Validations; +module.exports = Validations; \ No newline at end of file