From 0052b054b1064664596856ab410072d73bf4c77d Mon Sep 17 00:00:00 2001 From: Seth Call Date: Thu, 31 Mar 2016 16:37:07 -0500 Subject: [PATCH] * wip --- admin/Gemfile | 2 + admin/app/admin/lesson_booking.rb | 47 + admin/app/admin/lesson_session.rb | 59 + admin/app/admin/students.rb | 4 +- db/up/lessons.sql | 9 + ruby/lib/jam_ruby/app/mailers/user_mailer.rb | 2567 +++++++++-------- .../student_lesson_accepted.html.erb | 2 +- .../student_lesson_booking_canceled.html.erb | 29 + .../student_lesson_booking_canceled.text.erb | 3 + .../student_lesson_booking_declined.html.erb | 20 + .../student_lesson_booking_declined.text.erb | 3 + .../student_lesson_canceled.html.erb | 23 + .../student_lesson_canceled.text.erb | 3 + .../student_lesson_request.html.erb | 6 +- .../student_lesson_request.text.erb | 2 +- .../student_lesson_update_all.html.erb | 2 +- ...ent_scheduled_jamclass_invitation.html.erb | 6 +- .../teacher_lesson_booking_canceled.html.erb | 29 + .../teacher_lesson_booking_canceled.text.erb | 3 + .../teacher_lesson_canceled.html.erb | 24 + .../teacher_lesson_canceled.text.erb | 3 + .../teacher_lesson_request.html.erb | 2 +- .../teacher_lesson_update_all.html.erb | 2 +- ...her_scheduled_jamclass_invitation.html.erb | 6 +- ruby/lib/jam_ruby/models/chat_message.rb | 2 +- ruby/lib/jam_ruby/models/jam_track.rb | 1 + ruby/lib/jam_ruby/models/lesson_booking.rb | 154 +- .../jam_ruby/models/lesson_booking_slot.rb | 41 +- ruby/lib/jam_ruby/models/lesson_session.rb | 150 +- ruby/lib/jam_ruby/models/music_session.rb | 6 +- ruby/lib/jam_ruby/models/notification.rb | 82 +- ruby/lib/jam_ruby/models/teacher.rb | 15 +- ruby/lib/jam_ruby/models/user.rb | 12 +- .../jam_ruby/models/lesson_booking_spec.rb | 154 +- ruby/spec/mailers/render_emails_spec.rb | 2 +- web/app/assets/javascripts/jam_rest.js | 47 + web/app/assets/javascripts/layout.js | 21 +- .../assets/javascripts/notificationPanel.js | 2 +- .../assets/javascripts/react-components.js | 1 + .../BookLessonFree.js.jsx.coffee | 49 +- .../LessonBooking.js.jsx.coffee | 683 +++++ .../LessonBookingDecision.js.jsx.coffee | 216 ++ .../LessonPayment.js.jsx.coffee | 2 +- .../LessonSession.js.jsx.coffee | 58 + .../react-components/Nav.js.jsx.coffee | 34 + .../TeacherSearchScreen.js.jsx.coffee | 9 +- .../actions/NavActions.js.coffee | 7 + .../mixins/ICheckMixin.js.coffee | 15 +- .../stores/NavStore.js.coffee | 46 + .../stylesheets/client/jamkazam.css.scss | 4 + .../react-components/LessonBooking.css.scss | 5 +- .../LessonBookingScreen.css.scss | 231 ++ .../react-components/LessonSession.css.scss | 113 + .../api_lesson_bookings_controller.rb | 98 +- .../views/api_jam_tracks/show_for_client.rabl | 5 - web/app/views/api_lesson_bookings/accept.rabl | 3 + web/app/views/api_lesson_bookings/cancel.rabl | 3 + .../views/api_lesson_bookings/counter.rabl | 3 + web/app/views/api_lesson_bookings/show.rabl | 27 +- web/app/views/clients/index.html.erb | 2 + .../jamclass/_book_lesson_free.html.slim | 2 +- .../jamclass/_lesson_booking.html.slim | 10 + .../jamclass/_lesson_session.html.slim | 10 + web/config/routes.rb | 4 + web/lib/tasks/lesson.rake | 46 + web/spec/factories.rb | 93 + 66 files changed, 3912 insertions(+), 1412 deletions(-) create mode 100644 admin/app/admin/lesson_booking.rb create mode 100644 admin/app/admin/lesson_session.rb create mode 100644 ruby/lib/jam_ruby/app/views/jam_ruby/user_mailer/student_lesson_booking_canceled.html.erb create mode 100644 ruby/lib/jam_ruby/app/views/jam_ruby/user_mailer/student_lesson_booking_canceled.text.erb create mode 100644 ruby/lib/jam_ruby/app/views/jam_ruby/user_mailer/student_lesson_booking_declined.html.erb create mode 100644 ruby/lib/jam_ruby/app/views/jam_ruby/user_mailer/student_lesson_booking_declined.text.erb create mode 100644 ruby/lib/jam_ruby/app/views/jam_ruby/user_mailer/student_lesson_canceled.html.erb create mode 100644 ruby/lib/jam_ruby/app/views/jam_ruby/user_mailer/student_lesson_canceled.text.erb create mode 100644 ruby/lib/jam_ruby/app/views/jam_ruby/user_mailer/teacher_lesson_booking_canceled.html.erb create mode 100644 ruby/lib/jam_ruby/app/views/jam_ruby/user_mailer/teacher_lesson_booking_canceled.text.erb create mode 100644 ruby/lib/jam_ruby/app/views/jam_ruby/user_mailer/teacher_lesson_canceled.html.erb create mode 100644 ruby/lib/jam_ruby/app/views/jam_ruby/user_mailer/teacher_lesson_canceled.text.erb create mode 100644 web/app/assets/javascripts/react-components/LessonBooking.js.jsx.coffee create mode 100644 web/app/assets/javascripts/react-components/LessonBookingDecision.js.jsx.coffee create mode 100644 web/app/assets/javascripts/react-components/LessonSession.js.jsx.coffee create mode 100644 web/app/assets/javascripts/react-components/Nav.js.jsx.coffee create mode 100644 web/app/assets/javascripts/react-components/actions/NavActions.js.coffee create mode 100644 web/app/assets/javascripts/react-components/stores/NavStore.js.coffee create mode 100644 web/app/assets/stylesheets/client/react-components/LessonBookingScreen.css.scss create mode 100644 web/app/assets/stylesheets/client/react-components/LessonSession.css.scss create mode 100644 web/app/views/api_lesson_bookings/accept.rabl create mode 100644 web/app/views/api_lesson_bookings/cancel.rabl create mode 100644 web/app/views/api_lesson_bookings/counter.rabl create mode 100644 web/app/views/clients/jamclass/_lesson_booking.html.slim create mode 100644 web/app/views/clients/jamclass/_lesson_session.html.slim create mode 100644 web/lib/tasks/lesson.rake diff --git a/admin/Gemfile b/admin/Gemfile index 2c28dbf41..ee4cdfe6e 100644 --- a/admin/Gemfile +++ b/admin/Gemfile @@ -77,6 +77,8 @@ gem 'influxdb', '0.1.8' gem 'influxdb-rails', '0.1.10' gem 'recurly' gem 'sendgrid_toolkit', '>= 1.1.1' +gem 'stripe' +gem 'zip-codes' group :libv8 do gem 'libv8', "~> 4.5.95" diff --git a/admin/app/admin/lesson_booking.rb b/admin/app/admin/lesson_booking.rb new file mode 100644 index 000000000..b30d6ca8a --- /dev/null +++ b/admin/app/admin/lesson_booking.rb @@ -0,0 +1,47 @@ +ActiveAdmin.register JamRuby::LessonBooking, :as => 'LessonBookings' do + + menu :label => 'LessonBooking', :parent => 'JamClass' + + config.sort_order = 'created_at desc' + config.batch_actions = false + config.per_page = 100 + config.paginate = true + config.filters = false + + scope("All", default: true ) { |scope| scope.unscoped.order('created_at desc') } + scope("Requested") { |scope| scope.unscoped.where(status: LessonBooking::STATUS_REQUESTED).order('created_at desc') } + scope("Approved") { |scope| scope.unscoped.approved.order('created_at desc') } + scope("Suspended" ) { |scope| scope.unscoped.suspended.order('created_at desc') } + scope("Canceled" ) { |scope| scope.unscoped.canceled.order('created_at desc') } + + index do + column "User Link" do |lesson_booking| + span do + link_to "Web URL", "#{Rails.application.config.external_root_url}/client#/jamclass/lesson-booking/#{lesson_booking.id}" + end + end + column "Type" do |lesson_booking| + lesson_booking.display_type + end + column "Status" do |lesson_booking| + lesson_booking.status + end + column "Teacher" do |lesson_booking| + teacher = lesson_booking.teacher + span do + link_to "#{teacher.name} (#{teacher.email})", "#{Rails.application.config.external_root_url}/client#/profile/teacher/#{teacher.id}" + end + end + column "Student" do |lesson_booking| + student = lesson_booking.student + span do + link_to "#{student.name} (#{student.email})", "#{Rails.application.config.external_root_url}/client#/profile/#{student.id}" + end + end + end + + show do + + end + +end \ No newline at end of file diff --git a/admin/app/admin/lesson_session.rb b/admin/app/admin/lesson_session.rb new file mode 100644 index 000000000..a75b00fba --- /dev/null +++ b/admin/app/admin/lesson_session.rb @@ -0,0 +1,59 @@ +ActiveAdmin.register JamRuby::LessonSession, :as => 'LessonSessions' do + + menu :label => 'LessonSession', :parent => 'JamClass' + + config.sort_order = 'created_at desc' + config.batch_actions = false + config.per_page = 100 + config.paginate = true + config.filters = false + + scope("All", default: true) { |scope| scope.unscoped.order('created_at desc') } + scope("Requested" ) { |scope| scope.unscoped.where(status: LessonBooking::STATUS_REQUESTED).order('created_at desc') } + scope("Approved") { |scope| scope.unscoped.approved.order('created_at desc') } + scope("Suspended" ) { |scope| scope.unscoped.suspended.order('created_at desc') } + scope("Canceled" ) { |scope| scope.unscoped.canceled.order('created_at desc') } + scope("Missed" ) { |scope| scope.unscoped.missed.order('created_at desc') } + scope("Completed" ) { |scope| scope.unscoped.completed.order('created_at desc') } + + index do + column "User Link" do |lesson_sesson| + lesson_booking = lesson_sesson.lesson_booking + span do + link_to "Web URL", "#{Rails.application.config.external_root_url}/client#/jamclass/lesson-booking/#{lesson_booking.id}" + end + end + column "Status" do |lesson_session| + lesson_session.status + end + column "Start Time" do |lesson_session| + span do + lesson_session.music_session.pretty_scheduled_start(true) + end + br + span do + lesson_session.music_session.scheduled_start + end + end + column "Duration" do |lesson_session| + lesson_session.duration + end + column "Teacher" do |lesson_session| + teacher = lesson_session.teacher + span do + link_to "#{teacher.name} (#{teacher.email})", "#{Rails.application.config.external_root_url}/client#/profile/teacher/#{teacher.id}" + end + end + column "Student" do |lesson_session| + student = lesson_session.student + span do + link_to "#{student.name} (#{student.email})", "#{Rails.application.config.external_root_url}/client#/profile/#{student.id}" + end + end + end + + show do + + end + +end \ No newline at end of file diff --git a/admin/app/admin/students.rb b/admin/app/admin/students.rb index a266e2625..8fd3c303c 100644 --- a/admin/app/admin/students.rb +++ b/admin/app/admin/students.rb @@ -8,7 +8,7 @@ ActiveAdmin.register JamRuby::User, :as => 'Students' do config.paginate = true def booked_anything(scope) - scope.joins(:student_lesson_bookings).where('lesson_bookings.status = ?' > LessonBooking::STATUS_APPROVED).uniq + scope.joins(:student_lesson_bookings).where('lesson_bookings.active = true').uniq end scope("Default", default: true) { |scope| booked_anything(scope).order('ready_for_session_at IS NULL DESC') } @@ -26,7 +26,7 @@ ActiveAdmin.register JamRuby::User, :as => 'Students' do column "Session Ready" do |teacher| div do - if teacher.ready_for_session + if teacher.ready_for_session_at span do 'YES' end diff --git a/db/up/lessons.sql b/db/up/lessons.sql index dd7281db2..462da8bed 100644 --- a/db/up/lessons.sql +++ b/db/up/lessons.sql @@ -12,6 +12,9 @@ CREATE TABLE lesson_package_types ( CREATE TABLE lesson_bookings ( id VARCHAR(64) PRIMARY KEY DEFAULT uuid_generate_v4(), user_id VARCHAR(64) REFERENCES users(id) NOT NULL, + active BOOLEAN NOT NULL DEFAULT FALSE, + accepter_id VARCHAR(64) REFERENCES users(id), + canceler_id VARCHAR(64) REFERENCES users(id), lesson_type VARCHAR(64) NOT NULL, recurring BOOLEAN NOT NULL, lesson_length INTEGER NOT NULL, @@ -22,6 +25,7 @@ CREATE TABLE lesson_bookings ( card_presumed_ok BOOLEAN NOT NULL DEFAULT FALSE, sent_notices BOOLEAN NOT NULL DEFAULT FALSE, status VARCHAR, + cancel_message VARCHAR, user_decremented BOOLEAN NOT NULL DEFAULT FALSE, created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP @@ -88,6 +92,8 @@ CREATE TABLE lesson_sessions ( analysed BOOLEAN NOT NULL DEFAULT FALSE, analysis JSON, analysed_at TIMESTAMP, + cancel_message VARCHAR, + canceler_id VARCHAR(64) REFERENCES users(id), charge_id VARCHAR(64) REFERENCES charges(id), success BOOLEAN NOT NULL DEFAULT FALSE, sent_notices BOOLEAN NOT NULL DEFAULT FALSE, @@ -119,6 +125,8 @@ CREATE TABLE lesson_booking_slots ( hour INTEGER, minute INTEGER, timezone VARCHAR NOT NULL, + message VARCHAR, + accept_message VARCHAR, update_all BOOLEAN NOT NULL DEFAULT FALSE, proposer_id VARCHAR(64) REFERENCES users(id) NOT NULL, created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, @@ -126,6 +134,7 @@ CREATE TABLE lesson_booking_slots ( ); ALTER TABLE lesson_bookings ADD COLUMN default_slot_id VARCHAR(64) REFERENCES lesson_booking_slots(id); +ALTER TABLE lesson_bookings ADD COLUMN counter_slot_id VARCHAR(64) REFERENCES lesson_booking_slots(id); ALTER TABLE lesson_sessions ADD COLUMN slot_id VARCHAR(64) REFERENCES lesson_booking_slots(id); ALTER TABLE chat_messages ADD COLUMN target_user_id VARCHAR(64) REFERENCES users(id); diff --git a/ruby/lib/jam_ruby/app/mailers/user_mailer.rb b/ruby/lib/jam_ruby/app/mailers/user_mailer.rb index 755385bcc..07e04e52d 100644 --- a/ruby/lib/jam_ruby/app/mailers/user_mailer.rb +++ b/ruby/lib/jam_ruby/app/mailers/user_mailer.rb @@ -1,1328 +1,1447 @@ - module JamRuby - # UserMailer must be configured to work - # Some common configs occur in jam_ruby/init.rb - # Environment specific configs occur in spec_helper.rb in jam-ruby and jam-web (to put it into test mode), - # and in config/initializers/email.rb in rails to configure sendmail account settings - # If UserMailer were to be used in another project, it would need to be configured there, as well. +module JamRuby + # UserMailer must be configured to work + # Some common configs occur in jam_ruby/init.rb + # Environment specific configs occur in spec_helper.rb in jam-ruby and jam-web (to put it into test mode), + # and in config/initializers/email.rb in rails to configure sendmail account settings + # If UserMailer were to be used in another project, it would need to be configured there, as well. - # Templates for UserMailer can be found in jam_ruby/app/views/jam_ruby/user_mailer - class UserMailer < ActionMailer::Base - include SendGrid + # Templates for UserMailer can be found in jam_ruby/app/views/jam_ruby/user_mailer + class UserMailer < ActionMailer::Base + include SendGrid - layout "user_mailer" + layout "user_mailer" - DEFAULT_SENDER = "JamKazam " + DEFAULT_SENDER = "JamKazam " - default :from => DEFAULT_SENDER + default :from => DEFAULT_SENDER - sendgrid_category :use_subject_lines - #sendgrid_enable :opentrack, :clicktrack # this makes our emails creepy, imo (seth) - sendgrid_unique_args :env => Environment.mode + sendgrid_category :use_subject_lines + #sendgrid_enable :opentrack, :clicktrack # this makes our emails creepy, imo (seth) + sendgrid_unique_args :env => Environment.mode - def confirm_email(user, signup_confirm_url) - @user = user - @signup_confirm_url = signup_confirm_url - sendgrid_category "Confirm Email" - sendgrid_unique_args :type => "confirm_email" + def confirm_email(user, signup_confirm_url) + @user = user + @signup_confirm_url = signup_confirm_url + sendgrid_category "Confirm Email" + sendgrid_unique_args :type => "confirm_email" - sendgrid_recipients([user.email]) - sendgrid_substitute('@USERID', [user.id]) + sendgrid_recipients([user.email]) + sendgrid_substitute('@USERID', [user.id]) - mail(:to => user.email, :subject => "Please confirm your JamKazam email") do |format| - format.text - format.html - end + mail(:to => user.email, :subject => "Please confirm your JamKazam email") do |format| + format.text + format.html + end + end + + def welcome_message(user) + @user = user + sendgrid_category "Welcome" + sendgrid_unique_args :type => "welcome_message" + + sendgrid_recipients([user.email]) + sendgrid_substitute('@USERID', [user.id]) + sendgrid_substitute(EmailBatchProgression::VAR_FIRST_NAME, [user.first_name]) + + mail(:to => user.email, :subject => "Welcome to JamKazam") do |format| + format.text + format.html + end + end + + def student_welcome_message(user) + @user = user + sendgrid_category "Welcome" + sendgrid_unique_args :type => "welcome_message" + + sendgrid_recipients([user.email]) + sendgrid_substitute('@USERID', [user.id]) + sendgrid_substitute(EmailBatchProgression::VAR_FIRST_NAME, [user.first_name]) + + mail(:to => user.email, :subject => "Welcome to JamKazam") do |format| + format.text + format.html + end + end + + def teacher_welcome_message(user) + @user = user + sendgrid_category "Welcome" + sendgrid_unique_args :type => "welcome_message" + + sendgrid_recipients([user.email]) + sendgrid_substitute('@USERID', [user.id]) + sendgrid_substitute(EmailBatchProgression::VAR_FIRST_NAME, [user.first_name]) + + mail(:to => user.email, :subject => "Welcome to JamKazam") do |format| + format.text + format.html + end + end + + def password_changed(user) + @user = user + + sendgrid_recipients([user.email]) + sendgrid_substitute('@USERID', [user.id]) + + sendgrid_unique_args :type => "password_changed" + mail(:to => user.email, :subject => "JamKazam Password Changed") do |format| + format.text + format.html + end + end + + def password_reset(user, password_reset_url) + @user = user + + sendgrid_recipients([user.email]) + sendgrid_substitute('@USERID', [user.id]) + + @password_reset_url = password_reset_url + sendgrid_unique_args :type => "password_reset" + mail(:to => user.email, :subject => "JamKazam Password Reset") do |format| + format.text + format.html + end + end + + def updating_email(user) + @user = user + + sendgrid_recipients([user.email]) + sendgrid_substitute('@USERID', [user.id]) + + sendgrid_unique_args :type => "updating_email" + mail(:to => user.update_email, :subject => "JamKazam Email Change Confirmation") do |format| + format.text + format.html + end + end + + def updated_email(user) + @user = user + + sendgrid_recipients([user.email]) + sendgrid_substitute('@USERID', [user.id]) + + sendgrid_unique_args :type => "updated_email" + mail(:to => user.email, :subject => "JamKazam Email Changed") do |format| + format.text + format.html + end + end + + def new_musicians(user, new_musicians, host='www.jamkazam.com') + @user, @new_musicians, @host = user, new_musicians, host + sendgrid_recipients([user.email]) + sendgrid_substitute('@USERID', [user.id]) + sendgrid_unique_args :type => "new_musicians" + + mail(:to => user.email, :subject => EmailBatchNewMusician.subject) do |format| + format.text + format.html + end + end + + #################################### NOTIFICATION EMAILS #################################### + def friend_request(user, msg, friend_request_id) + return if !user.subscribe_email + + email = user.email + subject = "You have a new friend request on JamKazam" + unique_args = {:type => "friend_request"} + + @url = Nav.accept_friend_request_dialog(friend_request_id) + @body = msg + sendgrid_category "Notification" + sendgrid_unique_args :type => unique_args[:type] + + sendgrid_recipients([email]) + sendgrid_substitute('@USERID', [user.id]) + + mail(:to => email, :subject => subject) do |format| + format.text + format.html + end + end + + def friend_request_accepted(user, msg) + return if !user.subscribe_email + + email = user.email + subject = "You have a new friend on JamKazam" + unique_args = {:type => "friend_request_accepted"} + + @body = msg + sendgrid_category "Notification" + sendgrid_unique_args :type => unique_args[:type] + + sendgrid_recipients([email]) + sendgrid_substitute('@USERID', [user.id]) + + mail(:to => email, :subject => subject) do |format| + format.text + format.html + end + end + + def new_user_follower(user, msg) + return if !user.subscribe_email + + email = user.email + subject = "You have a new follower on JamKazam" + unique_args = {:type => "new_user_follower"} + + @body = msg + sendgrid_category "Notification" + sendgrid_unique_args :type => unique_args[:type] + + sendgrid_recipients([email]) + sendgrid_substitute('@USERID', [user.id]) + + mail(:to => email, :subject => subject) do |format| + format.text + format.html + end + end + + def new_band_follower(user, msg) + return if !user.subscribe_email + + email = user.email + subject = "Your band has a new follower on JamKazam" + unique_args = {:type => "new_band_follower"} + + @body = msg + sendgrid_category "Notification" + sendgrid_unique_args :type => unique_args[:type] + + sendgrid_recipients([email]) + sendgrid_substitute('@USERID', [user.id]) + + mail(:to => email, :subject => subject) do |format| + format.text + format.html + end + end + + def session_invitation(user, msg) + return if !user.subscribe_email + + email = user.email + subject = "You have been invited to a session on JamKazam" + unique_args = {:type => "session_invitation"} + + @body = msg + sendgrid_category "Notification" + sendgrid_unique_args :type => unique_args[:type] + + sendgrid_recipients([email]) + sendgrid_substitute('@USERID', [user.id]) + + mail(:to => email, :subject => subject) do |format| + format.text + format.html + end + end + + def musician_session_join(user, msg, session_id) + return if !user.subscribe_email + + email = user.email + subject = "Someone you know is in a session on JamKazam" + unique_args = {:type => "musician_session_join"} + @body = msg + @session_url = "#{APP_CONFIG.external_root_url}/sessions/#{session_id}" + sendgrid_category "Notification" + sendgrid_unique_args :type => unique_args[:type] + + sendgrid_recipients([email]) + sendgrid_substitute('@USERID', [user.id]) + + mail(:to => email, :subject => subject) do |format| + format.text + format.html + end + end + + def scheduled_session_invitation(user, msg, session) + return if !user.subscribe_email + + email = user.email + subject = "Session Invitation" + unique_args = {:type => "scheduled_session_invitation"} + @body = msg + @session_name = session.name + @session_date = session.pretty_scheduled_start(true) + @session_url = "#{APP_CONFIG.external_root_url}/sessions/#{session.id}/details" + sendgrid_category "Notification" + sendgrid_unique_args :type => unique_args[:type] + + sendgrid_recipients([email]) + sendgrid_substitute('@USERID', [user.id]) + + mail(:to => email, :subject => subject) do |format| + format.text + format.html + end + end + + def scheduled_session_rsvp(user, msg, session) + return if !user.subscribe_email + + email = user.email + subject = "Session RSVP" + unique_args = {:type => "scheduled_session_rsvp"} + @body = msg + @session_name = session.name + @session_date = session.pretty_scheduled_start(true) + @session_url = "#{APP_CONFIG.external_root_url}/sessions/#{session.id}/details" + sendgrid_category "Notification" + sendgrid_unique_args :type => unique_args[:type] + + sendgrid_recipients([email]) + sendgrid_substitute('@USERID', [user.id]) + + mail(:to => email, :subject => subject) do |format| + format.text + format.html + end + end + + def scheduled_session_rsvp_approved(user, msg, session) + return if !user.subscribe_email + + email = user.email + subject = "Session RSVP Approved" + unique_args = {:type => "scheduled_session_rsvp_approved"} + @body = msg + @session_name = session.name + @session_date = session.pretty_scheduled_start(true) + @session_url = "#{APP_CONFIG.external_root_url}/sessions/#{session.id}/details" + sendgrid_category "Notification" + sendgrid_unique_args :type => unique_args[:type] + + sendgrid_recipients([email]) + sendgrid_substitute('@USERID', [user.id]) + + mail(:to => email, :subject => subject) do |format| + format.text + format.html + end + end + + def scheduled_session_rsvp_cancelled(user, msg, session) + return if !user.subscribe_email + + email = user.email + subject = "Session RSVP Cancelled" + unique_args = {:type => "scheduled_session_rsvp_cancelled"} + @body = msg + @session_name = session.name + @session_date = session.pretty_scheduled_start(true) + @session_url = "#{APP_CONFIG.external_root_url}/sessions/#{session.id}/details" + sendgrid_category "Notification" + sendgrid_unique_args :type => unique_args[:type] + + sendgrid_recipients([email]) + sendgrid_substitute('@USERID', [user.id]) + + mail(:to => email, :subject => subject) do |format| + format.text + format.html + end + end + + def scheduled_session_rsvp_cancelled_org(user, msg, session) + return if !user.subscribe_email + + email = user.email + subject = "Your Session RSVP Cancelled" + unique_args = {:type => "scheduled_session_rsvp_cancelled_org"} + @body = msg + @session_name = session.name + @session_date = session.pretty_scheduled_start(true) + @session_url = "#{APP_CONFIG.external_root_url}/sessions/#{session.id}/details" + sendgrid_category "Notification" + sendgrid_unique_args :type => unique_args[:type] + + sendgrid_recipients([email]) + sendgrid_substitute('@USERID', [user.id]) + + mail(:to => email, :subject => subject) do |format| + format.text + format.html + end + end + + def scheduled_session_cancelled(user, msg, session) + return if !user.subscribe_email + + email = user.email + subject = "Session Cancelled" + unique_args = {:type => "scheduled_session_cancelled"} + @body = msg + @session_name = session.name + @session_date = session.pretty_scheduled_start(true) + @session_url = "#{APP_CONFIG.external_root_url}/sessions/#{session.id}/details" + sendgrid_category "Notification" + sendgrid_unique_args :type => unique_args[:type] + + sendgrid_recipients([email]) + sendgrid_substitute('@USERID', [user.id]) + + mail(:to => email, :subject => subject) do |format| + format.text + format.html + end + end + + def scheduled_session_rescheduled(user, msg, session) + return if !user.subscribe_email + + email = user.email + subject = "Session Rescheduled" + unique_args = {:type => "scheduled_session_rescheduled"} + @body = msg + @session_name = session.name + @session_date = session.pretty_scheduled_start(true) + @session_url = "#{APP_CONFIG.external_root_url}/sessions/#{session.id}/details" + sendgrid_category "Notification" + sendgrid_unique_args :type => unique_args[:type] + + sendgrid_recipients([email]) + sendgrid_substitute('@USERID', [user.id]) + + mail(:to => email, :subject => subject) do |format| + format.text + format.html + end + end + + def scheduled_session_reminder_upcoming(user, session) + subject = "Your JamKazam session starts in 1 hour!" + unique_args = {:type => "scheduled_session_reminder_upcoming"} + send_scheduled_session_reminder(user, session, subject, unique_args) + end + + def scheduled_session_reminder_day(user, session) + subject = "JamKazam Session Reminder" + unique_args = {:type => "scheduled_session_reminder_day"} + send_scheduled_session_reminder(user, session, subject, unique_args) + end + + def send_scheduled_session_reminder(user, session, subject, unique_args) + return if !user.subscribe_email + + email = user.email + @user = user + @session_name = session.name + @session_date = session.pretty_scheduled_start(true) + @session_url = "#{APP_CONFIG.external_root_url}/sessions/#{session.id}/details" + sendgrid_category "Notification" + sendgrid_unique_args :type => unique_args[:type] + + sendgrid_recipients([email]) + sendgrid_substitute('@USERID', [user.id]) + + mail(:to => email, :subject => subject) do |format| + format.text + format.html + end + end + + def scheduled_session_comment(target_user, sender, msg, comment, session) + return if !target_user.subscribe_email + + email = target_user.email + subject = "New Session Comment" + unique_args = {:type => "scheduled_session_comment"} + @body = msg + @session_name = session.name + @session_date = session.pretty_scheduled_start(true) + @comment = comment + @sender = sender + @suppress_user_has_account_footer = true + @session_url = "#{APP_CONFIG.external_root_url}/sessions/#{session.id}/details" + sendgrid_category "Notification" + sendgrid_unique_args :type => unique_args[:type] + + sendgrid_recipients([email]) + sendgrid_substitute('@USERID', [target_user.id]) + + mail(:to => email, :subject => subject) do |format| + format.text + format.html { render :layout => "from_user_mailer" } + end + end + + def scheduled_session_daily(receiver, sessions_and_latency) + sendgrid_category "Notification" + sendgrid_unique_args :type => "scheduled_session_daily" + + sendgrid_recipients([receiver.email]) + sendgrid_substitute('@USERID', [receiver.id]) + + @user = receiver + @sessions_and_latency = sessions_and_latency + + @title = 'New Scheduled Sessions Matched to You' + mail(:to => receiver.email, + :subject => EmailBatchScheduledSessions.subject) do |format| + format.text + format.html + end + end + + def band_session_join(user, msg, session_id) + return if !user.subscribe_email + + email = user.email + subject = "A band that you follow has joined a session" + unique_args = {:type => "band_session_join"} + + @body = msg + @session_url = "#{APP_CONFIG.external_root_url}/sessions/#{session_id}" + sendgrid_category "Notification" + sendgrid_unique_args :type => unique_args[:type] + + sendgrid_recipients([email]) + sendgrid_substitute('@USERID', [user.id]) + + mail(:to => email, :subject => subject) do |format| + format.text + format.html + end + end + + def musician_recording_saved(user, msg) + return if !user.subscribe_email + + email = user.email + subject = "A musician has saved a new recording on JamKazam" + unique_args = {:type => "musician_recording_saved"} + + @body = msg + sendgrid_category "Notification" + sendgrid_unique_args :type => unique_args[:type] + + sendgrid_recipients([email]) + sendgrid_substitute('@USERID', [user.id]) + + mail(:to => email, :subject => subject) do |format| + format.text + format.html + end + end + + def band_recording_saved(user, msg) + return if !user.subscribe_email + + email = user.email + subject = "A band has saved a new recording on JamKazam" + unique_args = {:type => "band_recording_saved"} + + @body = msg + sendgrid_category "Notification" + sendgrid_unique_args :type => unique_args[:type] + + sendgrid_recipients([email]) + sendgrid_substitute('@USERID', [user.id]) + + mail(:to => email, :subject => subject) do |format| + format.text + format.html + end + end + + def band_invitation(user, msg) + return if !user.subscribe_email + + email = user.email + subject = "You have been invited to join a band on JamKazam" + unique_args = {:type => "band_invitation"} + + @body = msg + sendgrid_category "Notification" + sendgrid_unique_args :type => unique_args[:type] + + sendgrid_recipients([email]) + sendgrid_substitute('@USERID', [user.id]) + + mail(:to => email, :subject => subject) do |format| + format.text + format.html + end + end + + def band_invitation_accepted(user, msg) + return if !user.subscribe_email + + email = user.email + subject = "Your band invitation was accepted" + unique_args = {:type => "band_invitation_accepted"} + + @body = msg + sendgrid_category "Notification" + sendgrid_unique_args :type => unique_args[:type] + + sendgrid_recipients([email]) + sendgrid_substitute('@USERID', [user.id]) + + mail(:to => email, :subject => subject) do |format| + format.text + format.html + end + end + + + def text_message(user, sender_id, sender_name, sender_photo_url, message) + return if !user.subscribe_email + + email = user.email + subject = "Message from #{sender_name}" + unique_args = {:type => "text_message"} + + @note = message + @url = Nav.home(dialog: 'text-message', dialog_opts: {d1: sender_id}) + @sender_id = sender_id + @sender_name = sender_name + @sender_photo_url = sender_photo_url + sendgrid_category "Notification" + sendgrid_unique_args :type => unique_args[:type] + + sendgrid_recipients([email]) + sendgrid_substitute('@USERID', [user.id]) + + mail(:to => email, :subject => subject) do |format| + format.text + format.html { render :layout => "from_user_mailer" } + end + end + + def student_lesson_request(lesson_booking) + email = lesson_booking.user.email + subject = "You have sent a lesson request to #{lesson_booking.teacher.name}!" + unique_args = {:type => "student_lesson_request"} + + @sender = lesson_booking.teacher + @lesson_booking = lesson_booking + + sendgrid_category "Notification" + sendgrid_unique_args :type => unique_args[:type] + + sendgrid_recipients([email]) + sendgrid_substitute('@USERID', [lesson_booking.user.id]) + + mail(:to => email, :subject => subject) do |format| + format.text + format.html { render :layout => "from_user_mailer" } + end + end + + def teacher_lesson_request(lesson_booking) + email = lesson_booking.teacher.email + subject = "You have received a lesson request through JamKazam!" + unique_args = {:type => "teacher_lesson_request"} + + @sender = lesson_booking.user + @lesson_booking = lesson_booking + + sendgrid_category "Notification" + sendgrid_unique_args :type => unique_args[:type] + + sendgrid_recipients([email]) + sendgrid_substitute('@USERID', [lesson_booking.teacher.id]) + + mail(:to => email, :subject => subject) do |format| + format.text + format.html { render :layout => "from_user_mailer" } + end + end + + def student_lesson_accepted(lesson_session, message, slot) + @slot = slot + if slot.is_teacher_created? + @target = lesson_session.student + @sender = lesson_session.teacher + @subject = "Your have confirmed a lesson!" + else + @target = lesson_session.teacher + @sender = lesson_session.student + @subject = "Your lesson request is confirmed!" + end + @lesson_session = lesson_session + @message = message + email = lesson_session.student.email + unique_args = {:type => "student_lesson_accepted"} + + sendgrid_category "Notification" + sendgrid_unique_args :type => unique_args[:type] + + sendgrid_recipients([email]) + sendgrid_substitute('@USERID', [lesson_session.student.id]) + + mail(:to => email, :subject => @subject) do |format| + format.text + format.html { render :layout => "from_user_mailer" } + end + end + + def teacher_lesson_accepted(lesson_session, message, slot) + @slot = slot + if slot.is_teacher_created? + @target = lesson_session.student + @sender = lesson_session.teacher + @subject = "Your lesson time change is confirmed by #{lesson_session.student.name}!" + else + @target = lesson_session.teacher + @sender = lesson_session.student + @subject = "You have confirmed a lesson!" end - def welcome_message(user) - @user = user - sendgrid_category "Welcome" - sendgrid_unique_args :type => "welcome_message" + @lesson_session = lesson_session + @message = message + email = lesson_session.teacher.email + unique_args = {:type => "teacher_lesson_accepted"} - sendgrid_recipients([user.email]) - sendgrid_substitute('@USERID', [user.id]) - sendgrid_substitute(EmailBatchProgression::VAR_FIRST_NAME, [user.first_name]) + sendgrid_category "Notification" + sendgrid_unique_args :type => unique_args[:type] - mail(:to => user.email, :subject => "Welcome to JamKazam") do |format| - format.text - format.html - end + sendgrid_recipients([email]) + sendgrid_substitute('@USERID', [lesson_session.teacher.id]) + + mail(:to => email, :subject => @subject) do |format| + format.text + format.html { render :layout => "from_user_mailer" } + end + end + + def student_lesson_update_all(lesson_session, message, slot) + @slot = slot + if slot.is_teacher_created? + @target = lesson_session.student + @sender = lesson_session.teacher + subject = "All lesson times changed with #{lesson_session.student.name}!" + else + @target = lesson_session.teacher + @sender = lesson_session.student + subject = "All lesson times changed with #{lesson_session.student.name}!" + end + @lesson_session = lesson_session + @message = message + email = lesson_session.student.email + unique_args = {:type => "student_lesson_accepted"} + + sendgrid_category "Notification" + sendgrid_unique_args :type => unique_args[:type] + + sendgrid_recipients([email]) + sendgrid_substitute('@USERID', [lesson_session.student.id]) + + mail(:to => email, :subject => subject) do |format| + format.text + format.html { render :layout => "from_user_mailer" } + end + end + + def teacher_lesson_update_all(lesson_session, message, slot) + @slot = slot + if slot.is_teacher_created? + @target = lesson_session.student + @sender = lesson_session.teacher + subject = "All lesson times changed with #{lesson_session.student.name}!" + else + @target = lesson_session.teacher + @sender = lesson_session.student + subject = "All lesson times changed with #{lesson_session.student.name}!" end - def student_welcome_message(user) - @user = user - sendgrid_category "Welcome" - sendgrid_unique_args :type => "welcome_message" + @lesson_session = lesson_session + @message = message + email = lesson_session.teacher.email + unique_args = {:type => "teacher_lesson_update_all"} - sendgrid_recipients([user.email]) - sendgrid_substitute('@USERID', [user.id]) - sendgrid_substitute(EmailBatchProgression::VAR_FIRST_NAME, [user.first_name]) + sendgrid_category "Notification" + sendgrid_unique_args :type => unique_args[:type] - mail(:to => user.email, :subject => "Welcome to JamKazam") do |format| - format.text - format.html - end + sendgrid_recipients([email]) + sendgrid_substitute('@USERID', [lesson_session.teacher.id]) + + mail(:to => email, :subject => subject) do |format| + format.text + format.html { render :layout => "from_user_mailer" } end + end - def teacher_welcome_message(user) - @user = user - sendgrid_category "Welcome" - sendgrid_unique_args :type => "welcome_message" + def teacher_scheduled_jamclass_invitation(user, msg, session) - sendgrid_recipients([user.email]) - sendgrid_substitute('@USERID', [user.id]) - sendgrid_substitute(EmailBatchProgression::VAR_FIRST_NAME, [user.first_name]) + email = user.email + @subject = "#{session.lesson_session.lesson_booking.display_type2.capitalize} JamClass Scheduled with #{session.lesson_session.student.name}" + unique_args = {:type => "scheduled_jamclass_invitation"} + @student = session.lesson_session.student + @teacher = session.lesson_session.teacher + @body = msg + @session_name = session.name + @session_description = session.description + @session_date = session.pretty_scheduled_start(true) + @session_url = session.lesson_session.web_url + sendgrid_category "Notification" + sendgrid_unique_args :type => unique_args[:type] - mail(:to => user.email, :subject => "Welcome to JamKazam") do |format| - format.text - format.html - end + sendgrid_recipients([email]) + sendgrid_substitute('@USERID', [user.id]) + + mail(:to => email, :subject => @subject) do |format| + format.text + format.html end + end - def password_changed(user) - @user = user + def student_scheduled_jamclass_invitation(user, msg, session) + return if !user.subscribe_email - sendgrid_recipients([user.email]) - sendgrid_substitute('@USERID', [user.id]) + email = user.email + @subject = "#{session.lesson_session.lesson_booking.display_type2.capitalize} JamClass Scheduled with #{session.lesson_session.teacher.name}" + unique_args = {:type => "scheduled_jamclass_invitation"} + @student = session.lesson_session.student + @teacher = session.lesson_session.teacher + @body = msg + @session_name = session.name + @session_description = session.description + @session_date = session.pretty_scheduled_start(true) + @session_url = session.lesson_session.web_url + sendgrid_category "Notification" + sendgrid_unique_args :type => unique_args[:type] - sendgrid_unique_args :type => "password_changed" - mail(:to => user.email, :subject => "JamKazam Password Changed") do |format| - format.text - format.html - end + sendgrid_recipients([email]) + sendgrid_substitute('@USERID', [user.id]) + + mail(:to => email, :subject => @subject) do |format| + format.text + format.html end + end - def password_reset(user, password_reset_url) - @user = user + # teacher proposed counter time; so send msg to the student + def student_lesson_counter(lesson_session, slot) - sendgrid_recipients([user.email]) - sendgrid_substitute('@USERID', [user.id]) + email = lesson_session.student.email + subject = "Instructor has proposed a different time for your lesson" + unique_args = {:type => "student_lesson_counter"} + @student = lesson_session.student + @teacher = lesson_session.teacher + @session_name = lesson_session.music_session.name + @session_description = lesson_session.music_session.description + @session_date = slot.pretty_scheduled_start(true) + @session_url = lesson_session.web_url + @lesson_session = lesson_session + sendgrid_category "Notification" + sendgrid_unique_args :type => unique_args[:type] - @password_reset_url = password_reset_url - sendgrid_unique_args :type => "password_reset" - mail(:to => user.email, :subject => "JamKazam Password Reset") do |format| - format.text - format.html - end + sendgrid_recipients([email]) + sendgrid_substitute('@USERID', [@student.id]) + + mail(:to => email, :subject => subject) do |format| + format.text + format.html end + end - def updating_email(user) - @user = user + # student proposed counter time; so send msg to the teacher + def teacher_lesson_counter(lesson_session, slot) - sendgrid_recipients([user.email]) - sendgrid_substitute('@USERID', [user.id]) + email = lesson_session.teacher.email + subject = "Student has proposed a different time for their lesson" + unique_args = {:type => "teacher_lesson_counter"} + @student = lesson_session.student + @teacher = lesson_session.teacher + @session_name = lesson_session.music_session.name + @session_description = lesson_session.music_session.description + @session_date = slot.pretty_scheduled_start(true) + @session_url = lesson_session.web_url + @lesson_session = lesson_session + sendgrid_category "Notification" + sendgrid_unique_args :type => unique_args[:type] - sendgrid_unique_args :type => "updating_email" - mail(:to => user.update_email, :subject => "JamKazam Email Change Confirmation") do |format| - format.text - format.html - end + sendgrid_recipients([email]) + sendgrid_substitute('@USERID', [@teacher.id]) + + mail(:to => email, :subject => subject) do |format| + format.text + format.html end + end - def updated_email(user) - @user = user + def teacher_lesson_completed(lesson_session) + @student = lesson_session.student + @teacher = lesson_session.teacher + @session_name = lesson_session.music_session.name + @session_description = lesson_session.music_session.description + @session_date = lesson_session.slot.pretty_scheduled_start(true) + @session_url = lesson_session.web_url + @lesson_session = lesson_session + email = lesson_session.teacher.email + subject = "You successfully completed a lesson with #{@student.name}" + unique_args = {:type => "teacher_lesson_completed"} - sendgrid_recipients([user.email]) - sendgrid_substitute('@USERID', [user.id]) + sendgrid_category "Notification" + sendgrid_unique_args :type => unique_args[:type] - sendgrid_unique_args :type => "updated_email" - mail(:to => user.email, :subject => "JamKazam Email Changed") do |format| - format.text - format.html - end + sendgrid_recipients([email]) + sendgrid_substitute('@USERID', [@teacher.id]) + + mail(:to => email, :subject => subject) do |format| + format.text + format.html { render :layout => "from_user_mailer" } end + end - def new_musicians(user, new_musicians, host='www.jamkazam.com') - @user, @new_musicians, @host = user, new_musicians, host - sendgrid_recipients([user.email]) - sendgrid_substitute('@USERID', [user.id]) - sendgrid_unique_args :type => "new_musicians" + # successfully completed, and has some remaining test drives + def student_test_drive_lesson_completed(lesson_session) - mail(:to => user.email, :subject => EmailBatchNewMusician.subject) do |format| - format.text - format.html - end + @student = lesson_session.student + @teacher = lesson_session.teacher + @session_name = lesson_session.music_session.name + @session_description = lesson_session.music_session.description + @session_date = lesson_session.slot.pretty_scheduled_start(true) + @session_url = lesson_session.web_url + @lesson_session = lesson_session + + email = @student.email + subject = "You have used #{@student.remaining_test_drives} of 4 TestDrive lesson credits" + unique_args = {:type => "student_test_drive_success"} + + sendgrid_category "Notification" + sendgrid_unique_args :type => unique_args[:type] + + sendgrid_recipients([email]) + sendgrid_substitute('@USERID', [@student.id]) + + mail(:to => email, :subject => subject) do |format| + format.text + format.html { render :layout => "from_user_mailer" } end + end - #################################### NOTIFICATION EMAILS #################################### - def friend_request(user, msg, friend_request_id) - return if !user.subscribe_email + # successfully completed, but no more test drives left + def student_test_drive_lesson_done(lesson_session) - email = user.email - subject = "You have a new friend request on JamKazam" - unique_args = {:type => "friend_request"} + @student = lesson_session.student + @teacher = lesson_session.teacher + @session_name = lesson_session.music_session.name + @session_description = lesson_session.music_session.description + @session_date = lesson_session.slot.pretty_scheduled_start(true) + @session_url = lesson_session.web_url + @lesson_session = lesson_session - @url = Nav.accept_friend_request_dialog(friend_request_id) - @body = msg - sendgrid_category "Notification" - sendgrid_unique_args :type => unique_args[:type] + email = @student.email + subject = "You have used all 4 TestDrive lesson credits" + unique_args = {:type => "student_test_drive_success"} - sendgrid_recipients([email]) - sendgrid_substitute('@USERID', [user.id]) + sendgrid_category "Notification" + sendgrid_unique_args :type => unique_args[:type] - mail(:to => email, :subject => subject) do |format| - format.text - format.html - end + sendgrid_recipients([email]) + sendgrid_substitute('@USERID', [@student.id]) + + mail(:to => email, :subject => subject) do |format| + format.text + format.html { render :layout => "raw_mailer" } end + end - def friend_request_accepted(user, msg) - return if !user.subscribe_email + def student_lesson_normal_no_bill(lesson_session) + @student = lesson_session.student + @teacher = lesson_session.teacher + @session_name = lesson_session.music_session.name + @session_description = lesson_session.music_session.description + @session_date = lesson_session.slot.pretty_scheduled_start(true) + @session_url = lesson_session.web_url + @lesson_session = lesson_session - email = user.email - subject = "You have a new friend on JamKazam" - unique_args = {:type => "friend_request_accepted"} + email = @student.email + subject = "Your lesson with #{@teacher.name} will not be billed" + unique_args = {:type => "student_lesson_normal_no_bill"} - @body = msg - sendgrid_category "Notification" - sendgrid_unique_args :type => unique_args[:type] + sendgrid_category "Notification" + sendgrid_unique_args :type => unique_args[:type] - sendgrid_recipients([email]) - sendgrid_substitute('@USERID', [user.id]) + sendgrid_recipients([email]) + sendgrid_substitute('@USERID', [@student.id]) - mail(:to => email, :subject => subject) do |format| - format.text - format.html - end + mail(:to => email, :subject => subject) do |format| + format.text + format.html { render :layout => "from_user_mailer" } end + end - def new_user_follower(user, msg) - return if !user.subscribe_email + def teacher_lesson_normal_no_bill(lesson_session) + @student = lesson_session.student + @teacher = lesson_session.teacher + @session_name = lesson_session.music_session.name + @session_description = lesson_session.music_session.description + @session_date = lesson_session.slot.pretty_scheduled_start(true) + @session_url = lesson_session.web_url + @lesson_session = lesson_session + email = lesson_session.teacher.email + subject = "Your student #{@student.name} will not be charged for their lesson" + unique_args = {:type => "teacher_lesson_normal_no_bill"} - email = user.email - subject = "You have a new follower on JamKazam" - unique_args = {:type => "new_user_follower"} + sendgrid_category "Notification" + sendgrid_unique_args :type => unique_args[:type] - @body = msg - sendgrid_category "Notification" - sendgrid_unique_args :type => unique_args[:type] + sendgrid_recipients([email]) + sendgrid_substitute('@USERID', [@teacher.id]) - sendgrid_recipients([email]) - sendgrid_substitute('@USERID', [user.id]) - - mail(:to => email, :subject => subject) do |format| - format.text - format.html - end + mail(:to => email, :subject => subject) do |format| + format.text + format.html { render :layout => "from_user_mailer" } end + end - def new_band_follower(user, msg) - return if !user.subscribe_email + def student_lesson_normal_done(lesson_session) + @student = lesson_session.student + @teacher = lesson_session.teacher + @session_name = lesson_session.music_session.name + @session_description = lesson_session.music_session.description + @session_date = lesson_session.slot.pretty_scheduled_start(true) + @session_url = lesson_session.web_url + @lesson_session = lesson_session - email = user.email - subject = "Your band has a new follower on JamKazam" - unique_args = {:type => "new_band_follower"} + email = @student.email + subject = "Your JamClass lesson today with #{@teacher.first_name}" + unique_args = {:type => "student_lesson_normal_done"} - @body = msg - sendgrid_category "Notification" - sendgrid_unique_args :type => unique_args[:type] + sendgrid_category "Notification" + sendgrid_unique_args :type => unique_args[:type] - sendgrid_recipients([email]) - sendgrid_substitute('@USERID', [user.id]) + sendgrid_recipients([email]) + sendgrid_substitute('@USERID', [@student.id]) - mail(:to => email, :subject => subject) do |format| - format.text - format.html - end + mail(:to => email, :subject => subject) do |format| + format.text + format.html { render :layout => "from_user_mailer" } end + end - def session_invitation(user, msg) - return if !user.subscribe_email + def teacher_lesson_normal_done(lesson_session) + @student = lesson_session.student + @teacher = lesson_session.teacher + @session_name = lesson_session.music_session.name + @session_description = lesson_session.music_session.description + @session_date = lesson_session.slot.pretty_scheduled_start(true) + @session_url = lesson_session.web_url + @lesson_session = lesson_session + email = lesson_session.teacher.email + subject = "Your JamClass lesson today with #{@student.first_name}" + unique_args = {:type => "teacher_lesson_normal_done"} - email = user.email - subject = "You have been invited to a session on JamKazam" - unique_args = {:type => "session_invitation"} + sendgrid_category "Notification" + sendgrid_unique_args :type => unique_args[:type] - @body = msg - sendgrid_category "Notification" - sendgrid_unique_args :type => unique_args[:type] + sendgrid_recipients([email]) + sendgrid_substitute('@USERID', [@teacher.id]) - sendgrid_recipients([email]) - sendgrid_substitute('@USERID', [user.id]) - - mail(:to => email, :subject => subject) do |format| - format.text - format.html - end + mail(:to => email, :subject => subject) do |format| + format.text + format.html { render :layout => "from_user_mailer" } end + end - def musician_session_join(user, msg, session_id) - return if !user.subscribe_email + def student_unable_charge(lesson_session) + @student = lesson_session.student + @teacher = lesson_session.teacher + @session_name = lesson_session.music_session.name + @session_description = lesson_session.music_session.description + @session_date = lesson_session.slot.pretty_scheduled_start(true) + @session_url = lesson_session.web_url + @lesson_session = lesson_session + @card_declined = lesson_session.is_card_declined? + @card_expired = lesson_session.is_card_expired? + @bill_date = lesson_session.last_billed_at_date - email = user.email - subject = "Someone you know is in a session on JamKazam" - unique_args = {:type => "musician_session_join"} - @body = msg - @session_url = "#{APP_CONFIG.external_root_url}/sessions/#{session_id}" - sendgrid_category "Notification" - sendgrid_unique_args :type => unique_args[:type] + email = @student.email + subject = "The credit card charge for your lesson today with #{@teacher.name} failed" + unique_args = {:type => "student_unable_charge"} - sendgrid_recipients([email]) - sendgrid_substitute('@USERID', [user.id]) + sendgrid_category "Notification" + sendgrid_unique_args :type => unique_args[:type] - mail(:to => email, :subject => subject) do |format| - format.text - format.html - end + sendgrid_recipients([email]) + sendgrid_substitute('@USERID', [@student.id]) + + mail(:to => email, :subject => subject) do |format| + format.text + format.html { render :layout => "from_user_mailer" } end + end - def scheduled_session_invitation(user, msg, session) - return if !user.subscribe_email + def teacher_unable_charge(lesson_session) + @student = lesson_session.student + @teacher = lesson_session.teacher + @session_name = lesson_session.music_session.name + @session_description = lesson_session.music_session.description + @session_date = lesson_session.slot.pretty_scheduled_start(true) + @session_url = lesson_session.web_url + @lesson_session = lesson_session + email = lesson_session.teacher.email + subject = "The credit card charge for your lesson today with #{@teacher.name} failed" + unique_args = {:type => "teacher_lesson_normal_done"} - email = user.email - subject = "Session Invitation" - unique_args = {:type => "scheduled_session_invitation"} - @body = msg - @session_name = session.name - @session_date = session.pretty_scheduled_start(true) - @session_url = "#{APP_CONFIG.external_root_url}/sessions/#{session.id}/details" - sendgrid_category "Notification" - sendgrid_unique_args :type => unique_args[:type] + sendgrid_category "Notification" + sendgrid_unique_args :type => unique_args[:type] - sendgrid_recipients([email]) - sendgrid_substitute('@USERID', [user.id]) + sendgrid_recipients([email]) + sendgrid_substitute('@USERID', [@teacher.id]) - mail(:to => email, :subject => subject) do |format| - format.text - format.html - end + mail(:to => email, :subject => subject) do |format| + format.text + format.html { render :layout => "from_user_mailer" } end + end - def scheduled_session_rsvp(user, msg, session) - return if !user.subscribe_email - - email = user.email - subject = "Session RSVP" - unique_args = {:type => "scheduled_session_rsvp"} - @body = msg - @session_name = session.name - @session_date = session.pretty_scheduled_start(true) - @session_url = "#{APP_CONFIG.external_root_url}/sessions/#{session.id}/details" - sendgrid_category "Notification" - sendgrid_unique_args :type => unique_args[:type] - - sendgrid_recipients([email]) - sendgrid_substitute('@USERID', [user.id]) - - mail(:to => email, :subject => subject) do |format| - format.text - format.html - end - end - - def scheduled_session_rsvp_approved(user, msg, session) - return if !user.subscribe_email - - email = user.email - subject = "Session RSVP Approved" - unique_args = {:type => "scheduled_session_rsvp_approved"} - @body = msg - @session_name = session.name - @session_date = session.pretty_scheduled_start(true) - @session_url = "#{APP_CONFIG.external_root_url}/sessions/#{session.id}/details" - sendgrid_category "Notification" - sendgrid_unique_args :type => unique_args[:type] - - sendgrid_recipients([email]) - sendgrid_substitute('@USERID', [user.id]) - - mail(:to => email, :subject => subject) do |format| - format.text - format.html - end - end - - def scheduled_session_rsvp_cancelled(user, msg, session) - return if !user.subscribe_email - - email = user.email - subject = "Session RSVP Cancelled" - unique_args = {:type => "scheduled_session_rsvp_cancelled"} - @body = msg - @session_name = session.name - @session_date = session.pretty_scheduled_start(true) - @session_url = "#{APP_CONFIG.external_root_url}/sessions/#{session.id}/details" - sendgrid_category "Notification" - sendgrid_unique_args :type => unique_args[:type] - - sendgrid_recipients([email]) - sendgrid_substitute('@USERID', [user.id]) - - mail(:to => email, :subject => subject) do |format| - format.text - format.html - end - end - - def scheduled_session_rsvp_cancelled_org(user, msg, session) - return if !user.subscribe_email - - email = user.email - subject = "Your Session RSVP Cancelled" - unique_args = {:type => "scheduled_session_rsvp_cancelled_org"} - @body = msg - @session_name = session.name - @session_date = session.pretty_scheduled_start(true) - @session_url = "#{APP_CONFIG.external_root_url}/sessions/#{session.id}/details" - sendgrid_category "Notification" - sendgrid_unique_args :type => unique_args[:type] - - sendgrid_recipients([email]) - sendgrid_substitute('@USERID', [user.id]) - - mail(:to => email, :subject => subject) do |format| - format.text - format.html - end - end - - def scheduled_session_cancelled(user, msg, session) - return if !user.subscribe_email - - email = user.email - subject = "Session Cancelled" - unique_args = {:type => "scheduled_session_cancelled"} - @body = msg - @session_name = session.name - @session_date = session.pretty_scheduled_start(true) - @session_url = "#{APP_CONFIG.external_root_url}/sessions/#{session.id}/details" - sendgrid_category "Notification" - sendgrid_unique_args :type => unique_args[:type] - - sendgrid_recipients([email]) - sendgrid_substitute('@USERID', [user.id]) - - mail(:to => email, :subject => subject) do |format| - format.text - format.html - end - end - - def scheduled_session_rescheduled(user, msg, session) - return if !user.subscribe_email - - email = user.email - subject = "Session Rescheduled" - unique_args = {:type => "scheduled_session_rescheduled"} - @body = msg - @session_name = session.name - @session_date = session.pretty_scheduled_start(true) - @session_url = "#{APP_CONFIG.external_root_url}/sessions/#{session.id}/details" - sendgrid_category "Notification" - sendgrid_unique_args :type => unique_args[:type] - - sendgrid_recipients([email]) - sendgrid_substitute('@USERID', [user.id]) - - mail(:to => email, :subject => subject) do |format| - format.text - format.html - end - end - - def scheduled_session_reminder_upcoming(user, session) - subject = "Your JamKazam session starts in 1 hour!" - unique_args = {:type => "scheduled_session_reminder_upcoming"} - send_scheduled_session_reminder(user, session, subject, unique_args) - end - - def scheduled_session_reminder_day(user, session) - subject = "JamKazam Session Reminder" - unique_args = {:type => "scheduled_session_reminder_day"} - send_scheduled_session_reminder(user, session, subject, unique_args) - end - - def send_scheduled_session_reminder(user, session, subject, unique_args) - return if !user.subscribe_email - - email = user.email - @user = user - @session_name = session.name - @session_date = session.pretty_scheduled_start(true) - @session_url = "#{APP_CONFIG.external_root_url}/sessions/#{session.id}/details" - sendgrid_category "Notification" - sendgrid_unique_args :type => unique_args[:type] - - sendgrid_recipients([email]) - sendgrid_substitute('@USERID', [user.id]) - - mail(:to => email, :subject => subject) do |format| - format.text - format.html - end - end - - def scheduled_session_comment(target_user, sender, msg, comment, session) - return if !target_user.subscribe_email - - email = target_user.email - subject = "New Session Comment" - unique_args = {:type => "scheduled_session_comment"} - @body = msg - @session_name = session.name - @session_date = session.pretty_scheduled_start(true) - @comment = comment - @sender = sender - @suppress_user_has_account_footer = true - @session_url = "#{APP_CONFIG.external_root_url}/sessions/#{session.id}/details" - sendgrid_category "Notification" - sendgrid_unique_args :type => unique_args[:type] - - sendgrid_recipients([email]) - sendgrid_substitute('@USERID', [target_user.id]) - - mail(:to => email, :subject => subject) do |format| - format.text - format.html { render :layout => "from_user_mailer" } - end - end - - def scheduled_session_daily(receiver, sessions_and_latency) - sendgrid_category "Notification" - sendgrid_unique_args :type => "scheduled_session_daily" - - sendgrid_recipients([receiver.email]) - sendgrid_substitute('@USERID', [receiver.id]) - - @user = receiver - @sessions_and_latency = sessions_and_latency - - @title = 'New Scheduled Sessions Matched to You' - mail(:to => receiver.email, - :subject => EmailBatchScheduledSessions.subject) do |format| - format.text - format.html - end - end - - def band_session_join(user, msg, session_id) - return if !user.subscribe_email - - email = user.email - subject = "A band that you follow has joined a session" - unique_args = {:type => "band_session_join"} - - @body = msg - @session_url = "#{APP_CONFIG.external_root_url}/sessions/#{session_id}" - sendgrid_category "Notification" - sendgrid_unique_args :type => unique_args[:type] - - sendgrid_recipients([email]) - sendgrid_substitute('@USERID', [user.id]) - - mail(:to => email, :subject => subject) do |format| - format.text - format.html - end - end - - def musician_recording_saved(user, msg) - return if !user.subscribe_email - - email = user.email - subject = "A musician has saved a new recording on JamKazam" - unique_args = {:type => "musician_recording_saved"} - - @body = msg - sendgrid_category "Notification" - sendgrid_unique_args :type => unique_args[:type] - - sendgrid_recipients([email]) - sendgrid_substitute('@USERID', [user.id]) - - mail(:to => email, :subject => subject) do |format| - format.text - format.html - end - end - - def band_recording_saved(user, msg) - return if !user.subscribe_email - - email = user.email - subject = "A band has saved a new recording on JamKazam" - unique_args = {:type => "band_recording_saved"} - - @body = msg - sendgrid_category "Notification" - sendgrid_unique_args :type => unique_args[:type] - - sendgrid_recipients([email]) - sendgrid_substitute('@USERID', [user.id]) - - mail(:to => email, :subject => subject) do |format| - format.text - format.html - end - end - - def band_invitation(user, msg) - return if !user.subscribe_email - - email = user.email - subject = "You have been invited to join a band on JamKazam" - unique_args = {:type => "band_invitation"} - - @body = msg - sendgrid_category "Notification" - sendgrid_unique_args :type => unique_args[:type] - - sendgrid_recipients([email]) - sendgrid_substitute('@USERID', [user.id]) - - mail(:to => email, :subject => subject) do |format| - format.text - format.html - end - end - - def band_invitation_accepted(user, msg) - return if !user.subscribe_email - - email = user.email - subject = "Your band invitation was accepted" - unique_args = {:type => "band_invitation_accepted"} - - @body = msg - sendgrid_category "Notification" - sendgrid_unique_args :type => unique_args[:type] - - sendgrid_recipients([email]) - sendgrid_substitute('@USERID', [user.id]) - - mail(:to => email, :subject => subject) do |format| - format.text - format.html - end + def student_unable_charge_monthly(lesson_package_purchase) + lesson_booking = lesson_package_purchase.lesson_booking + @student = lesson_booking.student + @teacher = lesson_booking.teacher + @lesson_package_purchase = lesson_package_purchase + @card_declined = lesson_package_purchase.is_card_declined? + @card_expired = lesson_package_purchase.is_card_expired? + @bill_date = lesson_package_purchase.last_billed_at_date + @lesson_booking = lesson_booking + @month_name = lesson_package_purchase.month_name + email = @student.email + if lesson_booking.is_suspended? + @subject = "Your weekly lessons with #{@teacher.name} have been suspended." + else + @subject = "The credit card charge for your #{@month_name} lessons with #{@teacher.name} failed." end - def text_message(user, sender_id, sender_name, sender_photo_url, message) - return if !user.subscribe_email + unique_args = {:type => "student_unable_charge_monthly"} - email = user.email - subject = "Message from #{sender_name}" - unique_args = {:type => "text_message"} + sendgrid_category "Notification" + sendgrid_unique_args :type => unique_args[:type] - @note = message - @url = Nav.home(dialog: 'text-message', dialog_opts: {d1: sender_id}) - @sender_id = sender_id - @sender_name = sender_name - @sender_photo_url = sender_photo_url - sendgrid_category "Notification" - sendgrid_unique_args :type => unique_args[:type] + sendgrid_recipients([email]) + sendgrid_substitute('@USERID', [@student.id]) - sendgrid_recipients([email]) - sendgrid_substitute('@USERID', [user.id]) - - mail(:to => email, :subject => subject) do |format| - format.text - format.html { render :layout => "from_user_mailer" } - end + mail(:to => email, :subject => @subject) do |format| + format.text + format.html { render :layout => "from_user_mailer" } end - - def student_lesson_request(lesson_booking) - email = lesson_booking.user.email - subject = "You have sent a lesson request to #{lesson_booking.teacher.name}!" - unique_args = {:type => "student_lesson_request"} - - @sender = lesson_booking.teacher - @lesson_booking = lesson_booking - - sendgrid_category "Notification" - sendgrid_unique_args :type => unique_args[:type] - - sendgrid_recipients([email]) - sendgrid_substitute('@USERID', [lesson_booking.user.id]) - - mail(:to => email, :subject => subject) do |format| - format.text - format.html { render :layout => "from_user_mailer" } - end - end - - def teacher_lesson_request(lesson_booking) - email = lesson_booking.teacher.email - subject = "You have received a lesson request through JamKazam!" - unique_args = {:type => "teacher_lesson_request"} - - @sender = lesson_booking.user - @lesson_booking = lesson_booking - - sendgrid_category "Notification" - sendgrid_unique_args :type => unique_args[:type] - - sendgrid_recipients([email]) - sendgrid_substitute('@USERID', [lesson_booking.teacher.id]) - - mail(:to => email, :subject => subject) do |format| - format.text - format.html { render :layout => "from_user_mailer" } - end - end - - def student_lesson_accepted(lesson_session, message, slot) - @slot = slot - if slot.is_teacher_created? - @target = lesson_session.student - @sender = lesson_session.teacher - @subject = "Your have confirmed a lesson!" - else - @target = lesson_session.teacher - @sender = lesson_session.student - @subject = "Your lesson request is confirmed!" - end - @lesson_session = lesson_session - @message = message - email = lesson_session.student.email - unique_args = {:type => "student_lesson_accepted"} - - sendgrid_category "Notification" - sendgrid_unique_args :type => unique_args[:type] - - sendgrid_recipients([email]) - sendgrid_substitute('@USERID', [lesson_session.student.id]) - - mail(:to => email, :subject => @subject) do |format| - format.text - format.html { render :layout => "from_user_mailer" } - end - end - - def teacher_lesson_accepted(lesson_session, message, slot) - @slot = slot - if slot.is_teacher_created? - @target = lesson_session.student - @sender = lesson_session.teacher - @subject = "Your lesson time change is confirmed by #{lesson_session.student.name}!" - else - @target = lesson_session.teacher - @sender = lesson_session.student - @subject = "You have confirmed a lesson!" - end - - @lesson_session = lesson_session - @message = message - email = lesson_session.teacher.email - unique_args = {:type => "teacher_lesson_accepted"} - - sendgrid_category "Notification" - sendgrid_unique_args :type => unique_args[:type] - - sendgrid_recipients([email]) - sendgrid_substitute('@USERID', [lesson_session.teacher.id]) - - mail(:to => email, :subject => @subject) do |format| - format.text - format.html { render :layout => "from_user_mailer" } - end - end - - def student_lesson_update_all(lesson_session, message, slot) - @slot = slot - if slot.is_teacher_created? - @target = lesson_session.student - @sender = lesson_session.teacher - subject = "All lesson times changed with #{lesson_session.student.name}!" - else - @target = lesson_session.teacher - @sender = lesson_session.student - subject = "All lesson times changed with #{lesson_session.student.name}!" - end - @lesson_session = lesson_session - @message = message - email = lesson_session.student.email - unique_args = {:type => "student_lesson_accepted"} - - sendgrid_category "Notification" - sendgrid_unique_args :type => unique_args[:type] - - sendgrid_recipients([email]) - sendgrid_substitute('@USERID', [lesson_session.student.id]) - - mail(:to => email, :subject => subject) do |format| - format.text - format.html { render :layout => "from_user_mailer" } - end - end - - def teacher_lesson_update_all(lesson_session, message, slot) - @slot = slot - if slot.is_teacher_created? - @target = lesson_session.student - @sender = lesson_session.teacher - subject = "All lesson times changed with #{lesson_session.student.name}!" - else - @target = lesson_session.teacher - @sender = lesson_session.student - subject = "All lesson times changed with #{lesson_session.student.name}!" - end - - @lesson_session = lesson_session - @message = message - email = lesson_session.teacher.email - unique_args = {:type => "teacher_lesson_update_all"} - - sendgrid_category "Notification" - sendgrid_unique_args :type => unique_args[:type] - - sendgrid_recipients([email]) - sendgrid_substitute('@USERID', [lesson_session.teacher.id]) - - mail(:to => email, :subject => subject) do |format| - format.text - format.html { render :layout => "from_user_mailer" } - end - end - - def teacher_scheduled_jamclass_invitation(user, msg, session) - - email = user.email - subject = "JamClass Scheduled with #{session.lesson_session.student.name}" - unique_args = {:type => "scheduled_jamclass_invitation"} - @student = session.lesson_session.student - @teacher = session.lesson_session.student - @body = msg - @session_name = session.name - @session_description = session.description - @session_date = session.pretty_scheduled_start(true) - @session_url = "#{APP_CONFIG.external_root_url}/sessions/#{session.id}/details" - sendgrid_category "Notification" - sendgrid_unique_args :type => unique_args[:type] - - sendgrid_recipients([email]) - sendgrid_substitute('@USERID', [user.id]) - - mail(:to => email, :subject => subject) do |format| - format.text - format.html - end - end - - def student_scheduled_jamclass_invitation(user, msg, session) - return if !user.subscribe_email - - email = user.email - subject = "JamClass Scheduled with #{session.lesson_session.teacher.name}" - unique_args = {:type => "scheduled_jamclass_invitation"} - @student = session.lesson_session.student - @teacher = session.lesson_session.student - @body = msg - @session_name = session.name - @session_description = session.description - @session_date = session.pretty_scheduled_start(true) - @session_url = "#{APP_CONFIG.external_root_url}/sessions/#{session.id}/details" - sendgrid_category "Notification" - sendgrid_unique_args :type => unique_args[:type] - - sendgrid_recipients([email]) - sendgrid_substitute('@USERID', [user.id]) - - mail(:to => email, :subject => subject) do |format| - format.text - format.html - end - end - - # teacher proposed counter time; so send msg to the student - def student_lesson_counter(lesson_session, slot) - - email = lesson_session.student.email - subject = "Instructor has proposed a different time for your lesson" - unique_args = {:type => "student_lesson_counter"} - @student = lesson_session.student - @teacher = lesson_session.teacher - @session_name = lesson_session.music_session.name - @session_description = lesson_session.music_session.description - @session_date = slot.pretty_scheduled_start(true) - @session_url = lesson_session.web_url - @lesson_session = lesson_session - sendgrid_category "Notification" - sendgrid_unique_args :type => unique_args[:type] - - sendgrid_recipients([email]) - sendgrid_substitute('@USERID', [@student.id]) - - mail(:to => email, :subject => subject) do |format| - format.text - format.html - end - end - # student proposed counter time; so send msg to the teacher - def teacher_lesson_counter(lesson_session, slot) - - email = lesson_session.teacher.email - subject = "Student has proposed a different time for their lesson" - unique_args = {:type => "teacher_lesson_counter"} - @student = lesson_session.student - @teacher = lesson_session.teacher - @session_name = lesson_session.music_session.name - @session_description = lesson_session.music_session.description - @session_date = slot.pretty_scheduled_start(true) - @session_url = lesson_session.web_url - @lesson_session = lesson_session - sendgrid_category "Notification" - sendgrid_unique_args :type => unique_args[:type] - - sendgrid_recipients([email]) - sendgrid_substitute('@USERID', [@teacher.id]) - - mail(:to => email, :subject => subject) do |format| - format.text - format.html - end - end - - def teacher_lesson_completed(lesson_session) - @student = lesson_session.student - @teacher = lesson_session.teacher - @session_name = lesson_session.music_session.name - @session_description = lesson_session.music_session.description - @session_date = lesson_session.slot.pretty_scheduled_start(true) - @session_url = lesson_session.web_url - @lesson_session = lesson_session - email = lesson_session.teacher.email - subject = "You successfully completed a lesson with #{@student.name}" - unique_args = {:type => "teacher_lesson_completed"} - - sendgrid_category "Notification" - sendgrid_unique_args :type => unique_args[:type] - - sendgrid_recipients([email]) - sendgrid_substitute('@USERID', [@teacher.id]) - - mail(:to => email, :subject => subject) do |format| - format.text - format.html { render :layout => "from_user_mailer" } - end - end - - # successfully completed, and has some remaining test drives - def student_test_drive_lesson_completed(lesson_session) - - @student = lesson_session.student - @teacher = lesson_session.teacher - @session_name = lesson_session.music_session.name - @session_description = lesson_session.music_session.description - @session_date = lesson_session.slot.pretty_scheduled_start(true) - @session_url = lesson_session.web_url - @lesson_session = lesson_session - - email = @student.email - subject = "You have used #{@student.remaining_test_drives} of 4 TestDrive lesson credits" - unique_args = {:type => "student_test_drive_success"} - - sendgrid_category "Notification" - sendgrid_unique_args :type => unique_args[:type] - - sendgrid_recipients([email]) - sendgrid_substitute('@USERID', [@student.id]) - - mail(:to => email, :subject => subject) do |format| - format.text - format.html { render :layout => "from_user_mailer" } - end - end - - # successfully completed, but no more test drives left - def student_test_drive_lesson_done(lesson_session) - - @student = lesson_session.student - @teacher = lesson_session.teacher - @session_name = lesson_session.music_session.name - @session_description = lesson_session.music_session.description - @session_date = lesson_session.slot.pretty_scheduled_start(true) - @session_url = lesson_session.web_url - @lesson_session = lesson_session - - email = @student.email - subject = "You have used all 4 TestDrive lesson credits" - unique_args = {:type => "student_test_drive_success"} - - sendgrid_category "Notification" - sendgrid_unique_args :type => unique_args[:type] - - sendgrid_recipients([email]) - sendgrid_substitute('@USERID', [@student.id]) - - mail(:to => email, :subject => subject) do |format| - format.text - format.html { render :layout => "raw_mailer" } - end - end - - def student_lesson_normal_no_bill(lesson_session) - @student = lesson_session.student - @teacher = lesson_session.teacher - @session_name = lesson_session.music_session.name - @session_description = lesson_session.music_session.description - @session_date = lesson_session.slot.pretty_scheduled_start(true) - @session_url = lesson_session.web_url - @lesson_session = lesson_session - - email = @student.email - subject = "Your lesson with #{@teacher.name} will not be billed" - unique_args = {:type => "student_lesson_normal_no_bill"} - - sendgrid_category "Notification" - sendgrid_unique_args :type => unique_args[:type] - - sendgrid_recipients([email]) - sendgrid_substitute('@USERID', [@student.id]) - - mail(:to => email, :subject => subject) do |format| - format.text - format.html { render :layout => "from_user_mailer" } - end - end - - def teacher_lesson_normal_no_bill(lesson_session) - @student = lesson_session.student - @teacher = lesson_session.teacher - @session_name = lesson_session.music_session.name - @session_description = lesson_session.music_session.description - @session_date = lesson_session.slot.pretty_scheduled_start(true) - @session_url = lesson_session.web_url - @lesson_session = lesson_session - email = lesson_session.teacher.email - subject = "Your student #{@student.name} will not be charged for their lesson" - unique_args = {:type => "teacher_lesson_normal_no_bill"} - - sendgrid_category "Notification" - sendgrid_unique_args :type => unique_args[:type] - - sendgrid_recipients([email]) - sendgrid_substitute('@USERID', [@teacher.id]) - - mail(:to => email, :subject => subject) do |format| - format.text - format.html { render :layout => "from_user_mailer" } - end - end - - def student_lesson_normal_done(lesson_session) - @student = lesson_session.student - @teacher = lesson_session.teacher - @session_name = lesson_session.music_session.name - @session_description = lesson_session.music_session.description - @session_date = lesson_session.slot.pretty_scheduled_start(true) - @session_url = lesson_session.web_url - @lesson_session = lesson_session - - email = @student.email - subject = "Your JamClass lesson today with #{@teacher.first_name}" - unique_args = {:type => "student_lesson_normal_done"} - - sendgrid_category "Notification" - sendgrid_unique_args :type => unique_args[:type] - - sendgrid_recipients([email]) - sendgrid_substitute('@USERID', [@student.id]) - - mail(:to => email, :subject => subject) do |format| - format.text - format.html { render :layout => "from_user_mailer" } - end - end - - def teacher_lesson_normal_done(lesson_session) - @student = lesson_session.student - @teacher = lesson_session.teacher - @session_name = lesson_session.music_session.name - @session_description = lesson_session.music_session.description - @session_date = lesson_session.slot.pretty_scheduled_start(true) - @session_url = lesson_session.web_url - @lesson_session = lesson_session - email = lesson_session.teacher.email - subject = "Your JamClass lesson today with #{@student.first_name}" - unique_args = {:type => "teacher_lesson_normal_done"} - - sendgrid_category "Notification" - sendgrid_unique_args :type => unique_args[:type] - - sendgrid_recipients([email]) - sendgrid_substitute('@USERID', [@teacher.id]) - - mail(:to => email, :subject => subject) do |format| - format.text - format.html { render :layout => "from_user_mailer" } - end - end - - def student_unable_charge(lesson_session) - @student = lesson_session.student - @teacher = lesson_session.teacher - @session_name = lesson_session.music_session.name - @session_description = lesson_session.music_session.description - @session_date = lesson_session.slot.pretty_scheduled_start(true) - @session_url = lesson_session.web_url - @lesson_session = lesson_session - @card_declined = lesson_session.is_card_declined? - @card_expired = lesson_session.is_card_expired? - @bill_date = lesson_session.last_billed_at_date - - email = @student.email - subject = "The credit card charge for your lesson today with #{@teacher.name} failed" - unique_args = {:type => "student_unable_charge"} - - sendgrid_category "Notification" - sendgrid_unique_args :type => unique_args[:type] - - sendgrid_recipients([email]) - sendgrid_substitute('@USERID', [@student.id]) - - mail(:to => email, :subject => subject) do |format| - format.text - format.html { render :layout => "from_user_mailer" } - end - end - - def teacher_unable_charge(lesson_session) - @student = lesson_session.student - @teacher = lesson_session.teacher - @session_name = lesson_session.music_session.name - @session_description = lesson_session.music_session.description - @session_date = lesson_session.slot.pretty_scheduled_start(true) - @session_url = lesson_session.web_url - @lesson_session = lesson_session - email = lesson_session.teacher.email - subject = "The credit card charge for your lesson today with #{@teacher.name} failed" - unique_args = {:type => "teacher_lesson_normal_done"} - - sendgrid_category "Notification" - sendgrid_unique_args :type => unique_args[:type] - - sendgrid_recipients([email]) - sendgrid_substitute('@USERID', [@teacher.id]) - - mail(:to => email, :subject => subject) do |format| - format.text - format.html { render :layout => "from_user_mailer" } - end - end - - def student_unable_charge_monthly(lesson_package_purchase) - lesson_booking = lesson_package_purchase.lesson_booking - @student = lesson_booking.student - @teacher = lesson_booking.teacher - @lesson_package_purchase = lesson_package_purchase - @card_declined = lesson_package_purchase.is_card_declined? - @card_expired = lesson_package_purchase.is_card_expired? - @bill_date = lesson_package_purchase.last_billed_at_date - @lesson_booking = lesson_booking - @month_name = lesson_package_purchase.month_name - email = @student.email - if lesson_booking.is_suspended? - @subject = "Your weekly lessons with #{@teacher.name} have been suspended." - else - @subject = "The credit card charge for your #{@month_name} lessons with #{@teacher.name} failed." - end - - - - unique_args = {:type => "student_unable_charge_monthly"} - - sendgrid_category "Notification" - sendgrid_unique_args :type => unique_args[:type] - - sendgrid_recipients([email]) - sendgrid_substitute('@USERID', [@student.id]) - - mail(:to => email, :subject => @subject) do |format| - format.text - format.html { render :layout => "from_user_mailer" } - end - end - - def teacher_unable_charge_monthly(lesson_package_purchase) - lesson_booking = lesson_package_purchase.lesson_booking - @student = lesson_booking.student - @teacher = lesson_booking.teacher - @lesson_package_purchase = lesson_package_purchase - @card_declined = lesson_package_purchase.is_card_declined? - @card_expired = lesson_package_purchase.is_card_expired? - @bill_date = lesson_package_purchase.last_billed_at_date - @lesson_booking = lesson_booking - @month_name = lesson_package_purchase.month_name - - email = @teacher.email - if lesson_booking.is_suspended? - @subject = "Your weekly lessons with #{@student.name} has been suspended." - else - @subject = "The student #{@student.name} had a failed credit card charge for #{@month_name}." - end - - - unique_args = {:type => "teacher_unable_charge_monthly"} - - sendgrid_category "Notification" - sendgrid_unique_args :type => unique_args[:type] - - sendgrid_recipients([email]) - sendgrid_substitute('@USERID', [@teacher.id]) - - mail(:to => email, :subject => @subject) do |format| - format.text - format.html { render :layout => "from_user_mailer" } - end - end - - def student_lesson_monthly_charged(lesson_package_purchase) - lesson_booking = lesson_package_purchase.lesson_booking - @student = lesson_booking.student - @teacher = lesson_booking.teacher - @lesson_package_purchase = lesson_package_purchase - @card_declined = lesson_package_purchase.is_card_declined? - @card_expired = lesson_package_purchase.is_card_expired? - @bill_date = lesson_package_purchase.last_billed_at_date - @lesson_booking = lesson_booking - @month_name = lesson_package_purchase.month_name - email = @student.email - @subject = "Your JamClass lessons with #{@teacher.first_name} for #{@month_name}" - - unique_args = {:type => "student_lesson_monthly_charged"} - - sendgrid_category "Notification" - sendgrid_unique_args :type => unique_args[:type] - - sendgrid_recipients([email]) - sendgrid_substitute('@USERID', [@student.id]) - - mail(:to => email, :subject => @subject) do |format| - format.text - format.html { render :layout => "from_user_mailer" } - end - end - - def teacher_lesson_monthly_charged(lesson_package_purchase) - lesson_booking = lesson_package_purchase.lesson_booking - @student = lesson_booking.student - @teacher = lesson_booking.teacher - @lesson_package_purchase = lesson_package_purchase - @card_declined = lesson_package_purchase.is_card_declined? - @card_expired = lesson_package_purchase.is_card_expired? - @bill_date = lesson_package_purchase.last_billed_at_date - @lesson_booking = lesson_booking - @month_name = lesson_package_purchase.month_name - - email = @teacher.email - if lesson_booking.is_suspended? - @subject = "Your weekly lessons with #{@student.name} has been suspended." - else - @subject = "The student #{@student.name} had a failed credit card charge for #{@month_name}." - end - - - unique_args = {:type => "student_lesson_monthly_charged"} - - sendgrid_category "Notification" - sendgrid_unique_args :type => unique_args[:type] - - sendgrid_recipients([email]) - sendgrid_substitute('@USERID', [@teacher.id]) - - mail(:to => email, :subject => @subject) do |format| - format.text - format.html { render :layout => "from_user_mailer" } - end - end - - def teacher_distribution_done(teacher_payment) - @teacher_payment = teacher_payment - @teacher = teacher_payment.teacher - email = @teacher.email - - @subject = "You have received payment for your participation in JamClass" - unique_args = {:type => "teacher_distribution_done"} - - sendgrid_category "Notification" - sendgrid_unique_args :type => unique_args[:type] - - sendgrid_recipients([email]) - sendgrid_substitute('@USERID', [@teacher.id]) - - mail(:to => email, :subject => @subject) do |format| - format.text - format.html - end - end - - def teacher_distribution_fail(teacher_payment) - @teacher_payment = teacher_payment - @teacher = teacher_payment.teacher - email = @teacher.email - - @card_declined = teacher_payment.is_card_declined? - @card_expired = teacher_payment.is_card_expired? - @bill_date = teacher_payment.last_billed_at_date - - - @subject = "We were unable to pay you today" - unique_args = {:type => "teacher_distribution_fail"} - - sendgrid_category "Notification" - sendgrid_unique_args :type => unique_args[:type] - - sendgrid_recipients([email]) - sendgrid_substitute('@USERID', [@teacher.id]) - - mail(:to => email, :subject => @subject) do |format| - format.text - format.html - end + end + + def teacher_unable_charge_monthly(lesson_package_purchase) + lesson_booking = lesson_package_purchase.lesson_booking + @student = lesson_booking.student + @teacher = lesson_booking.teacher + @lesson_package_purchase = lesson_package_purchase + @card_declined = lesson_package_purchase.is_card_declined? + @card_expired = lesson_package_purchase.is_card_expired? + @bill_date = lesson_package_purchase.last_billed_at_date + @lesson_booking = lesson_booking + @month_name = lesson_package_purchase.month_name + + email = @teacher.email + if lesson_booking.is_suspended? + @subject = "Your weekly lessons with #{@student.name} has been suspended." + else + @subject = "The student #{@student.name} had a failed credit card charge for #{@month_name}." end + unique_args = {:type => "teacher_unable_charge_monthly"} + sendgrid_category "Notification" + sendgrid_unique_args :type => unique_args[:type] - def monthly_recurring_done(lesson_session) - @student = lesson_session.student - @teacher = lesson_session.teacher - @session_name = lesson_session.music_session.name - @session_description = lesson_session.music_session.description - @session_date = lesson_session.slot.pretty_scheduled_start(true) - @session_url = lesson_session.web_url - @lesson_session = lesson_session + sendgrid_recipients([email]) + sendgrid_substitute('@USERID', [@teacher.id]) - email = @student.email - subject = "Your JamClass lesson today with #{@teacher.first_name}" - unique_args = {:type => "student_lesson_normal_no_bill"} + mail(:to => email, :subject => @subject) do |format| + format.text + format.html { render :layout => "from_user_mailer" } + end + end - sendgrid_category "Notification" - sendgrid_unique_args :type => unique_args[:type] + def student_lesson_monthly_charged(lesson_package_purchase) + lesson_booking = lesson_package_purchase.lesson_booking + @student = lesson_booking.student + @teacher = lesson_booking.teacher + @lesson_package_purchase = lesson_package_purchase + @card_declined = lesson_package_purchase.is_card_declined? + @card_expired = lesson_package_purchase.is_card_expired? + @bill_date = lesson_package_purchase.last_billed_at_date + @lesson_booking = lesson_booking + @month_name = lesson_package_purchase.month_name + email = @student.email + @subject = "Your JamClass lessons with #{@teacher.first_name} for #{@month_name}" - sendgrid_recipients([email]) - sendgrid_substitute('@USERID', [@student.id]) + unique_args = {:type => "student_lesson_monthly_charged"} - mail(:to => email, :subject => subject) do |format| - format.text - format.html { render :layout => "from_user_mailer" } - end + sendgrid_category "Notification" + sendgrid_unique_args :type => unique_args[:type] + + sendgrid_recipients([email]) + sendgrid_substitute('@USERID', [@student.id]) + + mail(:to => email, :subject => @subject) do |format| + format.text + format.html { render :layout => "from_user_mailer" } + end + end + + def teacher_lesson_monthly_charged(lesson_package_purchase) + lesson_booking = lesson_package_purchase.lesson_booking + @student = lesson_booking.student + @teacher = lesson_booking.teacher + @lesson_package_purchase = lesson_package_purchase + @card_declined = lesson_package_purchase.is_card_declined? + @card_expired = lesson_package_purchase.is_card_expired? + @bill_date = lesson_package_purchase.last_billed_at_date + @lesson_booking = lesson_booking + @month_name = lesson_package_purchase.month_name + + email = @teacher.email + if lesson_booking.is_suspended? + @subject = "Your weekly lessons with #{@student.name} has been suspended." + else + @subject = "The student #{@student.name} had a failed credit card charge for #{@month_name}." end - def monthly_recurring_no_bill(lesson_session) - @student = lesson_session.student - @teacher = lesson_session.teacher - @session_name = lesson_session.music_session.name - @session_description = lesson_session.music_session.description - @session_date = lesson_session.slot.pretty_scheduled_start(true) - @session_url = lesson_session.web_url - @lesson_session = lesson_session - email = @student.email - subject = "Your lesson with #{@teacher.name} will not be billed" - unique_args = {:type => "student_lesson_normal_done"} + unique_args = {:type => "student_lesson_monthly_charged"} - sendgrid_category "Notification" - sendgrid_unique_args :type => unique_args[:type] + sendgrid_category "Notification" + sendgrid_unique_args :type => unique_args[:type] - sendgrid_recipients([email]) - sendgrid_substitute('@USERID', [@student.id]) + sendgrid_recipients([email]) + sendgrid_substitute('@USERID', [@teacher.id]) - mail(:to => email, :subject => subject) do |format| - format.text - format.html { render :layout => "from_user_mailer" } - end + mail(:to => email, :subject => @subject) do |format| + format.text + format.html { render :layout => "from_user_mailer" } + end + end + + def teacher_distribution_done(teacher_payment) + @teacher_payment = teacher_payment + @teacher = teacher_payment.teacher + email = @teacher.email + + @subject = "You have received payment for your participation in JamClass" + unique_args = {:type => "teacher_distribution_done"} + + sendgrid_category "Notification" + sendgrid_unique_args :type => unique_args[:type] + + sendgrid_recipients([email]) + sendgrid_substitute('@USERID', [@teacher.id]) + + mail(:to => email, :subject => @subject) do |format| + format.text + format.html + end + end + + def teacher_distribution_fail(teacher_payment) + @teacher_payment = teacher_payment + @teacher = teacher_payment.teacher + email = @teacher.email + + @card_declined = teacher_payment.is_card_declined? + @card_expired = teacher_payment.is_card_expired? + @bill_date = teacher_payment.last_billed_at_date + + + @subject = "We were unable to pay you today" + unique_args = {:type => "teacher_distribution_fail"} + + sendgrid_category "Notification" + sendgrid_unique_args :type => unique_args[:type] + + sendgrid_recipients([email]) + sendgrid_substitute('@USERID', [@teacher.id]) + + mail(:to => email, :subject => @subject) do |format| + format.text + format.html + end + end + + def monthly_recurring_done(lesson_session) + @student = lesson_session.student + @teacher = lesson_session.teacher + @session_name = lesson_session.music_session.name + @session_description = lesson_session.music_session.description + @session_date = lesson_session.slot.pretty_scheduled_start(true) + @session_url = lesson_session.web_url + @lesson_session = lesson_session + + email = @student.email + subject = "Your JamClass lesson today with #{@teacher.first_name}" + unique_args = {:type => "student_lesson_normal_no_bill"} + + sendgrid_category "Notification" + sendgrid_unique_args :type => unique_args[:type] + + sendgrid_recipients([email]) + sendgrid_substitute('@USERID', [@student.id]) + + mail(:to => email, :subject => subject) do |format| + format.text + format.html { render :layout => "from_user_mailer" } + end + end + + def monthly_recurring_no_bill(lesson_session) + @student = lesson_session.student + @teacher = lesson_session.teacher + @session_name = lesson_session.music_session.name + @session_description = lesson_session.music_session.description + @session_date = lesson_session.slot.pretty_scheduled_start(true) + @session_url = lesson_session.web_url + @lesson_session = lesson_session + + email = @student.email + subject = "Your lesson with #{@teacher.name} will not be billed" + unique_args = {:type => "student_lesson_normal_done"} + + sendgrid_category "Notification" + sendgrid_unique_args :type => unique_args[:type] + + sendgrid_recipients([email]) + sendgrid_substitute('@USERID', [@student.id]) + + mail(:to => email, :subject => subject) do |format| + format.text + format.html { render :layout => "from_user_mailer" } + end + end + + def student_lesson_booking_declined(lesson_booking, message) + @lesson_booking = lesson_booking + @student = lesson_booking.student + @teacher = lesson_booking.teacher + @message = message + @lesson_session = lesson_booking.next_lesson + @session_name = @lesson_session.music_session.name + @session_description = @lesson_session.music_session.description + @session_date = @lesson_session.slot.pretty_scheduled_start(true) + email = @student.email + @subject = "We're sorry your lesson request has been declined" + unique_args = {:type => "student_lesson_booking_declined"} + + sendgrid_category "Notification" + sendgrid_unique_args :type => unique_args[:type] + sendgrid_recipients([email]) + sendgrid_substitute('@USERID', [@student.id]) + + mail(:to => email, :subject => @subject) do |format| + format.text + format.html { render :layout => "from_user_mailer" } + end + end + + def student_lesson_booking_canceled(lesson_booking, message) + @lesson_booking = lesson_booking + @student = lesson_booking.student + @teacher = lesson_booking.teacher + @message = message + @lesson_session = lesson_booking.next_lesson + @session_name = @lesson_session.music_session.name + @session_description = @lesson_session.music_session.description + @session_date = @lesson_session.slot.pretty_scheduled_start(true) + email = @student.email + @subject = "Your lesson has been canceled" + unique_args = {:type => "student_lesson_booking_canceled"} + + sendgrid_category "Notification" + sendgrid_unique_args :type => unique_args[:type] + sendgrid_recipients([email]) + sendgrid_substitute('@USERID', [@student.id]) + + mail(:to => email, :subject => @subject) do |format| + format.text + format.html { render :layout => "from_user_mailer" } + end + end + + def teacher_lesson_booking_canceled(lesson_booking, message) + @lesson_booking = lesson_booking + @student = lesson_booking.student + @teacher = lesson_booking.teacher + @message = message + @lesson_session = lesson_booking.next_lesson + @session_name = @lesson_session.music_session.name + @session_description = @lesson_session.music_session.description + @session_date = @lesson_session.slot.pretty_scheduled_start(true) + + email = @teacher.email + @subject = "Your lesson has been canceled" + unique_args = {:type => "teacher_lesson_booking_canceled"} + + sendgrid_category "Notification" + sendgrid_unique_args :type => unique_args[:type] + sendgrid_recipients([email]) + sendgrid_substitute('@USERID', [@teacher.id]) + + mail(:to => email, :subject => @subject) do |format| + format.text + format.html { render :layout => "from_user_mailer" } + end + end + + def student_lesson_canceled(lesson_session, message) + @lesson_booking = lesson_booking = lesson_session.lesson_booking + @student = lesson_booking.student + @teacher = lesson_booking.teacher + @message = message + @lesson_session = lesson_booking.next_lesson + @session_name = @lesson_session.music_session.name + @session_description = @lesson_session.music_session.description + @session_date = @lesson_session.slot.pretty_scheduled_start(true) + email = @student.email + @subject = "Your lesson has been canceled" + unique_args = {:type => "student_lesson_canceled"} + + sendgrid_category "Notification" + sendgrid_unique_args :type => unique_args[:type] + sendgrid_recipients([email]) + sendgrid_substitute('@USERID', [@student.id]) + + mail(:to => email, :subject => @subject) do |format| + format.text + format.html { render :layout => "from_user_mailer" } + end + end + + def teacher_lesson_canceled(lesson_session, message) + @lesson_booking = lesson_booking = lesson_session.lesson_booking + @student = lesson_booking.student + @teacher = lesson_booking.teacher + @message = message + @lesson_session = lesson_booking.next_lesson + @session_name = @lesson_session.music_session.name + @session_description = @lesson_session.music_session.description + @session_date = @lesson_session.slot.pretty_scheduled_start(true) + + email = @teacher.email + @subject = "Your lesson has been canceled" + unique_args = {:type => "teacher_lesson_canceled"} + + sendgrid_category "Notification" + sendgrid_unique_args :type => unique_args[:type] + sendgrid_recipients([email]) + sendgrid_substitute('@USERID', [@teacher.id]) + + mail(:to => email, :subject => @subject) do |format| + format.text + format.html { render :layout => "from_user_mailer" } end end end +end diff --git a/ruby/lib/jam_ruby/app/views/jam_ruby/user_mailer/student_lesson_accepted.html.erb b/ruby/lib/jam_ruby/app/views/jam_ruby/user_mailer/student_lesson_accepted.html.erb index 914557fb5..d60afb1dc 100644 --- a/ruby/lib/jam_ruby/app/views/jam_ruby/user_mailer/student_lesson_accepted.html.erb +++ b/ruby/lib/jam_ruby/app/views/jam_ruby/user_mailer/student_lesson_accepted.html.erb @@ -9,7 +9,7 @@ You have confirmed a lesson request. <% end %> - <% if @message %> + <% if @message.present? %>

<%= @sender.name %> says:
<%= @message %>
diff --git a/ruby/lib/jam_ruby/app/views/jam_ruby/user_mailer/student_lesson_booking_canceled.html.erb b/ruby/lib/jam_ruby/app/views/jam_ruby/user_mailer/student_lesson_booking_canceled.html.erb new file mode 100644 index 000000000..bc819bb5e --- /dev/null +++ b/ruby/lib/jam_ruby/app/views/jam_ruby/user_mailer/student_lesson_booking_canceled.html.erb @@ -0,0 +1,29 @@ +<% provide(:title, @subject) %> +<% provide(:photo_url, @lesson_booking.canceler.resolved_photo_url) %> + +<% content_for :note do %> +

+ <% if @lesson_booking.recurring %> + + All lessons that were scheduled for <%= @lesson_booking.dayWeekDesc %> with <%= @teacher.name %> have been canceled. + + <% else %> + Your lesson with <%= @teacher.name %> has been canceled.

+ + Session Name: <%= @session_name %>
+ Session Description: <%= @session_description %>
+ <%= @session_date %> + <% end %> + + <% if @message.present? %> +

<%= @lesson_booking.canceler.name %> says: +
<%= @message %> +
+ <% end %> +

Click the button below to view more info about the canceled session.

+

+ VIEW LESSON DETAILS +

+<% end %> + + diff --git a/ruby/lib/jam_ruby/app/views/jam_ruby/user_mailer/student_lesson_booking_canceled.text.erb b/ruby/lib/jam_ruby/app/views/jam_ruby/user_mailer/student_lesson_booking_canceled.text.erb new file mode 100644 index 000000000..c7506b0ad --- /dev/null +++ b/ruby/lib/jam_ruby/app/views/jam_ruby/user_mailer/student_lesson_booking_canceled.text.erb @@ -0,0 +1,3 @@ +<%= @subject %> + +To see this lesson, click here: <%= @lesson_session.web_url %> \ No newline at end of file diff --git a/ruby/lib/jam_ruby/app/views/jam_ruby/user_mailer/student_lesson_booking_declined.html.erb b/ruby/lib/jam_ruby/app/views/jam_ruby/user_mailer/student_lesson_booking_declined.html.erb new file mode 100644 index 000000000..410621edb --- /dev/null +++ b/ruby/lib/jam_ruby/app/views/jam_ruby/user_mailer/student_lesson_booking_declined.html.erb @@ -0,0 +1,20 @@ +<% provide(:title, @subject) %> +<% provide(:photo_url, @teacher.resolved_photo_url) %> + +<% content_for :note do %> +

+ + This teacher has declined your lesson request. + + <% if @message.present? %> +

<%= @teacher.name %> says: +
<%= @message %> +
+ <% end %> +

Click the button below to view the teacher's response.

+

+ VIEW RESPONSE +

+<% end %> + + diff --git a/ruby/lib/jam_ruby/app/views/jam_ruby/user_mailer/student_lesson_booking_declined.text.erb b/ruby/lib/jam_ruby/app/views/jam_ruby/user_mailer/student_lesson_booking_declined.text.erb new file mode 100644 index 000000000..c7506b0ad --- /dev/null +++ b/ruby/lib/jam_ruby/app/views/jam_ruby/user_mailer/student_lesson_booking_declined.text.erb @@ -0,0 +1,3 @@ +<%= @subject %> + +To see this lesson, click here: <%= @lesson_session.web_url %> \ No newline at end of file diff --git a/ruby/lib/jam_ruby/app/views/jam_ruby/user_mailer/student_lesson_canceled.html.erb b/ruby/lib/jam_ruby/app/views/jam_ruby/user_mailer/student_lesson_canceled.html.erb new file mode 100644 index 000000000..26194e95f --- /dev/null +++ b/ruby/lib/jam_ruby/app/views/jam_ruby/user_mailer/student_lesson_canceled.html.erb @@ -0,0 +1,23 @@ +<% provide(:title, @subject) %> +<% provide(:photo_url, @lesson_session.canceler.resolved_photo_url) %> + +<% content_for :note do %> +

+ Your lesson with <%= @teacher.name %> has been canceled.

+ + Session Name: <%= @session_name %>
+ Session Description: <%= @session_description %>
+ <%= @session_date %> + + <% if @message.present? %> +

<%= @lesson_session.canceler.name %> says: +
<%= @message %> +
+ <% end %> +

Click the button below to view more info about the canceled session.

+

+ VIEW RESPONSE +

+<% end %> + + diff --git a/ruby/lib/jam_ruby/app/views/jam_ruby/user_mailer/student_lesson_canceled.text.erb b/ruby/lib/jam_ruby/app/views/jam_ruby/user_mailer/student_lesson_canceled.text.erb new file mode 100644 index 000000000..c7506b0ad --- /dev/null +++ b/ruby/lib/jam_ruby/app/views/jam_ruby/user_mailer/student_lesson_canceled.text.erb @@ -0,0 +1,3 @@ +<%= @subject %> + +To see this lesson, click here: <%= @lesson_session.web_url %> \ No newline at end of file diff --git a/ruby/lib/jam_ruby/app/views/jam_ruby/user_mailer/student_lesson_request.html.erb b/ruby/lib/jam_ruby/app/views/jam_ruby/user_mailer/student_lesson_request.html.erb index ab60f3f5b..4636052b0 100644 --- a/ruby/lib/jam_ruby/app/views/jam_ruby/user_mailer/student_lesson_request.html.erb +++ b/ruby/lib/jam_ruby/app/views/jam_ruby/user_mailer/student_lesson_request.html.erb @@ -1,10 +1,10 @@ -<% provide(:title, "Lesson Request sent to #{@sender.name}") %> +<% provide(:title, "Lesson requested of #{@sender.name}") %> <% provide(:photo_url, @sender.resolved_photo_url) %> <% content_for :note do %> -

You have requested a <%= @lesson_booking.display_type %> lesson.

Click the button below to see your lesson request. You will receive another email when the teacher accepts or reject the request.

+

You have requested a <%= @lesson_booking.display_type %> lesson.

Click the button below to see your lesson request. You will receive another email when the teacher accepts or rejects the request.

- VIEW LESSON REQUEST + VIEW LESSON REQUEST

<% end %> diff --git a/ruby/lib/jam_ruby/app/views/jam_ruby/user_mailer/student_lesson_request.text.erb b/ruby/lib/jam_ruby/app/views/jam_ruby/user_mailer/student_lesson_request.text.erb index 068228c3e..9ec7f863e 100644 --- a/ruby/lib/jam_ruby/app/views/jam_ruby/user_mailer/student_lesson_request.text.erb +++ b/ruby/lib/jam_ruby/app/views/jam_ruby/user_mailer/student_lesson_request.text.erb @@ -1,3 +1,3 @@ You have requested a lesson from <%= @sender.name %>. -To see this lesson request, click here: <%= @lesson_booking.home_url %> \ No newline at end of file +To see this lesson request, click here: <%= @lesson_booking.web_url %> \ No newline at end of file diff --git a/ruby/lib/jam_ruby/app/views/jam_ruby/user_mailer/student_lesson_update_all.html.erb b/ruby/lib/jam_ruby/app/views/jam_ruby/user_mailer/student_lesson_update_all.html.erb index bf02ed64f..d0259e567 100644 --- a/ruby/lib/jam_ruby/app/views/jam_ruby/user_mailer/student_lesson_update_all.html.erb +++ b/ruby/lib/jam_ruby/app/views/jam_ruby/user_mailer/student_lesson_update_all.html.erb @@ -5,7 +5,7 @@

All lessons with <%= @lesson_session.teacher.name %> have been rescheduled. - <% if @message %> + <% if @message.present? %>

<%= @sender.name %> says:
<%= @message %>
diff --git a/ruby/lib/jam_ruby/app/views/jam_ruby/user_mailer/student_scheduled_jamclass_invitation.html.erb b/ruby/lib/jam_ruby/app/views/jam_ruby/user_mailer/student_scheduled_jamclass_invitation.html.erb index f697780ce..67590256e 100644 --- a/ruby/lib/jam_ruby/app/views/jam_ruby/user_mailer/student_scheduled_jamclass_invitation.html.erb +++ b/ruby/lib/jam_ruby/app/views/jam_ruby/user_mailer/student_scheduled_jamclass_invitation.html.erb @@ -1,11 +1,11 @@ -<% provide(:title, "JamClass Scheduled with #{@teacher.name}") %> +<% provide(:title, @subject) %>

<%= @body %>

- <%= @session_name %>
+ Session Name: <%= @session_name %>
<%= @session_description %>
<%= @session_date %>

-

View Session Details

\ No newline at end of file +

VIEW LESSON DETAILS

\ No newline at end of file diff --git a/ruby/lib/jam_ruby/app/views/jam_ruby/user_mailer/teacher_lesson_booking_canceled.html.erb b/ruby/lib/jam_ruby/app/views/jam_ruby/user_mailer/teacher_lesson_booking_canceled.html.erb new file mode 100644 index 000000000..c0095a170 --- /dev/null +++ b/ruby/lib/jam_ruby/app/views/jam_ruby/user_mailer/teacher_lesson_booking_canceled.html.erb @@ -0,0 +1,29 @@ +<% provide(:title, @subject) %> +<% provide(:photo_url, @lesson_booking.canceler.resolved_photo_url) %> + +<% content_for :note do %> +

+ <% if @lesson_booking.recurring %> + + All lessons that were scheduled for <%= @lesson_booking.dayWeekDesc %> with <%= @student.name %> have been canceled. + + <% else %> + Your lesson with <%= @student.name %> has been canceled.

+ + Session Name: <%= @session_name %>
+ Session Description: <%= @session_description %>
+ <%= @session_date %> + <% end %> + + <% if @message.present? %> +

<%= @lesson_booking.canceler.name %> says: +
<%= @message %> +
+ <% end %> +

Click the button below to view more info about the canceled session.

+

+ VIEW LESSON DETAILS +

+<% end %> + + diff --git a/ruby/lib/jam_ruby/app/views/jam_ruby/user_mailer/teacher_lesson_booking_canceled.text.erb b/ruby/lib/jam_ruby/app/views/jam_ruby/user_mailer/teacher_lesson_booking_canceled.text.erb new file mode 100644 index 000000000..c7506b0ad --- /dev/null +++ b/ruby/lib/jam_ruby/app/views/jam_ruby/user_mailer/teacher_lesson_booking_canceled.text.erb @@ -0,0 +1,3 @@ +<%= @subject %> + +To see this lesson, click here: <%= @lesson_session.web_url %> \ No newline at end of file diff --git a/ruby/lib/jam_ruby/app/views/jam_ruby/user_mailer/teacher_lesson_canceled.html.erb b/ruby/lib/jam_ruby/app/views/jam_ruby/user_mailer/teacher_lesson_canceled.html.erb new file mode 100644 index 000000000..4a60fe695 --- /dev/null +++ b/ruby/lib/jam_ruby/app/views/jam_ruby/user_mailer/teacher_lesson_canceled.html.erb @@ -0,0 +1,24 @@ +<% provide(:title, @subject) %> +<% provide(:photo_url, @lesson_session.canceler.resolved_photo_url) %> + +<% content_for :note do %> +

+ + Your lesson with <%= @teacher.name %> has been canceled.

+ + Session Name: <%= @session_name %>
+ Session Description: <%= @session_description %>
+ <%= @session_date %> + + <% if @message.present? %> +

<%= @lesson_session.canceler.name %> says: +
<%= @message %> +
+ <% end %> +

Click the button below to view more info about the canceled session.

+

+ VIEW LESSON DETAILS +

+<% end %> + + diff --git a/ruby/lib/jam_ruby/app/views/jam_ruby/user_mailer/teacher_lesson_canceled.text.erb b/ruby/lib/jam_ruby/app/views/jam_ruby/user_mailer/teacher_lesson_canceled.text.erb new file mode 100644 index 000000000..c7506b0ad --- /dev/null +++ b/ruby/lib/jam_ruby/app/views/jam_ruby/user_mailer/teacher_lesson_canceled.text.erb @@ -0,0 +1,3 @@ +<%= @subject %> + +To see this lesson, click here: <%= @lesson_session.web_url %> \ No newline at end of file diff --git a/ruby/lib/jam_ruby/app/views/jam_ruby/user_mailer/teacher_lesson_request.html.erb b/ruby/lib/jam_ruby/app/views/jam_ruby/user_mailer/teacher_lesson_request.html.erb index e3f0e537a..a82e118cb 100644 --- a/ruby/lib/jam_ruby/app/views/jam_ruby/user_mailer/teacher_lesson_request.html.erb +++ b/ruby/lib/jam_ruby/app/views/jam_ruby/user_mailer/teacher_lesson_request.html.erb @@ -4,7 +4,7 @@ <% content_for :note do %>

This student has requested to schedule a <%= @lesson_booking.display_type %> lesson.

Click the button below to get more information and to respond to this lesson request. You must respond to this lesson request promptly, or it will be cancelled, thank you!

- VIEW LESSON REQUEST + VIEW LESSON REQUEST

<% end %> diff --git a/ruby/lib/jam_ruby/app/views/jam_ruby/user_mailer/teacher_lesson_update_all.html.erb b/ruby/lib/jam_ruby/app/views/jam_ruby/user_mailer/teacher_lesson_update_all.html.erb index d60477bf7..ff9c4a3b6 100644 --- a/ruby/lib/jam_ruby/app/views/jam_ruby/user_mailer/teacher_lesson_update_all.html.erb +++ b/ruby/lib/jam_ruby/app/views/jam_ruby/user_mailer/teacher_lesson_update_all.html.erb @@ -5,7 +5,7 @@

All lessons with <%= @lesson_session.student.name %> have been rescheduled. - <% if @message %> + <% if @message.present? %>

<%= @sender.name %> says:
<%= @message %>
diff --git a/ruby/lib/jam_ruby/app/views/jam_ruby/user_mailer/teacher_scheduled_jamclass_invitation.html.erb b/ruby/lib/jam_ruby/app/views/jam_ruby/user_mailer/teacher_scheduled_jamclass_invitation.html.erb index 1d466412d..67590256e 100644 --- a/ruby/lib/jam_ruby/app/views/jam_ruby/user_mailer/teacher_scheduled_jamclass_invitation.html.erb +++ b/ruby/lib/jam_ruby/app/views/jam_ruby/user_mailer/teacher_scheduled_jamclass_invitation.html.erb @@ -1,11 +1,11 @@ -<% provide(:title, "JamClass Scheduled with #{@student.name}") %> +<% provide(:title, @subject) %>

<%= @body %>

- <%= @session_name %>
+ Session Name: <%= @session_name %>
<%= @session_description %>
<%= @session_date %>

-

View Session Details

\ No newline at end of file +

VIEW LESSON DETAILS

\ No newline at end of file diff --git a/ruby/lib/jam_ruby/models/chat_message.rb b/ruby/lib/jam_ruby/models/chat_message.rb index 131ccdcb3..3c6b056db 100644 --- a/ruby/lib/jam_ruby/models/chat_message.rb +++ b/ruby/lib/jam_ruby/models/chat_message.rb @@ -60,7 +60,7 @@ module JamRuby query = ChatMessage.where('music_session_id = ?', music_session_id) end - query = query.offset(start).limit(limit).order('created_at DESC') + query = query.offset(start).limit(limit).order('created_at DESC').includes([:user]) if query.length == 0 [query, nil] diff --git a/ruby/lib/jam_ruby/models/jam_track.rb b/ruby/lib/jam_ruby/models/jam_track.rb index 1ad7fb09d..72febb08c 100644 --- a/ruby/lib/jam_ruby/models/jam_track.rb +++ b/ruby/lib/jam_ruby/models/jam_track.rb @@ -338,6 +338,7 @@ module JamRuby query = query.select("original_artist, array_agg(jam_tracks.id) AS id, MIN(name) AS name, MIN(description) AS description, MIN(recording_type) AS recording_type, MIN(original_artist) AS original_artist, MIN(songwriter) AS songwriter, MIN(publisher) AS publisher, MIN(sales_region) AS sales_region, MIN(price) AS price, MIN(version) AS version") query = query.group("original_artist") query = query.order('jam_tracks.original_artist') + query = query.includes([{ jam_track_tracks: :instrument }, { genres_jam_tracks: :genre }]) else query = query.group("jam_tracks.id") if options[:sort_by] == 'jamtrack' diff --git a/ruby/lib/jam_ruby/models/lesson_booking.rb b/ruby/lib/jam_ruby/models/lesson_booking.rb index 982b4bbcb..c8e67efb9 100644 --- a/ruby/lib/jam_ruby/models/lesson_booking.rb +++ b/ruby/lib/jam_ruby/models/lesson_booking.rb @@ -11,8 +11,9 @@ module JamRuby STATUS_CANCELED = 'canceled' STATUS_APPROVED = 'approved' STATUS_SUSPENDED = 'suspended' + STATUS_COUNTERED = 'countered' - STATUS_TYPES = [STATUS_REQUESTED, STATUS_CANCELED, STATUS_APPROVED, STATUS_SUSPENDED] + STATUS_TYPES = [STATUS_REQUESTED, STATUS_CANCELED, STATUS_APPROVED, STATUS_SUSPENDED, STATUS_COUNTERED] LESSON_TYPE_FREE = 'single-free' LESSON_TYPE_TEST_DRIVE = 'test-drive' @@ -30,7 +31,10 @@ module JamRuby belongs_to :user, class_name: "JamRuby::User" belongs_to :teacher, class_name: "JamRuby::User" + belongs_to :accepter, class_name: "JamRuby::User" + belongs_to :canceler, class_name: "JamRuby::User" belongs_to :default_slot, class_name: "JamRuby::LessonBookingSlot", foreign_key: :default_slot_id, inverse_of: :defaulted_booking + belongs_to :counter_slot, class_name: "JamRuby::LessonBookingSlot", foreign_key: :counter_slot_id, inverse_of: :countered_booking has_many :lesson_booking_slots, class_name: "JamRuby::LessonBookingSlot" has_many :lesson_sessions, class_name: "JamRuby::LessonSession" @@ -38,15 +42,16 @@ module JamRuby validates :user, presence: true validates :teacher, presence: true - validates :lesson_type, presence: true, inclusion: {in: LESSON_TYPES} + validates :lesson_type, inclusion: {in: LESSON_TYPES} validates :status, presence: true, inclusion: {in: STATUS_TYPES} validates :recurring, inclusion: {in: [true, false]} validates :sent_notices, inclusion: {in: [true, false]} validates :card_presumed_ok, inclusion: {in: [true, false]} - validates :lesson_length, presence: true, inclusion: {in: [30, 45, 60, 90, 120]} + validates :active, inclusion: {in: [true, false]} + validates :lesson_length, inclusion: {in: [30, 45, 60, 90, 120]} validates :payment_style, inclusion: {in: PAYMENT_STYLES} validates :booked_price, presence: true - validates :description, no_profanity: true, length: {minimum: 10, maximum: 20000}, presence: true + validates :description, no_profanity: true, length: {minimum: 10, maximum: 20000} validate :validate_user, on: :create validate :validate_recurring @@ -62,6 +67,7 @@ module JamRuby around_save :around_update scope :test_drive, -> { where(lesson_type: LESSON_TYPE_TEST_DRIVE) } + scope :active, -> { where(active: true) } scope :approved, -> { where(status: STATUS_APPROVED) } scope :requested, -> { where(status: STATUS_REQUESTED) } scope :canceled, -> { where(status: STATUS_CANCELED) } @@ -107,18 +113,43 @@ module JamRuby booked_price end + + def alt_slot + found = nil + lesson_booking_slots.each do |slot| + if slot.id != default_slot.id + found = slot + break + end + end + found + end + def student user end - def accept(lesson_session, slot) - if !is_approved? + def next_lesson + if recurring + lesson_sessions.joins(:music_session).where("scheduled_start is not null").where("scheduled_start > ?", Time.now).order(:created_at).first + else + lesson_sessions[0] + end + end + + def accept(lesson_session, slot, accepter) + if !is_active? self.accepting = true end + self.active = true + self.status = STATUS_APPROVED + self.counter_slot = nil self.default_slot = slot + self.accepter = accepter if !self.save + puts "unable to accept lesson booking #{errors.inspect}" raise ActiveRecord::Rollback end end @@ -126,6 +157,8 @@ module JamRuby def counter(lesson_session, proposer, slot) self.countering = true self.lesson_booking_slots << slot + self.counter_slot = slot + #self.status = STATUS_COUNTERED if !self.save raise ActiveRecord::Rollback end @@ -244,7 +277,7 @@ module JamRuby if sessions.count == 0 needed_sessions = 1 end - elsif is_approved? + elsif is_active? expected_num_sessions = recurring ? 2 : 1 needed_sessions = expected_num_sessions - sessions.count end @@ -267,7 +300,7 @@ module JamRuby rsvps = [{instrument_id: 'other', proficiency_level: 0, approve: true}] music_session = MusicSession.create(student, { - name: "JamClass taught by #{teacher.name}", + name: "#{display_type2} JamClass taught by #{teacher.name}", description: "This is a #{lesson_length}-minute #{display_type2} with #{teacher.name}.", musician_access: false, fan_access: false, @@ -293,8 +326,11 @@ module JamRuby raise ActiveRecord::Rollback end - # send out email to student to act as something they can add to their calendar - Notification.send_student_jamclass_invitation(music_session, student) + if lesson_session.is_active? + # send out email to student to act as something they can add to their calendar + Notification.send_student_jamclass_invitation(music_session, student) + end + end end @@ -318,11 +354,8 @@ module JamRuby else raise "unable to determine object type of #{target}" end - - end - def is_requested? status == STATUS_REQUESTED end @@ -339,17 +372,22 @@ module JamRuby status == STATUS_SUSPENDED end + def is_active? + active + end + def validate_accepted - if !is_requested? + if self.status_was != STATUS_REQUESTED && self.status_was != STATUS_COUNTERED self.errors.add(:status, "This lesson is already #{self.status}.") end - self.status = STATUS_APPROVED + self.accepting = false end def send_notices UserMailer.student_lesson_request(self).deliver UserMailer.teacher_lesson_request(self).deliver + Notification.send_lesson_message('accept', lesson_sessions[0], false) # TODO: this isn't quite an 'accept' self.sent_notices = true self.save end @@ -380,7 +418,12 @@ module JamRuby elsif is_test_drive? "TestDrive" elsif is_normal? - "Lesson Purchase" + if recurring + "recurring" + else + "single" + end + end end @@ -404,10 +447,8 @@ module JamRuby elsif is_normal? booked_price * 100 end - end - def is_single_free? lesson_type == LESSON_TYPE_FREE end @@ -420,6 +461,70 @@ module JamRuby lesson_type == LESSON_TYPE_PAID end + def dayWeekDesc(slot = default_slot) + day = case slot.day_of_week + when 0 then "Sunday" + when 1 then "Monday" + when 2 then "Tuesday" + when 3 then "Wednesday" + when 4 then "Thursday" + when 5 then "Friday" + when 6 then "Saturday" + end + + + if slot.hour > 11 + hour = slot.hour - 12 + if hour == 0 + hour = 12 + end + am_pm = 'pm' + else + hour = slot.hour + am_pm = 'am' + end + + "#{day} at #{hour}:#{slot.minute}#{am_pm}" + + end + + def approved_before? + !self.accepter_id.nil? + end + def cancel(canceler, other, message) + + self.active = false + self.status = STATUS_CANCELED + self.cancel_message = message + self.canceler = canceler + if save + if approved_before? + # just tell both people it's cancelled, to act as confirmation + Notification.send_lesson_message('canceled', next_lesson, false) + Notification.send_lesson_message('canceled', next_lesson, true) + UserMailer.student_lesson_booking_canceled(self, message).deliver + UserMailer.teacher_lesson_booking_canceled(self, message).deliver + chat_message_prefix = "Lesson Canceled" + else + if canceler == student + # if it's the first time acceptance student canceling, we call it a 'cancel' + Notification.send_lesson_message('canceled', next_lesson, false) + UserMailer.teacher_lesson_booking_canceled(self, message).deliver + chat_message_prefix = "Lesson Canceled" + else + # if it's the first time acceptance teacher, it was declined + UserMailer.student_lesson_booking_declined(self, message).deliver + Notification.send_lesson_message('declined', next_lesson, true) + chat_message_prefix = "Lesson Declined" + end + end + + chat_message = message.nil? ? chat_message_prefix : "#{chat_message_prefix}: #{message}" + msg = ChatMessage.create(canceler, nil, chat_message, ChatMessage::CHANNEL_LESSON, nil, other, self) + + end + end + def card_approved self.card_presumed_ok = true if self.save && !sent_notices @@ -437,8 +542,8 @@ module JamRuby # errors.add(:user, 'has no credit card stored') #end elsif is_test_drive? - if user.has_requested_test_drive? - errors.add(:user, "have requested test drives") + if user.has_requested_test_drive?(teacher) && !user.admin + errors.add(:user, "has a requested TestDrive with this teacher") end if !user.has_test_drives? && !user.can_buy_test_drive? errors.add(:user, "have no remaining test drives") @@ -520,6 +625,7 @@ module JamRuby lesson_booking.lesson_booking_slots = lesson_booking_slots lesson_booking_slots.each do |slot| slot.lesson_booking = lesson_booking + slot.message = description end if lesson_booking_slots if lesson_booking.save @@ -539,7 +645,7 @@ module JamRuby def self.find_bookings_needing_sessions(minimum_start_time) - MusicSession.select([:lesson_booking_id]).joins(:lesson_session => :lesson_booking).where("lesson_bookings.status = '#{STATUS_APPROVED}'").where('lesson_bookings.recurring = true').where("scheduled_start is not null").where("scheduled_start > ?", minimum_start_time).group(:lesson_booking_id).having('count(lesson_booking_id) < 2') + MusicSession.select([:lesson_booking_id]).joins(:lesson_session => :lesson_booking).where("lesson_bookings.active = true").where('lesson_bookings.recurring = true').where("scheduled_start is not null").where("scheduled_start > ?", minimum_start_time).group(:lesson_booking_id).having('count(lesson_booking_id) < 2') end # check for any recurring sessions where there are not at least 2 sessions into the future. If not, we need to make sure they get made @@ -577,7 +683,7 @@ module JamRuby .joins("LEFT JOIN lesson_package_purchases ON (lesson_package_purchases.lesson_booking_id = lesson_bookings.id AND (lesson_package_purchases.year = #{current_month_first_day.year} AND lesson_package_purchases.month = #{current_month_first_day.month}))") .where("lesson_package_purchases.id IS NULL OR (lesson_package_purchases.id IS NOT NULL AND lesson_package_purchases.post_processed = false)") .where(payment_style: PAYMENT_STYLE_MONTHLY) - .where(status: STATUS_APPROVED) + .active .where('music_sessions.scheduled_start >= ?', current_month_first_day) .where('music_sessions.scheduled_start <= ?', current_month_last_day).uniq @@ -653,6 +759,7 @@ module JamRuby def suspend! # when this is called, the calling code sends out a email to let the student and teacher know (it feels unnatural it's not here, though) self.status = STATUS_SUSPENDED + self.active = false if self.save future_sessions.each do |lesson_session| LessonSession.find(lesson_session.id).suspend! @@ -663,6 +770,7 @@ module JamRuby def unsuspend! if self.status == STATUS_SUSPENDED self.status = STATUS_APPROVED + self.active = true if self.save future_sessions.each do |lesson_session| LessonSession.find(lesson_session.id).unsuspend! @@ -692,7 +800,7 @@ module JamRuby end def web_url - APP_CONFIG.external_root_url + "/client#/jamclass/lesson-request/" + id + APP_CONFIG.external_root_url + "/client#/jamclass/lesson-booking/" + id end def update_payment_url diff --git a/ruby/lib/jam_ruby/models/lesson_booking_slot.rb b/ruby/lib/jam_ruby/models/lesson_booking_slot.rb index fdc6fbabe..2f45c55a8 100644 --- a/ruby/lib/jam_ruby/models/lesson_booking_slot.rb +++ b/ruby/lib/jam_ruby/models/lesson_booking_slot.rb @@ -8,6 +8,7 @@ module JamRuby belongs_to :lesson_session, class_name: "JamRuby::LessonSession" belongs_to :proposer, class_name: "JamRuby::User" has_one :defaulted_booking, class_name: "JamRuby::LessonBooking", foreign_key: :default_slot_id, inverse_of: :default_slot + has_one :countered_booking, class_name: "JamRuby::LessonBooking", foreign_key: :counter_slot_id, inverse_of: :counter_slot SLOT_TYPE_SINGLE = 'single' SLOT_TYPE_RECURRING = 'recurring' @@ -46,6 +47,10 @@ module JamRuby self.proposer == container.teacher end + def is_student_created? + !is_teacher_created? + end + def is_teacher_approved? !is_teacher_created? end @@ -122,7 +127,7 @@ module JamRuby found ||= lesson_session.lesson_booking end - def pretty_scheduled_start(with_timezone) + def pretty_scheduled_start(with_timezone = true) start_time = scheduled_time(0) @@ -149,8 +154,34 @@ module JamRuby else "#{start_time.strftime("%A, %B %e")} - #{start_time.strftime("%l:%M%P").strip}" end + end + def pretty_start_time(with_timezone = true) + start_time = scheduled_time(0) + + begin + tz = TZInfo::Timezone.get(timezone) + rescue Exception => e + @@log.error("unable to find timezone=#{tz_identifier}, e=#{e}") + end + + if tz + begin + start_time = tz.utc_to_local(start_time) + rescue Exception => e + @@log.error("unable to convert #{scheduled_start} to #{tz}, e=#{e}") + puts "unable to convert #{e}" + end + end + + duration = lesson_length * 60 # convert from minutes to seconds + end_time = start_time + duration + if with_timezone + "#{start_time.strftime("%a, %b %e")} at #{start_time.strftime("%l:%M%P").strip} #{tz.name}" + else + "#{start_time.strftime("%a, %b %e")} at #{start_time.strftime("%l:%M%P").strip}" + end end def validate_proposer @@ -183,7 +214,10 @@ module JamRuby if is_teacher_created? return # the thinking is that a teacher can propose much tighter to the time; since they only counter; maybe they talked to the student end - minimum_start_time = create_minimum_booking_time + + # + # minimum_start_time = create_minimum_booking_time + minimum_start_time = Time.now if day_of_week # this is recurring; it will sort itself out @@ -191,7 +225,8 @@ module JamRuby time = scheduled_time(0) if time <= minimum_start_time - errors.add("must be at least #{APP_CONFIG.minimum_lesson_booking_hrs} hours out from now") + #errors.add(:base, "must be at least #{APP_CONFIG.minimum_lesson_booking_hrs} hours in the future") + errors.add(:preferred_day, "can not be in the past") end end diff --git a/ruby/lib/jam_ruby/models/lesson_session.rb b/ruby/lib/jam_ruby/models/lesson_session.rb index 6ee8770d0..4c861f24b 100644 --- a/ruby/lib/jam_ruby/models/lesson_session.rb +++ b/ruby/lib/jam_ruby/models/lesson_session.rb @@ -3,13 +3,14 @@ module JamRuby class LessonSession < ActiveRecord::Base - attr_accessor :accepting, :creating, :countering, :countered_slot, :countered_lesson + attr_accessor :accepting, :creating, :countering, :countered_slot, :countered_lesson, :canceling @@log = Logging.logger[LessonSession] delegate :sent_billing_notices, :last_billing_attempt_at, :billing_attempts, :billing_should_retry, :billed, :billed_at, :billing_error_detail, :billing_error_reason, :is_card_declined?, :is_card_expired?, :last_billed_at_date, :sent_billing_notices, to: :lesson_payment_charge - delegate :is_test_drive?, :is_single_free?, :is_normal?, to: :lesson_booking + delegate :is_test_drive?, :is_single_free?, :is_normal?, :approved_before?, :is_active?, to: :lesson_booking + delegate :pretty_scheduled_start, to: :music_session STATUS_REQUESTED = 'requested' @@ -18,8 +19,9 @@ module JamRuby STATUS_COMPLETED = 'completed' STATUS_APPROVED = 'approved' STATUS_SUSPENDED = 'suspended' + STATUS_COUNTERED = 'countered' - STATUS_TYPES = [STATUS_REQUESTED, STATUS_CANCELED, STATUS_MISSED, STATUS_COMPLETED, STATUS_APPROVED, STATUS_SUSPENDED] + STATUS_TYPES = [STATUS_REQUESTED, STATUS_CANCELED, STATUS_MISSED, STATUS_COMPLETED, STATUS_APPROVED, STATUS_SUSPENDED, STATUS_COUNTERED] LESSON_TYPE_SINGLE = 'paid' LESSON_TYPE_SINGLE_FREE = 'single-free' @@ -28,6 +30,7 @@ module JamRuby has_one :music_session, class_name: "JamRuby::MusicSession" belongs_to :teacher, class_name: "JamRuby::User", foreign_key: :teacher_id, inverse_of: :taught_lessons + belongs_to :canceler, class_name: "JamRuby::User", foreign_key: :canceler_id belongs_to :lesson_package_purchase, class_name: "JamRuby::LessonPackagePurchase" belongs_to :lesson_booking, class_name: "JamRuby::LessonBooking" belongs_to :slot, class_name: "JamRuby::LessonBookingSlot", foreign_key: :slot_id @@ -50,10 +53,19 @@ module JamRuby validate :validate_creating, :if => :creating validate :validate_accepted, :if => :accepting + validate :validate_canceled, :if => :canceling + after_save :after_counter, :if => :countering after_save :manage_slot_changes after_create :create_charge + scope :approved, -> { where(status: STATUS_APPROVED) } + scope :requested, -> { where(status: STATUS_REQUESTED) } + scope :canceled, -> { where(status: STATUS_CANCELED) } + scope :suspended, -> { where(status: STATUS_SUSPENDED) } + scope :completed, -> { where(status: STATUS_COMPLETED) } + scope :missed, -> { where(status: STATUS_MISSED) } + def create_charge if !is_test_drive? self.lesson_payment_charge = LessonPaymentCharge.new @@ -310,6 +322,10 @@ module JamRuby status == STATUS_SUSPENDED end + def is_countered? + status == STATUS_COUNTERED + end + def validate_creating if !is_requested? && !is_approved? self.errors.add(:status, "is not valid for a new lesson session.") @@ -321,16 +337,31 @@ module JamRuby end def validate_accepted - if !is_requested? - self.errors.add(:status, "This session is already #{self.status}.") + if self.status_was != STATUS_REQUESTED && self.status_was != STATUS_COUNTERED + self.errors.add(:status, "This session is already #{self.status_was}.") end - if lesson_booking && lesson_booking.is_test_drive? && lesson_package_purchase.nil? - self.errors.add(:lesson_package_purchase, "must be specified for a test drive purchase") + if approved_before? + # only checking for this on 1st time through acceptance + if lesson_booking && lesson_booking.is_test_drive? && lesson_package_purchase.nil? + self.errors.add(:lesson_package_purchase, "must be specified for a test drive purchase") + end end self.accepting = false - self.status = STATUS_APPROVED + end + + def validate_canceled + if !is_canceled? + self.errors.add(:status, "This session is already #{self.status}.") + end + + # check 24 hour window + if Time.now.to_i - scheduled_start.to_i > 24 * 60 * 60 + self.errors.add(:base, "This session is due to start within 24 hours and can not be canceled") + end + + self.canceling = false end def self.create(booking) @@ -391,7 +422,7 @@ module JamRuby def update_scheduled_start(week_offset) music_session.scheduled_start = slot.scheduled_time(week_offset) - music_session.save + music_session.save! end # grabs the next available time that's after the present, to avoid times being scheduled in the past @@ -422,16 +453,43 @@ module JamRuby message = params[:message] slot = params[:slot] - slot = LessonBookingSlot.find(slot) - self.slot = slot + accepter = params[:accepter] + self.slot = slot = LessonBookingSlot.find(slot) + self.slot.accept_message = message + self.slot.save! + self.accepting = true + self.status = STATUS_APPROVED - if is_approved? + if !approved_before? + # 1st time this has ever been approved; there are other things we need to do + + if lesson_package_purchase.nil? && lesson_booking.is_test_drive? + self.lesson_package_purchase = student.most_recent_test_drive_purchase + end + + if self.save + # also let the lesson_booking know we got accepted + lesson_booking.accept(self, slot, accepter) + UserMailer.student_lesson_accepted(self, message, slot).deliver + UserMailer.teacher_lesson_accepted(self, message, slot).deliver + chat_message = message ? "Lesson Approved: '#{message}'" : "Lesson Approved" + msg = ChatMessage.create(teacher, nil, chat_message, ChatMessage::CHANNEL_LESSON, nil, student, lesson_booking) + Notification.send_jamclass_invitation_teacher(music_session, teacher) + Notification.send_student_jamclass_invitation(music_session, student) + Notification.send_lesson_message('accept', self, true) + + else + @@log.error("unable to accept slot #{slot.id} for lesson #{self.id}") + puts("unable to accept slot #{slot.id} for lesson #{self.id}") + end + else # this implies a new slot has been countered, and now approved if self.save if slot.update_all - lesson_booking.accept(self, slot) - msg = ChatMessage.create(teacher, nil, message, ChatMessage::CHANNEL_LESSON, nil, student, lesson_booking) + lesson_booking.accept(self, slot, accepter) + chat_message = message ? "All Lesson Times Updated: '#{message}'" : "All Lesson Times Updated" + msg = ChatMessage.create(slot.proposer, nil, chat_message, ChatMessage::CHANNEL_LESSON, nil, slot.recipient, lesson_booking) Notification.send_lesson_message('accept', self, true) # TODO: this isn't quite an 'accept' UserMailer.student_lesson_update_all(self, message, slot).deliver UserMailer.teacher_lesson_update_all(self, message, slot).deliver @@ -444,33 +502,16 @@ module JamRuby puts("unable to accept slot #{slot.id} for lesson #{self.id} because it's in the past") raise ActiveRecord::Rollback end + chat_message = message ? "Lesson Updated Time Approved: '#{message}'" : "Lesson Updated Time Approved" + msg = ChatMessage.create(slot.proposer, nil, chat_message, ChatMessage::CHANNEL_LESSON, nil, slot.recipient, lesson_booking) UserMailer.student_lesson_accepted(self, message, slot).deliver UserMailer.teacher_lesson_accepted(self, message, slot).deliver end else - @@log.error("unable to accept slot #{slot.id} for lesson #{self.id}") - puts("unable to accept slot #{slot.id} for lesson #{self.id}") - end - else - self.accepting = true - - if lesson_package_purchase.nil? && lesson_booking.is_test_drive? - self.lesson_package_purchase = student.most_recent_test_drive_purchase - end - - if self.save - lesson_booking.accept(self, slot) - msg = ChatMessage.create(teacher, nil, message, ChatMessage::CHANNEL_LESSON, nil, student, lesson_booking) - Notification.send_lesson_message('accept', self, true) - UserMailer.student_lesson_accepted(self, message, slot).deliver - UserMailer.teacher_lesson_accepted(self, message, slot).deliver - else - @@log.error("unable to accept slot #{slot.id} for lesson #{self.id}") - puts("unable to accept slot #{slot.id} for lesson #{self.id}") + @@log.error("unable to accept slot #{slot.id} for lesson #{self.id} #{errors.inspect}") + puts("unable to accept slot #{slot.id} for lesson #{self.id} #{errors.inspect}") end end - - end end @@ -482,9 +523,11 @@ module JamRuby self.countering = true slot.proposer = proposer slot.lesson_session = self + slot.message = message self.lesson_booking_slots << slot self.countered_slot = slot self.countered_lesson = self + self.status = STATUS_COUNTERED if self.save if slot.update_all || lesson_booking.is_requested? lesson_booking.counter(self, proposer, slot) @@ -497,6 +540,41 @@ module JamRuby Notification.send_lesson_message('counter', self, slot.is_teacher_created?) end + + # teacher accepts the lesson + def cancel(params) + LessonSession.transaction do + + canceler = params[:canceler] + other = canceler == teacher ? student : teacher + message = params[:message] + + if params[:update_all].present? + update_all = params[:update_all] + else + update_all = !lesson_booking.recurring + end + + + self.status = STATUS_CANCELED + self.cancel_message = message + self.canceler = canceler + self.canceling = true + + if self.save + if update_all + lesson_booking.cancel(canceler, other, message) + else + msg = ChatMessage.create(canceler, nil, message, ChatMessage::CHANNEL_LESSON, nil, other, lesson_booking) + Notification.send_lesson_message('canceled', self, false) + Notification.send_lesson_message('canceled', self, true) + UserMailer.student_lesson_canceled(self, message).deliver + UserMailer.teacher_lesson_canceled(self, message).deliver + end + end + end + end + def description(lesson_booking) lesson_booking.lesson_package_type.description(lesson_booking) end @@ -510,7 +588,7 @@ module JamRuby end def web_url - APP_CONFIG.external_root_url + "/client#/jamclass/lesson-request/" + id + APP_CONFIG.external_root_url + "/client#/jamclass/lesson-booking/" + id end def update_payment_url diff --git a/ruby/lib/jam_ruby/models/music_session.rb b/ruby/lib/jam_ruby/models/music_session.rb index d7bb3a24c..d63c798db 100644 --- a/ruby/lib/jam_ruby/models/music_session.rb +++ b/ruby/lib/jam_ruby/models/music_session.rb @@ -423,7 +423,9 @@ module JamRuby when CREATE_TYPE_RSVP, CREATE_TYPE_SCHEDULE_FUTURE Notification.send_scheduled_session_invitation(ms, receiver) when CREATE_TYPE_LESSON - Notification.send_jamclass_invitation(ms, receiver) + if ms.lesson_session.is_active? + Notification.send_jamclass_invitation_teacher(ms, receiver) + end else Notification.send_session_invitation(receiver, user, ms.id) end @@ -942,7 +944,7 @@ SQL # with_timezone = FALSE # Thursday, July 10 - 10:00pm # this should be in a helper - def pretty_scheduled_start(with_timezone) + def pretty_scheduled_start(with_timezone = true) if scheduled_start && scheduled_duration start_time = scheduled_start diff --git a/ruby/lib/jam_ruby/models/notification.rb b/ruby/lib/jam_ruby/models/notification.rb index 4ade21ce3..275fd069d 100644 --- a/ruby/lib/jam_ruby/models/notification.rb +++ b/ruby/lib/jam_ruby/models/notification.rb @@ -62,7 +62,7 @@ module JamRuby end end - self.class.format_msg(self.description, {:user => source_user, :band => band, :session => session}) + self.class.format_msg(self.description, {:user => source_user, target: target_user :band => band, :session => session, purpose: purpose, student_directed: student_directed}) end # TODO: MAKE ALL METHODS BELOW ASYNC SO THE CLIENT DOESN'T BLOCK ON NOTIFICATION LOGIC @@ -132,6 +132,8 @@ module JamRuby user = options[:user] band = options[:band] session = options[:session] + purpose = options[:purpose] + student_directed = options[:student_directed] name, band_name = "" unless user.nil? @@ -249,8 +251,38 @@ module JamRuby when NotificationTypes::BAND_INVITATION_ACCEPTED return "#{name} has accepted your band invitation to join #{band_name}." + when NotificationTypes::LESSON_MESSAGE + notification_msg = 'Lesson Changed' + + if purpose == 'requested' + notification_msg = 'You have received a lesson request' + elsif purpose == 'accept' + notification_msg = 'Your lesson request is confirmed!' + elsif purpose == 'declined' + notification_msg = "We're sorry your lesson request has been declined." + elsif purpose == 'canceled' + notification_msg = "Your lesson request has been canceled." + elsif purpose == 'counter' + if student_directed + notification_msg = "Instructor has proposed a different time for your lesson." + else + notification_msg = "Student has proposed a different time for your lesson." + end + elsif purpose == 'reschedule' + 'A lesson reschedule has been requested' + end + return notification_msg + + when NotificationTypes::SCHEDULED_JAMCLASS_INVITATION + if student_directed + + "You have been scheduled to take a JamClass with #{user.name}." + else + "You have been scheduled to teach a JamClass to #{user.name}" + end + else - return "" + return description end end @@ -389,25 +421,9 @@ module JamRuby notification.purpose = purpose notification.session_id = lesson_session.music_session.id - notification_msg = 'Lesson Changed' + notification_msg = format_msg(NotificationTypes::LESSON_MESSAGE, {purpose: purpose}) - if purpose == 'requested' - notification_msg = 'You have received a lesson request' - elsif purpose == 'accept' - notification_msg = 'Your lesson request is confirmed!' - elsif purpose == 'declined' - notification_msg = "We're sorry your lesson request has been declined." - elsif purpose == 'counter' - if student_directed - notification_msg = "Instructor has proposed a different time for your lesson." - else - notification_msg = "Student has proposed a different time for your lesson." - end - elsif purpose == 'reschedule' - 'A lesson reschedule has been requested' - end - - notification.message = notification_msg + #notification.message = notification_msg notification.save @@ -701,20 +717,23 @@ module JamRuby end end - def send_jamclass_invitation(music_session, user) + def send_jamclass_invitation_teacher(music_session, user) return if music_session.nil? || user.nil? - target_user = user - source_user = music_session.creator + teacher = target_user = user + student = source_user = music_session.creator + + notification_msg = format_msg(NotificationTypes::SCHEDULED_JAMCLASS_INVITATION, {user: student, student_directed: false}) notification = Notification.new notification.description = NotificationTypes::SCHEDULED_JAMCLASS_INVITATION notification.source_user_id = source_user.id notification.target_user_id = target_user.id notification.session_id = music_session.id + #notification.message = notification_msg notification.save - notification_msg = "You have been scheduled to teach a JamClass with #{name}." + if target_user.online msg = @@message_factory.scheduled_jamclass_invitation( @@ -734,25 +753,25 @@ module JamRuby begin UserMailer.teacher_scheduled_jamclass_invitation(music_session.lesson_session.teacher, notification_msg, music_session).deliver rescue => e - @@log.error("Unable to send SCHEDULED_JAMCLASS_INVITATION email to user #{target_user.email} #{e}") + @@log.error("Unable to send SCHEDULED_JAMCLASS_INVITATION email to user #{music_session.lesson_session.teacher.email} #{e}") end end def send_student_jamclass_invitation(music_session, user) return if music_session.nil? || user.nil? - target_user = user - source_user = music_session.lesson_session.teacher + student = target_user = user + teacher = source_user = music_session.lesson_session.teacher + notification_msg = format_msg(NotificationTypes::SCHEDULED_JAMCLASS_INVITATION, {teacher: teacher, student_directed: true}) notification = Notification.new notification.description = NotificationTypes::SCHEDULED_JAMCLASS_INVITATION notification.source_user_id = source_user.id notification.target_user_id = target_user.id notification.session_id = music_session.id + #notification.message = notification_msg notification.save - notification_msg = "You have been scheduled to student a JamClass with #{name}." - if target_user.online msg = @@message_factory.scheduled_jamclass_invitation( target_user.id, @@ -769,10 +788,11 @@ module JamRuby end begin - UserMailer.teacher_scheduled_jamclass_invitation(target_user, notification_msg, music_session).deliver + UserMailer.student_scheduled_jamclass_invitation(student, notification_msg, music_session).deliver rescue => e - @@log.error("Unable to send SCHEDULED_JAMCLASS_INVITATION email to user #{target_user.email} #{e}") + @@log.error("Unable to send SCHEDULED_JAMCLASS_INVITATION email to user #{student.email} #{e}") end + end diff --git a/ruby/lib/jam_ruby/models/teacher.rb b/ruby/lib/jam_ruby/models/teacher.rb index 101ed40f7..da65da58e 100644 --- a/ruby/lib/jam_ruby/models/teacher.rb +++ b/ruby/lib/jam_ruby/models/teacher.rb @@ -54,6 +54,9 @@ module JamRuby query = User.joins(:teacher) + # only show teachers with background check set and ready for session set to true + query = query.where('teachers.ready_for_session_at IS NOT NULL') + instruments = params[:instruments] if instruments && !instruments.blank? && instruments.length > 0 query = query.joins("inner JOIN teachers_instruments AS tinst ON tinst.teacher_id = teachers.id") @@ -89,7 +92,7 @@ module JamRuby end years_teaching = params[:years_teaching].to_i - if years_teaching && years_teaching > 0 + if params[:years_teaching] && years_teaching > 0 query = query.where('years_teaching >= ?', years_teaching) end @@ -97,20 +100,20 @@ module JamRuby teaches_intermediate = params[:teaches_intermediate] teaches_advanced = params[:teaches_advanced] - if teaches_beginner || teaches_intermediate || teaches_advanced + if teaches_beginner.present? || teaches_intermediate.present? || teaches_advanced.present? clause = '' - if teaches_beginner + if teaches_beginner == true clause << 'teaches_beginner = true' end - if teaches_intermediate + if teaches_intermediate == true if clause.length > 0 clause << ' OR ' end clause << 'teaches_intermediate = true' end - if teaches_advanced + if teaches_advanced == true if clause.length > 0 clause << ' OR ' end @@ -120,7 +123,7 @@ module JamRuby end student_age = params[:student_age].to_i - if student_age && student_age > 0 + if params[:student_age] && student_age > 0 query = query.where("teaches_age_lower <= ? AND (CASE WHEN teaches_age_upper = 0 THEN true ELSE teaches_age_upper >= ? END)", student_age, student_age) end diff --git a/ruby/lib/jam_ruby/models/user.rb b/ruby/lib/jam_ruby/models/user.rb index 4ab5a538d..7204519c4 100644 --- a/ruby/lib/jam_ruby/models/user.rb +++ b/ruby/lib/jam_ruby/models/user.rb @@ -1871,8 +1871,8 @@ module JamRuby !unprocessed_test_drive.nil? end - def has_requested_test_drive? - !requested_test_drive.nil? + def has_requested_test_drive?(teacher = nil) + !requested_test_drive(teacher).nil? end def fetch_stripe_customer @@ -1970,8 +1970,12 @@ module JamRuby {lesson: booking, test_drive: test_drive, intent:intent, purchase: purchase} end - def requested_test_drive - LessonBooking.requested(self).where(lesson_type: LessonBooking::LESSON_TYPE_TEST_DRIVE).first + def requested_test_drive(teacher = nil) + query = LessonBooking.requested(self).where(lesson_type: LessonBooking::LESSON_TYPE_TEST_DRIVE) + if teacher + query = query.where(teacher_id: teacher.id) + end + query.first end def unprocessed_test_drive diff --git a/ruby/spec/jam_ruby/models/lesson_booking_spec.rb b/ruby/spec/jam_ruby/models/lesson_booking_spec.rb index 577350687..ac64a0f3a 100644 --- a/ruby/spec/jam_ruby/models/lesson_booking_spec.rb +++ b/ruby/spec/jam_ruby/models/lesson_booking_spec.rb @@ -16,11 +16,13 @@ describe LessonBooking do describe "suspend!" do it "should set status as well as update status of all associated lesson_sessions" do booking = LessonBooking.book_normal(user, teacher_user, valid_recurring_slots, "Hey I've heard of you before.", true, LessonBooking::PAYMENT_STYLE_MONTHLY, 60) - booking.lesson_sessions[0].accept({message: "got it", slot: booking.lesson_booking_slots[0].id}) - + booking.lesson_sessions[0].accept({accepter: teacher_user, message: "got it", slot: booking.lesson_booking_slots[0].id}) + booking.reload + booking.active.should eql true booking.suspend! booking.errors.any?.should be false booking.reload + booking.active.should eql false booking.status.should eql LessonBooking::STATUS_SUSPENDED booking.lesson_sessions.count.should eql 2 booking.lesson_sessions.each do |lesson_session| @@ -45,7 +47,7 @@ describe LessonBooking do time = day.to_time Timecop.freeze(time) booking = LessonBooking.book_normal(user, teacher_user, valid_recurring_slots, "Hey I've heard of you before.", true, LessonBooking::PAYMENT_STYLE_MONTHLY, 60) - booking.accept(booking.lesson_sessions[0], booking.lesson_booking_slots[0]) + booking.accept(booking.lesson_sessions[0], booking.lesson_booking_slots[0], teacher_user) booking.errors.any?.should be false LessonBooking.count.should eql 1 @@ -119,12 +121,6 @@ describe LessonBooking do LessonBooking.bill_monthlies LessonPackagePurchase.count.should eql 1 purchase.reload - if purchase.billing_error_detail - # to aid in test failure debugging. shouldn't usually 'puts' - puts purchase.billing_error_reason - puts purchase.billing_error_detail - end - purchase.month.should eql 1 purchase.year.should eql 2016 purchase.lesson_booking.should eql booking @@ -148,7 +144,7 @@ describe LessonBooking do time = day.to_time Timecop.freeze(time) booking = LessonBooking.book_normal(user, teacher_user, valid_recurring_slots, "Hey I've heard of you before.", true, LessonBooking::PAYMENT_STYLE_MONTHLY, 60) - booking.accept(booking.lesson_sessions[0], booking.lesson_booking_slots[0]) + booking.accept(booking.lesson_sessions[0], booking.lesson_booking_slots[0], teacher_user) booking.errors.any?.should be false LessonBooking.count.should eql 1 @@ -203,7 +199,7 @@ describe LessonBooking do time = day.to_time Timecop.freeze(time) booking = LessonBooking.book_normal(user, teacher_user, valid_recurring_slots, "Hey I've heard of you before.", true, LessonBooking::PAYMENT_STYLE_MONTHLY, 60) - booking.accept(booking.lesson_sessions[0], booking.lesson_booking_slots[0]) + booking.accept(booking.lesson_sessions[0], booking.lesson_booking_slots[0], teacher_user) booking.errors.any?.should be false LessonBooking.count.should eql 1 @@ -307,7 +303,7 @@ describe LessonBooking do time = Date.new(2016, 1, 1) Timecop.freeze(time) booking = LessonBooking.book_normal(user, teacher_user, valid_recurring_slots, "Hey I've heard of you before.", true, LessonBooking::PAYMENT_STYLE_MONTHLY, 60) - booking.accept(booking.lesson_sessions[0], booking.lesson_booking_slots[0]) + booking.accept(booking.lesson_sessions[0], booking.lesson_booking_slots[0], teacher_user) booking.errors.any?.should be false now = Time.now @@ -524,7 +520,7 @@ describe LessonBooking do booking = LessonBooking.book_test_drive(user, teacher_user, valid_single_slots, "Hey I've heard of you before.") booking.errors.any?.should be true - booking.errors[:user].should eq ["have requested test drives"] + booking.errors[:user].should eq ["has a requested TestDrive with this teacher"] ChatMessage.count.should eq 1 end @@ -648,7 +644,7 @@ describe LessonBooking do booking = LessonBooking.book_normal(user, teacher_user, valid_recurring_slots, "Hey I've heard of you before.", true, LessonBooking::PAYMENT_STYLE_WEEKLY, 60) booking.lesson_sessions.length.should eql 1 - booking.accept(booking.lesson_sessions[0], booking.lesson_booking_slots[0]) + booking.accept(booking.lesson_sessions[0], booking.lesson_booking_slots[0], teacher_user) booking.errors.any?.should be false booking.reload booking.lesson_sessions.length.should eql 2 @@ -686,13 +682,116 @@ describe LessonBooking do booking = LessonBooking.book_normal(user, teacher_user, valid_recurring_slots, "Hey I've heard of you before.", false, LessonBooking::PAYMENT_STYLE_SINGLE, 60) booking.lesson_sessions.length.should eql 1 - booking.accept(booking.lesson_sessions[0], booking.lesson_booking_slots[0]) + booking.accept(booking.lesson_sessions[0], booking.lesson_booking_slots[0], user) booking.errors.any?.should be false booking.reload booking.lesson_sessions.length.should eql 1 + booking.accepter.should eql user end end + describe "canceling" do + + after do + Timecop.return + end + + it "single session gets canceled before accepted" do + + booking = LessonBooking.book_normal(user, teacher_user, valid_single_slots, "Hey I've heard of you before.", false, LessonBooking::PAYMENT_STYLE_SINGLE, 60) + lesson_session = booking.lesson_sessions[0] + lesson_session.status.should eql LessonSession::STATUS_REQUESTED + lesson_session.scheduled_start.should eql booking.default_slot.scheduled_time(0) + + # avoid 24 hour problem + + UserMailer.deliveries.clear + Timecop.freeze(7.days.ago) + lesson_session.cancel({canceler: teacher_user, message: 'meh', slot: booking.default_slot.id, update_all: false}) + lesson_session.errors.any?.should be_false + lesson_session.status.should eql LessonSession::STATUS_CANCELED + lesson_session.reload + booking.reload + booking.status.should eql LessonSession::STATUS_CANCELED + UserMailer.deliveries.length.should eql 1 + end + + it "single session gets canceled after accepted" do + booking = LessonBooking.book_normal(user, teacher_user, valid_single_slots, "Hey I've heard of you before.", false, LessonBooking::PAYMENT_STYLE_SINGLE, 60) + lesson_session = booking.lesson_sessions[0] + lesson_session.status.should eql LessonSession::STATUS_REQUESTED + lesson_session.scheduled_start.should eql booking.default_slot.scheduled_time(0) + + lesson_session.accept({accepter: teacher_user, message: 'Yeah I got this', slot: booking.default_slot.id, update_all: false}) + lesson_session.errors.any?.should be_false + lesson_session.status.should eql LessonSession::STATUS_APPROVED + lesson_session.reload + lesson_session.scheduled_start.should eql booking.default_slot.scheduled_time(0) + + UserMailer.deliveries.clear + Timecop.freeze(7.days.ago) + lesson_session.cancel({canceler: user, message: 'meh', slot: booking.default_slot.id, update_all: false}) + lesson_session.errors.any?.should be_false + lesson_session.status.should eql LessonSession::STATUS_CANCELED + lesson_session.reload + booking.reload + booking.status.should eql LessonSession::STATUS_CANCELED + UserMailer.deliveries.length.should eql 2 + end + + it "recurring session gets canceled after accepted" do + booking = LessonBooking.book_normal(user, teacher_user, valid_recurring_slots, "Hey I've heard of you before.", true, LessonBooking::PAYMENT_STYLE_MONTHLY, 60) + booking.active.should eql false + lesson_session = booking.lesson_sessions[0] + lesson_session.status.should eql LessonSession::STATUS_REQUESTED + lesson_session.scheduled_start.should eql booking.default_slot.scheduled_time(0) + + lesson_session.accept({accepter: teacher_user, message: 'Yeah I got this', slot: booking.default_slot.id, update_all: false}) + lesson_session.errors.any?.should be_false + lesson_session.status.should eql LessonSession::STATUS_APPROVED + lesson_session.reload + lesson_session.scheduled_start.should eql booking.default_slot.scheduled_time(0) + booking.reload + booking.active.should eql true + + UserMailer.deliveries.clear + Timecop.freeze(7.days.ago) + lesson_session.cancel({canceler: user, message: 'meh', slot: booking.default_slot.id, update_all: false}) + lesson_session.errors.any?.should be_false + lesson_session.status.should eql LessonSession::STATUS_CANCELED + lesson_session.reload + lesson_session.canceler.should eql user + booking.reload + booking.active.should eql true + booking.status.should eql LessonSession::STATUS_APPROVED + booking.canceler.should be_nil + UserMailer.deliveries.length.should eql 2 + end + + it "recurring booking gets canceled after accepted" do + booking = LessonBooking.book_normal(user, teacher_user, valid_recurring_slots, "Hey I've heard of you before.", true, LessonBooking::PAYMENT_STYLE_MONTHLY, 60) + lesson_session = booking.lesson_sessions[0] + lesson_session.status.should eql LessonSession::STATUS_REQUESTED + lesson_session.scheduled_start.should eql booking.default_slot.scheduled_time(0) + + lesson_session.accept({accepter: teacher_user, message: 'Yeah I got this', slot: booking.default_slot.id, update_all: false}) + lesson_session.errors.any?.should be_false + lesson_session.status.should eql LessonSession::STATUS_APPROVED + lesson_session.reload + lesson_session.scheduled_start.should eql booking.default_slot.scheduled_time(0) + + UserMailer.deliveries.clear + Timecop.freeze(7.days.ago) + lesson_session.cancel({canceler: user, message: 'meh', slot: booking.default_slot.id, update_all: true}) + lesson_session.errors.any?.should be_false + lesson_session.status.should eql LessonSession::STATUS_CANCELED + lesson_session.reload + booking.reload + booking.status.should eql LessonSession::STATUS_CANCELED + booking.canceler.should eql user + UserMailer.deliveries.length.should eql 2 + end + end describe "rescheduling" do after do @@ -707,14 +806,19 @@ describe LessonBooking do counter = FactoryGirl.build(:lesson_booking_slot_single, hour: 16) lesson_session.counter({proposer: user, slot: counter, message: 'Does this work better?'}) lesson_session.errors.any?.should be false - lesson_session.status.should eql LessonSession::STATUS_REQUESTED + lesson_session.status.should eql LessonSession::STATUS_COUNTERED lesson_session.scheduled_start.should eql booking.default_slot.scheduled_time(0) + booking.reload + booking.counter_slot.should eql counter - lesson_session.accept({message: 'Yeah I got this', slot: counter.id, update_all: false}) + lesson_session.accept({accepter: teacher_user, message: 'Yeah I got this', slot: counter.id, update_all: false}) lesson_session.errors.any?.should be_false lesson_session.status.should eql LessonSession::STATUS_APPROVED lesson_session.reload lesson_session.scheduled_start.should eql counter.scheduled_time(0) + booking.reload + booking.accepter.should eql teacher_user + booking.counter_slot.should be_nil end it "recurring" do @@ -727,16 +831,17 @@ describe LessonBooking do counter = FactoryGirl.build(:lesson_booking_slot_recurring, day_of_week: 2) lesson_session.counter({proposer: user, slot: counter, message: 'Does this work better?'}) lesson_session.errors.any?.should be false - lesson_session.status.should eql LessonSession::STATUS_REQUESTED + lesson_session.status.should eql LessonSession::STATUS_COUNTERED lesson_session.scheduled_start.should eql booking.default_slot.scheduled_time(0) # to help scoot out the 'created_at' of the lessons Timecop.freeze(Time.now + 10) - lesson_session.accept({message: 'Yeah I got this', slot: counter.id, update_all: false}) + lesson_session.accept({accepter: teacher_user, message: 'Yeah I got this', slot: counter.id, update_all: false}) lesson_session.errors.any?.should be_false lesson_session.status.should eql LessonSession::STATUS_APPROVED booking.reload + booking.status.should eql LessonSession::STATUS_APPROVED lesson_session.reload lesson_session.scheduled_start.should eql counter.scheduled_time(0) @@ -750,10 +855,10 @@ describe LessonBooking do counter2 = FactoryGirl.build(:lesson_booking_slot_recurring, day_of_week: 4, update_all: false) lesson_session.counter({proposer: user, slot: counter2, message: 'ACtually, let\'s do this instead for just this one'}) lesson_session.errors.any?.should be false - lesson_session.status.should eql LessonSession::STATUS_APPROVED + lesson_session.status.should eql LessonSession::STATUS_COUNTERED lesson_session.scheduled_start.should eql counter.scheduled_time(0) - lesson_session.accept({message: 'OK, lets fix just this one', slot: counter2.id}) + lesson_session.accept({accepter: teacher_user, message: 'OK, lets fix just this one', slot: counter2.id}) lesson_session.errors.any?.should be_false lesson_session.status.should eql LessonSession::STATUS_APPROVED booking.reload @@ -768,17 +873,20 @@ describe LessonBooking do counter3 = FactoryGirl.build(:lesson_booking_slot_recurring, day_of_week: 5, update_all: true) lesson_session.counter({proposer: user, slot: counter3, message: 'ACtually, let\'s do this instead for just this one... again'}) lesson_session.errors.any?.should be false - lesson_session.status.should eql LessonSession::STATUS_APPROVED + lesson_session.status.should eql LessonSession::STATUS_COUNTERED lesson_session.reload lesson_session2.reload lesson_session.scheduled_start.should eql counter2.scheduled_time(0) lesson_session2.scheduled_start.should eql counter.scheduled_time(1) + booking.reload + booking.counter_slot.should eql counter3 - lesson_session.accept({message: 'OK, lets fix all of them', slot: counter3.id}) + lesson_session.accept({accepter: teacher_user, message: 'OK, lets fix all of them', slot: counter3.id}) lesson_session.errors.any?.should be_false lesson_session.status.should eql LessonSession::STATUS_APPROVED booking.reload + booking.counter_slot.should be_nil lesson_session.reload lesson_session2.reload lesson_session.created_at.should be < lesson_session2.created_at diff --git a/ruby/spec/mailers/render_emails_spec.rb b/ruby/spec/mailers/render_emails_spec.rb index 72b57d3de..8e974560c 100644 --- a/ruby/spec/mailers/render_emails_spec.rb +++ b/ruby/spec/mailers/render_emails_spec.rb @@ -74,7 +74,7 @@ describe "RenderMailers", :slow => true do lesson_session = testdrive_lesson(user, teacher) UserMailer.deliveries.clear - UserMailer.student_lesson_accepted(lesson_session, "custom message").deliver + UserMailer.student_lesson_accepted(lesson_session, "custom message", lesson_session.lesson_booking.default_slot).deliver end it "teacher_scheduled_jamclass_invitation" do diff --git a/web/app/assets/javascripts/jam_rest.js b/web/app/assets/javascripts/jam_rest.js index 8c823135d..fa74e105d 100644 --- a/web/app/assets/javascripts/jam_rest.js +++ b/web/app/assets/javascripts/jam_rest.js @@ -2118,6 +2118,19 @@ }) } + + function getLessonBooking(options) { + options = options || {} + return $.ajax({ + type: "GET", + url: '/api/lesson_bookings/' + options.id, + dataType: "json", + contentType: 'application/json', + data: JSON.stringify(options) + }) + } + + function getUnprocessedLesson(options) { options = options || {} return $.ajax({ @@ -2140,6 +2153,36 @@ }) } + function acceptLessonBooking(options) { + return $.ajax({ + type: "POST", + url: '/api/lesson_bookings/' + options.id + '/accept', + dataType: "json", + contentType: 'application/json', + data: JSON.stringify(options) + }) + } + + function counterLessonBooking(options) { + return $.ajax({ + type: "POST", + url: '/api/lesson_bookings/' + options.id + '/counter', + dataType: "json", + contentType: 'application/json', + data: JSON.stringify(options) + }) + } + + + function cancelLessonBooking(options) { + return $.ajax({ + type: "POST", + url: '/api/lesson_bookings/' + options.id + '/cancel', + dataType: "json", + contentType: 'application/json', + data: JSON.stringify(options) + }) + } function createAlert(subject, data) { var message = {subject:subject}; @@ -2384,8 +2427,12 @@ this.signup = signup; this.portOverCarts = portOverCarts; this.bookLesson = bookLesson; + this.getLessonBooking = getLessonBooking; this.getUnprocessedLesson = getUnprocessedLesson; this.getUnprocessedLessonOrIntent = getUnprocessedLessonOrIntent; + this.acceptLessonBooking = acceptLessonBooking; + this.cancelLessonBooking = cancelLessonBooking; + this.counterLessonBooking = counterLessonBooking; this.submitStripe = submitStripe; this.getLessonSessions = getLessonSessions; this.getTestDriveStatus = getTestDriveStatus; diff --git a/web/app/assets/javascripts/layout.js b/web/app/assets/javascripts/layout.js index c552750a3..85a435521 100644 --- a/web/app/assets/javascripts/layout.js +++ b/web/app/assets/javascripts/layout.js @@ -506,6 +506,12 @@ $.btOffAll(); // add any prod bubbles if you close a dialog } + function screenProperty(screen, property) { + if (screen && screen in screenBindings) { + return screenBindings[screen][property] + } + return null; + } function screenEvent(screen, evtName, data) { if (screen && screen in screenBindings) { if (evtName in screenBindings[screen]) { @@ -563,8 +569,7 @@ // reset the hash to where it just was context.location.hash = currentHash; } - else { - // not rejected by the screen; let it go + else {(screen) return postFunction(e); } } @@ -583,8 +588,9 @@ logger.debug("layout: changing screen to " + currentScreen); + // notify everyone $(document).triggerHandler(EVENTS.SCREEN_CHANGED, {previousScreen: previousScreen, newScreen: currentScreen}) - + window.NavActions.screenChanged(currentScreen, screenProperty(currentScreen, 'navName')) context.JamTrackPreviewActions.screenChange() screenEvent(currentScreen, 'beforeShow', data); @@ -731,6 +737,13 @@ } logger.debug("opening dialog: " + dialog) + var $dialog = $('[layout-id="' + dialog + '"]'); + if($dialog.length == 0) { + logger.debug("unknown dialog encountered: " + dialog) + return + } + + var $overlay = $('.dialog-overlay') if (opts.sizeOverlayToContent) { @@ -743,12 +756,12 @@ $overlay.show(); centerDialog(dialog); - var $dialog = $('[layout-id="' + dialog + '"]'); stackDialogs($dialog, $overlay); addScreenContextToDialog($dialog) $dialog.show(); // maintain center (un-attach previous sensor if applicable, then re-add always) + window.ResizeSensor.detach($dialog.get(0)) new window.ResizeSensor($dialog, function(){ centerDialog(dialog); diff --git a/web/app/assets/javascripts/notificationPanel.js b/web/app/assets/javascripts/notificationPanel.js index 175a9489c..fd651e60d 100644 --- a/web/app/assets/javascripts/notificationPanel.js +++ b/web/app/assets/javascripts/notificationPanel.js @@ -918,7 +918,7 @@ handleNotification(payload, header.type); app.notify({ - "title": "JamClass Invitation", + "title": "JamClass Scheduled", "text": payload.msg + "

" + payload.session_name + "
" + payload.session_date, "icon_url": context.JK.resolveAvatarUrl(payload.photo_url) }, [{ diff --git a/web/app/assets/javascripts/react-components.js b/web/app/assets/javascripts/react-components.js index aa06843e3..487321f8f 100644 --- a/web/app/assets/javascripts/react-components.js +++ b/web/app/assets/javascripts/react-components.js @@ -3,6 +3,7 @@ //= require_directory ./react-components/helpers //= require_directory ./react-components/actions //= require ./react-components/stores/AppStore +//= require ./react-components/stores/NavStore //= require ./react-components/stores/UserStore //= require ./react-components/stores/UserActivityStore //= require ./react-components/stores/InstrumentStore diff --git a/web/app/assets/javascripts/react-components/BookLessonFree.js.jsx.coffee b/web/app/assets/javascripts/react-components/BookLessonFree.js.jsx.coffee index 1e9c5a174..9fa17dce5 100644 --- a/web/app/assets/javascripts/react-components/BookLessonFree.js.jsx.coffee +++ b/web/app/assets/javascripts/react-components/BookLessonFree.js.jsx.coffee @@ -44,6 +44,17 @@ UserStore = context.UserStore componentDidUpdate:() -> @iCheckify() + @slot1Date = @root.find('.slot-1 .date-picker') + @slot2Date = @root.find('.slot-2 .date-picker') + @slot1Date.datepicker({ + dateFormat: "D M d yy", + onSelect: ((e) => @toggleDate(e)) + }) + @slot2Date.datepicker({ + dateFormat: "D M d yy", + onSelect: ((e) => @toggleDate(e)) + }) + toggleDate: (e) -> @@ -97,6 +108,7 @@ UserStore = context.UserStore teacherId: null, generalErrors: null, descriptionErrors: null, + bookedPriceErrors: null, slot1Errors: null, slot2Errors: null updating: false, @@ -120,7 +132,6 @@ UserStore = context.UserStore hour = new Number(hour) if am_pm == 'PM' hour += 12 - hour -= 1 else hour = null @@ -140,7 +151,7 @@ UserStore = context.UserStore {hour: hour, minute: minute, date: date, day_of_week: day_of_week} resetErrors: () -> - @setState({generalErrors: null, slot1Errors: null, slot2Errors: null, descriptionErrors: null}) + @setState({generalErrors: null, slot1Errors: null, slot2Errors: null, descriptionErrors: null, bookedPriceErrors: null}) isRecurring: () -> @state.recurring == 'recurring' @@ -199,7 +210,8 @@ UserStore = context.UserStore options.recurring = @isRecurring() parsed = @bookingOption() - options.lesson_length = parsed? && parsed.lesson_length + if parsed? + options.lesson_length = parsed.lesson_length else @@ -212,7 +224,7 @@ UserStore = context.UserStore booked: (response) -> @setState({updating: false}) if response.user['has_stored_credit_card?'] - context.location ="/client#/jamclass/lesson-request/" + response.id + context.location ="/client#/jamclass/lesson-session/" + response.id else context.location = '/client#/jamclass/payment' @@ -225,6 +237,10 @@ UserStore = context.UserStore for errorType, errors of body.errors if errorType == 'description' @setState({descriptionErrors: errors}) + else if errorType == 'booked_price' + @setState({bookedPriceErrors: errors}) + else if errorType == 'lesson_length' + # swallow, because 'booked_price' covers this else if errorType == 'lesson_booking_slots' # do nothing. these are handled better by the _children errors else @@ -263,7 +279,7 @@ UserStore = context.UserStore if duration_enabled enabledMinutes.push(minutes) - if !@state.recurring + if !@isRecurring() for minutes in enabledMinutes lesson_price = teacher["price_per_lesson_#{minutes}_cents"] value = "single|#{minutes}" @@ -284,7 +300,7 @@ UserStore = context.UserStore results.push(``) if results.length == 0 - results.push(``) + results.push(``) else results.unshift(``) results @@ -305,7 +321,11 @@ UserStore = context.UserStore hours = [] for hour in ['01', '02', '03', '04', '05', '06', '07', '08', '09', '10', '11', '12'] - hours.push(``) + if hour == '12' + key = '00' + else + key = hour + hours.push(``) minutes = [] for minute in ['00', '15', '30', '45'] @@ -317,17 +337,19 @@ UserStore = context.UserStore cancelClasses = classNames({"button-grey": true, disabled: !this.state.teacher? && !@state.updating}) descriptionErrors = context.JK.reactSingleFieldErrors('description', @state.descriptionErrors) + bookedPriceErrors = context.JK.reactSingleFieldErrors('booked_price', @state.bookedPriceErrors) slot1Errors = context.JK.reactErrors(@state.slot1Errors, {preferred_day: 'Date', day_of_week: 'Day'}) slot2Errors = context.JK.reactErrors(@state.slot2Errors, {preferred_day: 'Date', day_of_week: 'Day'}) generalErrors = context.JK.reactErrors(@state.generalErrors, {user: 'You'}) + bookedPriceClasses = classNames({booked_price: true, error: bookedPriceErrors?, field: true, 'booking-options': true}) descriptionClasses = classNames({description: true, error: descriptionErrors?}) slot1Classes = classNames({slot: true, 'slot-1': true, error: slot1Errors?}) slot2Classes = classNames({slot: true, 'slot-2': true, error: slot2Errors?}) generalClasses = classNames({general: true, error: generalErrors?}) - if !@state.recurring + if !@isRecurring() slots = `
@@ -412,8 +434,8 @@ UserStore = context.UserStore testDriveLessons = "#{this.state.user?.remaining_test_drives} TestDrive lesson credits" actions = `` columnLeft = `
@@ -451,10 +473,10 @@ UserStore = context.UserStore else if @isNormal() bookingOptionsForTeacher = @constructBookingOptions() - header = `

book a lesson

` + header = `

book a lesson with {teacher_first_name}

` outActions = `` columnLeft = `
@@ -467,9 +489,10 @@ UserStore = context.UserStore
-
+
- + + {bookedPriceErrors}
Tell {teacher_first_name} a little about yourself as a student.
diff --git a/web/app/assets/javascripts/react-components/LessonBooking.js.jsx.coffee b/web/app/assets/javascripts/react-components/LessonBooking.js.jsx.coffee new file mode 100644 index 000000000..e4ab134e5 --- /dev/null +++ b/web/app/assets/javascripts/react-components/LessonBooking.js.jsx.coffee @@ -0,0 +1,683 @@ +context = window +rest = context.JK.Rest() +logger = context.JK.logger + +UserStore = context.UserStore + +@LessonBooking = React.createClass({ + + mixins: [ + Reflux.listenTo(AppStore, "onAppInit"), + Reflux.listenTo(UserStore, "onUserChanged") + ] + + onAppInit: (@app) -> + @app.bindScreen('jamclass/lesson-booking', + {beforeShow: @beforeShow, afterShow: @afterShow, beforeHide: @beforeHide, navName: 'Lesson Booking'}) + + onUserChanged: (userState) -> + @setState({user: userState?.user}) + + onSlotDecision: (slot_decision) -> + @setState({slot_decision: slot_decision?.slot_decision}) + + componentWillMount: () -> + + componentDidMount: () -> + @checkboxes = [{selector: 'input.slot-decision', stateKey: 'slot-decision'}] + @root = $(@getDOMNode()) + + componentDidUpdate: () -> + + # add friendly helpers to a slot + processSlot: (slot, booking) -> + if !slot? + return + + slot.slotTime = @slotTime(slot, booking) + slot.is_recurring = @isRecurring() + if slot['is_teacher_created?'] + slot.creatorRole = 'teacher' + slot.creatorRoleRelative = 'teacher' + else + slot.creatorRole = 'student' + slot.creatorRoleRelative = 'student' + if context.JK.currentUserId == slot.proposer_id + slot.creatorRoleRelative = "your" + slot.mySlot = @mySlot(slot) + + console.log("SLOT", slot) + + componentWillUpdate: (nextProps, nextState) -> + if nextState.booking? + booking = nextState.booking + if !booking.post_processed + booking.post_processed = true + for slot in booking.slots + @processSlot(slot, booking) + @processSlot(booking.counter_slot, booking) + @processSlot(booking.default_slot, booking) + @processSlot(booking.alt_slot, booking) + + getInitialState: () -> + { + user: null, + booking: null, + updating: false, + updatingLesson: false + } + + beforeHide: (e) -> + + beforeShow: (e) -> + + afterShow: (e) -> + @setState({updating: true}) + rest.getLessonBooking({ + id: e.id, + }).done((response) => @getLessonBookingDone(response)).fail(@app.ajaxError) + + getLessonBookingDone: (response) -> + + if response.counter_slot? + startSlotDecision = response.counter_slot.id + else + startSlotDecision = response.default_slot.id + + @setState({booking: response, updating: false, slot_decision: startSlotDecision}) + + toJamClassMain: (e) -> + e.preventDefault() + window.location.href = '/client#/jamclass' + + onCancel: () -> + # what to do? + window.location.href = '/client#/jamclass' + + onAccept: () -> + + @setState({updatingLesson: true}) + if @state.slot_decision == 'counter' + request = @getSlotData(0) + request.id = this.state.booking.id + request.timezone = window.jstz.determine().name() + request.message = @getMessage() + rest.counterLessonBooking(request).done((response) => @counterLessonBookingDone(response)).fail((response) => @counterLessonBookingFail(response)) + else if @state.slot_decision == 'decline' + request = {} + request.message = @getMessage() + request.id = this.state.booking.id + rest.cancelLessonBooking(request).done((response) => @cancelLessonBookingDone(response)).fail((response) => @cancelLessonBookingFail(response)) + else + request = {} + request.message = @getMessage() + request.id = this.state.booking.id + request.slot = this.state.slot_decision + rest.acceptLessonBooking(request).done((response) => @acceptLessonBookingDone(response)).fail((response) => @acceptLessonBookingFail(response)) + + onCancelLesson: (e) -> + @setState({updatingLesson: true}) + request = {} + request.message = @getMessage() + request.id = this.state.booking.id + rest.cancelLessonBooking(request).done((response) => @cancelLessonBookingDone(response)).fail(@app.ajaxError) + + acceptLessonBookingDone: (response ) -> + logger.debug("accept lesson booking done") + @setState({booking:response, updatingLesson: false}) + + cancelLessonBookingDone: (response ) -> + logger.debug("cancel lesson booking done") + @setState({booking:response, updatingLesson: false}) + + counterLessonBookingDone: (response ) -> + logger.debug("counter lesson booking done") + @setState({booking:response, updatingLesson: false}) + + counterLessonBookingFail: (response ) -> + @setState({updatingLesson: false}) + logger.debug("counter lesson booking failed", response) + @app.ajaxError(arguments[0], arguments[1], arguments[2]) + + acceptLessonBookingFail: (response ) -> + @setState({updatingLesson: false}) + logger.debug("accept lesson booking failed", response) + @app.ajaxError(arguments[0], arguments[1], arguments[2]) + + cancelLessonBookingFail: (response ) -> + @setState({updatingLesson: false}) + logger.debug("cancel lesson booking failed", response) + @app.ajaxError(arguments[0], arguments[1], arguments[2]) + + getMessage: () -> + @root.find('textarea.message').val() + + getSlotData: (position) -> + $slot = @root.find('.slot-' + (position + 1)) + picker = $slot.find('.date-picker') + + hour = $slot.find('.hour').val() + minute = $slot.find('.minute').val() + am_pm = $slot.find('.am_pm').val() + + + if hour? and hour != '' + hour = new Number(hour) + if am_pm == 'PM' + hour += 12 + else + hour = null + + if minute? and minute != '' + minute = new Number(minute) + else + minute = null + + if !@isRecurring() + date = picker.datepicker("getDate") + if date? + date = context.JK.formatDateYYYYMMDD(date) + else + day_of_week = $slot.find('.day_of_week').val() + + + {hour: hour, minute: minute, date: date, day_of_week: day_of_week} + + student: () -> + @state.booking?.user + + teacher: () -> + @state.booking?.teacher + + otherRole: () -> + if @teacherViewing() + 'student' + else + 'teacher' + + other: () -> + if @teacherViewing() + @student() + else if @studentViewing() + @teacher() + else + null + + myself: () -> + if @teacherViewing() + @teacher() + else if @studentViewing() + @student() + else + null + + neverAccepted: () -> + !this.state.booking?.accepter_id? + + defaultSlot: () -> + @state.booking?.default_slot + + counteredSlot: () -> + @state.booking?.counter_slot + + canceler: () -> + if @student().id == this.state.booking?.canceler_id + @student() + else + @teacher() + + counterer: () -> + if @counteredSlot()?['is_teacher_created?'] + @teacher() + else + @student() + + otherCountered: () -> + @myself().id == @counterer().id + + studentCanceled: () -> + @canceler().id == @student().id + + selfCanceled: () -> + @canceler().id == @myself().id + + studentMadeDefaultSlot: () -> + @student()?.id == @defaultSlot()?.proposer_id + + teacherViewing: () -> + @state.booking? && @state.booking.teacher_id == context.JK.currentUserId + + studentViewing: () -> + @state.booking? && @state.booking.user_id == context.JK.currentUserId + + isActive: () -> + @state.booking?.active == true + + isRequested: () -> + @state.booking?.status == 'requested' && !@isCounter() + + isCounter: () -> + @counteredSlot()? && !@isCanceled() && !@isSuspended() + + isInitialCounter: () -> + @isCounter() && !@isActive() + + isActiveCounter: () -> + @isCounter() && @isActive() + + isApproved: () -> + @state.booking?.status == 'approved' + + isCanceled: () -> + @state.booking?.status == 'canceled' + + isSuspended: () -> + @state.booking?.status == 'suspended' + + isStudentCountered: () -> + @counteredSlot()?['is_student_created?'] + + isTeacherCountered: () -> + @counteredSlot()?['is_teacher_created?'] + + isTestDrive: () -> + @state.booking?.lesson_type == 'test-drive' + + isRecurring: (booking = this.state.booking) -> + booking?.recurring + + lessonLength: () -> + @state.booking?.lesson_length + + lessonDesc: () -> + if @isRecurring() + lessonType = "weekly recurring #{this.lessonLength()}-minute lesson" + else + lessonType = "single #{this.lessonLength()}-minute lesson" + + bookedPrice: () -> + this.state.booking?.booked_price + + lessonPaymentAmt: () -> + if @state.booking?.payment_style == 'elsewhere' + '$10' + else if @state.booking?.payment_style == 'single' + "$#{this.bookedPrice()}" + else if @state.booking?.payment_style == 'weekly' + "at $#{this.bookedPrice()} per lesson" + else if @state.booking?.payment_style == 'monthly' + "monthly at $#{this.bookedPrice()} per month" + else + "$???" + + selfLastToAct: () -> + if @isRequested() + @studentViewing() + else if @isCounter() + @counterer().id == @myself().id + else if @isCanceled() + @canceler().id == @myself().id + else if @isSuspended() + @studentViewing() + else + false + + mySlot: (slot) -> + slot.proposer_id == context.JK.currentUserId + + slotsDescription: (defaultSlot, altSlot) -> + text = "Preferred day/time for lesson is #{this.slotTime(defaultSlot)}. Secondary option is #{this.slotTime(altSlot)}." + + slotTime: (slot, booking = this.state.booking) -> + if @isRecurring(booking) + "#{this.dayOfWeek(slot)} at #{this.dayTime(slot)}" + else + slot.pretty_start_time + + slotTimePhrase: (slot) -> + if @isRecurring() + "each " + @slotTime(slot) + else + @slotTime(slot) + + slotMessage: (slot, qualifier = '') -> + @messageBlock(slot.mySlot,slot[qualifier + 'message'] ) + + messageBlock: (selfWroteMessage, message) -> + + if selfWroteMessage + whoSaid = "You said:" + else + whoSaid = "Message from #{this.other().first_name}:" + + if message && message.length > 0 + description = ` + + + + +
{whoSaid}{message}
` + description + + dayTime: (slot) -> + if slot.hour > 11 + hour = slot.hour - 12 + if hour == 0 + hour = 12 + end + am_pm = 'pm' + else + hour = slot.hour + am_pm = 'am' + + "#{hour + 1}:#{slot.minute}#{am_pm}" + + isNow: () -> + startTime = new Date(@state.booking.next_lesson.scheduled_start).getTime() + endTime = (startTime + @lessonLength() * 60) + now = new Date().getTime() + + now > startTime && now < endTime + + isPast: () -> + new Date().getTime() > new Date(@state.booking.next_lesson.scheduled_start).getTime() + + sessionLink: () -> + link = "/client#/session/#{this.stateb.booking.next_lesson.music_session_id}" + + `JOIN SESSION` + + nextLessonSummaryWithAvatar: () -> + `
+ {this.userHeader(this.other())} + {this.nextLessonSummary()} +
` + nextLessonSummary: () -> + if @isActive() + if @isNow() + `

You should join this session immediately: {this.sessionLink()}

` + else if @isPast() + `

This lesson is over.

` + else + `

This lesson is scheduled to start at {this.state.booking.next_lesson.pretty_scheduled_start}

` + else if @isRequested() + `

This lesson is scheduled to start at {this.state.booking.next_lesson.pretty_scheduled_start}

` + + renderCancelLesson: () -> + `
+

Cancel this Lesson

+

If you would like to cancel this lesson, you have to do so 24 hours in advance.

+ CANCEL LESSON +
` + + dayOfWeek: (slot) -> + switch slot.day_of_week + when 0 then "Sunday" + when 1 then "Monday" + when 2 then "Tuesday" + when 3 then "Wednesday" + when 4 then "Thursday" + when 5 then "Friday" + when 6 then "Saturday" + + userHeader: (user) -> + photo_url = user?.photo_url + if !photo_url? + photo_url = '/assets/shared/avatar_generic.png' + + `
+
+ +
+
+ {user.name} +
+
` + + render: () -> + if @state.updating + @renderLoading() + else if @teacherViewing() + @renderTeacher() + else if @studentViewing() + @renderStudent() + else + @renderLoading() + + + renderTeacher: () -> + if @isRequested() + header = 'respond to lesson request' + content = @renderTeacherRequested() + + if @isCounter() + if @isTeacherCountered() + header = 'your proposed alternate day/time is still pending' + else + header = 'student has proposed an alternate day/time' + content = @renderTeacherCountered() + + else if @isApproved() + if @isNow() + header = 'the lesson is scheduled for right now!' + else if @isPast() + header = 'this lesson is over' + else + header = 'this lesson is coming up soon' + content = @renderTeacherApproved() + + else if @isCanceled() + + header = 'this lesson is canceled' + content = @renderTeacherCanceled() + + else if @isSuspended() + + header = 'This lesson has been suspended' + content = @renderTeacherSuspended() + + `
+
` + + + renderStudent: () -> + if @isRequested() + header = 'your lesson has been requested' + content = @renderStudentRequested() + + if @isCounter() + if @isTeacherCountered() + header = 'teacher has proposed an alternate day/time' + else + header = 'your proposed alternate day/time is still pending' + content = @renderTeacherCountered() + + else if @isApproved() + if @isNow() + header = 'the lesson is scheduled for right now!' + else if @isPast() + header = 'this lesson is over' + else + header = 'this lesson is coming up soon' + content = @renderStudentApproved() + + else if @isCanceled() + + if @neverAccepted() && @studentViewing() && !@studentCanceled() + header = "we're sorry, but your lesson request has been declined" + else + header = 'this lesson is canceled' + + content = @renderStudentCanceled() + + else if @isSuspended() + + header = 'this lesson has been suspended' + content = @renderStudentSuspended() + + `
+
` + + renderLoading: () -> + header = 'Loading...' + `
+
` + + + renderStudentRequested: () -> + `
+
+ {this.userHeader(this.myself())} + Your request has been sent. You will receive an email when {this.teacher().name} responds. +
+
` + + renderStudentApproved: () -> + + if @studentMadeDefaultSlot() + message = this.slotMessage(this.state.booking.default_slot, 'accept') + + if @isRecurring() + detail = `

Your {this.lessonDesc()} will take place each {this.slotTime(this.state.booking.default_slot)}

` + else + detail = `

Your {this.lessonDesc()} will take place this {this.slotTime(this.state.booking.default_slot)}

` + + `
+
+ {this.userHeader(this.teacher())} +

Has accepted your lesson request.

+ {detail} + {message} +
+
+

What Now?

+

We strongly recommending adding this lesson to your calendar now so you don't forget it!

+

You can do this manually today; we will soon add a easier way to do so automatically.

+ {this.nextLessonSummary()} +
+
+ {this.renderCancelLesson()} +
+
` + + renderStudentCanceled: () -> + @renderCanceled() + + renderStudentSuspended: () -> + + #

Message from {this.other().first_name}:

+ #
+ renderStudentCountered: () -> + @renderCountered() + + renderTeacherRequested: () -> + + if @isTestDrive() + action = `

Has requested a TestDrive {this.lessonLength()}-minute lesson, for which you will be paid $10.

` + else + action = `

Has requested a {this.lessonDesc()} lesson, for which you will be paid {this.lessonPaymentAmt()}.

` + + `
+
+ {this.userHeader(this.other())} + {action} + {this.slotMessage(this.state.booking.default_slot)} +
+ +
` + + renderTeacherApproved: () -> + `
+ {this.nextLessonSummaryWithAvatar()} +
+ {this.renderCancelLesson()} +
+
` + + renderTeacherCanceled: () -> + @renderCanceled() + + renderTeacherSuspended: () -> + + renderTeacherCountered: () -> + @renderCountered() + + renderCanceled: () -> + canceler = @canceler() + myself = @myself() + initial = @neverAccepted() + + if initial + if @studentViewing() + if @studentCanceled() + action = `

You canceled this lesson request.

` + else + action = `

Has declined your lesson request.

` + else + if @studentCanceled() + action = `

Has canceled this lesson request.

` + else + action = `

You declined this lesson request.

` + + if @studentViewing() + + if @studentCanceled() + blurb = `

We're sorry this scheduling attempt did not working out for you. Please search our community of instructors to find someone else who looks like a good fit for you, and submit a new lesson request

` + else + blurb = `

We're sorry this instructor has declined your request. Please search our community of instructors to find someone else who looks like a good fit for you, and submit a new lesson request

` + + whatNow = + `
+

What Now?

+ {blurb} + SEARCH INSTRUCTORS NOW +
` + `
+
+ {this.userHeader(canceler)} + {action} + {this.messageBlock(this.selfCanceled(), this.state.booking.cancel_message)} +
+ {whatNow} +
` + + renderCountered: () -> + counterer = @counterer() + myself = @myself() + initial = @neverAccepted() + + phrase = this.slotTimePhrase(this.counteredSlot()) + action = `

Has suggested a different time for your lesson.

` + detail = `

Proposed alternate day/time is {phrase}

` + + `
+
+ {this.userHeader(counterer)} + {action} + {detail} + {this.slotMessage(this.counteredSlot())} +
+ +
` + +}) \ No newline at end of file diff --git a/web/app/assets/javascripts/react-components/LessonBookingDecision.js.jsx.coffee b/web/app/assets/javascripts/react-components/LessonBookingDecision.js.jsx.coffee new file mode 100644 index 000000000..da7d82223 --- /dev/null +++ b/web/app/assets/javascripts/react-components/LessonBookingDecision.js.jsx.coffee @@ -0,0 +1,216 @@ +@LessonBookingDecision = React.createClass({ + + #slot.creatorRole + #slot.slotTime + + # props.initial + # props.counter + # props.slots + # props.is_recurring + # props.slot_decision + # props.otherRole + + mixins: [ + ICheckMixin, + ] + + propTypes: { + onSlotDecision: React.PropTypes.func.isRequired + onUserCancel: React.PropTypes.func.isRequired + onUserDecision: React.PropTypes.func.isRequired + } + + getInitialState: () -> + { + slot_decision: null + } + + componentWillMount: () -> + @days = [] + @days.push(``) + @days.push(``) + @days.push(``) + @days.push(``) + @days.push(``) + @days.push(``) + @days.push(``) + @days.push(``) + + @hours = [] + for hour in ['01', '02', '03', '04', '05', '06', '07', '08', '09', '10', '11', '12'] + if hour == '12' + key = '00' + else + key = hour + @hours.push(``) + + @minutes = [] + for minute in ['00', '15', '30', '45'] + @minutes.push(``) + + @am_pm = [``, ``] + + componentDidMount: () -> + @checkboxes = [{selector: 'input.slot-decision', stateKey: 'slot-decision'}] + @root = $(@getDOMNode()) + @iCheckify() + + componentDidUpdate: () -> + @iCheckify() + @slotDate = @root.find('.date-picker') + @slotDate.datepicker({ + dateFormat: "D M d yy", + onSelect: ((e) => @toggleDate(e)) + }) + + checkboxChanged: (e) -> + checked = $(e.target).is(':checked') + + value = $(e.target).val() + + @props.onSlotDecision({slot_decision: value}) + + onUserDecision: (e) -> + e.preventDefault() + + if this.props.disabled + return + + this.props.onUserDecision(this.state.slot_decision) + + onUserCancel: (e) -> + e.preventDefault() + + if this.props.disabled + return + + this.props.onUserCancel() + + dayOfWeek: (slot) -> + switch slot.day_of_week + when 0 then "Sunday" + when 1 then "Monday" + when 2 then "Tuesday" + when 3 then "Wednesday" + when 4 then "Thursday" + when 5 then "Friday" + when 6 then "Saturday" + + slotLabelText: (index, slot) -> + if @props.counter + "Accept #{slot.creatorRoleRelative} proposed day/time" + else + if index == 0 + "Accept #{slot.creatorRoleRelative} preferred day/time" + else + "Accept #{slot.creatorRoleRelative} secondary day/time" + + showDeclineVerb: () -> + this.props.initial && this.props.otherRole == 'student' + + render: () -> + + if this.props.selfLastToAct + userPromptHeader = `

Would you like to do something else?

` + else + userPromptHeader = `

How do you want to handle this request?

` + + if this.props.slot_decision == 'counter' + actionBtnText = "PROPOSE ALTERNATE TIME" + else if this.props.slot_decision == 'decline' + + if @showDeclineVerb() + verb = "DECLINE" + else + verb = "CANCEL" + actionBtnText = "#{verb} LESSON" + else if this.props.initial + actionBtnText = "ACCEPT & SCHEDULE LESSON" + else + actionBtnText = "ACCEPT & UPDATE LESSON" + + if this.props.is_recurring + + slotAltPrompt = `
+ + Day: + + + + Time: + : + + +
` + else + slotAltPrompt = `
+ + Date: + + + + Time: + : + + +
` + + if @showDeclineVerb() + declineVerb = "Decline" + else + declineVerb = "Cancel" + + cancelClasses = {cancel: true, "button-grey": true, disabled: this.props.disabled} + scheduleClasses = {schedule: true, "button-orange": true, disabled: this.props.disabled} + slots = [] + + if !(this.props.counter && this.props.selfLastToAct) + proposeAltLabelText = "Propose alternate day/time" + for slot, i in @props.slots + + if this.props.is_recurring + slotDetail = `
Each {slot.slotTime}
` + else + slotDetail = `
{slot.slotTime}
` + + slots.push(`
+
+ +
+ {slotDetail} +
`) + else + proposeAltLabelText = "Propose new alternate day/time" + # if you have issued a counter, you should be able to withdraw it + # TODO + + `
+
+ {userPromptHeader} + +
+ {slots} +
+
+ + +
+ {slotAltPrompt} +
+
+ +
+
+
+
+

Send message to {this.props.otherRole} with your response.

+ + +
+
` +}) \ No newline at end of file diff --git a/web/app/assets/javascripts/react-components/LessonPayment.js.jsx.coffee b/web/app/assets/javascripts/react-components/LessonPayment.js.jsx.coffee index ab40330d3..319bf819b 100644 --- a/web/app/assets/javascripts/react-components/LessonPayment.js.jsx.coffee +++ b/web/app/assets/javascripts/react-components/LessonPayment.js.jsx.coffee @@ -215,7 +215,7 @@ UserStore = context.UserStore title: "Lesson Requested", text: "The teacher has been notified of your lesson request, and should respond soon.

We've taken you automatically to the page for this request, and sent an email to you with a link here as well. All communication with the teacher will show up on this page and in email." }) - window.location = "/client#/jamclass/lesson-request/" + response.lesson.id + window.location = "/client#/jamclass/lesson-session/" + response.lesson.id else if response.test_drive? || response.intent_book_test_drive? if response.test_drive?.teacher_id diff --git a/web/app/assets/javascripts/react-components/LessonSession.js.jsx.coffee b/web/app/assets/javascripts/react-components/LessonSession.js.jsx.coffee new file mode 100644 index 000000000..16d63fdef --- /dev/null +++ b/web/app/assets/javascripts/react-components/LessonSession.js.jsx.coffee @@ -0,0 +1,58 @@ +context = window +rest = context.JK.Rest() +logger = context.JK.logger + +UserStore = context.UserStore + +@LessonSession = React.createClass({ + + mixins: [ + Reflux.listenTo(AppStore, "onAppInit"), + Reflux.listenTo(UserStore, "onUserChanged") + ] + + onAppInit: (@app) -> + @app.bindScreen('jamclass/lesson-session', + {beforeShow: @beforeShow, afterShow: @afterShow, beforeHide: @beforeHide}) + + onUserChanged: (userState) -> + + @setState({user: userState?.user}) + + componentDidMount: () -> + + @root = $(@getDOMNode()) + + getInitialState: () -> + { + user: null, + lesson: null, + updating: false, + } + + beforeHide: (e) -> + @resetErrors() + + beforeShow: (e) -> + + afterShow: (e) -> + @setState({updating: true}) + + + render: () -> + header = "header" + + `
+
+ {header} + +
+
+ +
+ +
+ +
` + +}) \ No newline at end of file diff --git a/web/app/assets/javascripts/react-components/Nav.js.jsx.coffee b/web/app/assets/javascripts/react-components/Nav.js.jsx.coffee new file mode 100644 index 000000000..f0c9d7730 --- /dev/null +++ b/web/app/assets/javascripts/react-components/Nav.js.jsx.coffee @@ -0,0 +1,34 @@ +context = window +teacherActions = window.JK.Actions.Teacher + +@Nav = React.createClass({ + + mixins: [ + Reflux.listenTo(AppStore, "onAppInit"), + Reflux.listenTo(NavStore, "onNavChanged") + ] + + onAppInit: (@app) -> + + onNavChanged: (nav) -> + @setState({nav: nav}) + + render: () -> + navs = [] + if this.state?.nav? + nav = this.state.nav + if nav.currentSection? + navs.push(` : `) + navs.push(`{nav.currentSection.name}`) + if nav.optionalParent? + navs.push(` : `) + navs.push(`{nav.optionalParent.name}`) + if nav.currentScreenName? + navs.push(` : `) + navs.push(`{nav.currentScreenName}`) + + `
+ JamKazam Home + {navs} +
` +}) \ No newline at end of file diff --git a/web/app/assets/javascripts/react-components/TeacherSearchScreen.js.jsx.coffee b/web/app/assets/javascripts/react-components/TeacherSearchScreen.js.jsx.coffee index c9cf4a92f..2db743425 100644 --- a/web/app/assets/javascripts/react-components/TeacherSearchScreen.js.jsx.coffee +++ b/web/app/assets/javascripts/react-components/TeacherSearchScreen.js.jsx.coffee @@ -121,7 +121,7 @@ ProfileActions = @ProfileActions logger.debug("TeacherSearchScreen: user offered test drive") @app.layout.showDialog('try-test-drive', {d1: user.teacher.id}) else if response.remaining_test_drives > 0 - if response.booked_with_teacher + if response.booked_with_teacher && !context.JK.currentUserAdmin logger.debug("TeacherSearchScreen: teacher already test-drived") context.JK.Banner.showAlert('TestDrive', "You have already take a TestDrive lesson from this teacher. With TestDrive, you need to use your lessons on 4 different teachers to find one who is best for you. We're sorry, but you cannot take multiple TestDrive lessons from a single teacher.") @@ -241,10 +241,11 @@ ProfileActions = @ProfileActions `
- LESSONS HOME :  - TEACHERS SEARCH :  + JamKazam Home :  + JamClass Home :  + Teachers Search :  - SEARCH RESULTS / + Search Results / {searchDesc}
diff --git a/web/app/assets/javascripts/react-components/actions/NavActions.js.coffee b/web/app/assets/javascripts/react-components/actions/NavActions.js.coffee new file mode 100644 index 000000000..5e3828859 --- /dev/null +++ b/web/app/assets/javascripts/react-components/actions/NavActions.js.coffee @@ -0,0 +1,7 @@ +context = window + +@NavActions = Reflux.createActions({ + setScreenInfo: {} + screenChanged: {} +}) + diff --git a/web/app/assets/javascripts/react-components/mixins/ICheckMixin.js.coffee b/web/app/assets/javascripts/react-components/mixins/ICheckMixin.js.coffee index c6d892e32..3ab17fcca 100644 --- a/web/app/assets/javascripts/react-components/mixins/ICheckMixin.js.coffee +++ b/web/app/assets/javascripts/react-components/mixins/ICheckMixin.js.coffee @@ -14,13 +14,20 @@ teacherActions = window.JK.Actions.Teacher for checkbox in @checkboxes selector = checkbox.selector stateKey = checkbox.stateKey - enabled = @state[stateKey] + choice = @state[stateKey] + + $candidate = @root.find(selector) @iCheckIgnore = true - if enabled - @root.find(selector).iCheck('check').attr('checked', true); + + if $candidate.attr('type') == 'radio' + $found = @root.find(selector + '[value="' + choice + '"]') + $found.iCheck('check').attr('checked', true) else - @root.find(selector).iCheck('uncheck').attr('checked', false); + if choice + $candidate.iCheck('check').attr('checked', true); + else + $candidate.iCheck('uncheck').attr('checked', false); @iCheckIgnore = false enableICheck: (e) -> diff --git a/web/app/assets/javascripts/react-components/stores/NavStore.js.coffee b/web/app/assets/javascripts/react-components/stores/NavStore.js.coffee new file mode 100644 index 000000000..5414200e2 --- /dev/null +++ b/web/app/assets/javascripts/react-components/stores/NavStore.js.coffee @@ -0,0 +1,46 @@ +$ = jQuery +context = window +logger = context.JK.logger +rest = new context.JK.Rest() + +@NavStore = Reflux.createStore( + { + + screenPath: null + currentSection: null + currentScreenName: null + + sections: {jamclass: {name: 'JamClass Home', url: '/client#/jamclass'}, jamtrack: {name: 'JamTrack Home', url: '/client#/jamtrack'}} + + listenables: @NavActions + + init: -> + this.listenTo(context.AppStore, this.onAppInit) + + onAppInit: (@app) -> + + onScreenChanged: (screenPath, screenName) -> + if screenPath == @screenPath + return + + @screenPath = screenPath + @currentScreenName = screenName + @currentSection = null + if screenPath? + index = screenPath.indexOf('/') + if index > -1 + rootPath = screenPath.substring(0, index) + else + rootPath = screenPath + @currentSection = @sections[rootPath] + + @changed() + + onSetScreenInfo: (currentScreenName) -> + @currentScreenName = currentScreenName + @changed() + + changed:() -> + @trigger({currentScreen: @currentScreen, currentSection: @currentSection, currentScreenName: @currentScreenName}) + } +) diff --git a/web/app/assets/stylesheets/client/jamkazam.css.scss b/web/app/assets/stylesheets/client/jamkazam.css.scss index 358974810..f54c59b1b 100644 --- a/web/app/assets/stylesheets/client/jamkazam.css.scss +++ b/web/app/assets/stylesheets/client/jamkazam.css.scss @@ -722,3 +722,7 @@ $ReactSelectVerticalPadding: 3px; opacity: 0.01; } } + +#ui-datepicker-div { + z-index:10 !important; +} \ No newline at end of file diff --git a/web/app/assets/stylesheets/client/react-components/LessonBooking.css.scss b/web/app/assets/stylesheets/client/react-components/LessonBooking.css.scss index e5c2092b8..90c6f1bee 100644 --- a/web/app/assets/stylesheets/client/react-components/LessonBooking.css.scss +++ b/web/app/assets/stylesheets/client/react-components/LessonBooking.css.scss @@ -81,7 +81,7 @@ margin:0 0 20px 0 !important; } .avatar { - display:inline-block; + display:inline-block; padding:1px; width:48px; height:48px; @@ -146,4 +146,7 @@ width:80%; } } + select.hour { + margin-left:20px; + } } diff --git a/web/app/assets/stylesheets/client/react-components/LessonBookingScreen.css.scss b/web/app/assets/stylesheets/client/react-components/LessonBookingScreen.css.scss new file mode 100644 index 000000000..9a7ae1d95 --- /dev/null +++ b/web/app/assets/stylesheets/client/react-components/LessonBookingScreen.css.scss @@ -0,0 +1,231 @@ +@import "client/common"; + +#lesson-booking { + + div[data-react-class="LessonBooking"] { + height:100%; + } + .content-body-scroller { + height:100%; + padding:30px; + @include border_box_sizing; + } + + h2 { + font-size: 24px; + font-weight:700; + margin-bottom: 20px !important; + display:inline-block; + } + .row { + margin-bottom:40px; + } + + h3 { + font-size: 16px; + font-weight:700; + color:white; + margin-bottom: 10px !important; + display:inline-block; + } + .contents { + padding-left:60px; + position:relative; + } + .no-charge { + float:right; + } + .column { + @include border_box_sizing; + width:50%; + } + .column-left { + float:left; + padding-right:20px; + &.stored { + display:none; + } + } + .column-right { + float:right; + padding-left:20px; + &.stored { + float:left; + } + } + label { + display:inline-block; + color: $ColorTextTypical; + } + select { + display:inline-block; + } + + .slot-decision { + vertical-align: top; + } + .slot-alt-prompt { + color: $ColorTextTypical; + display: inline-block; + margin-top: 4px; + padding-left:22px; + label { + margin-bottom:10px; + } + } + + .slot-detail { + color: $ColorTextTypical; + display: inline-block; + margin-top: 4px; + padding-left:22px; + } + .alt-date-block { + white-space: nowrap; + float:left; + display:block; + margin-bottom:10px; + vertical-align: middle; + line-height:31px; + } + + .alt-time-block { + white-space: nowrap; + float:left; + display:block; + margin-bottom:10px; + vertical-align: middle; + line-height:31px; + } + + td.description { + color: $ColorTextTypical; + vertical-align: top; + white-space: nowrap; + } + td.message { + color: $ColorTextTypical; + padding-left: 10px; + vertical-align: top; + } + + .date-picker { + margin-right:20px; + } + .alt-date { + margin-right:10px; + } + .alt-time { + margin-right:10px; + } + + input { + display:inline-block; + //width: calc(100% - 150px); + width:auto; + @include border_box_sizing; + } + textarea { + width:100%; + @include border_box_sizing; + height:125px; + } + .field { + position:relative; + display:block; + margin-bottom:15px; + + label { + width:auto; + } + } + p { + line-height:125% !important; + font-size:14px !important; + margin:0 0 10px 0 !important; + color:$ColorTextTypical !important; + } + .user-header { + position:relative; + height:42px; + } + .user-name { + line-height:48px; + vertical-align:middle; + } + .avatar { + position:absolute; + left:-60px; + display:inline-block; + padding:1px; + width:48px; + height:48px; + background-color:#ed4818; + margin:0 20px 0 0; + -webkit-border-radius:24px; + -moz-border-radius:24px; + border-radius:24px; + float:none; + } + .avatar img { + + width: 48px; + height: 48px; + -webkit-border-radius:24px; + -moz-border-radius:24px; + border-radius:24px; + } + .teacher-name { + font-size:16px; + display:inline-block; + height:48px; + vertical-align:middle; + } + .actions { + margin-left:-3px; + margin-bottom:20px; + } + .error-text { + display:block; + } + + .actions { + clear:both; + a.cancel { + float:left; + } + a.schedule { + float:right; + } + a { + margin-bottom:20px; // in case the floating wraps + } + } + + .site-nav { + + margin-bottom:10px; + } + + .iradio_minimal { + display:inline-block; + top: -2px; + margin-right: 5px; + } + + textarea.message { + width:100%; + height:150px; + margin-bottom:20px; + } + + a.cancel-lesson { + margin-left:2px; + } + a.search-for-more-teachers { + margin-top:40px; + text-align:center; + display:block; + } + +} \ No newline at end of file diff --git a/web/app/assets/stylesheets/client/react-components/LessonSession.css.scss b/web/app/assets/stylesheets/client/react-components/LessonSession.css.scss new file mode 100644 index 000000000..487626938 --- /dev/null +++ b/web/app/assets/stylesheets/client/react-components/LessonSession.css.scss @@ -0,0 +1,113 @@ +@import "client/common"; + +#lesson-session { + + div[data-react-class="LessonSession"] { + height:100%; + } + .content-body-scroller { + height:100%; + padding:30px; + @include border_box_sizing; + } + + h2 { + font-size: 20px; + font-weight:700; + margin-bottom: 20px !important; + display:inline-block; + } + .no-charge { + float:right; + } + .column { + @include border_box_sizing; + width:50%; + } + .column-left { + float:left; + padding-right:20px; + &.stored { + display:none; + } + } + .column-right { + float:right; + padding-left:20px; + &.stored { + float:left; + } + } + label { + display:inline-block; + } + select { + display:inline-block; + } + + + input { + display:inline-block; + width: calc(100% - 150px); + @include border_box_sizing; + } + textarea { + width:100%; + @include border_box_sizing; + height:125px; + } + .field { + position:relative; + display:block; + margin-top:15px; + margin-bottom:25px; + + label { + width:150px; + } + } + p { + line-height:125% !important; + font-size:14px !important; + margin:0 0 20px 0 !important; + } + .avatar { + display:inline-block; + padding:1px; + width:48px; + height:48px; + background-color:#ed4818; + margin:10px 20px 0 0; + -webkit-border-radius:24px; + -moz-border-radius:24px; + border-radius:24px; + float:none; + } + .avatar img { + width: 48px; + height: 48px; + -webkit-border-radius:24px; + -moz-border-radius:24px; + border-radius:24px; + } + .teacher-name { + font-size:16px; + display:inline-block; + height:48px; + vertical-align:middle; + } + .actions { + margin-left:-3px; + margin-bottom:20px; + } + .error-text { + display:block; + } + + .actions { + float:left; + clear:both; + } + + +} \ No newline at end of file diff --git a/web/app/controllers/api_lesson_bookings_controller.rb b/web/app/controllers/api_lesson_bookings_controller.rb index 88ed8129a..7e193b2c4 100644 --- a/web/app/controllers/api_lesson_bookings_controller.rb +++ b/web/app/controllers/api_lesson_bookings_controller.rb @@ -1,6 +1,8 @@ class ApiLessonBookingsController < ApiController before_filter :api_signed_in_user + before_filter :lookup_lesson_booking, :only => [:accept, :counter, :cancel, :show] + before_filter :auth_lesson_booking, :only => [:accept, :counter, :cancel, :show] respond_to :json def index @@ -12,6 +14,10 @@ class ApiLessonBookingsController < ApiController render "api_lesson_bookings/index", :layout => nil end + def show + + end + def create if params[:lesson_type] == LessonBooking::LESSON_TYPE_FREE @@ -43,7 +49,7 @@ class ApiLessonBookingsController < ApiController specified_slot.preferred_day = day specified_slot.hour = slot[:hour] specified_slot.minute = slot[:minute] - specified_slot.timezone = slot[:timezone] + specified_slot.timezone = params[:timezone] slots << specified_slot end @@ -63,6 +69,7 @@ class ApiLessonBookingsController < ApiController slots = [] for slot in specified_slots specified_slot = LessonBookingSlot.new + specified_slot.slot_type = LessonBookingSlot::SLOT_TYPE_SINGLE if slot[:date].present? day = slot[:date] @@ -71,7 +78,7 @@ class ApiLessonBookingsController < ApiController end specified_slot.hour = slot[:hour] specified_slot.minute = slot[:minute] - specified_slot.timezone = slot[:timezone] + specified_slot.timezone = params[:timezone] slots << specified_slot end @@ -103,9 +110,10 @@ class ApiLessonBookingsController < ApiController end end + specified_slot.hour = slot[:hour] specified_slot.minute = slot[:minute] - specified_slot.timezone = slot[:timezone] + specified_slot.timezone = params[:timezone] slots << specified_slot end @@ -118,6 +126,70 @@ class ApiLessonBookingsController < ApiController end end + def accept + next_lesson = @lesson_booking.next_lesson + next_lesson.accept({ + message: params[:message], + slot: params[:slot], + accepter: current_user + }) + + if next_lesson.errors.any? + respond_with_model next_lesson + return + end + @lesson_booking.reload + end + + def counter + + next_lesson = @lesson_booking.next_lesson + + slot = LessonBookingSlot.new + if @lesson_booking.recurring + slot.slot_type = LessonBookingSlot::SLOT_TYPE_RECURRING + slot.day_of_week = slot[:day_of_week] + else + slot.slot_type = LessonBookingSlot::SLOT_TYPE_SINGLE + + if params[:date].present? + day = params[:date] + day = Date.parse(day) if day && !day.include?('NaN') + slot.preferred_day = day + end + end + slot.hour = params[:hour] + slot.minute = params[:minute] + slot.timezone = params[:timezone] + + next_lesson.counter({ + proposer: current_user, + message: params[:message], + slot: slot + }) + + if next_lesson.errors.any? + respond_with_model next_lesson + return + end + @lesson_booking.reload + end + + def cancel + next_lesson = @lesson_booking.next_lesson + next_lesson.cancel({ + canceler: current_user, + message: params[:message], + update_all: true + }) + + if next_lesson.errors.any? + respond_with_model next_lesson + return + end + @lesson_booking.reload + end + def unprocessed @show_teacher = true @lesson_booking = LessonBooking.unprocessed(current_user).first @@ -129,4 +201,24 @@ class ApiLessonBookingsController < ApiController @lesson_booking = LessonBooking.unprocessed(current_user).first @intent = TeacherIntent.recent_test_drive(current_user) end + + private + def lookup_lesson_booking + @lesson_booking = LessonBooking.find_by_id(params[:id]) + + if @lesson_booking.nil? + # try with lesson session + lesson_session = LessonSession.find_by_id(params[:id]) + if lesson_session + @lesson_booking = lesson_session.lesson_booking + end + end + raise ActiveRecord::RecordNotFound, "Can't find lesson booking" if @lesson_booking.nil? + end + + def auth_lesson_booking + if current_user.id != @lesson_booking.teacher.id && current_user.id != @lesson_booking.student.id + raise JamPermissionError, "You do not have access to this lesson booking" + end + end end diff --git a/web/app/views/api_jam_tracks/show_for_client.rabl b/web/app/views/api_jam_tracks/show_for_client.rabl index 8d19fc807..4187817eb 100644 --- a/web/app/views/api_jam_tracks/show_for_client.rabl +++ b/web/app/views/api_jam_tracks/show_for_client.rabl @@ -39,8 +39,3 @@ node :mixdowns do |jam_track| end items end - - -child(:jam_track_tap_ins => :tap_ins) { - attributes :offset_time, :bpm, :tap_in_count -} \ No newline at end of file diff --git a/web/app/views/api_lesson_bookings/accept.rabl b/web/app/views/api_lesson_bookings/accept.rabl new file mode 100644 index 000000000..818490f5b --- /dev/null +++ b/web/app/views/api_lesson_bookings/accept.rabl @@ -0,0 +1,3 @@ +object @lesson_booking + +extends "api_lesson_bookings/show" \ No newline at end of file diff --git a/web/app/views/api_lesson_bookings/cancel.rabl b/web/app/views/api_lesson_bookings/cancel.rabl new file mode 100644 index 000000000..818490f5b --- /dev/null +++ b/web/app/views/api_lesson_bookings/cancel.rabl @@ -0,0 +1,3 @@ +object @lesson_booking + +extends "api_lesson_bookings/show" \ No newline at end of file diff --git a/web/app/views/api_lesson_bookings/counter.rabl b/web/app/views/api_lesson_bookings/counter.rabl new file mode 100644 index 000000000..818490f5b --- /dev/null +++ b/web/app/views/api_lesson_bookings/counter.rabl @@ -0,0 +1,3 @@ +object @lesson_booking + +extends "api_lesson_bookings/show" \ No newline at end of file diff --git a/web/app/views/api_lesson_bookings/show.rabl b/web/app/views/api_lesson_bookings/show.rabl index 368d7b88b..5d482905c 100644 --- a/web/app/views/api_lesson_bookings/show.rabl +++ b/web/app/views/api_lesson_bookings/show.rabl @@ -1,15 +1,32 @@ object @lesson_booking -attributes :id, :lesson_type, :payment_style, :recurring, :teacher_id, :description, :lesson_length, :created_at +attributes :id, :status, :lesson_type, :payment_style, :recurring, :teacher_id, :description, :lesson_length, :created_at, :user_id, :active, :accepter_id, :canceler_id, :cancel_message child(:lesson_booking_slots => :slots) { - attributes :id, :preferred_day, :day_of_week, :hour, :minute, :slot_type + attributes :id, :preferred_day, :day_of_week, :hour, :minute, :slot_type, :pretty_scheduled_start, :message, :pretty_start_time, :proposer_id, :is_student_created?, :is_teacher_created? } +child(:default_slot => :default_slot) { + attributes :id, :preferred_day, :day_of_week, :hour, :minute, :slot_type, :pretty_scheduled_start, :message, :pretty_start_time, :proposer_id, :is_student_created?, :is_teacher_created? +} + +child(:alt_slot => :alt_slot) { + attributes :id, :preferred_day, :day_of_week, :hour, :minute, :slot_type, :pretty_scheduled_start, :message, :pretty_start_time, :proposer_id, :is_student_created?, :is_teacher_created? +} + +child(:counter_slot => :counter_slot) { + attributes :id, :preferred_day, :day_of_week, :hour, :minute, :slot_type, :pretty_scheduled_start, :message, :pretty_start_time, :proposer_id, :is_student_created?, :is_teacher_created? +} + + child(:user => :user) { - attributes :id, :has_stored_credit_card? + attributes :id, :has_stored_credit_card?, :first_name, :last_name, :photo_url, :name } -child(:teacher => :teacher) do |teacher| - partial "api_users/show", object: teacher +node :teacher do |lesson_booking| + partial "api_users/show", object: lesson_booking.teacher +end + +child(:next_lesson => :next_lesson) do |next_lesson| + attributes :id, :scheduled_start, :status, :music_session_id, :pretty_scheduled_start end \ No newline at end of file diff --git a/web/app/views/clients/index.html.erb b/web/app/views/clients/index.html.erb index 0d1fb6ecc..385285e63 100644 --- a/web/app/views/clients/index.html.erb +++ b/web/app/views/clients/index.html.erb @@ -47,6 +47,8 @@ <%= render "clients/teachers/search/search_results" %> <%= render "clients/jamclass/book_lesson_free" %> <%= render "clients/jamclass/lesson_payment" %> +<%= render "clients/jamclass/lesson_session" %> +<%= render "clients/jamclass/lesson_booking" %> <%= render "clients/jamclass/jamclass_student" %> <%= render "users/feed_music_session_ajax" %> <%= render "users/feed_recording_ajax" %> diff --git a/web/app/views/clients/jamclass/_book_lesson_free.html.slim b/web/app/views/clients/jamclass/_book_lesson_free.html.slim index 2a23fe3e0..dd3c51c79 100644 --- a/web/app/views/clients/jamclass/_book_lesson_free.html.slim +++ b/web/app/views/clients/jamclass/_book_lesson_free.html.slim @@ -1,4 +1,4 @@ -#lesson-book-free.screen.secondary layout="screen" layout-id="jamclass/book-lesson" layout-arg="id" +#lesson-book.screen.secondary layout="screen" layout-id="jamclass/book-lesson" layout-arg="id" .content-head .content-icon = image_tag "content/icon_account.png", :size => "27x20" diff --git a/web/app/views/clients/jamclass/_lesson_booking.html.slim b/web/app/views/clients/jamclass/_lesson_booking.html.slim new file mode 100644 index 000000000..b483b4fc0 --- /dev/null +++ b/web/app/views/clients/jamclass/_lesson_booking.html.slim @@ -0,0 +1,10 @@ +#lesson-booking.screen.secondary layout="screen" layout-id="jamclass/lesson-booking" layout-arg="id" + .content-head + .content-icon + = image_tag "content/icon_account.png", :size => "27x20" + h1 + | jamclass + = render "screen_navigation" + .content-body + = react_component 'LessonBooking', {} + diff --git a/web/app/views/clients/jamclass/_lesson_session.html.slim b/web/app/views/clients/jamclass/_lesson_session.html.slim new file mode 100644 index 000000000..1274d5677 --- /dev/null +++ b/web/app/views/clients/jamclass/_lesson_session.html.slim @@ -0,0 +1,10 @@ +#lesson-payment.screen.secondary layout="screen" layout-id="jamclass/lesson-session" + .content-head + .content-icon + = image_tag "content/icon_account.png", :size => "27x20" + h1 + | jamclass + = render "screen_navigation" + .content-body + = react_component 'LessonSession', {} + diff --git a/web/config/routes.rb b/web/config/routes.rb index a00f065c1..466a60901 100644 --- a/web/config/routes.rb +++ b/web/config/routes.rb @@ -684,6 +684,10 @@ SampleApp::Application.routes.draw do match '/lesson_sessions' => 'api_lesson_sessions#index', :via => :get match '/lesson_bookings' => 'api_lesson_bookings#create', :via => :post + match '/lesson_bookings/:id/accept' => 'api_lesson_bookings#accept', :via => :post + match '/lesson_bookings/:id/counter' => 'api_lesson_bookings#counter', :via => :post + match '/lesson_bookings/:id/cancel' => 'api_lesson_bookings#cancel', :via => :post + match '/lesson_bookings/:id' => 'api_lesson_bookings#show', :via => :get match '/lesson_bookings/unprocessed' => 'api_lesson_bookings#unprocessed', :via => :get match '/lesson_bookings/unprocessed_or_intent' => 'api_lesson_bookings#unprocessed_or_intent', :via => :get diff --git a/web/lib/tasks/lesson.rake b/web/lib/tasks/lesson.rake new file mode 100644 index 000000000..d5cb57ca4 --- /dev/null +++ b/web/lib/tasks/lesson.rake @@ -0,0 +1,46 @@ +require 'factory_girl' + +namespace :lessons do + + task book_test_drive: :environment do |task, args| + user = User.find_by_email(ENV['STUDENT_EMAIL']) + teacher = User.find_by_email(ENV['TEACHER_EMAIL']) + recurring = ENV['RECURRING'] == '1' + + slots = [] + + if recurring + slots << FactoryGirl.build(:lesson_booking_slot_recurring, timezone: 'America/Chicago') + slots << FactoryGirl.build(:lesson_booking_slot_recurring, timezone: 'America/Chicago') + else + slots << FactoryGirl.build(:lesson_booking_slot_single, timezone: 'America/Chicago') + slots << FactoryGirl.build(:lesson_booking_slot_single, timezone: 'America/Chicago') + + end + + if user.stored_credit_card == false + user.stored_credit_card = true + user.save! + end + + + booking = LessonBooking.book_test_drive(user, teacher, slots, "Hey I've heard of you before.") + if booking.errors.any? + puts booking.errors.inspect + raise "booking failed" + end + lesson = booking.lesson_sessions[0] + + if user.most_recent_test_drive_purchase.nil? + LessonPackagePurchase.create(user, booking, LessonPackageType.test_drive) + end + + #lesson.accept({message: 'Yeah I got this', slot: slots[0]}) + #lesson.errors.any?.should be_false + #lesson.reload + #lesson.slot.should eql slots[0] + #lesson.status.should eql LessonSession::STATUS_APPROVED + + puts "http://localhost:3000/client#/jamclass/lesson-booking/#{booking.id}" + end +end diff --git a/web/spec/factories.rb b/web/spec/factories.rb index 39f4b45f9..d8648f2ae 100644 --- a/web/spec/factories.rb +++ b/web/spec/factories.rb @@ -874,4 +874,97 @@ FactoryGirl.define do sequence(:jamblaster_client_id ) { |n| "jamblaster_client_id#{n}" } sequence(:sibling_key ) { |n| "sibling_key#{n}" } end + + + factory :lesson_booking_slot, class: 'JamRuby::LessonBookingSlot' do + factory :lesson_booking_slot_single do + slot_type 'single' + preferred_day Date.today + 3 + day_of_week nil + hour 12 + minute 30 + timezone 'UTC' + end + + factory :lesson_booking_slot_recurring do + slot_type 'recurring' + preferred_day nil + day_of_week 0 + hour 12 + minute 30 + timezone 'UTC' + end + end + + factory :lesson_booking, class: 'JamRuby::LessonBooking' do + association :user, factory: :user + association :teacher, factory: :teacher_user + card_presumed_ok false + sent_notices false + recurring false + lesson_length 30 + lesson_type JamRuby::LessonBooking::LESSON_TYPE_FREE + payment_style JamRuby::LessonBooking::PAYMENT_STYLE_ELSEWHERE + description "Oh my goodness!" + status JamRuby::LessonBooking::STATUS_REQUESTED + before(:create) do |lesson_booking, evaluator| + lesson_booking.lesson_booking_slots = [FactoryGirl.build(:lesson_booking_slot_single, lesson_booking: lesson_booking), + FactoryGirl.build(:lesson_booking_slot_single, lesson_booking: lesson_booking)] + end + #lesson_booking_slots [FactoryGirl.build(:lesson_booking_slot_single), FactoryGirl.build(:lesson_booking_slot_single)] + end + + factory :lesson_package_purchase, class: "JamRuby::LessonPackagePurchase" do + lesson_package_type { JamRuby::LessonPackageType.single } + association :user, factory: :user + association :teacher, factory: :teacher_user + price 30.00 + + factory :test_drive_purchase do + lesson_package_type { JamRuby::LessonPackageType.test_drive } + association :lesson_booking, factory: :lesson_booking + price 49.99 + end + end + + factory :lesson_session, class: 'JamRuby::LessonSession' do + + ignore do + student nil + end + + music_session {FactoryGirl.create(:music_session, creator: student)} + lesson_booking {FactoryGirl.create(:lesson_booking, user: student, teacher: teacher)} + association :teacher, factory: :teacher_user + lesson_type JamRuby::LessonSession::LESSON_TYPE_SINGLE + duration 30 + booked_price 49.99 + status JamRuby::LessonSession::STATUS_REQUESTED + #teacher_complete true + #student_complete true + end + + factory :charge, class: 'JamRuby::Charge' do + type 'JamRuby::Charge' + amount_in_cents 1000 + end + + factory :teacher_payment_charge, parent: :charge, class: 'JamRuby::TeacherPaymentCharge' do + type 'JamRuby::TeacherPaymentCharge' + end + + + factory :teacher_payment, class: 'JamRuby::TeacherPayment' do + association :teacher, factory: :teacher_user + association :teacher_payment_charge, factory: :teacher_payment_charge + amount_in_cents 1000 + end + + # you gotta pass either lesson_session or lesson_package_purchase for this to make sense + factory :teacher_distribution, class: 'JamRuby::TeacherDistribution' do + association :teacher, factory: :teacher_user + association :teacher_payment, factory: :teacher_payment + ready false + amount_in_cents 1000 + end end