diff --git a/app/assets/javascripts/shared-ember-helpers/translation.js.coffee b/app/assets/javascripts/shared-ember-helpers/translation.js.coffee
index b8f4bd46..14222eb9 100644
--- a/app/assets/javascripts/shared-ember-helpers/translation.js.coffee
+++ b/app/assets/javascripts/shared-ember-helpers/translation.js.coffee
@@ -1,4 +1,4 @@
Ember.Handlebars.registerHelper 't', (path, params..., options)->
text = t(path)
- tag = if options.hash.bare then text else "#{text}"
+ tag = if options.hash.bare then text else "#{text}"
new Handlebars.SafeString tag
diff --git a/app/assets/javascripts/supplier/app/app.js.coffee b/app/assets/javascripts/supplier/app/app.js.coffee
index 3c6bd8bd..d7d07acb 100644
--- a/app/assets/javascripts/supplier/app/app.js.coffee
+++ b/app/assets/javascripts/supplier/app/app.js.coffee
@@ -1,5 +1,6 @@
@App = Ember.Application.create
LOG_TRANSITIONS: true
+ LOG_VIEW_LOOKUPS: true
rootElement: '#ember-app-container'
store: -> @__container__.lookup('controller:application').store
@App.modals = Ember.Namespace.create()
diff --git a/app/assets/javascripts/supplier/app/components/edit_currency_component.js.coffee b/app/assets/javascripts/supplier/app/components/edit_currency_component.js.coffee
new file mode 100644
index 00000000..47af963d
--- /dev/null
+++ b/app/assets/javascripts/supplier/app/components/edit_currency_component.js.coffee
@@ -0,0 +1,49 @@
+App.EditCurrencyComponent = Ember.Component.extend
+ classNames: ['edit-currency-container', 'row', 'collapse']
+ classNameBindings: ['has_error:error']
+ currencySymbol: '€'
+ has_error: false
+ placeholder: '0.00'
+ validatePresence: false
+
+ inputValue: Ember.computed (key, value, previousValue)->
+ key = "value"
+ if arguments.length > 1
+ if value
+ # if typeof value is 'number'
+ # return_value = value.toPrecision()
+ # @set key, value
+ if typeof value is 'string' and value.match(/^[+-]?\d+(\.?\d?\d)?$/)
+ @set 'has_error', false
+ @set key, parseFloat(value)
+ else
+ @set 'has_error', true
+
+ else
+ @set key, 0.0 # empty
+ @set 'has_error', false
+ return_value = value
+ return_value ||= @get key
+ @set 'has_error', true if @validatePresence and !return_value
+ return_value = return_value.toFixed(2) if typeof return_value is 'number'
+ return_value
+
+ #didInsertElement: ->
+ #@addObserver "model.#{@attribute}", (attribute)=>
+ #if value = @get("model.#{@attribute}")
+ #@set 'value', value.toFixed(2) if parseFloat(@get('value')) isnt value
+ #else
+ #@set 'value', 0
+ ## @set('value', @get("model.#{@attribute}").toFixed)
+ ## # dynamically observe the model's attribute
+ ## # if this changes outside the component's context, it is not
+ ## # observed by the computed property. model.@attribute is not (yet) working :)
+ ## current_value = @get 'value'
+ ## if value = @get("model.#{@attribute}")
+ ## string_value = value.toPrecision()
+ ## @set('value', string_value) if parseFloat(current_value) isnt @get("model.#{@attribute}")
+ #@addObserver "model.errors.#{@attribute}.length", (attribute)=>
+ #@set 'has_error', !!@get("model.errors.#{@attribute}.length")
+ #@model.validate().then =>
+ #@set 'has_error', !!@get("model.errors.#{@attribute}.length")
+
diff --git a/app/assets/javascripts/supplier/app/components/menu_product_component.js.coffee b/app/assets/javascripts/supplier/app/components/menu_product_component.js.coffee
new file mode 100644
index 00000000..2b32e3f7
--- /dev/null
+++ b/app/assets/javascripts/supplier/app/components/menu_product_component.js.coffee
@@ -0,0 +1,19 @@
+App.MenuProductComponent = Ember.Component.extend
+ editMode: false
+ actions:
+ makeEditable: -> @set('editMode', true)
+ save: ->
+ @get('product').save() if @get('product.isDirty')
+ @set 'editMode', false
+ destroyProduct: (product)->
+ if product.get('isNew')
+ product.deleteRecord()
+ else
+ @get('targetObject').modal 'confirm',
+ model: product
+ title_path: 'product.destroy_confirmation'
+ ok: -> product.destroyRecord()
+ didInsertElement: ->
+ @set 'editMode', true if @get('product.isNew')
+
+ #templateName: 'menu/product'
diff --git a/app/assets/javascripts/supplier/app/components/sections_header_component.js.coffee b/app/assets/javascripts/supplier/app/components/sections_header_component.js.coffee
new file mode 100644
index 00000000..126597a1
--- /dev/null
+++ b/app/assets/javascripts/supplier/app/components/sections_header_component.js.coffee
@@ -0,0 +1,8 @@
+App.SectionsHeaderComponent = Ember.Component.extend
+ sections: (-> @get('targetObject.store').all('section') ).property()
+ actions:
+ setSection: (section)->
+ @$('dd').removeClass('active')
+ @$("[data-section=#{if section then section.id else 'all'}]").addClass('active')
+ @set('section', section)
+ didInsertElement: -> @send("setSection", @get('section'))
diff --git a/app/assets/javascripts/supplier/app/controllers/menu_controller.js.coffee b/app/assets/javascripts/supplier/app/controllers/menu_controller.js.coffee
index b03e1614..e0f03d01 100644
--- a/app/assets/javascripts/supplier/app/controllers/menu_controller.js.coffee
+++ b/app/assets/javascripts/supplier/app/controllers/menu_controller.js.coffee
@@ -16,3 +16,5 @@ App.MenuController = Ember.ObjectController.extend
@modal 'product_category_new',
model: @store.createRecord('product_category', position: @get('product_categories.length'))
close: -> @get('model').deleteRecord()
+ addProduct: (product_category)->
+ product_category.get('products').addObject @store.createRecord 'product', position: product_category.get('products.length')
diff --git a/app/assets/javascripts/supplier/app/controllers/modals/product_category_move_controller.js.coffee b/app/assets/javascripts/supplier/app/controllers/modals/product_category_move_controller.js.coffee
index 041cd885..c51fb9f8 100644
--- a/app/assets/javascripts/supplier/app/controllers/modals/product_category_move_controller.js.coffee
+++ b/app/assets/javascripts/supplier/app/controllers/modals/product_category_move_controller.js.coffee
@@ -13,17 +13,18 @@ App.modals.ProductCategoryMoveController = App.modals.BaseController.extend
if below_product_category and product_category.id is below_product_category.id
@set 'model.position', position += 1
@get('model').save()
-
position += 1
+
@send 'close'
- # moveBelow: (->
- # debugger
- # ).observes('move_below_selection')
- # change: ->
- # debugger
product_categories: (->
@store.all('product_category').filter( (pc) => pc.id isnt @get('model.id')).sortBy('position')
).property('model.id')
- # setProductCategories: (-> @set 'product_categories', @store.all('product_category')).on('init')
+ sortableUpdate: (ids)->
+ products = @get('model.products')
+ ids.forEach (id, i)->
+ if product = products.findProperty('id', id)
+ #TODO: raise in frontend if product.get('isDirty'). Cannot modify position of product containing non persisted change
+ product.set('position', i)
+ product.save() if product.get('isDirty')
diff --git a/app/assets/javascripts/supplier/app/controllers/orders_display_controller.js.coffee b/app/assets/javascripts/supplier/app/controllers/orders_display_controller.js.coffee
index 34c1eaf7..5312f5c4 100644
--- a/app/assets/javascripts/supplier/app/controllers/orders_display_controller.js.coffee
+++ b/app/assets/javascripts/supplier/app/controllers/orders_display_controller.js.coffee
@@ -6,15 +6,3 @@ App.OrdersDisplayController = Ember.ObjectController.extend
orders = @get('model').filterBy('needs_supplier_attention')
orders = orders.filterBy('section.id', id) if id = @get('active_section.id')
orders.sortBy('created_at') # Not reversed, oldest on top, start with oldest order first :-) Customer happyness
- activeSectionDidChange: Ember.observer 'active_section.id', ->
- container = Ember.$('.orders-display-nav')
- container.find('dd').removeClass('active')
- if id = @get('active_section.id')
- container.find("[data-section='#{id}']").addClass 'active'
- else
- container.find('[data-section="all"]').addClass 'active'
- actions:
- clearActiveSection: ->
- @set 'active_section', null
- setActiveSection: (section)->
- @set 'active_section', section
diff --git a/app/assets/javascripts/supplier/app/models/product.js.coffee b/app/assets/javascripts/supplier/app/models/product.js.coffee
index 7ec7b997..b859c41b 100644
--- a/app/assets/javascripts/supplier/app/models/product.js.coffee
+++ b/app/assets/javascripts/supplier/app/models/product.js.coffee
@@ -2,5 +2,12 @@ attr = DS.attr
App.Product = DS.Model.extend
name: attr 'string'
price: attr 'number'
+ code: attr 'string'
+ visible: attr('boolean', defaultValue: true)
+ position: attr('number', defaultValue: 0)
product_category: DS.belongsTo('product_category')
product_orders: DS.hasMany('product_order')
+
+ code_or_empty: (->
+ @get('code') or new Ember.Handlebars.SafeString(' ')
+ ).property('code')
diff --git a/app/assets/javascripts/supplier/app/models/product_category.js.coffee b/app/assets/javascripts/supplier/app/models/product_category.js.coffee
index 618fab8c..95e5076b 100644
--- a/app/assets/javascripts/supplier/app/models/product_category.js.coffee
+++ b/app/assets/javascripts/supplier/app/models/product_category.js.coffee
@@ -15,6 +15,8 @@ App.ProductCategory = DS.Model.extend
end_on: attr('number')
position: attr('number')
+ sorted_products: (-> @get('products').sortBy('position') ).property('products.@each.position')
+
availability_text: Ember.computed 'active_on_sunday', 'active_on_monday', 'active_on_tuesday', 'active_on_wednesday', 'active_on_thursday', 'active_on_friday', 'active_on_saturday', 'full_day', 'start_from', 'end_on', ->
days = ['sunday', 'monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday']
active_days = days.filter (day)=>@get("active_on_#{day}")
diff --git a/app/assets/javascripts/supplier/app/templates/components/edit-currency.emblem b/app/assets/javascripts/supplier/app/templates/components/edit-currency.emblem
new file mode 100644
index 00000000..c148420f
--- /dev/null
+++ b/app/assets/javascripts/supplier/app/templates/components/edit-currency.emblem
@@ -0,0 +1,3 @@
+.large-2.columns: label.prefix= currencySymbol
+.large-4.columns.end= input valueBinding="inputValue" placeholder=placeholder
+
diff --git a/app/assets/javascripts/supplier/app/templates/components/menu-product.emblem b/app/assets/javascripts/supplier/app/templates/components/menu-product.emblem
new file mode 100644
index 00000000..45ddfe85
--- /dev/null
+++ b/app/assets/javascripts/supplier/app/templates/components/menu-product.emblem
@@ -0,0 +1,13 @@
+.row.menu-product-container
+ if editMode
+ .small-3.columns= input value=product.name
+ .small-3.columns= edit-currency value=product.price validatePresence=true
+ .small-3.columns= input value=product.code
+ .small-3.columns
+ a.destroy-product-action{action "destroyProduct" product}: span
+ a.save-product-action{action "save"}: span
+ else
+ .small-3.columns: span= product.name
+ .small-3.columns= currency product.price
+ .small-3.columns: span= product.code_or_empty
+ .small-3.columns: span.fa.fa-edit{action "makeEditable"}
diff --git a/app/assets/javascripts/supplier/app/templates/components/sections-header.emblem b/app/assets/javascripts/supplier/app/templates/components/sections-header.emblem
new file mode 100644
index 00000000..244ef4c6
--- /dev/null
+++ b/app/assets/javascripts/supplier/app/templates/components/sections-header.emblem
@@ -0,0 +1,7 @@
+dl.sections-header-container.sub-nav
+ dd data-section="all": a.section-header-title{action "setSection"} href="" = t 'sections_header.all_sections'
+ each s in sections
+ dd data-section=s.id
+ a.section-header-title{action "setSection" s} href="#" = s.title
+ = link-to "section" s.id class="section-jumper"
+ span.fa.fa-chevron-circle-right
diff --git a/app/assets/javascripts/supplier/app/templates/form_elements/boolean_switch.emblem b/app/assets/javascripts/supplier/app/templates/form_elements/boolean_switch.emblem
index 2eb5f2f5..fd22b59a 100644
--- a/app/assets/javascripts/supplier/app/templates/form_elements/boolean_switch.emblem
+++ b/app/assets/javascripts/supplier/app/templates/form_elements/boolean_switch.emblem
@@ -1,2 +1,2 @@
-Ember.Checkbox id=view.switchId checkedBinding="view.value"
+= input type="checkbox" id=view.switchId checkedBinding="view.value"
label for=view.switchId
diff --git a/app/assets/javascripts/supplier/app/templates/index.emblem b/app/assets/javascripts/supplier/app/templates/index.emblem
index 63e27e9b..d8316676 100644
--- a/app/assets/javascripts/supplier/app/templates/index.emblem
+++ b/app/assets/javascripts/supplier/app/templates/index.emblem
@@ -1,7 +1,9 @@
+= sections-header sectionBinding="controller.controllers.application.active_section"
.page-header
div.dashboard-section-selection
- App.HomeSectionSelectorView selectionBinding="controller.controllers.application.active_section" content=controller.sections prompt=controllers.application.supplier.name
- App.HomeSectionJumperView
+ /App.HomeSectionSelectorView selectionBinding="controller.controllers.application.active_section" content=controller.sections prompt=controllers.application.supplier.name
+ /= home-section-selector sectionBinding="controller.controllers.application.active_section"
+ /= view "home-section-jumper"
if active_lists.length
h3.dashboard-lists-header{action "toggleDashboardLists"}
if show_lists
diff --git a/app/assets/javascripts/supplier/app/templates/menu.emblem b/app/assets/javascripts/supplier/app/templates/menu.emblem
index 53ee5970..165fa8f3 100644
--- a/app/assets/javascripts/supplier/app/templates/menu.emblem
+++ b/app/assets/javascripts/supplier/app/templates/menu.emblem
@@ -6,10 +6,9 @@ each product_category in sorted_product_categories
span.title= product_category.name
span.availability= product_category.availability_text
a.edit-product-category-button{action "editProductCategory" product_category} href="#"
- each product in product_category.products
- .row
- .small-4.columns= product.name
- .small-8.columns= currency product.price
+ a.add-product-product-category-button{action "addProduct" product_category} href="#": span
+ each product in product_category.sorted_products
+ = menu-product product=product
.row
.small-12.columns
a.button{action "newProductCategory"} href="#" = t 'product_category.new_button'
diff --git a/app/assets/javascripts/supplier/app/templates/modals/product_category_form.emblem b/app/assets/javascripts/supplier/app/templates/modals/product_category_form.emblem
index ac117209..a0c0f528 100644
--- a/app/assets/javascripts/supplier/app/templates/modals/product_category_form.emblem
+++ b/app/assets/javascripts/supplier/app/templates/modals/product_category_form.emblem
@@ -6,32 +6,32 @@
unless model.supplier.week_starts_on_monday
.form-row
.form-label.half= t 'date.day_name.sunday'
- .form-field.half: App.BooleanSwitchView value=model.active_on_sunday
+ .form-field.half= view "boolean-switch" value=model.active_on_sunday
.form-row
.form-label.half= t 'date.day_name.monday'
- .form-field.half: App.BooleanSwitchView value=model.active_on_monday
+ .form-field.half= view "boolean-switch" value=model.active_on_monday
.form-row
.form-label.half= t 'date.day_name.tuesday'
- .form-field.half: App.BooleanSwitchView value=model.active_on_tuesday
+ .form-field.half= view "boolean-switch" value=model.active_on_tuesday
.form-row
.form-label.half= t 'date.day_name.wednesday'
- .form-field.half: App.BooleanSwitchView value=model.active_on_wednesday
+ .form-field.half= view "boolean-switch" value=model.active_on_wednesday
.form-row
.form-label.half= t 'date.day_name.thursday'
- .form-field.half: App.BooleanSwitchView value=model.active_on_thursday
+ .form-field.half= view "boolean-switch" value=model.active_on_thursday
.form-row
.form-label.half= t 'date.day_name.friday'
- .form-field.half: App.BooleanSwitchView value=model.active_on_friday
+ .form-field.half= view "boolean-switch" value=model.active_on_friday
.form-row
.form-label.half= t 'date.day_name.saturday'
- .form-field.half: App.BooleanSwitchView value=model.active_on_saturday
+ .form-field.half= view "boolean-switch" value=model.active_on_saturday
if model.supplier.week_starts_on_monday
.form-row
.form-label.half= t 'date.day_name.sunday'
- .form-field.half: App.BooleanSwitchView valueBinding=model.active_on_sunday
+ .form-field.half= view "boolean-switch" valueBinding=model.active_on_sunday
.small-6.columns
.row
- .small-12.columns.text-center: App.BooleanButtonView value=model.full_day reverse=true text_path="product_category.modal.active_between.top"
+ .small-12.columns.text-center= view 'boolean-button' value=model.full_day reverse=true text_path="product_category.modal.active_between.top"
unless model.full_day
.row
.small-12.columns= view "select-minute-of-day" value=model.start_from
diff --git a/app/assets/javascripts/supplier/app/templates/modals/product_category_move.emblem b/app/assets/javascripts/supplier/app/templates/modals/product_category_move.emblem
index 0c837c02..ea2645e2 100644
--- a/app/assets/javascripts/supplier/app/templates/modals/product_category_move.emblem
+++ b/app/assets/javascripts/supplier/app/templates/modals/product_category_move.emblem
@@ -10,4 +10,12 @@ each product_category in product_categories
span.title= product_category.name
span.availability= product_category.availability_text
hr
+h4=t 'product_category.modal.move.products.title'
+hr
+ul.sortable
+ each product in model.sorted_products
+ li.sortable-item-container data-sortable-id=product.id
+ span.handle
+ span= product.name
+hr
button.modal-close{action "close"}=t 'section.add_tables.modal.close_button'
diff --git a/app/assets/javascripts/supplier/app/templates/orders_display.emblem b/app/assets/javascripts/supplier/app/templates/orders_display.emblem
index bc9123cd..2e46c0f5 100644
--- a/app/assets/javascripts/supplier/app/templates/orders_display.emblem
+++ b/app/assets/javascripts/supplier/app/templates/orders_display.emblem
@@ -1,7 +1,5 @@
-dl.orders-display-nav.sub-nav
- dd.active data-section="all": a.active{action "clearActiveSection"} href="" All
- each section in sections
- dd data-section=section.id: a{action "setActiveSection" section} href="#" = section.title
+= sections-header sectionBinding="section"
+h2= section.title
table.table
thead
tr
diff --git a/app/assets/javascripts/supplier/app/views/home_section_jumper_view.js.coffee b/app/assets/javascripts/supplier/app/views/home_section_jumper_view.js.coffee
deleted file mode 100644
index 4fba307f..00000000
--- a/app/assets/javascripts/supplier/app/views/home_section_jumper_view.js.coffee
+++ /dev/null
@@ -1,9 +0,0 @@
-App.HomeSectionJumperView = Ember.View.extend
- tagName: 'a'
- classNames: ['main-board-section-jumper']
- href: '#'
- isVisible: (-> !!@get('controller.active_section.id') ).property('controller.active_section.id')
- template: Ember.Handlebars.compile('')
- click: (e)->
- e.preventDefault()
- @get('controller').transitionToRoute 'section', @get('controller.active_section.id')
diff --git a/app/assets/javascripts/supplier/app/views/home_section_selector_view.js.coffee b/app/assets/javascripts/supplier/app/views/home_section_selector_view.js.coffee
deleted file mode 100644
index d4599d37..00000000
--- a/app/assets/javascripts/supplier/app/views/home_section_selector_view.js.coffee
+++ /dev/null
@@ -1,9 +0,0 @@
-HomeSectionOption = Ember.SelectOption.extend
- select_label: (-> "- #{@get('content.title')}").property('content.title')
- valueBinding: 'content.id'
-App.HomeSectionSelectorView = Ember.Select.extend
- classNames: 'section_selector'
- optionView: HomeSectionOption
- #valueBinding: 'controller.active_section_id'
- optionValuePath: 'content.id'
- optionLabelPath: 'select_label'
diff --git a/app/assets/javascripts/supplier/app/views/modal_view.js.coffee b/app/assets/javascripts/supplier/app/views/modal_view.js.coffee
index b778c9c8..ad3745f0 100644
--- a/app/assets/javascripts/supplier/app/views/modal_view.js.coffee
+++ b/app/assets/javascripts/supplier/app/views/modal_view.js.coffee
@@ -1,3 +1,13 @@
App.ModalView = Ember.View.extend
layoutName: 'modals/layout'
+ didInsertElement: ->
+ sortable = $('.sortable')
+ controller = @get('controller')
+ if sortable.length
+ sortable.sortable
+ update: (e, ui)->
+ ids = sortable.find('.sortable-item-container').map((i, el) -> $(el).data('sortableId')).toArray()
+ if callback = controller.sortableUpdate
+ callback.call(controller, ids)
+
diff --git a/app/assets/javascripts/supplier/foundation1/application.js.erb b/app/assets/javascripts/supplier/foundation1/application.js.erb
index 41a6838b..67c9092e 100644
--- a/app/assets/javascripts/supplier/foundation1/application.js.erb
+++ b/app/assets/javascripts/supplier/foundation1/application.js.erb
@@ -2,6 +2,7 @@
//= require jquery
//= require jquery_ujs
//= require jquery-ui/sortable
+//= require jquery.ui.touch-punch
// require foundation FOUNDATION 5 JAVASCRIPT IMPLEMENTATIONS AND EMBER ARE NOT COMPATIBLE, FOUNDATION IS TOO SIMPLISTIC AT THE MOMENT AND DESTROYS DOM EVENTS
//= require js-routes
//= require moment
diff --git a/app/assets/javascripts/translations.js.coffee.erb b/app/assets/javascripts/translations.js.coffee.erb
index c9361244..789f9d29 100644
--- a/app/assets/javascripts/translations.js.coffee.erb
+++ b/app/assets/javascripts/translations.js.coffee.erb
@@ -23,8 +23,7 @@
# return translation in the form
# Tafel
-@tspan = (path, vars={})->
- "#{t(path)}"
+@tspan = (path, vars={}) -> "#{t(path, vars)}"
@t = (path, vars={}) ->
diff --git a/app/assets/stylesheets/supplier/foundation1/_foundation_and_overrides.css.sass b/app/assets/stylesheets/supplier/foundation1/_foundation_and_overrides.css.sass
index 26c09ae8..84582d61 100644
--- a/app/assets/stylesheets/supplier/foundation1/_foundation_and_overrides.css.sass
+++ b/app/assets/stylesheets/supplier/foundation1/_foundation_and_overrides.css.sass
@@ -1249,6 +1249,11 @@ $secondary-color: #d7d7d7
// CUSTOM VARIABLES
@import 'foundation'
+
+// Prevent empty columns from collapsing
+.column, .columns
+ min-height: 1px
+
$button-margin: rem-calc(10)
$button-qr-code-color: #555
$button-index-color: $secondary-color
diff --git a/app/assets/stylesheets/supplier/foundation1/components/_edit_currency.css.sass b/app/assets/stylesheets/supplier/foundation1/components/_edit_currency.css.sass
new file mode 100644
index 00000000..2b2180e2
--- /dev/null
+++ b/app/assets/stylesheets/supplier/foundation1/components/_edit_currency.css.sass
@@ -0,0 +1,12 @@
+.edit-currency-container
+ input
+ text-align: right
+ &.error
+ input
+ border-color: $alert-color
+ color: darken($alert-color, 40%)
+ label.prefix
+ background-color: $alert-color
+ color: white
+ font-weight: bold
+
diff --git a/app/assets/stylesheets/supplier/foundation1/components/_modal.css.sass b/app/assets/stylesheets/supplier/foundation1/components/_modal.css.sass
index 997a02b3..af3ba991 100644
--- a/app/assets/stylesheets/supplier/foundation1/components/_modal.css.sass
+++ b/app/assets/stylesheets/supplier/foundation1/components/_modal.css.sass
@@ -12,6 +12,13 @@
.modal-destroy
+button($bg: $alert-color)
margin-right: 8px
+ .sortable
+ list-style: none
+ .sortable-item-container
+ cursor: pointer
+ .handle
+ @extend .fa, .fa-arrows-v
+ margin-right: 10px
.modal-alert
color: $alert-color
diff --git a/app/assets/stylesheets/supplier/foundation1/components/_product_categories.css.sass b/app/assets/stylesheets/supplier/foundation1/components/_product_categories.css.sass
index fb897b4c..e0ff0bdf 100644
--- a/app/assets/stylesheets/supplier/foundation1/components/_product_categories.css.sass
+++ b/app/assets/stylesheets/supplier/foundation1/components/_product_categories.css.sass
@@ -1,3 +1,4 @@
+//DEPRICATED
#product-category-list
list-style: none
li
diff --git a/app/assets/stylesheets/supplier/foundation1/components/_products_menu.css.sass b/app/assets/stylesheets/supplier/foundation1/components/_products_menu.css.sass
index a34e2f13..777ef1a0 100644
--- a/app/assets/stylesheets/supplier/foundation1/components/_products_menu.css.sass
+++ b/app/assets/stylesheets/supplier/foundation1/components/_products_menu.css.sass
@@ -1,3 +1,4 @@
+//DEPRICATED
.row.product_category-container
margin-bottom: 15px
.product_category-header
@@ -7,6 +8,7 @@
@extend .fa
// @extend .fa-lg
@extend .fa-arrows
+ margin-right: 8px
.title
font-weight: bold
font-size: 1.3em
@@ -22,6 +24,13 @@
@extend .fa
@extend .fa-lg
@extend .fa-edit
+ .add-product-product-category-button
+ float: right
+ margin-top: 1.2em
+ span
+ @extend .fa
+ @extend .fa-lg
+ @extend .fa-plus
.product_category-move-row
.availability
font-size: 0.8em
@@ -29,3 +38,18 @@
color: #444
.time-range
color: rgb(39, 6, 121)
+
+.menu-product-container
+ .destroy-product-action
+ color: $alert-color
+ margin-right: 12px
+ span
+ @extend .fa
+ @extend .fa-lg
+ @extend .fa-trash
+ .save-product-action
+ color: $success-color
+ span
+ @extend .fa
+ @extend .fa-lg
+ @extend .fa-save
diff --git a/app/assets/stylesheets/supplier/foundation1/components/_sections_header.css.sass b/app/assets/stylesheets/supplier/foundation1/components/_sections_header.css.sass
new file mode 100644
index 00000000..39a3077b
--- /dev/null
+++ b/app/assets/stylesheets/supplier/foundation1/components/_sections_header.css.sass
@@ -0,0 +1,13 @@
+.sections-header-container
+ .section-header-title
+ padding-right: 0.5em
+ color: #555
+ .section-jumper
+ display: none
+ .active
+ .section-jumper
+ display: inline-block
+ +button($bg: #ddd)
+ margin: 0
+ margin-left: 4px
+ padding: 0 5px
diff --git a/app/controllers/suppliers/products_controller.rb b/app/controllers/suppliers/products_controller.rb
index 69e8883f..2bb0782a 100644
--- a/app/controllers/suppliers/products_controller.rb
+++ b/app/controllers/suppliers/products_controller.rb
@@ -49,7 +49,7 @@ module Suppliers
respond_to do |format|
if @product.save
format.html { redirect_to [:suppliers, :products], notice: t('action.create.successfull', model: Product.model_name.human) }
- format.json { render json: @product, status: :created, location: @product }
+ format.json { render json: @product, status: :created }
else
format.html { render action: "new" }
format.json { render json: @product.errors, status: :unprocessable_entity }
@@ -65,7 +65,7 @@ module Suppliers
respond_to do |format|
if @product.update_attributes(product_params)
format.html { redirect_to [:suppliers, :products], notice: t('action.update.successfull', model: Product.model_name.human) }
- format.json { head :no_content }
+ format.json { render json: @product }
else
format.html { render action: "edit" }
format.json { render json: @product.errors, status: :unprocessable_entity }
@@ -95,7 +95,7 @@ module Suppliers
private
def product_params
- params.require(:product).permit(:name, :code, :price, :description, :image, product_category_ids: [])
+ params.require(:product).permit(:name, :code, :price, :description, :image, :visible, :position, :product_category_id)
end
end
end
diff --git a/app/models/product.rb b/app/models/product.rb
index 914d40a8..8579b570 100644
--- a/app/models/product.rb
+++ b/app/models/product.rb
@@ -7,9 +7,11 @@ class Product
property :code
property :price, type: Float
property :description
+ property :visible, type: :boolean, default: true
+ property :position, type: Fixnum
- #belongs_to :product_category
- has_and_belongs_to_many :product_categories, storing_keys: false
+ belongs_to :product_category
+ #has_and_belongs_to_many :product_categories, storing_keys: false
belongs_to :supplier # direct! category is an aid
has_many :product_orders
@@ -20,12 +22,16 @@ class Product
validates :price, presence: true, numericality: true
view :by_supplier_id_and_id, key: [:supplier_id, :_id]
- after_save :persist_product_category_ids
+ #after_save :persist_product_category_ids
- def product_category_ids=(ids)
- @product_category_ids = ids.select(&:present?)
- is_dirty
- end
+ #def product_category_ids=(ids)
+ #@product_category_ids = ids.select(&:present?)
+ #is_dirty
+ #end
+
+ #def product_category_id=(id)
+ #self.product_category_ids = [id]
+ #end
property :image_file_name
property :image_content_type
@@ -38,24 +44,24 @@ class Product
validates_attachment :image, content_type: {content_type: ["image/jpg", "image/jpeg", "image/png", "image/gif"]}
-private
+#private
- def persist_product_category_ids
- return unless defined?(@product_category_ids) # Do not do anything if nothing happened to this attribute
- @product_category_ids ||= []
- existing_product_categories = product_categories
+ #def persist_product_category_ids
+ #return unless defined?(@product_category_ids) # Do not do anything if nothing happened to this attribute
+ #@product_category_ids ||= []
+ #existing_product_categories = product_categories
- # do nothing if nothing has changed
- return if @product_category_ids == existing_product_categories.map(&:id)
+ ## do nothing if nothing has changed
+ #return if @product_category_ids == existing_product_categories.map(&:id)
- # clear removed product categories
- existing_product_categories.reject{|pc| @product_category_ids.include?(pc.id) }.each{|pc| pc.remove_product(self) }
+ ## clear removed product categories
+ #existing_product_categories.reject{|pc| @product_category_ids.include?(pc.id) }.each{|pc| pc.remove_product(self) }
- # Add product to newly added product categories
- database.load(@product_category_ids - existing_product_categories.map(&:id)).each do |product_category|
- product_category.add_product(self)
- end
- end
+ ## Add product to newly added product categories
+ #database.load(@product_category_ids - existing_product_categories.map(&:id)).each do |product_category|
+ #product_category.add_product(self)
+ #end
+ #end
end
diff --git a/app/models/product_category.rb b/app/models/product_category.rb
index 92a44fad..e86c3b12 100644
--- a/app/models/product_category.rb
+++ b/app/models/product_category.rb
@@ -17,7 +17,8 @@ class ProductCategory
property :active_on_saturday, type: :boolean, default: true
belongs_to :supplier
- has_and_belongs_to_many :products, storing_keys: true
+ #has_and_belongs_to_many :products, storing_keys: true
+ has_many :products
attr_protected :supplier_id
diff --git a/app/serializers/product_serializer.rb b/app/serializers/product_serializer.rb
index 5c68a99f..a658f134 100644
--- a/app/serializers/product_serializer.rb
+++ b/app/serializers/product_serializer.rb
@@ -1,6 +1,6 @@
class ProductSerializer < Qwaiter::Serializer
embed :ids, include: true
- attributes :name, :price, :description, :image
+ attributes :name, :price, :description, :image, :code, :position, :visible, :product_category_id
def image
if object.image.present?
diff --git a/app/views/suppliers/application/_top_menu.html.slim b/app/views/suppliers/application/_top_menu.html.slim
index 81279450..ce165435 100644
--- a/app/views/suppliers/application/_top_menu.html.slim
+++ b/app/views/suppliers/application/_top_menu.html.slim
@@ -3,10 +3,8 @@ header.top-menu
span
.menu-content
section.main-buttons
- //li= link_to t('supplier.menu.active_orders', orders: Order.model_name.human_plural), supplier_active_orders_path
- //li= link_to t('supplier.menu.active_lists', lists: List.model_name.human_plural), supplier_active_lists_path
= link_to image_tag('icons/logo-small.png'), supplier_root_path, class: 'top-menu-root'
- = link_to 'Menu', suppliers_menu_path, class: 'top-menu-menu'
+ = link_to t('supplier.top_menu.menu'), "/supplier#/menu", class: 'top-menu-menu'
= link_to ProductCategory.model_name.human_plural, suppliers_product_categories_path, data: {t: 'models.plural.product_category'}, class: 'top-menu-product_categories'
= link_to Product.model_name.human_plural, suppliers_products_path, data: {t: 'models.plural.product'}, class: 'top-menu-products'
= link_to Section.model_name.human_plural, "/supplier#/sections", data: {t: 'models.plural.section'}, class: 'top-menu-sections'
diff --git a/config/locales/supplier.en.yml b/config/locales/supplier.en.yml
index a70317ee..540b40ee 100644
--- a/config/locales/supplier.en.yml
+++ b/config/locales/supplier.en.yml
@@ -24,8 +24,8 @@ en:
could_not_arrange_tables_distributed: 'The tables could not be arranged. Does the ${models.section|downcase} have a width and a height?'
could_not_arrange_tables_by_row: 'The tables could not be arranged. Does the ${models.section|downcase} have a width and a height?'
could_not_arrange_tables_by_column: 'The tables could not be arranged. Does the ${models.section|downcase} have a width and a height?'
- menu:
- active_lists: Active lists
+ top_menu:
+ menu: Menu
active_lists:
title: Active lists
price: Price
@@ -73,6 +73,8 @@ en:
order:
being_processed: 'In process!'
being_served: 'Is delivered!'
+ sections_header:
+ all_sections: All
section:
first_section_title: Room
show:
@@ -157,9 +159,10 @@ en:
title: Move ${models.product_category|downcase}
body_header: ''
move_to_top: Move to top
- move_below_label: "Place below ${product_category|downcase}"
+ move_below_label: "Place below ${models.product_category|downcase}"
product:
new: 'New ${model.product|downcase}'
+ destroy_confirmation: Are you sure you want to delete ${models.product|downcase} %{name}
preview:
header: 'Select moment to preview products'
description: 'Products visible to customers at chosen moment:'
diff --git a/config/locales/supplier.nl.yml b/config/locales/supplier.nl.yml
index 26510369..48129910 100644
--- a/config/locales/supplier.nl.yml
+++ b/config/locales/supplier.nl.yml
@@ -23,8 +23,8 @@ nl:
could_not_arrange_tables_distributed: 'De ${models.plural.table} konden niet worden gepositioneerd. Heeft de ${models.section|downcase} een hoogte en breedte?'
could_not_arrange_tables_by_row: 'De ${models.plural.table} konden niet worden gepositioneerd. Heeft de ${models.section|downcase} een hoogte en breedte?'
could_not_arrange_tables_by_column: 'De ${models.plural.table} konden niet worden gepositioneerd. Heeft de ${models.section|downcase} een hoogte en breedte?'
- menu:
- active_lists: Actieve lijsten
+ top_menu:
+ menu: Menu
active_lists:
title: Actieve lijsten
price: Prijs
@@ -72,6 +72,8 @@ nl:
order:
being_processed: 'Ben bezig!'
being_served: 'Ik kom het brengen!'
+ sections_header:
+ all_sections: Alles
section:
first_section_title: Ruimte
show:
@@ -139,7 +141,7 @@ nl:
active_between:
top: Actief tussen
middle: en
- destroy_confirm_text: 'Weet je zeker dat je ${models.product_category} %{name} wil verwijderen?'
+ destroy_confirm_text: 'Weet je zeker dat je ${models.product_category|downcase} %{name} wil verwijderen?'
new:
title: ${models.product_category} toevoegen
body_header: ''
@@ -158,9 +160,12 @@ nl:
title: Verplaats ${models.product_category|downcase}
body_header: ''
move_to_top: Plaats bovenaan
- move_below_label: "Plaats onder ${product_category|downcase}"
+ move_below_label: "Plaats onder ${models.product_category|downcase}"
+ products:
+ title: Sorteer ${models.plural.product|downcase}
product:
new: 'Nieuw ${model.product|downcase}'
+ destroy_confirmation: Weet je zeker dat je ${models.product|downcase} %{name} wilt verwijderen
preview:
header: 'Selecteer tijdstip voor voorbeeld'
description: 'Producten op gekozen tijdstip:'
diff --git a/vendor/assets/javascripts/jquery.ui.touch-punch.js b/vendor/assets/javascripts/jquery.ui.touch-punch.js
new file mode 100644
index 00000000..16ce41d1
--- /dev/null
+++ b/vendor/assets/javascripts/jquery.ui.touch-punch.js
@@ -0,0 +1,180 @@
+/*!
+ * jQuery UI Touch Punch 0.2.3
+ *
+ * Copyright 2011–2014, Dave Furfero
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ *
+ * Depends:
+ * jquery.ui.widget.js
+ * jquery.ui.mouse.js
+ */
+(function ($) {
+
+ // Detect touch support
+ $.support.touch = 'ontouchend' in document;
+
+ // Ignore browsers without touch support
+ if (!$.support.touch) {
+ return;
+ }
+
+ var mouseProto = $.ui.mouse.prototype,
+ _mouseInit = mouseProto._mouseInit,
+ _mouseDestroy = mouseProto._mouseDestroy,
+ touchHandled;
+
+ /**
+ * Simulate a mouse event based on a corresponding touch event
+ * @param {Object} event A touch event
+ * @param {String} simulatedType The corresponding mouse event
+ */
+ function simulateMouseEvent (event, simulatedType) {
+
+ // Ignore multi-touch events
+ if (event.originalEvent.touches.length > 1) {
+ return;
+ }
+
+ event.preventDefault();
+
+ var touch = event.originalEvent.changedTouches[0],
+ simulatedEvent = document.createEvent('MouseEvents');
+
+ // Initialize the simulated mouse event using the touch event's coordinates
+ simulatedEvent.initMouseEvent(
+ simulatedType, // type
+ true, // bubbles
+ true, // cancelable
+ window, // view
+ 1, // detail
+ touch.screenX, // screenX
+ touch.screenY, // screenY
+ touch.clientX, // clientX
+ touch.clientY, // clientY
+ false, // ctrlKey
+ false, // altKey
+ false, // shiftKey
+ false, // metaKey
+ 0, // button
+ null // relatedTarget
+ );
+
+ // Dispatch the simulated event to the target element
+ event.target.dispatchEvent(simulatedEvent);
+ }
+
+ /**
+ * Handle the jQuery UI widget's touchstart events
+ * @param {Object} event The widget element's touchstart event
+ */
+ mouseProto._touchStart = function (event) {
+
+ var self = this;
+
+ // Ignore the event if another widget is already being handled
+ if (touchHandled || !self._mouseCapture(event.originalEvent.changedTouches[0])) {
+ return;
+ }
+
+ // Set the flag to prevent other widgets from inheriting the touch event
+ touchHandled = true;
+
+ // Track movement to determine if interaction was a click
+ self._touchMoved = false;
+
+ // Simulate the mouseover event
+ simulateMouseEvent(event, 'mouseover');
+
+ // Simulate the mousemove event
+ simulateMouseEvent(event, 'mousemove');
+
+ // Simulate the mousedown event
+ simulateMouseEvent(event, 'mousedown');
+ };
+
+ /**
+ * Handle the jQuery UI widget's touchmove events
+ * @param {Object} event The document's touchmove event
+ */
+ mouseProto._touchMove = function (event) {
+
+ // Ignore event if not handled
+ if (!touchHandled) {
+ return;
+ }
+
+ // Interaction was not a click
+ this._touchMoved = true;
+
+ // Simulate the mousemove event
+ simulateMouseEvent(event, 'mousemove');
+ };
+
+ /**
+ * Handle the jQuery UI widget's touchend events
+ * @param {Object} event The document's touchend event
+ */
+ mouseProto._touchEnd = function (event) {
+
+ // Ignore event if not handled
+ if (!touchHandled) {
+ return;
+ }
+
+ // Simulate the mouseup event
+ simulateMouseEvent(event, 'mouseup');
+
+ // Simulate the mouseout event
+ simulateMouseEvent(event, 'mouseout');
+
+ // If the touch interaction did not move, it should trigger a click
+ if (!this._touchMoved) {
+
+ // Simulate the click event
+ simulateMouseEvent(event, 'click');
+ }
+
+ // Unset the flag to allow other widgets to inherit the touch event
+ touchHandled = false;
+ };
+
+ /**
+ * A duck punch of the $.ui.mouse _mouseInit method to support touch events.
+ * This method extends the widget with bound touch event handlers that
+ * translate touch events to mouse events and pass them to the widget's
+ * original mouse event handling methods.
+ */
+ mouseProto._mouseInit = function () {
+
+ var self = this;
+
+ // Delegate the touch handlers to the widget's element
+ self.element.bind({
+ touchstart: $.proxy(self, '_touchStart'),
+ touchmove: $.proxy(self, '_touchMove'),
+ touchend: $.proxy(self, '_touchEnd')
+ });
+
+ // Call the original $.ui.mouse init method
+ _mouseInit.call(self);
+ };
+
+ /**
+ * Remove the touch event handlers
+ */
+ mouseProto._mouseDestroy = function () {
+
+ var self = this;
+
+ // Delegate the touch handlers to the widget's element
+ self.element.unbind({
+ touchstart: $.proxy(self, '_touchStart'),
+ touchmove: $.proxy(self, '_touchMove'),
+ touchend: $.proxy(self, '_touchEnd')
+ });
+
+ // Call the original $.ui.mouse destroy method
+ _mouseDestroy.call(self);
+ };
+
+})(jQuery);
\ No newline at end of file