best_boy 0.2.2 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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