diff --git a/back-office/app/models/brand.rb b/back-office/app/models/brand.rb
new file mode 100644
index 0000000..c7ebc71
--- /dev/null
+++ b/back-office/app/models/brand.rb
@@ -0,0 +1,3 @@
+class Brand < ActiveRecord::Base
+ has_many :items
+end
diff --git a/back-office/app/models/item.rb b/back-office/app/models/item.rb
index 016389e..a59816b 100644
--- a/back-office/app/models/item.rb
+++ b/back-office/app/models/item.rb
@@ -3,6 +3,7 @@ class Item < ActiveRecord::Base
has_many :multi_media_descriptions
belongs_to :sub_category
belongs_to :supplier
+ belongs_to :brand
has_and_belongs_to_many :item_groups, :join_table => 'item_item_groups'
validates_presence_of :name, :description, :list_price, :current_input_price, :tags, :unit_id, :code, :sub_category_id, :weight, :supplier_id
diff --git a/front-api/controllers/item.rb b/front-api/controllers/item.rb
index d491405..4cdfc54 100644
--- a/front-api/controllers/item.rb
+++ b/front-api/controllers/item.rb
@@ -4,7 +4,8 @@ def prepare_items_for_mass_display(items)
:include => [
:unit ,
:multi_media_descriptions ,
- :sub_category
+ :sub_category,
+ :brand
])
end
@@ -94,4 +95,4 @@ get '/item/item_group/:item_group_id/offset/:offset/limit/:limit' do |item_group
items = ItemGroup.find(item_group_id).all_items(offset, limit)
prepare_items_for_mass_display(items)
-end
\ No newline at end of file
+end
diff --git a/front-api/db/migrate/20150328132019_create_brands.rb b/front-api/db/migrate/20150328132019_create_brands.rb
new file mode 100644
index 0000000..200961b
--- /dev/null
+++ b/front-api/db/migrate/20150328132019_create_brands.rb
@@ -0,0 +1,9 @@
+class CreateBrands < ActiveRecord::Migration
+ def change
+ create_table :brands do |t|
+ t.string :name
+ end
+
+ add_column :items, :brand_id, :integer
+ end
+end
diff --git a/front-api/db/schema.rb b/front-api/db/schema.rb
index 59ad6a6..f4a1995 100644
--- a/front-api/db/schema.rb
+++ b/front-api/db/schema.rb
@@ -11,11 +11,15 @@
#
# It's strongly recommended that you check this file into your version control system.
-ActiveRecord::Schema.define(version: 20150324044314) do
+ActiveRecord::Schema.define(version: 20150328132019) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
+ create_table "brands", force: :cascade do |t|
+ t.string "name"
+ end
+
create_table "carts", force: :cascade do |t|
t.integer "user_id"
t.boolean "ordered", default: false
@@ -125,6 +129,7 @@ ActiveRecord::Schema.define(version: 20150324044314) do
t.decimal "weight", precision: 5, scale: 3
t.integer "supplier_id"
t.integer "delivery_time_estimation_id"
+ t.integer "brand_id"
end
create_table "link_banners", force: :cascade do |t|
diff --git a/front-api/models/brand.rb b/front-api/models/brand.rb
new file mode 100644
index 0000000..c7ebc71
--- /dev/null
+++ b/front-api/models/brand.rb
@@ -0,0 +1,3 @@
+class Brand < ActiveRecord::Base
+ has_many :items
+end
diff --git a/front-api/models/item.rb b/front-api/models/item.rb
index 25a6904..dbba0c2 100644
--- a/front-api/models/item.rb
+++ b/front-api/models/item.rb
@@ -1,5 +1,6 @@
class Item < ActiveRecord::Base
belongs_to :unit
+ belongs_to :brand
has_many :multi_media_descriptions
belongs_to :sub_category
diff --git a/front-ui/app/actions/menuItemActions.js b/front-ui/app/actions/menuItemActions.js
new file mode 100644
index 0000000..d07768a
--- /dev/null
+++ b/front-ui/app/actions/menuItemActions.js
@@ -0,0 +1,24 @@
+var AppDispatcher = require('../dispatcher/appDispatcher');
+var MenuItemConstants = require('../constants/menuItemConstants');
+
+// Define action methods
+var MenuItemActions = {
+ loadMenuItems: function() {
+ AppDispatcher.handleAction({
+ actionType: MenuItemConstants.LOAD_MENU_ITEMS,
+ })
+ },
+ setMenuItemHover: function(menuItem) {
+ AppDispatcher.handleAction({
+ actionType: MenuItemConstants.SET_MENU_ITEM_HOVER,
+ menuItem: menuItem
+ });
+ },
+ unsetMenuItemHover: function() {
+ AppDispatcher.handleAction({
+ actionType: MenuItemConstants.UNSET_MENU_ITEM_HOVER
+ });
+ }
+};
+
+module.exports = MenuItemActions;
diff --git a/front-ui/app/actions/navigationActions.js b/front-ui/app/actions/navigationActions.js
index 17a7d4a..be3c001 100644
--- a/front-ui/app/actions/navigationActions.js
+++ b/front-ui/app/actions/navigationActions.js
@@ -91,6 +91,19 @@ var NavigationActions = {
actionType: NavigationConstants.CHANGE_URL,
url: '/pretraga?q=' + q
});
+ },
+ goToMenuItem: function(menuItem) {
+ var url = '';
+ if (menuItem.get) {
+ url = menuItem.get('url');
+ } else {
+ url = menuItem.url;
+ }
+
+ AppDispatcher.handleAction({
+ actionType: NavigationConstants.CHANGE_URL,
+ url: url
+ });
}
};
diff --git a/front-ui/app/components/account/login.js b/front-ui/app/components/account/login.js
index d3335a4..fd72fa8 100644
--- a/front-ui/app/components/account/login.js
+++ b/front-ui/app/components/account/login.js
@@ -52,8 +52,11 @@ var Login = React.createClass({
renderErrorMessage: function(message){
return (
{message}
)
},
- doLogin: function(e) {
-
+ onLoginClick: function(e) {
+ this.doLogin();
+ e.preventDefault();
+ },
+ doLogin: function() {
if(this.validate()) {
var loginInfo = new LoginModel({
email: this.state.email,
@@ -61,10 +64,8 @@ var Login = React.createClass({
});
UserActions.userLogin(loginInfo);
-
- }
- e.preventDefault();
+ }
},
renderLoginFailure: function() {
@@ -75,6 +76,12 @@ var Login = React.createClass({
return ()
},
+ onKeyPress: function(e) {
+ var enterKeyCode = 13;
+ if(e.which == enterKeyCode) {
+ this.doLogin();
+ }
+ },
render : function() {
return (
diff --git a/front-ui/app/components/account/register.js b/front-ui/app/components/account/register.js
index adc364e..8b809db 100644
--- a/front-ui/app/components/account/register.js
+++ b/front-ui/app/components/account/register.js
@@ -32,6 +32,12 @@ var Register = React.createClass({
myBabyOnTheWay: (e.currentTarget.value === "1" ? true: false)
});
},
+ onKeyPress: function(e) {
+ var enterKeyCode = 13;
+ if(e.which == enterKeyCode) {
+ this.doRegister();
+ }
+ },
renderMonthSelector: function() {
var months = ['Januar', 'Februar', 'Mart', 'April', 'Maj', 'Juni',
'Juli','August','Septembar', 'Oktobar','Novembar','Decembar'];
@@ -194,7 +200,11 @@ var Register = React.createClass({
loginState : UserStore.getLoginState()
});
},
- register: function(e) {
+ onRegisterClick: function(e) {
+ this.doRegister();
+ e.preventDefault();
+ },
+ doRegister: function() {
if(this.validate()) {
var children = [];
if (this.state.myBabyDetailsVisible) {
@@ -231,8 +241,6 @@ var Register = React.createClass({
UserActions.registerUser(user);
}
-
- e.preventDefault();
},
successContinue: function(e) {
NavigationActions.goToHome();
@@ -284,7 +292,7 @@ var Register = React.createClass({
@@ -292,28 +300,28 @@ var Register = React.createClass({
-
+
{this.getValidationMessages('passwordConfirmation').map(this.renderErrorMessage)}
@@ -335,7 +343,7 @@ var Register = React.createClass({
-
diff --git a/front-ui/app/components/items/itemWithDetailsPage.js b/front-ui/app/components/items/itemWithDetailsPage.js
index 3361fc5..63ef7f1 100644
--- a/front-ui/app/components/items/itemWithDetailsPage.js
+++ b/front-ui/app/components/items/itemWithDetailsPage.js
@@ -29,6 +29,7 @@ var ItemWithDetailsPage = React.createClass({
{this.state.item.get('name')}
+
{this.state.item.get('brand').name}
{this.state.item.get('list_price')} KM
{this.state.item.get('pricePerUnit')}
{this.state.item.get('description')}
diff --git a/front-ui/app/components/items/singleItem.js b/front-ui/app/components/items/singleItem.js
index 4a56217..0aeb1bb 100644
--- a/front-ui/app/components/items/singleItem.js
+++ b/front-ui/app/components/items/singleItem.js
@@ -25,6 +25,7 @@ var SingleItem = React.createClass({
{ this.props.item.get('name') }
+
{ this.props.item.get('brand')? this.props.item.get('brand').name : '' }
{ this.props.item.get('list_price') } KM
);
diff --git a/front-ui/app/components/rootApp.js b/front-ui/app/components/rootApp.js
index f3d8ae2..a75328b 100644
--- a/front-ui/app/components/rootApp.js
+++ b/front-ui/app/components/rootApp.js
@@ -1,5 +1,5 @@
var React = require('react'),
- SectionsListComponent = require('./shared/sectionsListComponent'),
+ MenuItemListComponent = require('./shared/menuItemListComponent'),
Router = require('react-router'),
Link = Router.Link,
RouteHandler = Router.RouteHandler,
@@ -57,7 +57,7 @@ var RootApp = React.createClass({
diff --git a/front-ui/app/components/shared/menuItemListComponent.js b/front-ui/app/components/shared/menuItemListComponent.js
new file mode 100644
index 0000000..43d421b
--- /dev/null
+++ b/front-ui/app/components/shared/menuItemListComponent.js
@@ -0,0 +1,93 @@
+var React = require('react'),
+ MenuItemCollection = require('../../models/menuItemCollection'),
+ MenuItem = require('../../models/menuItem'),
+ Backbone = require('backbone'),
+ NavigationStore = require('../../stores/navigationStore'),
+ MenuItemStore = require('../../stores/menuItemStore'),
+ MenuItemActions = require('../../actions/menuItemActions'),
+ NavigationActions = require('../../actions/navigationActions');
+
+Backbone.$ = $;
+
+var MenuItemListComponent = React.createClass({
+
+ _onChange: function () {
+ if (this.isMounted()) {
+ this.setState(MenuItemStore.getState());
+ }
+ },
+
+ getInitialState: function() {
+ return MenuItemStore.getState();
+ },
+
+ componentDidMount: function() {
+ MenuItemStore.addChangeListener(this._onChange);
+ MenuItemActions.loadMenuItems();
+ },
+ onMouseOver: function(menuItem) {
+ MenuItemActions.setMenuItemHover(menuItem);
+ },
+ onMouseOut: function() {
+ MenuItemActions.unsetMenuItemHover();
+ },
+ onMouseLeave: function() {
+ MenuItemActions.unsetMenuItemHover();
+ },
+ onMenuItemClick: function(menuItem) {
+ MenuItemActions.unsetMenuItemHover();
+ NavigationActions.goToMenuItem(menuItem);
+ event.preventDefault();
+ },
+ //onCategoryClick: function(category, section) {
+ //MenuItemActions.unsetSectionHover();
+ //NavigationActions.goToCategory(new Category(category), section);
+ //event.preventDefault();
+ //},
+ //onSubcategoryClick: function(subcategory) {
+ //// implement in navigation actions
+ //// and call
+ //// when ready
+ //return false;
+ //},
+ render: function() {
+ var self = this;
+ var style = {
+ position: 'relative'
+ };
+ var abStyle = {
+ position: 'absolute'
+ };
+ return (
+
+ );
+ }
+});
+
+module.exports = MenuItemListComponent;
diff --git a/front-ui/app/constants/menuItemConstants.js b/front-ui/app/constants/menuItemConstants.js
new file mode 100644
index 0000000..72ac8bc
--- /dev/null
+++ b/front-ui/app/constants/menuItemConstants.js
@@ -0,0 +1,8 @@
+var keyMirror = require('react/lib/keyMirror');
+
+// Define action constants
+module.exports = keyMirror({
+ LOAD_MENU_ITEMS: null,
+ SET_MENU_ITEM_HOVER: null,
+ UNSET_MENU_ITEM_HOVER: null
+});
diff --git a/front-ui/app/models/item.js b/front-ui/app/models/item.js
index 7534dfe..861df83 100644
--- a/front-ui/app/models/item.js
+++ b/front-ui/app/models/item.js
@@ -2,8 +2,10 @@ var Backbone = require('backbone');
var Globals = require('../globals');
var Item = Backbone.Model.extend({
- urlRoot : Globals.ApiUrl + '/item',
-
+ urlRoot : Globals.ApiUrl + '/item',
+ defaults : {
+ brand: {}
+ }
diff --git a/front-ui/app/models/itemWithDetails.js b/front-ui/app/models/itemWithDetails.js
index 8840940..56648fa 100644
--- a/front-ui/app/models/itemWithDetails.js
+++ b/front-ui/app/models/itemWithDetails.js
@@ -15,6 +15,9 @@ var ItemWithDetails = Backbone.Model.extend({
var descriptionSuffix = this.get('unit').description_suffix;
return (+pricePerUnit).toString() + " KM " + descriptionSuffix;
}
+ },
+ defaults : {
+ brand: {}
}
});
diff --git a/front-ui/app/models/menuItemCollection.js b/front-ui/app/models/menuItemCollection.js
index 674eb36..bd66009 100644
--- a/front-ui/app/models/menuItemCollection.js
+++ b/front-ui/app/models/menuItemCollection.js
@@ -4,7 +4,7 @@ var Backbone = require('backbone'),
var MenuItemCollection = Backbone.Collection.extend({
model: MenuItem,
- url: Globals.ApiUrl + '/menu_item'
+ url: Globals.ApiUrl + '/menuitem'
});
module.exports = MenuItemCollection;
diff --git a/front-ui/app/stores/menuItemStore.js b/front-ui/app/stores/menuItemStore.js
new file mode 100644
index 0000000..252bc00
--- /dev/null
+++ b/front-ui/app/stores/menuItemStore.js
@@ -0,0 +1,86 @@
+var AppDispatcher = require('../dispatcher/appDispatcher');
+var EventEmitter = require('events').EventEmitter;
+var MenuItemCollection = require('../models/menuItemCollection');
+var MenuItem = require('../models/menuItem');
+var MenuItemConstants = require('../constants/menuItemConstants');
+var _ = require('underscore');
+
+var menuItemState = {
+ menuItems : [],
+ hoveredMenuItem : ''
+};
+
+
+var loadMenuItems = function() {
+ var menuItems = new MenuItemCollection();
+ menuItems.fetch({success: function() {
+ menuItemState.menuItems = menuItems.models;
+ // change will be called automatically when
+ // action is run but we need to emit it again
+ // when the data arive
+ // it's a bit "unfluxy" but convenient.
+ // "true philosophy" would be to run another "data arrived" action
+ MenuItemStore.emitChange();
+ }});
+};
+
+var setHovered = function(id) {
+ menuItemState.hoveredMenuItem = id;
+}
+
+
+// Extend MenuItemStore with EventEmitter to add eventing capabilities
+var MenuItemStore = _.extend({}, EventEmitter.prototype, {
+
+ // Return Single Item With Details
+ getState: function() {
+ return menuItemState;
+ },
+ // Emit Change event
+ emitChange: function() {
+ console.log("Emmiting MenuItemStore 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
+AppDispatcher.register(function(payload) {
+ var action = payload.action;
+ var text;
+
+ switch(action.actionType) {
+
+ // Respond to SELECT_ITEM action
+ case MenuItemConstants.LOAD_MENU_ITEMS:
+ loadMenuItems();
+ break;
+
+ case MenuItemConstants.SET_MENU_ITEM_HOVER:
+ setHovered(action.menuItem.get('id'));
+ break;
+
+ case MenuItemConstants.UNSET_MENU_ITEM_HOVER:
+ setHovered('');
+ break;
+ default:
+ return true;
+ }
+
+ // If action was responded to, emit change event
+ MenuItemStore.emitChange();
+ return true;
+
+});
+
+module.exports = MenuItemStore;