diff --git a/ruby/lib/jam_ruby/app/mailers/admin_mailer.rb b/ruby/lib/jam_ruby/app/mailers/admin_mailer.rb index 6f8db1c02..993b9f81b 100644 --- a/ruby/lib/jam_ruby/app/mailers/admin_mailer.rb +++ b/ruby/lib/jam_ruby/app/mailers/admin_mailer.rb @@ -30,7 +30,7 @@ module JamRuby def social(options) mail(to: APP_CONFIG.email_social_alias, - from: APP_CONFIG.email_generic_from, + from: options[:from] || APP_CONFIG.email_generic_from, body: options[:body], content_type: "text/plain", subject: options[:subject]) diff --git a/ruby/lib/jam_ruby/models/teacher.rb b/ruby/lib/jam_ruby/models/teacher.rb index 357dc8f69..0dcee13fc 100644 --- a/ruby/lib/jam_ruby/models/teacher.rb +++ b/ruby/lib/jam_ruby/models/teacher.rb @@ -58,7 +58,7 @@ module JamRuby # only show teachers with ready for session set to true query = query.where('teachers.ready_for_session_at IS NOT NULL') - if params[:onlyMySchool] && params[:onlyMySchool] != 'false' && user.school_id + if user && params[:onlyMySchool] && params[:onlyMySchool] != 'false' && user.school_id query = query.where("teachers.school_id = ?", user.school_id) end diff --git a/ruby/lib/jam_ruby/models/user.rb b/ruby/lib/jam_ruby/models/user.rb index 2421a5c3c..aed3d83c1 100644 --- a/ruby/lib/jam_ruby/models/user.rb +++ b/ruby/lib/jam_ruby/models/user.rb @@ -2113,19 +2113,9 @@ module JamRuby end def has_rated_teacher(teacher) - teacher_rating(teacher) - end - - def has_rated_student(student) - Review.where(target_id: student.id).where(target_type: "JamRuby::User").count > 0 + teacher_rating(teacher).count > 0 end - def teacher_rating(teacher) - if teacher.is_a?(JamRuby::User) - teacher = teacher.teacher - end - Review.where(target_id: teacher.id).where(target_type: teacher.class.to_s) - end def teacher_rating(teacher) if teacher.is_a?(JamRuby::User) teacher = teacher.teacher @@ -2134,13 +2124,21 @@ module JamRuby end def has_rated_student(student) - Review.where(target_id: student.id).where(target_type: "JamRuby::User").count > 0 + student_rating(student).count > 0 + end + + def student_rating(student) + Review.where(target_id: student.id).where(target_type: "JamRuby::User") end def teacher_profile_url "#{APP_CONFIG.external_root_url}/client#/profile/teacher/#{id}" end + def profile_url + "#{APP_CONFIG.external_root_url}/client#/profile/#{id}" + end + def ratings_url "#{APP_CONFIG.external_root_url}/client?tile=ratings#/profile/teacher/#{id}" end diff --git a/web/app/assets/javascripts/everywhere/everywhere.js b/web/app/assets/javascripts/everywhere/everywhere.js index 18f829975..80c5f8ccd 100644 --- a/web/app/assets/javascripts/everywhere/everywhere.js +++ b/web/app/assets/javascripts/everywhere/everywhere.js @@ -261,7 +261,11 @@ return; } - var activate = ["jamtrack/search", "jamtrack/filter", "shoppingCart", "checkoutPayment", "checkoutOrder", "redeemComplete", "checkoutComplete", "teachers/setup/introduction", "teachers/setup/basics", "teachers/setup/experience", "teachers/setup/pricing", "account/profile", "account/profile/experience", "account/profile/interests", "account/profile/samples"] + var activate = ["jamtrack/search", "jamtrack/filter", + "shoppingCart", "checkoutPayment", "checkoutOrder", "redeemComplete", "checkoutComplete", + "teachers/setup/introduction", "teachers/setup/basics", "teachers/setup/experience", "teachers/setup/pricing", + "account/profile", "account/profile/experience", "account/profile/interests", "account/profile/samples", + "jamclass"] $(document).on(context.JK.EVENTS.SCREEN_CHANGED, function(e, data) { var show = false; diff --git a/web/app/assets/javascripts/helpBubbleHelper.js b/web/app/assets/javascripts/helpBubbleHelper.js index 9c61d67eb..06a1adc17 100644 --- a/web/app/assets/javascripts/helpBubbleHelper.js +++ b/web/app/assets/javascripts/helpBubbleHelper.js @@ -186,7 +186,7 @@ helpBubble.showBuyNormalLesson = function($element, $offsetParent, user, callback) { return context.JK.onceBubble($element, 'side-buy-normal-lesson', user, {offsetParent:$offsetParent, width:260, positions:['right'], postShow: function(container) { - var $bookNow = $('a.book-now') + var $bookNow = container.find('a.book-now') $bookNow.off('click').on('click', function(e) { e.preventDefault() callback() @@ -194,4 +194,17 @@ }) }}) } + + helpBubble.didntFindTeacher = function($element, $offsetParent, user, callback) { + return context.JK.onceBubble($element, 'side-didnt-find-teacher', user, {offsetParent:$offsetParent, width:260, positions:['right'], postShow: function(container) { + var $bookNow = container.find('a.post-help') + console.log("container", $bookNow) + $bookNow.off('click').on('click', function(e) { + e.preventDefault() + callback(container.find('.note').val(), container.find('.email').val(), container.find('.phonenumber').val()) + return false; + }) + console.log("hehelllo!") + }}) + } })(window, jQuery); \ No newline at end of file diff --git a/web/app/assets/javascripts/jam_rest.js b/web/app/assets/javascripts/jam_rest.js index 6f848d596..01db700d4 100644 --- a/web/app/assets/javascripts/jam_rest.js +++ b/web/app/assets/javascripts/jam_rest.js @@ -2491,6 +2491,17 @@ }); } + function askSearchHelp(options) { + + return $.ajax({ + type: "POST", + url: '/api/teachers/search_help', + dataType: "json", + contentType: 'application/json', + data: JSON.stringify(options), + }) + } + function initialize() { return self; } @@ -2714,7 +2725,7 @@ this.listTeacherDistributions = listTeacherDistributions; this.lessonStartTime = lessonStartTime; this.createReview = createReview; - + this.askSearchHelp = askSearchHelp; return this; }; })(window,jQuery); diff --git a/web/app/assets/javascripts/react-components/BroadcastHolder.js.jsx.coffee b/web/app/assets/javascripts/react-components/BroadcastHolder.js.jsx.coffee index 575432605..1c71e942f 100644 --- a/web/app/assets/javascripts/react-components/BroadcastHolder.js.jsx.coffee +++ b/web/app/assets/javascripts/react-components/BroadcastHolder.js.jsx.coffee @@ -12,7 +12,9 @@ BroadcastHolder = React.createClass( notification = [] if this.state.notification - if this.state.notification.isLesson + if this.state.notification.isJamClass + result = `` + else if this.state.notification.isLesson result = `` else result = `` diff --git a/web/app/assets/javascripts/react-components/JamClassPhone.js.jsx.coffee b/web/app/assets/javascripts/react-components/JamClassPhone.js.jsx.coffee new file mode 100644 index 000000000..99f7c91f5 --- /dev/null +++ b/web/app/assets/javascripts/react-components/JamClassPhone.js.jsx.coffee @@ -0,0 +1,24 @@ +context = window + +@JamClassPhone = React.createClass( + { + displayName: 'JamClassPhone', + + render: -> + `
+ + +
+
+ Call  + + 877-37-MUSIC + +
+
+ Have questions? Call now! +
+
+
` + } +) \ 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 af66a945f..956edcd95 100644 --- a/web/app/assets/javascripts/react-components/TeacherSearchScreen.js.jsx.coffee +++ b/web/app/assets/javascripts/react-components/TeacherSearchScreen.js.jsx.coffee @@ -22,6 +22,7 @@ ProfileActions = @ProfileActions visible: false needToSearch: true root: null + screen: null endOfList: null contentBodyScroller: null refreshing: false @@ -36,7 +37,6 @@ ProfileActions = @ProfileActions @visible = true afterShow: (e) -> - @visible = false #@setState(TeacherSearchStore.getState()) #if @state.results.length == 0 # don't issue a new search every time someone comes to the screen, to preserve location from previous browsing @@ -48,7 +48,9 @@ ProfileActions = @ProfileActions @needToSearch = false afterHide: (e) -> + @visible = false @contentBodyScroller.off('scroll') + @hideSideBubble() onTeacherSearchStore: (storeChanged) -> @needToSearch = true @@ -68,10 +70,12 @@ ProfileActions = @ProfileActions componentDidMount: () -> @root = $(@getDOMNode()) + @screen = $('#teacherSearch') @resultsNode = @root.find('.results') @endOfList = @root.find('.end-of-teacher-list') @contentBodyScroller = @root + registerInfiniteScroll:() -> $scroller = @contentBodyScroller logger.debug("registering infinite scroll") @@ -87,6 +91,33 @@ ProfileActions = @ProfileActions logger.debug("refreshing more teachers for infinite scroll") TeacherSearchResultsActions.nextPage() ) + showSideBubble: () -> + setTimeout( + (() => ( + if @visible + context.JK.HelpBubbleHelper.didntFindTeacher(@screen, null, @state.user || {}, ((note, email, phone) => @postHelp(note, email, phone))) + )), 3000) + + + hideSideBubble: () -> + if @screen.btOff + @screen.btOff() + + postHelp: (value, email, phone) -> + + if !value? || value == '' + @app.layout.notify({title: 'note required', text: 'Please enter something about what you are looking for.'}) + return + if !context.JK.currentUserId? && (!email? || email == '') + @app.layout.notify({title: 'email required', text: 'Please enter your email.'}) + return + + rest.askSearchHelp({note: value, email: email, phone: phone}).done((response) => @postHelpDone()).fail(@app.ajaxError) + + postHelpDone: () -> + console.log("show notice") + context.JK.Banner.showNotice("request received", "We got your note. We will reach back shortly!") + @hideSideBubble() componentDidUpdate: () -> @resultsNode.find('.teacher-bio').each((index, element) => ( @@ -99,6 +130,9 @@ ProfileActions = @ProfileActions if @visible + if @state.currentPage > 1 + @showSideBubble() + if @state.next == null @contentBodyScroller.off('scroll') if @state.currentPage == 1 and @state.results.length == 0 diff --git a/web/app/assets/javascripts/react-components/landing/JamClassAffiliateLandingPage.js.jsx.coffee b/web/app/assets/javascripts/react-components/landing/JamClassAffiliateLandingPage.js.jsx.coffee index fbdb6cc42..379a8d79f 100644 --- a/web/app/assets/javascripts/react-components/landing/JamClassAffiliateLandingPage.js.jsx.coffee +++ b/web/app/assets/javascripts/react-components/landing/JamClassAffiliateLandingPage.js.jsx.coffee @@ -51,6 +51,7 @@ rest = context.JK.Rest()

Do you own or operate a music store or school?

+
diff --git a/web/app/assets/javascripts/react-components/landing/JamClassSchoolLandingPage.js.jsx.coffee b/web/app/assets/javascripts/react-components/landing/JamClassSchoolLandingPage.js.jsx.coffee index bd0320d4d..fffdf3dda 100644 --- a/web/app/assets/javascripts/react-components/landing/JamClassSchoolLandingPage.js.jsx.coffee +++ b/web/app/assets/javascripts/react-components/landing/JamClassSchoolLandingPage.js.jsx.coffee @@ -51,6 +51,7 @@ rest = context.JK.Rest()

Do you own/operate a music school?

+
diff --git a/web/app/assets/javascripts/react-components/landing/JamClassStudentLandingPage.js.jsx.coffee b/web/app/assets/javascripts/react-components/landing/JamClassStudentLandingPage.js.jsx.coffee index f3cb70d50..3eaf9af5e 100644 --- a/web/app/assets/javascripts/react-components/landing/JamClassStudentLandingPage.js.jsx.coffee +++ b/web/app/assets/javascripts/react-components/landing/JamClassStudentLandingPage.js.jsx.coffee @@ -51,6 +51,7 @@ rest = context.JK.Rest()

Finally, online music lessons
that really work!

+
diff --git a/web/app/assets/javascripts/react-components/landing/JamClassTeacherLandingPage.js.jsx.coffee b/web/app/assets/javascripts/react-components/landing/JamClassTeacherLandingPage.js.jsx.coffee index 7ea5bb6f9..657c9bb18 100644 --- a/web/app/assets/javascripts/react-components/landing/JamClassTeacherLandingPage.js.jsx.coffee +++ b/web/app/assets/javascripts/react-components/landing/JamClassTeacherLandingPage.js.jsx.coffee @@ -51,6 +51,7 @@ rest = context.JK.Rest()

Finally, online music lessons
that really work!

+
diff --git a/web/app/assets/javascripts/react-components/stores/BroadcastStore.js.coffee b/web/app/assets/javascripts/react-components/stores/BroadcastStore.js.coffee index cbaf025a3..fb5f69aab 100644 --- a/web/app/assets/javascripts/react-components/stores/BroadcastStore.js.coffee +++ b/web/app/assets/javascripts/react-components/stores/BroadcastStore.js.coffee @@ -16,9 +16,11 @@ BroadcastStore = Reflux.createStore( broadcast: null currentLessonTimer: null teacherFault: false + isJamClass: false init: -> - this.listenTo(context.AppStore, this.onAppInit); + this.listenTo(context.AppStore, this.onAppInit) this.listenTo(context.SessionStore, this.onSessionChange) + this.listenTo(context.NavStore, this.onNavChange) onAppInit: (@app) -> @@ -104,6 +106,12 @@ BroadcastStore = Reflux.createStore( if @currentLessonTimer? clearInterval(@currentLessonTimer) @currentLessonTimer = null + + onNavChange: (nav) -> + path = nav.screenPath.toLowerCase() + @isJamClass = path.indexOf('jamclass') > -1 || path.indexOf('teacher') > -1 + @changed() + onSessionChange: (session) -> @session = session @@ -158,6 +166,8 @@ BroadcastStore = Reflux.createStore( this.trigger(null) else this.trigger(@currentLesson) + else if @isJamClass + this.trigger({isJamClass: true}) else this.trigger(@broadcast) } diff --git a/web/app/assets/javascripts/react-components/stores/NavStore.js.coffee b/web/app/assets/javascripts/react-components/stores/NavStore.js.coffee index 5414200e2..651b899d7 100644 --- a/web/app/assets/javascripts/react-components/stores/NavStore.js.coffee +++ b/web/app/assets/javascripts/react-components/stores/NavStore.js.coffee @@ -41,6 +41,6 @@ rest = new context.JK.Rest() @changed() changed:() -> - @trigger({currentScreen: @currentScreen, currentSection: @currentSection, currentScreenName: @currentScreenName}) + @trigger({screenPath: @screenPath, currentScreen: @currentScreen, currentSection: @currentSection, currentScreenName: @currentScreenName}) } ) diff --git a/web/app/assets/javascripts/utils.js b/web/app/assets/javascripts/utils.js index 1fc350fbb..0d91f1fbe 100644 --- a/web/app/assets/javascripts/utils.js +++ b/web/app/assets/javascripts/utils.js @@ -148,7 +148,7 @@ context.JK.popExternalLinks($(container)) if (originalPostShow) { - originalPostShow(container); + originalPostShow($(container)); } } diff --git a/web/app/assets/stylesheets/client/help.css.scss b/web/app/assets/stylesheets/client/help.css.scss index ec34250dd..02362ab94 100644 --- a/web/app/assets/stylesheets/client/help.css.scss +++ b/web/app/assets/stylesheets/client/help.css.scss @@ -1,7 +1,11 @@ @import "client/common"; -body.jam, body.web, .dialog{ +//body.jam, body.web, .dialog{ +html { .bt-wrapper { + font-size: 14px; + font-family: 'Raleway', Arial, Helvetica, sans-serif; + font-weight: 300; .bt-content { color:#cccccc; @@ -91,7 +95,7 @@ body.jam, body.web, .dialog{ } - .side-remaining-test-drives, .side-buy-test-drive, .side-buy-normal-lesson { + .side-remaining-test-drives, .side-buy-test-drive, .side-buy-normal-lesson, .side-didnt-find-teacher { h2 { font-size:20px; color:white; @@ -106,6 +110,40 @@ body.jam, body.web, .dialog{ display:block; margin:30px auto; } + .post-help { + width:100px; + display:block; + margin:30px auto; + } + + .textarea-wrapper { + padding: 0 1em; + width:100%; + @include border_box_sizing; + } + + textarea { + height:70px; + @include border_box_sizing; + width:100%; + font-size:14px; + } + + .field { + margin: 0 1em; + label { + width:50px; + display:inline-block; + font-size:14px; + } + input { + font-size:14px; + display:inline-block; + margin-bottom:20px; + width:178px; + } + } + } diff --git a/web/app/assets/stylesheets/client/jamkazam.css.scss b/web/app/assets/stylesheets/client/jamkazam.css.scss index 8b972af82..00a2b64cf 100644 --- a/web/app/assets/stylesheets/client/jamkazam.css.scss +++ b/web/app/assets/stylesheets/client/jamkazam.css.scss @@ -750,4 +750,30 @@ button.stripe-connect { .site-nav { margin-bottom:10px; +} + +.jamclass-phone { + background-color:#262626; + float:right; + height:50px; + font-size:16px; + img { + display:inline-block; + margin-right:7px; + vertical-align:baseline; + } + .callwrapper { + display:inline-block; + } + .call-num { + white-space:nowrap; + margin-bottom:4px; + text-align:right; + } + .call-prompt { + white-space:nowrap; + } + .phonenumber { + font-size:20px; + } } \ No newline at end of file diff --git a/web/app/assets/stylesheets/landings/individual_jamtrack.css.scss b/web/app/assets/stylesheets/landings/individual_jamtrack.css.scss index 6bfcd8747..c4f719ef2 100644 --- a/web/app/assets/stylesheets/landings/individual_jamtrack.css.scss +++ b/web/app/assets/stylesheets/landings/individual_jamtrack.css.scss @@ -57,6 +57,12 @@ body.web.individual_jamtrack { } } + .jamclass-phone { + position: relative; + top: -150px; + right: 107px; + background-color:black; + } .name-and-artist { padding-top: 60px; diff --git a/web/app/controllers/api_teachers_controller.rb b/web/app/controllers/api_teachers_controller.rb index 0a3dcfae9..904e83273 100644 --- a/web/app/controllers/api_teachers_controller.rb +++ b/web/app/controllers/api_teachers_controller.rb @@ -1,6 +1,6 @@ class ApiTeachersController < ApiController - before_filter :api_signed_in_user, :except => [:index, :detail, :search] + before_filter :api_signed_in_user, :except => [:index, :detail, :search, :search_help] before_filter :auth_teacher, :only => [:update, :delete] before_filter :auth_user, :only => [:create, :update] @@ -46,7 +46,54 @@ class ApiTeachersController < ApiController respond_with_model(@intent) end -private + + def search_help + email = params[:email] + if current_user && email.blank? + email = current_user.email + end + if current_user + subject = "#{current_user.name} wants help searching for a teacher" + body = "#{current_user.name} (#{email}) needs help locating a teacher.\n\n" + if params[:phone].present? + body << "Phone Number: #{params[:phone]}\n\n" + else + body << "Phone Number: None Entered\n\n" + end + + if params[:note].present? + body << "Here's what they wrote: \n\n\n" + body << params[:note] + else + body << "...They didn't write anything..." + end + + body << "\n\nAdmin: #{current_user.admin_url}" + body << "\nProfile: #{current_user.profile_url}" + + else + subject = "#{email} wants help searching for a teacher" + body = "#{email} needs help locating a teacher.\n\n" + if params[:phone].present? + body << "Phone Number: #{params[:phone]}\n\n" + else + body << "Phone Number: None Entered\n\n" + end + + if params[:note].present? + body << "Here's what they wrote: \n\n\n" + body << params[:note] + else + body << "...They didn't write anything..." + end + end + + AdminMailer.social({from: email, body: body, subject: subject}).deliver + + render json: { success: true }, :status => 200 + end + + private def auth_teacher @teacher = Teacher.find(params[:id]) @@ -71,6 +118,6 @@ private else @user=current_user end - end + end diff --git a/web/app/views/clients/_help.html.slim b/web/app/views/clients/_help.html.slim index cdaacd3d8..138ba6a74 100644 --- a/web/app/views/clients/_help.html.slim +++ b/web/app/views/clients/_help.html.slim @@ -423,4 +423,21 @@ script type="text/template" id="template-help-side-buy-normal-lesson" a.book-now.button-orange BOOK NOW! p Or call us at p 877-376-8742 (877-37-MUSIC) - p And we can answer any questions and help set you up over the phone. \ No newline at end of file + p And we can answer any questions and help set you up over the phone. + +script type="text/template" id="template-help-side-didnt-find-teacher" + .side-didnt-find-teacher + h2 Let us help! + p + | Didn't find the teacher you want? Tell us what you're looking for, + | and our concierge team will find one or more teachers who meet your requirements in about a week. We are 100% committed to helping you connect to your ideal teacher! + + .field + label Email + input.email type="text" placeholder="Email address" value="{{data.email}}" + .field + label Phone + input.phonenumber type="text" placeholder="Callback number" + .textarea-wrapper + textarea.note placeholder="Write a note here explaining what you need in your teacher..." + a.post-help.button-orange SEND NOTE \ No newline at end of file diff --git a/web/app/views/clients/_jamclass_phone.html.slim b/web/app/views/clients/_jamclass_phone.html.slim new file mode 100644 index 000000000..4f0e89059 --- /dev/null +++ b/web/app/views/clients/_jamclass_phone.html.slim @@ -0,0 +1,9 @@ +.jamclass-phone + + = image_tag("content/phone_icon.png", {width:32, height:32}) + + .call-num + | Call + span.phonenumber 877-37-MUSIC + .call-prompt + | Have questions? Call now! diff --git a/web/config/routes.rb b/web/config/routes.rb index ceac86c98..fb67e9e5a 100644 --- a/web/config/routes.rb +++ b/web/config/routes.rb @@ -497,6 +497,7 @@ SampleApp::Application.routes.draw do # teachers match '/teachers' => 'api_teachers#index', :via => :get match '/teachers/detail' => 'api_teachers#detail', :via => :get, :as => 'api_teacher_detail' + match '/teachers/search_help' => 'api_teachers#search_help', :via => :post match '/teachers' => 'api_teachers#create', :via => :post match '/teachers/:id' => 'api_teachers#update', :via => :post match '/teachers/:id' => 'api_teachers#delete', :via => :delete