best_boy 0.2.2 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,156 @@
1
+ /*!
2
+ * Datepicker for Bootstrap
3
+ *
4
+ * Copyright 2012 Stefan Petre
5
+ * Licensed under the Apache License v2.0
6
+ * http://www.apache.org/licenses/LICENSE-2.0
7
+ *
8
+ */
9
+ .datepicker {
10
+ top: 0;
11
+ left: 0;
12
+ padding: 4px;
13
+ margin-top: 1px;
14
+ -webkit-border-radius: 4px;
15
+ -moz-border-radius: 4px;
16
+ border-radius: 4px;
17
+ /*.dow {
18
+ border-top: 1px solid #ddd !important;
19
+ }*/
20
+ }
21
+ .datepicker:before {
22
+ content: '';
23
+ display: inline-block;
24
+ border-left: 7px solid transparent;
25
+ border-right: 7px solid transparent;
26
+ border-bottom: 7px solid #ccc;
27
+ border-bottom-color: rgba(0, 0, 0, 0.2);
28
+ position: absolute;
29
+ top: -7px;
30
+ left: 6px;
31
+ }
32
+ .datepicker:after {
33
+ content: '';
34
+ display: inline-block;
35
+ border-left: 6px solid transparent;
36
+ border-right: 6px solid transparent;
37
+ border-bottom: 6px solid #ffffff;
38
+ position: absolute;
39
+ top: -6px;
40
+ left: 7px;
41
+ }
42
+ .datepicker > div {
43
+ display: none;
44
+ }
45
+ .datepicker table {
46
+ width: 100%;
47
+ margin: 0;
48
+ }
49
+ .datepicker td, .datepicker th {
50
+ text-align: center;
51
+ width: 20px;
52
+ height: 20px;
53
+ -webkit-border-radius: 4px;
54
+ -moz-border-radius: 4px;
55
+ border-radius: 4px;
56
+ }
57
+ .datepicker td.day:hover {
58
+ background: #eeeeee;
59
+ cursor: pointer;
60
+ }
61
+ .datepicker td.old, .datepicker td.new {
62
+ color: #999999;
63
+ }
64
+ .datepicker td.active, .datepicker td.active:hover {
65
+ background-color: #006dcc;
66
+ background-image: -moz-linear-gradient(top, #0088cc, #0044cc);
67
+ background-image: -ms-linear-gradient(top, #0088cc, #0044cc);
68
+ background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0044cc));
69
+ background-image: -webkit-linear-gradient(top, #0088cc, #0044cc);
70
+ background-image: -o-linear-gradient(top, #0088cc, #0044cc);
71
+ background-image: linear-gradient(top, #0088cc, #0044cc);
72
+ background-repeat: repeat-x;
73
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#0088cc', endColorstr='#0044cc', GradientType=0);
74
+ border-color: #0044cc #0044cc #002a80;
75
+ border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
76
+ filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
77
+ color: #fff;
78
+ text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);
79
+ }
80
+ .datepicker td.active:hover,
81
+ .datepicker td.active:hover:hover,
82
+ .datepicker td.active:active,
83
+ .datepicker td.active:hover:active,
84
+ .datepicker td.active.active,
85
+ .datepicker td.active:hover.active,
86
+ .datepicker td.active.disabled,
87
+ .datepicker td.active:hover.disabled,
88
+ .datepicker td.active[disabled],
89
+ .datepicker td.active:hover[disabled] {
90
+ background-color: #0044cc;
91
+ }
92
+ .datepicker td.active:active,
93
+ .datepicker td.active:hover:active,
94
+ .datepicker td.active.active,
95
+ .datepicker td.active:hover.active {
96
+ background-color: #003399 \9;
97
+ }
98
+ .datepicker td span {
99
+ display: block;
100
+ width: 47px;
101
+ height: 54px;
102
+ line-height: 54px;
103
+ float: left;
104
+ margin: 2px;
105
+ cursor: pointer;
106
+ -webkit-border-radius: 4px;
107
+ -moz-border-radius: 4px;
108
+ border-radius: 4px;
109
+ }
110
+ .datepicker td span:hover {
111
+ background: #eeeeee;
112
+ }
113
+ .datepicker td span.active {
114
+ background-color: #006dcc;
115
+ background-image: -moz-linear-gradient(top, #0088cc, #0044cc);
116
+ background-image: -ms-linear-gradient(top, #0088cc, #0044cc);
117
+ background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0044cc));
118
+ background-image: -webkit-linear-gradient(top, #0088cc, #0044cc);
119
+ background-image: -o-linear-gradient(top, #0088cc, #0044cc);
120
+ background-image: linear-gradient(top, #0088cc, #0044cc);
121
+ background-repeat: repeat-x;
122
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#0088cc', endColorstr='#0044cc', GradientType=0);
123
+ border-color: #0044cc #0044cc #002a80;
124
+ border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
125
+ filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
126
+ color: #fff;
127
+ text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);
128
+ }
129
+ .datepicker td span.active:hover,
130
+ .datepicker td span.active:active,
131
+ .datepicker td span.active.active,
132
+ .datepicker td span.active.disabled,
133
+ .datepicker td span.active[disabled] {
134
+ background-color: #0044cc;
135
+ }
136
+ .datepicker td span.active:active, .datepicker td span.active.active {
137
+ background-color: #003399 \9;
138
+ }
139
+ .datepicker td span.old {
140
+ color: #999999;
141
+ }
142
+ .datepicker th.switch {
143
+ width: 145px;
144
+ }
145
+ .datepicker thead tr:first-child th {
146
+ cursor: pointer;
147
+ }
148
+ .datepicker thead tr:first-child th:hover {
149
+ background: #eeeeee;
150
+ }
151
+ .input-append.date .add-on i, .input-prepend.date .add-on i {
152
+ display: block;
153
+ cursor: pointer;
154
+ width: 16px;
155
+ height: 16px;
156
+ }
@@ -9,7 +9,22 @@ module BestBoy
9
9
 
10
10
  helper_method :available_owner_types, :available_events, :available_event_sources, :available_years, :current_owner_type,
11
11
  :current_event, :current_event_source, :current_year, :collection, :statistics, :stats_by_event_and_month,
12
- :stats_by_event_source_and_month, :render_chart, :event_source_details, :month_name_array
12
+ :stats_by_event_source_and_month, :render_chart, :event_source_details, :month_name_array, :detail_count,
13
+ :current_month, :stats_by_event_source_and_day
14
+
15
+ def monthly_details
16
+ data_table = GoogleVisualr::DataTable.new
17
+ data_table.new_column('string', 'time')
18
+ available_event_sources.each do |source|
19
+ data_table.new_column('number', source.to_s)
20
+ end
21
+
22
+ (1..(Time.days_in_month("1-#{current_month}-#{current_year}".to_time.month))).each do |periode|
23
+ time = "#{periode}-#{current_month}-#{current_year}".to_time
24
+ data_table.add_row( [ periode.to_s] + available_event_sources.map{ |source| custom_data_count(source, time)})
25
+ end
26
+ @chart = GoogleVisualr::Interactive::AreaChart.new(data_table, { width: 900, height: 240, title: "" })
27
+ end
13
28
 
14
29
  private
15
30
 
@@ -17,6 +32,16 @@ module BestBoy
17
32
  chart.to_js(dom).html_safe
18
33
  end
19
34
 
35
+ def prepare_chart
36
+ data_table = GoogleVisualr::DataTable.new
37
+ data_table.new_column('string', 'time')
38
+ data_table.new_column('number', current_owner_type.to_s)
39
+ time_periode_range.each do |periode|
40
+ data_table.add_row([chart_legend_time_name(periode), custom_data_count(current_event_source, calculated_point_in_time(periode))])
41
+ end
42
+ @chart = GoogleVisualr::Interactive::AreaChart.new(data_table, { width: 900, height: 240, title: "" })
43
+ end
44
+
20
45
  def week_name_array
21
46
  %w(Mon Tue Wed Thu Fri Sat Sun)
22
47
  end
@@ -25,10 +50,10 @@ module BestBoy
25
50
  %w(Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec)
26
51
  end
27
52
 
28
- def custom_data_count(time)
53
+ def custom_data_count(source, time)
29
54
  scope = BestBoyEvent.where("best_boy_events.owner_type = ?", current_owner_type)
30
55
  scope = scope.where("best_boy_events.event = ?", current_event) if current_event.present?
31
- scope = scope.where("best_boy_events.event_source = ?", current_event_source) if current_event_source.present?
56
+ scope = scope.where("best_boy_events.event_source = ?", source) if source.present?
32
57
  scope = scope.send("per_#{ current_time_interval == "year" ? "month" : "day" }", time)
33
58
  scope.count
34
59
  end
@@ -71,9 +96,24 @@ module BestBoy
71
96
  BestBoyEvent.where("best_boy_events.owner_type = ? AND best_boy_events.event = ?", current_owner_type, event).per_month(date).count
72
97
  end
73
98
 
99
+ def stats_by_owner_and_event_and_event_source(source)
100
+ if source.present?
101
+ scope = BestBoyEvent.where("best_boy_events.owner_type = ? AND best_boy_events.event = ? AND best_boy_events.event_source = ?", current_owner_type, current_event, source)
102
+ else
103
+ scope = BestBoyEvent.where("best_boy_events.owner_type = ? AND best_boy_events.event = ? AND best_boy_events.event_source IS NULL", current_owner_type, current_event)
104
+ end
105
+ end
106
+
74
107
  def stats_by_event_source_and_month(source, month)
75
108
  date = "1-#{month}-#{current_year}".to_time
76
- BestBoyEvent.where("best_boy_events.owner_type = ? AND best_boy_events.event = ? AND best_boy_events.event_source = ?", current_owner_type, current_event, source).per_month(date).count
109
+ scope = stats_by_owner_and_event_and_event_source(source)
110
+ scope.per_month(date).count
111
+ end
112
+
113
+ def stats_by_event_source_and_day(source, day)
114
+ date = "#{day}-#{current_month}-#{current_year}".to_time
115
+ scope = stats_by_owner_and_event_and_event_source(source)
116
+ scope.per_day(date).count
77
117
  end
78
118
 
79
119
  def current_date
@@ -100,6 +140,10 @@ module BestBoy
100
140
  @current_year ||= available_years.include?(params[:year]) ? params[:year] : Time.zone.now.year
101
141
  end
102
142
 
143
+ def current_month
144
+ @current_month ||= month_name_array.include?(params[:month]) ? params[:month] : Time.zone.now.month
145
+ end
146
+
103
147
  def available_events
104
148
  @available_events ||= (
105
149
  scope = BestBoyEvent.where("best_boy_events.owner_type = ?", current_owner_type)
@@ -124,43 +168,48 @@ module BestBoy
124
168
  @available_owner_types ||= BestBoyEvent.select("DISTINCT best_boy_events.owner_type").order("best_boy_events.owner_type ASC").map(&:owner_type)
125
169
  end
126
170
 
171
+ def detail_count
172
+ @detail_count ||= current_scope({:owner_type => params[:owner_type], :event => params[:event]}).count
173
+ end
174
+
175
+ def current_scope(options = {})
176
+ options.each do |key, value|
177
+ instance_var = "@#{key}"
178
+ instance_variable_set(instance_var, value)
179
+ end
180
+
181
+ scope = BestBoyEvent
182
+ scope = scope.where("best_boy_events.owner_type = ?", @owner_type) if @owner_type.present?
183
+ scope = scope.where("best_boy_events.event = ?", @event) if @event.present?
184
+ scope = scope.where("best_boy_events.event_source = ?", @event_source) if @event_source.present?
185
+ scope = scope.per_day(@date) if @date.present?
186
+ scope
187
+ end
188
+
189
+ def prepare_details(base_collection, key, options = {})
190
+ array = Array.new
191
+ base_collection.each do |item|
192
+ scope = current_scope(options.to_a + [[key.to_sym, item]])
193
+ array.push([item, scope.count] + %w(year month week day).map{ |delimiter| scope.send("per_#{delimiter}", Time.zone.now).count })
194
+ end
195
+ array
196
+ end
197
+
127
198
  def collection
128
199
  @best_boy_events ||= (
129
- scope = BestBoyEvent
130
- scope = scope.where("best_boy_events.owner_type = ?", params[:owner_type]) if params[:owner_type].present?
131
- scope = scope.where("best_boy_events.event = ?", current_event) if current_event.present?
132
- scope = scope.per_day(current_date) if current_date.present?
200
+ scope = current_scope({:owner_type => params[:owner_type], :event_source => current_event, :date => current_date})
133
201
  scope = scope.order("best_boy_events.created_at DESC, best_boy_events.event ASC")
134
202
  scope.page(params[:page]).per(50)
135
203
  )
136
204
  end
137
205
 
138
206
  def statistics
139
- @statistics = Array.new
140
- available_events.each do |event|
141
- scope = BestBoyEvent.where("best_boy_events.owner_type = ? AND best_boy_events.event = ?", current_owner_type, event)
142
- @statistics.push([event, scope.count] + %w(year month week day).map{ |delimiter| scope.send("per_#{delimiter}", Time.zone.now).count })
143
- end
144
- @statistics
207
+ @statistics = prepare_details(available_events, "event", {:owner_type => current_owner_type})
145
208
  end
146
209
 
147
210
  def event_source_details
148
- @event_source_details = Array.new
149
- available_event_sources.each do |source|
150
- scope = BestBoyEvent.where("best_boy_events.owner_type = ? AND best_boy_events.event = ?", current_owner_type, current_event).where("best_boy_events.event_source = ?", source)
151
- @event_source_details.push([source, scope.count] + %w(year month week day).map{ |delimiter| scope.send("per_#{delimiter}", Time.zone.now).count })
152
- end
153
- @event_source_details
211
+ @event_source_details = prepare_details(available_event_sources, "event_source", {:owner_type => current_owner_type, :event => current_event})
154
212
  end
155
213
 
156
- def prepare_chart
157
- data_table = GoogleVisualr::DataTable.new
158
- data_table.new_column('string', 'time')
159
- data_table.new_column('number', current_owner_type.to_s)
160
- time_periode_range.each do |periode|
161
- data_table.add_row([chart_legend_time_name(periode), custom_data_count(calculated_point_in_time(periode))])
162
- end
163
- @chart = GoogleVisualr::Interactive::AreaChart.new(data_table, { width: 900, height: 240, title: "" })
164
- end
165
214
  end
166
215
  end
@@ -11,18 +11,21 @@
11
11
  <thead>
12
12
  <tr>
13
13
  <th>Source</th>
14
- <th>overall</th>
15
- <th>year</th>
16
- <th>month</th>
17
- <th>week</th>
18
- <th>day</th>
14
+ <th colspan="2">overall</th>
15
+ <th colspan="2">year</th>
16
+ <th colspan="2">month</th>
17
+ <th colspan="2">week</th>
18
+ <th colspan="2">day</th>
19
19
  </tr>
20
20
  </thead>
21
21
  <tbody>
22
22
  <% event_source_details.each do |best_boy_event_source| %>
23
23
  <tr>
24
24
  <% (0..5).each do |key| %>
25
- <td><%= best_boy_event_source[key] %></td>
25
+ <td><%= best_boy_event_source[key].present? ? best_boy_event_source[key] : "n.a." %></td>
26
+ <% if key != 0 %>
27
+ <td><%= number_with_precision((best_boy_event_source[key].to_f / detail_count) * 100, :precision => 2) %> %</td>
28
+ <% end %>
26
29
  <% end %>
27
30
  </tr>
28
31
  <% end %>
@@ -46,14 +49,14 @@
46
49
  <tr>
47
50
  <th>Event</th>
48
51
  <% month_name_array.each do |month| %>
49
- <th><%= month %></th>
52
+ <th><%= link_to month, best_boy_admin_monthly_details_path(:owner_type => current_owner_type, :event => current_event, :month => month, :year => current_year, :time_interval => "month") %></th>
50
53
  <% end %>
51
54
  </tr>
52
55
  </thead>
53
56
  <tbody>
54
57
  <% available_event_sources.each do |source| %>
55
58
  <tr>
56
- <td><%= source %></td>
59
+ <td><%= source.present? ? source : "n.a." %></td>
57
60
  <% %w(1 2 3 4 5 6 7 8 9 10 11 12).each do |month| %>
58
61
  <td><%= stats_by_event_source_and_month source, month %></td>
59
62
  <% end %>
@@ -0,0 +1,51 @@
1
+ <% content_for :javascripts do %>
2
+ <script src='https://www.google.com/jsapi'></script>
3
+ <% end %>
4
+
5
+ <div class="span12">
6
+ <div class="well">
7
+ <%= link_to "<< back to stats", best_boy_admin_stats_path(:owner_type => current_owner_type) %>
8
+ </div>
9
+ </div>
10
+
11
+ <div class="span12">
12
+ <div class="well">
13
+ <h3 class="pull-left">Detailed Statistics for <%= current_month %> <%= current_year %></h3>
14
+ <div class="pull-right">
15
+ <%= form_tag best_boy_admin_monthly_details_path, :method => :get do %>
16
+ <%= hidden_field_tag :owner_type, current_owner_type %>
17
+ <%= hidden_field_tag :event, current_event %>
18
+ <%= hidden_field_tag :time_interval, "month" %>
19
+ <%= select_tag :month, options_for_select(%w(Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec), :selected => current_month), :onchange => "submit();" %>
20
+ <%= select_tag :year, options_for_select(available_years, :selected => current_year), :onchange => "submit();" %>
21
+ <% end %>
22
+ </div>
23
+ <table class="table table-striped table-bordered small-font">
24
+ <thead>
25
+ <tr>
26
+ <th>Event</th>
27
+ <% (1..(Time.days_in_month("1-#{current_month}-#{current_year}".to_time.month))).each do |day| %>
28
+ <td><%= day %></td>
29
+ <% end %>
30
+ </tr>
31
+ </thead>
32
+ <tbody>
33
+ <% available_event_sources.each do |source| %>
34
+ <tr>
35
+ <td><%= source.present? ? source : "n.a." %></td>
36
+ <% (1..(Time.days_in_month("1-#{current_month}-#{current_year}".to_time.month))).each do |day| %>
37
+ <td><%= stats_by_event_source_and_day source, day %></td>
38
+ <% end %>
39
+ </tr>
40
+ <% end %>
41
+ </tbody>
42
+ </table>
43
+ </div>
44
+ </div>
45
+
46
+ <div class="span12">
47
+ <div class="well">
48
+ <div id='chart'></div>
49
+ <%= render_chart(@chart, 'chart') %>
50
+ </div>
51
+ </div>
@@ -10,6 +10,9 @@
10
10
  <%= yield :stylesheets %>
11
11
  <%= yield :javascripts %>
12
12
  <style>
13
+ .small-font {
14
+ font-size: 9px;
15
+ }
13
16
  /* FIX for kaminari gem */
14
17
  nav.pagination {
15
18
  text-align: center;
@@ -1,7 +1,8 @@
1
- Rails.application.routes.draw do |map|
1
+ Rails.application.routes.draw do
2
2
  get "best_boy_admin" => "best_boy/best_boy_events#index", :as => :best_boy_admin
3
3
  get "best_boy_admin/stats" => "best_boy/best_boy_events#stats", :as => :best_boy_admin_stats
4
4
  get "best_boy_admin/lists" => "best_boy/best_boy_events#lists", :as => :best_boy_admin_lists
5
5
  get "best_boy_admin/charts" => "best_boy/best_boy_events#charts", :as => :best_boy_admin_charts
6
6
  get "best_boy_admin/details" => "best_boy/best_boy_events#details", :as => :best_boy_admin_details
7
+ get "best_boy_admin/monthly_details" => "best_boy/best_boy_events#monthly_details", :as => :best_boy_admin_monthly_details
7
8
  end
Binary file
@@ -1,3 +1,3 @@
1
1
  module BestBoy
2
- VERSION = "0.2.2"
2
+ VERSION = "0.3.0"
3
3
  end
@@ -4,14 +4,19 @@ module BestBoy
4
4
  hook_for :orm
5
5
  source_root File.expand_path('../templates', __FILE__)
6
6
 
7
+ class_option :asset_pipeline, :type => :string, :aliases => "-a", :desc => "skip template creation due asset pipeline use", :default => "asset"
8
+ class_option :asset, :type => :boolean, :default => false
9
+
7
10
  def copy_config_file
8
11
  template 'best_boy.rb', 'config/initializers/best_boy.rb'
9
- template 'bootstrap/glyphicons-halflings-white.png', 'public/images/bootstrap/glyphicons-halflings-white.png'
10
- template 'bootstrap/glyphicons-halflings.png', 'public/images/bootstrap/glyphicons-halflings.png'
11
- template 'bootstrap/bootstrap.css', 'public/stylesheets/bootstrap.css'
12
- #datepicker by Stefan Petre (http://www.eyecon.ro/bootstrap-datepicker)
13
- template 'bootstrap/bootstrap_datepicker.css', 'public/stylesheets/bootstrap_datepicker.css'
14
- template 'bootstrap/bootstrap_datepicker.js', 'public/javascripts/bootstrap_datepicker.js'
12
+ if not options[:asset_pipeline] == "asset" or not options[:asset]
13
+ template 'bootstrap/glyphicons-halflings-white.png', 'public/images/bootstrap/glyphicons-halflings-white.png'
14
+ template 'bootstrap/glyphicons-halflings.png', 'public/images/bootstrap/glyphicons-halflings.png'
15
+ template 'bootstrap/bootstrap.css', 'public/stylesheets/bootstrap.css'
16
+ #datepicker by Stefan Petre (http://www.eyecon.ro/bootstrap-datepicker)
17
+ template 'bootstrap/bootstrap_datepicker.css', 'public/stylesheets/bootstrap_datepicker.css'
18
+ template 'bootstrap/bootstrap_datepicker.js', 'public/javascripts/bootstrap_datepicker.js'
19
+ end
15
20
  end
16
21
  end
17
22
  end