conschedule 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (77) hide show
  1. checksums.yaml +7 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README.md +154 -0
  4. data/Rakefile +37 -0
  5. data/app/assets/config/conschedule_manifest.js +2 -0
  6. data/app/assets/fonts/icomoon.eot +0 -0
  7. data/app/assets/fonts/proxima_nova_100.eot +0 -0
  8. data/app/assets/fonts/proxima_nova_400.eot +0 -0
  9. data/app/assets/fonts/proxima_nova_700.eot +0 -0
  10. data/app/assets/images/conschedule/chosen-sprite-small.png +0 -0
  11. data/app/assets/images/conschedule/chosen-sprite.png +0 -0
  12. data/app/assets/images/conschedule/close.png +0 -0
  13. data/app/assets/images/conschedule/spinner-small.gif +0 -0
  14. data/app/assets/images/conschedule/spinner.gif +0 -0
  15. data/app/assets/javascripts/conschedule/application.js +22 -0
  16. data/app/assets/javascripts/conschedule/calendar.js +467 -0
  17. data/app/assets/javascripts/conschedule/date.js +104 -0
  18. data/app/assets/javascripts/conschedule/form.js +53 -0
  19. data/app/assets/javascripts/conschedule/home.js +149 -0
  20. data/app/assets/javascripts/conschedule/jquery-ui-datepicker.min.js +1674 -0
  21. data/app/assets/javascripts/conschedule/jquery.easing.min.js +44 -0
  22. data/app/assets/javascripts/conschedule/jquery.validate.js +1532 -0
  23. data/app/assets/javascripts/conschedule/js_time_zone.js +1433 -0
  24. data/app/assets/javascripts/conschedule/moment-timezone.js +1209 -0
  25. data/app/assets/javascripts/conschedule/moment.js +4195 -0
  26. data/app/assets/javascripts/conschedule/schedules.js +22 -0
  27. data/app/assets/javascripts/conschedule/time_zones_drop_down.js +609 -0
  28. data/app/assets/stylesheets/conschedule/application.css +4 -0
  29. data/app/assets/stylesheets/conschedule/common.css +816 -0
  30. data/app/assets/stylesheets/conschedule/home.css +2441 -0
  31. data/app/assets/stylesheets/conschedule/main.css +884 -0
  32. data/app/assets/stylesheets/conschedule/schedules.css +4 -0
  33. data/app/controllers/conschedule/application_controller.rb +49 -0
  34. data/app/controllers/conschedule/schedules_controller.rb +125 -0
  35. data/app/helpers/conschedule/application_helper.rb +15 -0
  36. data/app/helpers/conschedule/schedules_helper.rb +43 -0
  37. data/app/jobs/conschedule/application_job.rb +4 -0
  38. data/app/mailers/conschedule/schedules_mailer.rb +46 -0
  39. data/app/models/conschedule/application_record.rb +5 -0
  40. data/app/models/conschedule/schedule.rb +63 -0
  41. data/app/views/conschedule/schedules/_confirmation.html.erb +38 -0
  42. data/app/views/conschedule/schedules/_page_one.html.erb +75 -0
  43. data/app/views/conschedule/schedules/_page_three.html.erb +94 -0
  44. data/app/views/conschedule/schedules/_page_two.html.erb +22 -0
  45. data/app/views/conschedule/schedules/_schedules.html.erb +122 -0
  46. data/app/views/conschedule/schedules/create.js.erb +11 -0
  47. data/app/views/conschedule/schedules/index.html.erb +123 -0
  48. data/app/views/conschedule/schedules/index.js.erb +3 -0
  49. data/app/views/conschedule/schedules/new.html.erb +11 -0
  50. data/app/views/conschedule/schedules_mailer/send_cancel_email_owner.html.erb +61 -0
  51. data/app/views/conschedule/schedules_mailer/send_cancel_email_user.html.erb +29 -0
  52. data/app/views/conschedule/schedules_mailer/send_confirmation_email_owner.html.erb +77 -0
  53. data/app/views/conschedule/schedules_mailer/send_confirmation_email_user.html.erb +30 -0
  54. data/app/views/kaminari/custom_theme/_first_page.html.erb +3 -0
  55. data/app/views/kaminari/custom_theme/_gap.html.erb +1 -0
  56. data/app/views/kaminari/custom_theme/_last_page.html.erb +3 -0
  57. data/app/views/kaminari/custom_theme/_next_page.html.erb +1 -0
  58. data/app/views/kaminari/custom_theme/_page.html.erb +5 -0
  59. data/app/views/kaminari/custom_theme/_paginator.html.erb +23 -0
  60. data/app/views/kaminari/custom_theme/_prev_page.html.erb +1 -0
  61. data/app/views/layouts/conschedule/application.html.erb +14 -0
  62. data/app/views/layouts/conschedule/mailer.html.erb +11 -0
  63. data/app/views/layouts/conschedule/schedules.html.erb +14 -0
  64. data/config/initializers/assets.rb +11 -0
  65. data/config/routes.rb +11 -0
  66. data/db/migrate/20160812085505_create_conschedule_schedules.rb +27 -0
  67. data/lib/conschedule.rb +34 -0
  68. data/lib/conschedule/configuration.rb +25 -0
  69. data/lib/conschedule/engine.rb +5 -0
  70. data/lib/conschedule/gem_dependencies.rb +2 -0
  71. data/lib/conschedule/version.rb +3 -0
  72. data/lib/generators/conschedule/install_generator.rb +23 -0
  73. data/lib/generators/conschedule/views_generator.rb +45 -0
  74. data/lib/generators/templates/README +40 -0
  75. data/lib/generators/templates/initializer.rb +25 -0
  76. data/lib/tasks/conschedule_tasks.rake +4 -0
  77. metadata +182 -0
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 93620dd4e9b1866e48c1b3d48271803f1429784c
4
+ data.tar.gz: a387a284eb4e5b8c0d00aadf9d89d7efb8dec04a
5
+ SHA512:
6
+ metadata.gz: 3051f2550ddb41658887a827d5bde6b8cab6542b9d148d50bb97f1908439b09bc54366bf955a33f12000e16d7c8bc2e4a1f9b46e24e50924f4d9c4ea0f74401b
7
+ data.tar.gz: c794bf2dd5cd43c9b8024e9319f8ac48b50c87cbb03a2d8e9cd6d199dcbbb1fa09c5363a802971995e8c51dca7dbe71a3ad072d210714435531d57a0e1f0788a
@@ -0,0 +1,20 @@
1
+ Copyright 2016 Sakilam Sandeep
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,154 @@
1
+ # Conschedule
2
+
3
+ Conschedule library for Rails
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ ```ruby
10
+ gem 'conschedule'
11
+ ```
12
+
13
+ And then execute:
14
+
15
+ $ bundle
16
+
17
+ Or install it yourself as:
18
+
19
+ $ gem install conschedule
20
+
21
+ ## Embedding in a Rails app
22
+
23
+ Add the following to your routes.rb file:
24
+
25
+ ``` ruby
26
+ mount Conschedule::Engine, at: "/"
27
+ ```
28
+
29
+ (NOTE: You may mount the server at any path, not just "/")
30
+
31
+ You can then browse to your application path to view listing page, conschedule form page i.e.
32
+
33
+ * For listing page: http://127.0.0.1:3000
34
+ * For contact form page: http://127.0.0.1:3000/schedules/new
35
+
36
+ If you wish to authenticate listing page with Devise, it would look something like:
37
+
38
+ ``` ruby
39
+ authenticate :admin do
40
+ get "/admin/schedules" => "conschedule/schedules#index"
41
+ end
42
+ ```
43
+
44
+ ## Configuration
45
+
46
+ Conschedule is extremely simple to setup. Just configure basic settings for Conschedule:
47
+
48
+ ```ruby
49
+ Conschedule.configuration do |config|
50
+ config.main_heading = "Contact"
51
+ config.purpose = 'An introduction to our product'
52
+ config.instructions = 'Learn about our product'
53
+ config.location_details = 'Details will be provided on confirmation'
54
+ config.system_time_zone = "UTC"
55
+ config.start_date = "2016-01-01"
56
+ config.end_date = "2016-12-31"
57
+ config.available_days = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"]
58
+ config.black_out_dates
59
+ config.sun_timings = ["09:00", "17:00"]
60
+ config.mon_timings = ["09:00", "17:00"]
61
+ config.tue_timings = ["09:00", "17:00"]
62
+ config.wed_timings = ["09:00", "17:00"]
63
+ config.thu_timings = ["09:00", "17:00"]
64
+ config.fri_timings = ["09:00", "17:00"]
65
+ config.sat_timings = ["09:00", "17:00"]
66
+ config.duration = 30
67
+ config.from_address = "PLEASE-CHANGE-ME@example.com"
68
+ config.send_confirmation_mail = false
69
+ config.send_cancel_mail = false
70
+ config.to_address = "PLEASE-CHANGE-ME@example.com"
71
+ config.contact_name = "PLEASE-CHANGE-ME"
72
+ config.enable_tz = true
73
+ end
74
+ ```
75
+
76
+ The key options available are:
77
+
78
+ | Option | Description |
79
+ | ----------------- | ------------------------------- |
80
+ | `main_heading` | String to add page heading/title. |
81
+ | `instructions` | String to convey a message to user. |
82
+ | `location_details` | String to provide location details to user. |
83
+ | `system_time_zone` | TimeZone defines time zone of the application. |
84
+ | `start_date` | Date defines the start date of the calendar. |
85
+ | `end_date` | Date defines the end date of the calendar. |
86
+ | `available_days` | Array of abbreviated weekday name. |
87
+ | `black_out_dates` | Array of dates to mark unavailable dates in calendar. |
88
+ | `sun_timings` | Array of times defines start and end time of weekday Sunday. |
89
+ | `mon_timings` | Array of times defines start and end time of weekday Monday. |
90
+ | `tue_timings` | Array of times defines start and end time of weekday Tuesday. |
91
+ | `wed_timings` | Array of times defines start and end time of weekday Wednesday. |
92
+ | `thu_timings` | Array of times defines start and end time of weekday Thursday. |
93
+ | `fri_timings` | Array of times defines start and end time of weekday Friday. |
94
+ | `sat_timings` | Array of times defines start and end time of weekday Saturday. |
95
+ | `duration` | Integer defines duration of the slot in minutes. |
96
+ | `from_address` | String for sending confirmation and cancel mails. |
97
+ | `send_confirmation_mail` | Boolean defines wheather a copy of confirmation mail to be sent to the 'to_address'. |
98
+ | `send_cancel_mail` | Boolean defines wheather a copy of cancel mail to be sent to the 'to_address'. |
99
+ | `to_address` | String for receving confirmation and cancel mails. |
100
+ | `contact_name` | String used in confirmation and cancel mails. |
101
+ | `enable_tz` | Boolean defines wheather the time zone drop down should be active/inactive. |
102
+
103
+ Ensure you have set 'from_address' and 'contact_name' in config/initializers/conschedule.rb
104
+
105
+ ```ruby
106
+ config.from_address = "foo@example.com"
107
+ config.contact_name = "foo"
108
+ ```
109
+
110
+ If you wish to receive confirmation and cancel mails, ensure you have set following config variables in config/initializers/conschedule.rb:
111
+
112
+ ```ruby
113
+ config.send_confirmation_mail = true
114
+ config.send_cancel_mail = true
115
+ config.to_address = "foo@example.com"
116
+ ```
117
+
118
+ ## Customization
119
+
120
+ We built Conschedule to help you quickly integrate contact form in your application. However, we don't want to be in your way when you need to customize it.
121
+
122
+ Since Conschedule is an engine, all its views are packaged inside the gem. These views will help you get started, but after some time you may want to change them. If this is the case, you just need to invoke the following generator, and it will copy all views to your application:
123
+
124
+ ```console
125
+ $ rails generate conschedule:views
126
+ ```
127
+
128
+ If you would like to generate only a few sets of views, like the ones for the `form` and `listing`,
129
+ you can pass a list of names to the generator with the `-v` flag.
130
+
131
+ ```console
132
+ $ rails generate conschedule:views -v form listing
133
+ ```
134
+
135
+ ## Contributing
136
+
137
+ 1. Fork it ( https://github.com/rubyeffect/conschedule/fork )
138
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
139
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
140
+ 4. Push to the branch (`git push origin my-new-feature`)
141
+ 5. Create a new Pull Request
142
+
143
+ ## Links
144
+
145
+ * Code: `git clone git://github.com/rubyeffect/conschedule.git`
146
+ * Home: <http://github.com/rubyeffect/conschedule>
147
+
148
+ ## About RubyEffect
149
+
150
+ ![RubyEffect](http://blog.rubyeffect.com/wp-content/uploads/2015/05/cropped-re_original_logo.png)
151
+
152
+ RubyEffect builds intuitive, live and elegant software that solves real world problems. We love open source and it's community.
153
+
154
+ We would love to work on your ideas and see them grow. Say hello @ http://rubyeffect.com/contact
@@ -0,0 +1,37 @@
1
+ begin
2
+ require 'bundler/setup'
3
+ rescue LoadError
4
+ puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
5
+ end
6
+
7
+ require 'rdoc/task'
8
+
9
+ RDoc::Task.new(:rdoc) do |rdoc|
10
+ rdoc.rdoc_dir = 'rdoc'
11
+ rdoc.title = 'Conschedule'
12
+ rdoc.options << '--line-numbers'
13
+ rdoc.rdoc_files.include('README.md')
14
+ rdoc.rdoc_files.include('lib/**/*.rb')
15
+ end
16
+
17
+ APP_RAKEFILE = File.expand_path("../test/dummy/Rakefile", __FILE__)
18
+ load 'rails/tasks/engine.rake'
19
+
20
+
21
+ load 'rails/tasks/statistics.rake'
22
+
23
+
24
+
25
+ require 'bundler/gem_tasks'
26
+
27
+ require 'rake/testtask'
28
+
29
+ Rake::TestTask.new(:test) do |t|
30
+ t.libs << 'lib'
31
+ t.libs << 'test'
32
+ t.pattern = 'test/**/*_test.rb'
33
+ t.verbose = false
34
+ end
35
+
36
+
37
+ task default: :test
@@ -0,0 +1,2 @@
1
+ //= link_directory ../javascripts/conschedule .js
2
+ //= link_directory ../stylesheets/conschedule .css
@@ -0,0 +1,22 @@
1
+ // This is a manifest file that'll be compiled into application.js, which will include all the files
2
+ // listed below.
3
+ //
4
+ // Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts,
5
+ // or any plugin's vendor/assets/javascripts directory can be referenced here using a relative path.
6
+ //
7
+ // It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
8
+ // compiled file. JavaScript code in this file should be added after the last require_* statement.
9
+ //
10
+ // Read Sprockets README (https://github.com/rails/sprockets#sprockets-directives) for details
11
+ // about supported directives.
12
+ //
13
+ //= require jquery
14
+ //= require jquery_ujs
15
+ //= require conschedule/jquery.easing.min
16
+ //= require conschedule/moment
17
+ //= require conschedule/moment-timezone
18
+ //= require conschedule/jquery.validate
19
+ //= require conschedule/js_time_zone
20
+ //= require conschedule/date
21
+ //= require conschedule/jquery-ui-datepicker.min
22
+ //= require conschedule/home
@@ -0,0 +1,467 @@
1
+ var page_info = gon.page_info;
2
+ if (page_info.enable_tz) {
3
+ var user_tz = jstz.determine().name();
4
+ }
5
+ else {
6
+ var user_tz = page_info.system_time_zone;
7
+ }
8
+ var calendar_data, selected_date, formatted_tz, slot_date, slot_start_time, slot_end_time;
9
+
10
+ function is_null_or_undef(variable) {
11
+ return (variable === null || variable === undefined);
12
+ }
13
+
14
+ function build_calendar(sequence) {
15
+ var date = start_date();
16
+ var no_of_days = 6;
17
+ var count = 0;
18
+ var dates_set = [];
19
+ while (dates_set.length <= no_of_days) {
20
+ if (!black_out_day(moment(date).format("ddd"))) {
21
+ dates_set.push(date);
22
+ count += 1;
23
+ }
24
+ date = sequence == "forward" ? tomorrow(date) : yesterday(date);
25
+ }
26
+ if ( sequence == "backward" ) {
27
+ dates_set = dates_set.reverse();
28
+ }
29
+ calendar_data = build_dates_set(dates_set);
30
+ generate_dates_template(calendar_data.days,calendar_data.today);
31
+ }
32
+
33
+ function start_date() {
34
+ return is_null_or_undef(page_info.start_date) ? user_cdt("YYYY-MM-DD") : moment.tz(page_info.start_date,page_info.system_time_zone).format("YYYY-MM-DD") < system_cdt("YYYY-MM-DD") ? system_cdt("YYYY-MM-DD") : moment.tz(page_info.start_date,page_info.system_time_zone).format("YYYY-MM-DD");
35
+ }
36
+
37
+ function end_date() {
38
+ return is_null_or_undef(page_info.end_date) ? null : moment.tz(page_info.end_date,page_info.system_time_zone).format("YYYY-MM-DD");
39
+ }
40
+
41
+ function user_cdt(pattern) {
42
+ return moment.tz(user_tz).format(pattern);
43
+ }
44
+
45
+ function system_cdt(pattern) {
46
+ return moment.tz(page_info.system_time_zone).format(pattern);
47
+ }
48
+
49
+ function black_out_day(weekday) {
50
+ return $.inArray(weekday, page_info.available_days) == -1
51
+ }
52
+
53
+ function tomorrow(date) {
54
+ return moment.tz(date,user_tz).add(1, 'days').format("YYYY-MM-DD");
55
+ }
56
+
57
+ function yesterday(date) {
58
+ return moment.tz(date,user_tz).add(-1, 'days').format("YYYY-MM-DD");
59
+ }
60
+
61
+ function build_dates_set(dates) {
62
+ if ( is_null_or_undef(page_info.calendar_start_date) ) {
63
+ page_info.calendar_start_date = dates[0];
64
+ }
65
+ data = {today: user_cdt("YYYY-MM-DD"), days: [], weeks: []};
66
+ var time_slots;
67
+ $.each(dates, function( index, date ) {
68
+ time_slots = get_time_slots(date);
69
+ day_set = {
70
+ date: date,
71
+ day_short: date_format(moment.tz(date,user_tz),"day_short"),
72
+ day_full: date_format(moment.tz(date,user_tz),"day_full"),
73
+ date_short: date_format(moment.tz(date,user_tz),"date_short"),
74
+ date_short_lz: date_format(moment.tz(date,user_tz),"date_short_lz"),
75
+ date_full: date_format(moment.tz(date,user_tz),"date_full"),
76
+ slots: time_slots,
77
+ status: get_day_status(date,end_date(),time_slots.availability),
78
+ separator: is_separator_point(date, dates[index + 1], index)
79
+ }
80
+ data.days.push(day_set);
81
+ if ( day_set.separator == "separator" || index == 6 ) {
82
+ data.weeks.push(build_labels_set(data.days,data.weeks,date));
83
+ }
84
+ });
85
+ return data;
86
+ }
87
+
88
+ function get_time_slots(date) {
89
+ var day = moment(date).format("ddd").toLowerCase();
90
+ var slots = {morning: [], noon: [], availability: true};
91
+ var slot_value;
92
+ if ( system_cdt("YYYY-MM-DD HH:mm") < day_end_time(day,date,false)) {
93
+ if ( date == system_cdt("YYYY-MM-DD") ) {
94
+ var computed_start_time = moment.tz(page_info.system_time_zone).tz(user_tz).format("YYYY-MM-DD HH:mm");
95
+ }
96
+ var start_time = day_start_time(day,date,true);
97
+ var end_time = day_end_time(day,date,true);
98
+ while (start_time < end_time) {
99
+ if ( is_null_or_undef(computed_start_time) ) {
100
+ slot_value = moment(start_time).format("hh:mma");
101
+ }
102
+ else {
103
+ if ( start_time > computed_start_time ) {
104
+ slot_value = moment(start_time).format("hh:mma");
105
+ }
106
+ }
107
+ if ( !is_null_or_undef(slot_value) ) {
108
+ if ( slot_value.search('am') != -1 ) {
109
+ slots.morning.push(slot_value);
110
+ }
111
+ else {
112
+ slots.noon.push(slot_value);
113
+ }
114
+ }
115
+ start_time = moment(start_time).add(page_info.duration, 'minutes').format("YYYY-MM-DD HH:mm");
116
+ }
117
+ }
118
+ if ( slots.morning.length == 0 && slots.noon.length == 0 ) {
119
+ slots.availability = false;
120
+ }
121
+ return slots;
122
+ }
123
+
124
+ function timings(day,position) {
125
+ var duration = day + "_timings";
126
+ return position == "start" ? page_info[duration][0] : page_info[duration][1];
127
+ }
128
+
129
+ function day_start_time(day,date,converted) {
130
+ var day_start_time = timings(day,'start');
131
+ var date_time = date + " " + day_start_time;
132
+ var dt_str;
133
+ if ( converted ) {
134
+ dt_str = moment.tz(date_time,page_info.system_time_zone).tz(user_tz).format("YYYY-MM-DD HH:mm");
135
+ }
136
+ else {
137
+ dt_str = moment.tz(date_time,page_info.system_time_zone).format("YYYY-MM-DD HH:mm");
138
+ }
139
+ return dt_str;
140
+ }
141
+
142
+ function day_end_time(day,date,converted) {
143
+ var day_end_time = timings(day,'end');
144
+ var date_time = date + " " + day_end_time;
145
+ var dt_str;
146
+ if ( converted ) {
147
+ dt_str = moment.tz(date_time,page_info.system_time_zone).tz(user_tz).format("YYYY-MM-DD HH:mm");
148
+ }
149
+ else {
150
+ dt_str = moment.tz(date_time,page_info.system_time_zone).format("YYYY-MM-DD HH:mm");
151
+ }
152
+ return dt_str;
153
+ }
154
+
155
+ function date_format(date, format) {
156
+ var date_str;
157
+ switch (format) {
158
+ case "day_short":
159
+ date_str = date.format("ddd");
160
+ break;
161
+ case "day_full":
162
+ date_str = date.format("dddd");
163
+ break;
164
+ case "date":
165
+ date_str = date.format("YYYY-MM-DD");
166
+ break;
167
+ case "date_time":
168
+ date_str = date.format("YYYY-MM-DD HH:mm");
169
+ break;
170
+ case "date_short":
171
+ date_str = date.format("MMM D");
172
+ break;
173
+ case "date_short_lz":
174
+ date_str = date.format("MMM DD");
175
+ break;
176
+ case "date_full":
177
+ date_str = date.format("MMMM D, YYYY");
178
+ break;
179
+ }
180
+ return date_str;
181
+ }
182
+
183
+ function get_day_status(date,finish_date,availability) {
184
+ return (date > finish_date || $.inArray(date, black_out_dates()) != -1 || availability == false) ? 'unavailable' : 'available'
185
+ }
186
+
187
+ function black_out_dates() {
188
+ dates = []
189
+ if ( !$.isEmptyObject(page_info.black_out_dates) ) {
190
+ $.each(page_info.black_out_dates, function( index, date ) {
191
+ dates.push(date_format(moment.tz(date,user_tz),"date"));
192
+ });
193
+ }
194
+ return dates;
195
+ }
196
+
197
+ function is_separator_point(date, next_date, count) {
198
+ return is_null_or_undef(next_date) ? "no-separator" : (week_number(date) != week_number(next_date) && count != 6) ? "separator" : "no-separator"
199
+ }
200
+
201
+ function week_number(date) {
202
+ return moment.tz(date,user_tz).isoWeek()
203
+ }
204
+
205
+ function build_labels_set(days,weeks,date) {
206
+ if ( $.isEmptyObject(weeks) ) {
207
+ var label = page_info.calendar_start_date == days[0].date ? "this week" : get_week_label(date);
208
+ var set = {label: label, "length": days.length};
209
+ }
210
+ else {
211
+ var total_length = 0;
212
+ $.each(weeks, function( index, week ) {
213
+ total_length += week.length;
214
+ });
215
+ var set = {label: get_week_label(date), "length": days.length - total_length};
216
+ }
217
+ return set;
218
+ }
219
+
220
+ function generate_dates_template(days,today_date) {
221
+ var ele = $('.js-days-body');
222
+ $.each(days, function( index, day ) {
223
+ var outer_html = '<div class="fraction js-day-wrapper ' + day.status + ' ' + day.separator + '"></div>';
224
+ if ( day.date === today_date ) {
225
+ var today_html = '<div class="today">– TODAY –</div>';
226
+ outer_html = $(outer_html).append(today_html);
227
+ }
228
+ var day_html = '<div class="day js-show-picker"></div>';
229
+ var day_full_html = '<div></div>';
230
+ var day_short_html = '<strong class="shorthand">' + day.day_short + '</strong><strong class="full">' + day.day_full + '</strong>';
231
+ day_full_html = $(day_full_html).append(day_short_html);
232
+ if ( day.date === today_date ) {
233
+ today_html = '<strong class="today-mobile">(TODAY)</strong>';
234
+ day_full_html = $(day_full_html).append(today_html);
235
+ }
236
+ day_html = $(day_html).append(day_full_html);
237
+ var date_html = '<div><div class="muted shorthand">' + day.date_short + '</div><div class="muted full">' + day.date_full + '</div></div>';
238
+ day_html = $(day_html).append(date_html);
239
+ var right_icon_html = '<i class="icon-arrow-right"></i>';
240
+ day_html = $(day_html).append(right_icon_html);
241
+ outer_html = $(outer_html).append(day_html);
242
+ if ( day.status === "unavailable" ) {
243
+ var status_html = '<span class="status">unavailable</span>';
244
+ outer_html = $(outer_html).append(status_html);
245
+ }
246
+ $('.js-spinner').addClass('hidden');
247
+ $('.js-navigation-prev').show();
248
+ $('.js-navigation-next').show();
249
+ $(ele).append(outer_html);
250
+ });
251
+ generate_labels_template(calendar_data.weeks);
252
+ }
253
+
254
+ function generate_labels_template(weeks) {
255
+ $(".js-weeks-region").html('<div><div class="scale"></div>');
256
+ var scale = $('.scale');
257
+ $.each(weeks, function( index, week ) {
258
+ var label_html = '<div class="division size' + week.length +'of7"><span class="label">' + week.label + '</span></div>';
259
+ scale.append(label_html);
260
+ });
261
+ load_calendar_navigation();
262
+ }
263
+
264
+ function calendar_date(order,format) {
265
+ var day = order == "start" ? calendar_data.days[0] : calendar_data.days[calendar_data.days.length - 1];
266
+ var date_str;
267
+ switch (format) {
268
+ case "date":
269
+ date_str = day.date;
270
+ break;
271
+ case "short_date_lz":
272
+ date_str = day.date_short_lz;
273
+ break;
274
+ }
275
+ return date_str;
276
+ }
277
+
278
+ function calendar_loader() {
279
+ $('.js-spinner').removeClass('hidden');
280
+ $('.js-navigation-prev').hide();
281
+ $('.js-navigation-next').hide();
282
+ $('.js-pagination-bar').empty();
283
+ $('.js-weeks-region').empty();
284
+ $('.js-days-body').empty();
285
+ }
286
+
287
+ function load_calendar_navigation() {
288
+ var left_navigation = '<strong class="left" data-nav="previous"><i class="icon-arrow-left-fill"></i>Before <span class="js-period-start-caption">' + calendar_date("start","short_date_lz") + '</span></strong>';
289
+ var right_navigation = '<strong class="right" data-nav="next">After <span class="js-period-end-caption">' + calendar_date("end","short_date_lz") + '</span><i class="icon-arrow-right-fill"></i></strong>';
290
+ $(".js-pagination-bar").append(left_navigation);
291
+ $(".js-pagination-bar").append(right_navigation);
292
+ if ( calendar_date("start","date") != page_info.calendar_start_date ) {
293
+ $('.js-navigation-prev').removeClass('disabled');
294
+ $('.left').removeClass('disabled');
295
+ }
296
+ else {
297
+ $('.js-navigation-prev').addClass('disabled');
298
+ $('.left').addClass('disabled');
299
+ }
300
+ calendar_bind_events();
301
+ }
302
+
303
+ function initialize_calendar(sequence) {
304
+ setTimeout(function() {
305
+ build_calendar(sequence);
306
+ }, 1000);
307
+ }
308
+
309
+ function get_week_label(date) {
310
+ var start_week_number = week_number(page_info.calendar_start_date);
311
+ var current_week_number = week_number(date);
312
+ var difference = current_week_number - start_week_number;
313
+ var week_str;
314
+ if ( difference == 1 ) {
315
+ week_str = "next week";
316
+ }
317
+ else {
318
+ week_str = difference + " weeks out";
319
+ }
320
+ return week_str;
321
+ }
322
+
323
+ function navigate(direction) {
324
+ calendar_loader();
325
+ page_info.start_date = direction == "forward" ? tomorrow(calendar_date("end","date")) : yesterday(calendar_date('start',"date"));
326
+ initialize_calendar(direction);
327
+ }
328
+
329
+ function load_calendar_tz(time_zone) {
330
+ user_tz = time_zone;
331
+ calendar_loader();
332
+ page_info.start_date = page_info.original_start_date;
333
+ initialize_calendar("forward");
334
+ }
335
+
336
+ function generate_date_slots_template(index) {
337
+ var time_slots = calendar_data.days[index].slots;
338
+ var am_template = $('<div class="js-am-spot-list"><ul class="spots"></ul></div>');
339
+ var pm_template = $('<div class="js-pm-spot-list"><ul class="spots"></ul></div>');
340
+ if ( time_slots.morning.length != 0 ) {
341
+ $.each(time_slots.morning, function( index, time ) {
342
+ am_template.find("ul.spots").append('<li class="spot available collapsed"><button class="time-button js-select">' + time + '<div class="status">available</div></button><button class="confirm-button hollow base js-confirm">Confirm</button></li>');
343
+ $('.js-spot-list').append(am_template);
344
+ });
345
+ }
346
+ if ( time_slots.morning.length != 0 && time_slots.noon.length != 0 ) {
347
+ $('.js-spot-list').append('<div class="js-meridiem meridiem" style="display: block;"><div class="text">noon</div></div>');
348
+ }
349
+ if ( time_slots.noon.length != 0 ) {
350
+ $.each(time_slots.noon, function( index, time ) {
351
+ pm_template.find("ul.spots").append('<li class="spot available collapsed"><button class="time-button js-select">' + time + '<div class="status">available</div></button><button class="confirm-button hollow base js-confirm">Confirm</button></li>');
352
+ $('.js-spot-list').append(pm_template);
353
+ });
354
+ }
355
+ time_slot_bind_events();
356
+ }
357
+
358
+ function calendar_bind_events() {
359
+ $('.right').on('click', function(){
360
+ navigate("forward");
361
+ });
362
+ $('.left').on('click', function(){
363
+ navigate("backward");
364
+ });
365
+ $(".js-day-wrapper").click(function() {
366
+ if ( !$(this).hasClass('unavailable') ) {
367
+ $(".js-spot-list").empty();
368
+ selected_date = moment($(this).find('div.full').html(),"MMMM DD, YYYY").format("YYYY-MM-DD");
369
+ $(".selected_day").html(date_format(moment(selected_date),"day_full"));
370
+ $(".selected_date").html(date_format(moment(selected_date),"date_full"));
371
+ $(".selected_tz").html(format_tz($(".chzn-single span").html()));
372
+ slot_date = date_format(moment(selected_date),"date");
373
+ generate_date_slots_template($(".js-day-wrapper").index($(this)));
374
+ reset_state($(".spot:first"));
375
+ wizard_next_step($(this));
376
+ }
377
+ });
378
+ }
379
+
380
+ function time_slot_bind_events() {
381
+ $(".spot").click(function(e) {
382
+ e.preventDefault();
383
+ reset_state($(this));
384
+ $(this).addClass("selected");
385
+ $(this).find(".time-button").addClass("neutral")
386
+ });
387
+ $(".confirm-button").click(function() {
388
+ var time = $(this).parent().find(".time-button").clone().children().remove().end().text();
389
+ $("div.slot-details").html('<i class="icon-clock"></i>' + " " + time + " - " + date_format(moment(selected_date),"day_full") + ", " + date_format(moment(selected_date),"date_full"));
390
+ $("div.tz-details").html('<i class="icon-globe"></i>' + " " + formatted_tz);
391
+ slot_start_time = moment(time,"HH:mma").format("HH:mm");
392
+ slot_end_time = moment(time,"HH:mma").add(page_info.duration,'minutes').format("HH:mm");
393
+ wizard_next_step($(this));
394
+ });
395
+ }
396
+
397
+ function reset_state(ele) {
398
+ var spots = ele.parent();
399
+ spots.find(".selected").removeClass("selected");
400
+ spots.find(".neutral").removeClass("neutral");
401
+ }
402
+
403
+ function format_tz(tz) {
404
+ formatted_tz = tz;
405
+ if ( tz.search('GMT') != -1 ) {
406
+ formatted_tz = tz.split(" ").slice(1).join(" ");
407
+ }
408
+ return formatted_tz;
409
+ }
410
+
411
+ function auto_detect_tz() {
412
+ if ( page_info.enable_tz ) {
413
+ var user_time_zone = jstz.determine().name();
414
+ $.each($('li.group-option'), function( index, li ) {
415
+ if ( $(li).data('timezone-identifier') == moment().tz_name(user_time_zone) ) {
416
+ $('#timezone_dropdown_chzn a span').html($(li).html());
417
+ $('.js-timezone-dropdown').val($(li).data('timezone-identifier'));
418
+ $("#schedule_user_tz_offset").val($(li).html());
419
+ }
420
+ if ( $(li).data('timezone-identifier') == page_info.system_time_zone ) {
421
+ $("#schedule_app_tz_offset").val($(li).html());
422
+ }
423
+ });
424
+ }
425
+ else {
426
+ $.each($('li.group-option'), function( index, li ) {
427
+ if ( $(li).data('timezone-identifier') == page_info.system_time_zone ) {
428
+ $('#timezone_dropdown_chzn a span').html($(li).html());
429
+ $('.js-timezone-dropdown').val($(li).data('timezone-identifier'));
430
+ $("#schedule_user_tz_offset").val($(li).html());
431
+ $("#schedule_app_tz_offset").val($(li).html());
432
+ }
433
+ });
434
+ }
435
+ }
436
+
437
+ $( document ).ready(function() {
438
+
439
+ $('#timezonesdropdown').timezonesdropdown();
440
+
441
+ auto_detect_tz();
442
+
443
+ if ( $('.js-timezone-dropdown').val() == "" ) {
444
+ $('.js-timezone-dropdown').val('UTC');
445
+ $("#timezone_dropdown_chzn a span").html("GMT+00:00 UTC Time");
446
+ }
447
+
448
+ load_calendar_tz(user_tz);
449
+
450
+ $(".js-navigation-next").click(function() {
451
+ if ( !$(this).hasClass("disabled") ) {
452
+ navigate("forward");
453
+ }
454
+ });
455
+
456
+ $(".js-navigation-prev").click(function() {
457
+ if ( !$(this).hasClass("disabled") ) {
458
+ navigate("backward");
459
+ }
460
+ });
461
+
462
+ $(".schedule-event").click(function() {
463
+ $("#schedule_slot_start_time").val(slot_date + " " + slot_start_time);
464
+ $("#schedule_slot_end_time").val(slot_date + " " + slot_end_time);
465
+ });
466
+
467
+ });