Time dependant product categories for users

This commit is contained in:
2015-01-22 17:49:32 +01:00
parent f434b53161
commit 36525849bd
24 changed files with 9981 additions and 46 deletions
+1 -4
View File
@@ -100,12 +100,9 @@ group :development do
end
group :test do
#gem 'steak'
# gem 'database_cleaner'
# gem 'capybara' #, '2.0.3'
#gem 'selenium-webdriver'
#gem 'capybara-webkit' #, '~>0.14.2' # version 1.1.0 does not yet compile in mavericks
gem 'selenium-webdriver'
#gem 'poltergeist'
gem 'capybara-screenshot'
gem 'turnip'
gem 'rspec-its'
@@ -5,14 +5,14 @@
helpers: <%= I18n.t('helpers', locale: :en).to_json %>
pagination: <%= I18n.t('views.pagination', locale: :en).to_json %>
errors: <%= I18n.t('errors', locale: :en).to_json %>
date: <%= {day_name: Hash[%w[sunday monday tuesday wednesday thursday friday saturday].zip(I18n.t('date.day_names', locale: :en))]}.to_json %>
date: <%= {day_name: Hash[Date::DAYNAMES.map(&:downcase).zip(I18n.t('date.day_names', locale: :en))]}.to_json %>
nl:
models: <%= I18n.t('activemodel.models', locale: :nl).to_json %>
attributes: <%= I18n.t('activemodel.attributes', locale: :nl).to_json %>
helpers: <%= I18n.t('helpers', locale: :nl).to_json %>
pagination: <%= I18n.t('views.pagination', locale: :nl).to_json %>
errors: <%= I18n.t('errors', locale: :nl).to_json %>
date: <%= {day_name: Hash[%w[sunday monday tuesday wednesday thursday friday saturday].zip(I18n.t('date.day_names', locale: :nl))]}.to_json %>
date: <%= {day_name: Hash[Date::DAYNAMES.map(&:downcase).zip(I18n.t('date.day_names', locale: :nl))]}.to_json %>
@day_minutes_to_time = (minutes)->
return "" unless minutes
@@ -1,3 +1,21 @@
now = new Date()
ClockService = Ember.Object.extend
minute_of_day: 60*now.getHours() + now.getMinutes()
run_times: 0
tick: (->
clock = this
Ember.run.later ->
now = new Date()
clock.set 'minute_of_day', 60*now.getHours() + now.getMinutes()
clock.set 'run_times', 1 + clock.get('run_times')
, 20000
).observes('run_times').on('init')
Ember.Application.initializer
name: 'clockServiceInitializer'
initialize: (container, application)->
container.register 'clock:service', ClockService
application.inject 'component:menu-product-categories', 'clock', 'clock:service'
@App = Ember.Application.create
LOG_TRANSITIONS: true
rootElement: '#ember-app-container'
@@ -1,9 +1,16 @@
App.MenuProductCategoriesComponent = Ember.Component.extend
orderProducts: false
timestamp: 0 # invalidation param
#minute_of_day: 0 # invalidation param
active_product_categories: (->
console.log "Reevaluate product categories"
list = @get('product_categories')
).property('product_categories.@each', 'timestamp')
now = new Date()
list = list.filter (product_category) =>
return false unless product_category.get("active_on_#{$day_names[now.getDay()]}")
return true if product_category.get('full_day')
product_category.get('start_from') <= @get('clock.minute_of_day') and @get('clock.minute_of_day') <= product_category.get('end_on')
list.sortBy('position')
).property('product_categories.@each', 'clock.minute_of_day')
actions:
toggleProductCategory: (product_category) -> product_category.toggleProperty('collapsed')
@@ -3,6 +3,7 @@ App.Product = DS.Model.extend
name: attr 'string'
price: attr 'number'
description: attr 'string'
position: attr('number', defaultValue: 0)
image: attr()
product_category: DS.belongsTo('product_category')
product_orders: DS.hasMany('product_order')
@@ -3,4 +3,17 @@ App.ProductCategory = DS.Model.extend
name: attr('string')
products: DS.hasMany('product')
supplier: DS.belongsTo('supplier')
active_on_sunday: attr('boolean', defaultValue: true)
active_on_monday: attr('boolean', defaultValue: true)
active_on_tuesday: attr('boolean', defaultValue: true)
active_on_wednesday: attr('boolean', defaultValue: true)
active_on_thursday: attr('boolean', defaultValue: true)
active_on_friday: attr('boolean', defaultValue: true)
active_on_saturday: attr('boolean', defaultValue: true)
full_day: attr 'boolean', defaultValue: true
start_from: attr('number')
end_on: attr('number')
position: attr('number')
collapsed: attr('boolean', defaultValue: false)
sorted_products: (-> @get('products').sortBy('position') ).property('products.@each.position')
@@ -1,7 +1,5 @@
each product_category in active_product_categories
.product-category-container
if orderProducts
h4 OderProducts
.product-category-container id="product-category-#{unbound product_category.id}"
if product_category.products
h4.product_category-title{action "toggleProductCategory" product_category}
if product_category.collapsed
@@ -11,5 +9,5 @@ each product_category in active_product_categories
= product_category.name
unless product_category.collapsed
ul.product_category-products
each product in product_category.products
each product in product_category.sorted_products
= menu-product product=product orderProducts=orderProducts
+3 -3
View File
@@ -94,9 +94,9 @@ module ApplicationHelper
current_user.try(:active_list_id)
end
def week_days
@week_days ||= %w[sunday monday tuesday wednesday thursday friday saturday].freeze # Do not allow changing this value
end
#def week_days
#@week_days ||= %w[sunday monday tuesday wednesday thursday friday saturday].freeze # Do not allow changing this value
#end
def current_supplier
#@current_supplier ||= ActiveDecorator::Decorator.instance.decorate(super)
-25
View File
@@ -4,7 +4,6 @@ class ProductCategory
property :name
property :position, type: Fixnum, default: 0
property :week_days, type: Array, default: Array.new(7, 1)
property :full_day, type: :boolean, default: true
property :start_from, type: Fixnum, default: 1320 # 22:00
property :end_on, type: Fixnum, default: 1380 # 23:00
@@ -28,30 +27,6 @@ class ProductCategory
validates :end_on, numericality: {less_than: 2880}, presence: {unless: :full_day?}
view :by_supplier_id_and_id, key: [:supplier_id, :_id]
view :by_supplier_id_and_week_time, type: :custom, map_function: "function(doc){
if(doc.ruby_class == 'ProductCategory'){
for(var i=0;i<7;i++){
if(doc.full_day || !doc.end_on){
if(doc.week_days[i]) emit([doc.supplier_id, i], 1);
}else{
for(var j=(doc.start_from || 0);j < doc.end_on;j++){
if(doc.week_days[i]) emit([doc.supplier_id, i, j], 1);
}
}
}
}
}", reduce_function: :_sum
#start_key: [supplier_id, wday, minute], end_key: [supplier_id, wday, 2880, minute]
#alias orignal_week_days= week_days=
def week_days=(ary)
#write_attribute(:week_days, ary.map(&:to_i))
typecasted_value = ary.map(&:to_i)
#return typecasted_value if @week_days == typecasted_value
week_days_will_change! unless @skip_dirty_tracking || typecasted_value == week_days
@week_days = typecasted_value
end
#TODO I am uuuuggggllyyyyy
def self.for_user(user, options = {})
@@ -14,6 +14,7 @@ html lang="en"
var $event_host = '#{Qwaiter.event_host}';
var $assets_path = './assets/';
var $app_version = '#{app_version}';
var $day_names = ["sunday", "monday", "tuesday", "wednesday", "thursday", "friday", "saturday"]
var $user_feedback_path = 'http://feedback.mozo.bar/user_feedback';
var Qstorage = window.localStorage;
Qstorage.setItem('root_url', '##root_url##');
@@ -27,6 +28,7 @@ html lang="en"
var $event_host = '#{Qwaiter.event_host}';
var $assets_path = '/assets/';
var $app_version = '#{app_version}';
var $day_names = ["sunday", "monday", "tuesday", "wednesday", "thursday", "friday", "saturday"]
var $user_feedback_path = 'http://feedback.mozo.bar/user_feedback';
var Qstorage = window.localStorage;
#{user_dynamic_data_host};
@@ -41,6 +43,7 @@ html lang="en"
var $event_host = '#{Qwaiter.event_host}';
var $assets_path = '/assets/';
var $app_version = '#{app_version}';
var $day_names = ["sunday", "monday", "tuesday", "wednesday", "thursday", "friday", "saturday"]
var $user_feedback_path = '/user_feedback';
var Qstorage = window.localStorage;
#{user_dynamic_data_host};
+1 -1
View File
@@ -70,7 +70,7 @@ module Qwaiter
# Set Time.zone default to the specified zone and make Active Record auto-convert to this zone.
# Run "rake -D time" for a list of tasks for finding time zone names. Default is UTC.
# config.time_zone = 'Central Time (US & Canada)'
config.time_zone = 'UTC'
#config.time_zone = 'UTC'
# The default locale is :en and all translations from config/locales/*.rb,yml are auto loaded.
# config.i18n.load_path += Dir[Rails.root.join('my', 'locales', '*.{rb,yml}').to_s]
+12
View File
@@ -0,0 +1,12 @@
class Date
# return the lowercased day name in English of the date object eg: monday or friday etc
def day_name
Date::DAYNAMES[wday].downcase
end
end
class Time
def minute_of_day
60 * hour + min
end
end
+1 -1
View File
@@ -116,7 +116,7 @@ en:
<li>Select the products you want</li>
<li>Click the order products button</li>
</ul>
Now your order is sent behind the bar.<br><br>
Now your order is received behind the bar.<br><br>
Feedback of your order is given by one or two checks next to your order.
feedback:
title: Feedback
@@ -53,4 +53,5 @@ Feature: Ordering a product as a user
And the user clicks on the lists link in the side menu
And the user opens the side menu again
And the user clicks on the order products link in the side menu
Then the user should see the products listed for the active list
Then the user page contains the product category beer
And the user should see the products listed for the active list
@@ -0,0 +1,50 @@
Feature:
The product categories are only visible on their specific times
@javascript
Scenario: Product category visibility by day
Given there is an open supplier with a menu
And there is a table
And I am signed in as a user
When the user is on the order products page
Then the user page contains the product category lunch
When the product category lunch is not visible today
And I reload the page
Then the user page contains the product category beer
And the user page does not contain the product category lunch
@javascript
Scenario: Product category visibility by minute when inside the range
Given there is an open supplier with a menu
And there is a table
And I am signed in as a user
When the user is on the order products page
Then the user page contains the product category lunch
When the product category lunch is visible at this time
And I reload the page
Then the user page contains the product category beer
And the user page contains the product category lunch
@javascript
Scenario: Product category visibility by minute when category is visible after now
Given there is an open supplier with a menu
And there is a table
And I am signed in as a user
When the user is on the order products page
Then the user page contains the product category lunch
When the product category lunch is visible later than now
And I reload the page
Then the user page contains the product category beer
And the user page does not contain the product category lunch
@javascript
Scenario: Product category visibility by minute when category is visible before now
Given there is an open supplier with a menu
And there is a table
And I am signed in as a user
When the user is on the order products page
Then the user page contains the product category lunch
When the product category lunch is visible earlyer than now
And I reload the page
Then the user page contains the product category beer
And the user page does not contain the product category lunch
@@ -0,0 +1,21 @@
step "the product category lunch is not visible today" do
@category_lunch.update_attributes "active_on_#{Date.today.day_name}" => false
end
step "the product category lunch is visible at this time" do
@category_lunch.update_attributes full_day: false,
start_from: 10.minutes.ago.getlocal.minute_of_day,
end_on: 10.minutes.from_now.getlocal.minute_of_day
end
step "the product category lunch is visible later than now" do
@category_lunch.update_attributes full_day: false,
start_from: 10.minutes.from_now.getlocal.minute_of_day,
end_on: 1440
end
step "the product category lunch is visible earlyer than now" do
@category_lunch.update_attributes full_day: false,
start_from: 0,
end_on: 10.minutes.ago.getlocal.minute_of_day
end
+4
View File
@@ -31,3 +31,7 @@ end
step "I open the debugger" do
binding.pry
end
step 'I reload the page' do
page.driver.browser.navigate.refresh()
end
+1 -1
View File
@@ -14,7 +14,7 @@ step "I am on the user homepage" do
end
step "the user is on the homepage" do
visit user_root_path
visit '/user'
end
step "the user should be redirected to the user order overview page" do
@@ -130,3 +130,12 @@ step "the user has an active list with a/an :order_status order" do |order_statu
end
end
step "the user page contains the product category lunch" do
js_text("#product-category-#{@category_lunch.id} .product_category-title").should include @category_lunch.name
end
step "the user page contains the product category beer" do
js_text("#product-category-#{@category_beer.id} .product_category-title").should include @category_beer.name
end
step "the user page does not contain the product category lunch" do
page.should_not have_selector "#product-category-#{@category_lunch.id} .product_category-title"
end
@@ -0,0 +1,25 @@
require 'spec_helper'
describe Date do
describe '#day_name' do
it 'returns the proper day name' do
travel_to Date.parse('2015-01-22') do
Date.today.day_name.should eq 'thursday'
end
end
end
end
describe Time do
describe '#minute_of_day' do
it 'returns the proper minute' do
Time.parse('2015-01-22T16:48:12Z').minute_of_day.should eq 1008
end
it 'works for relative time' do
travel_to Time.parse('2015-01-22T16:48:12Z') do
12.minutes.from_now.minute_of_day.should eq 1020
end
end
end
end
+3
View File
@@ -10,6 +10,7 @@ require 'turnip/capybara'
require 'in_memory_q_counter'
require 'capybara-screenshot/rspec'
require 'webmock/rspec'
#require 'capybara/poltergeist'
# Requires supporting ruby files with custom matchers and macros, etc,
# in spec/support/ and its subdirectories.
@@ -20,6 +21,7 @@ Dir.glob("spec/acceptance_steps/**/*steps.rb") { |f| load f, true }
I18n.locale =I18n.default_locale
Devise.stretches = 1
#Capybara.javascript_driver = :webkit
#Capybara.javascript_driver = :poltergeist
Capybara.javascript_driver = :selenium
Capybara.default_wait_time = 4 # ember needs more time than the default of 2
Capybara::Screenshot.webkit_options = { width: 1024, height: 768 }
@@ -86,6 +88,7 @@ RSpec.configure do |config|
config.include Devise::TestHelpers, type: :controller
config.include EndWithMatcher
config.include Matchers
config.include ActiveSupport::Testing::TimeHelpers
config.include Features::BasicHelpers, type: :feature
config.include SpecRouteHelpers, type: :feature
config.include SpecEmberHelpers, type: :feature
+5
View File
@@ -37,6 +37,11 @@ module SpecEmberHelpers
page.execute_script "$('#{selector}').click()"
end
def js_text(selector)
find selector
page.evaluate_script("$('#{selector}').text()")
end
def ember_find(typeKey, id)
h = page.evaluate_script <<-SCRIPT
App.__container__.lookup('store:main').all('#{typeKey}').findBy('id', '#{id}').serialize()
File diff suppressed because it is too large Load Diff
+3 -2
View File
@@ -1,2 +1,3 @@
//= require './moment.min'
//= require './langs.min'
// require './moment.min'
// require './langs.min'
//= require 'moment-with-locales'