From 141736ad2f05a2dac5f98f70fc6fe8cf4e74f2cd Mon Sep 17 00:00:00 2001 From: Seth Call Date: Tue, 17 May 2016 13:31:53 -0500 Subject: [PATCH] * add rating dialogs for teacher/students and have them pop at end of lesson, be accessible from teacher rating profile pgae, and also from link in email --- ruby/lib/jam_ruby/models/review.rb | 44 +- ruby/lib/jam_ruby/models/review_summary.rb | 2 +- ruby/lib/jam_ruby/models/user.rb | 14 +- web/app/assets/javascripts/profile.js | 1848 +++++++++-------- .../AccountPaymentHistoryScreen.js.jsx.coffee | 1 - .../RateUserDialog.js.jsx.coffee | 150 +- .../SessionLeaveBtn.js.jsx.coffee | 7 - .../TeacherProfile.js.jsx.coffee | 24 +- .../mixins/ICheckMixin.js.coffee | 10 +- .../stores/SessionStore.js.coffee | 13 + .../react-components/TeacherProfile.css.scss | 6 + .../dialogs/rateUserDialog.css.scss | 52 + web/app/controllers/api_reviews_controller.rb | 16 +- web/app/views/dialogs/_dialogs.html.haml | 1 + .../views/dialogs/_rateUserDialog.html.slim | 2 + web/config/environments/development.rb | 1 + web/config/environments/test.rb | 1 + 17 files changed, 1229 insertions(+), 963 deletions(-) create mode 100644 web/app/assets/stylesheets/dialogs/rateUserDialog.css.scss create mode 100644 web/app/views/dialogs/_rateUserDialog.html.slim diff --git a/ruby/lib/jam_ruby/models/review.rb b/ruby/lib/jam_ruby/models/review.rb index 4fe6e755b..48cdb7148 100644 --- a/ruby/lib/jam_ruby/models/review.rb +++ b/ruby/lib/jam_ruby/models/review.rb @@ -17,9 +17,42 @@ module JamRuby validates :target, presence: true validates :user_id, presence: true validates :target_id, uniqueness: {scope: :user_id, message: "There is already a review for this User and Target."} + validate :requires_lesson after_save :reduce + def requires_lesson + if target_type == 'JamRuby::User' + + # you are rating a student + lesson = LessonSession.joins(:music_session).where('music_sessions.user_id = ?', target.id).where(teacher_id: user.id).first + if lesson.nil? + errors.add(:target, "You must have at least scheduled or been in a lesson with this student") + end + + elsif target_type == "JamRuby::Teacher" + + # you are rating a teacher + lesson = LessonSession.joins(:music_session).where('music_sessions.user_id = ?', user.id).where(teacher_id: target.user.id).first + if lesson.nil? + errors.add(:target, "You must have at least scheduled or been in a lesson with this teacher") + end + end + end + + def self.create_or_update(params) + review = Review.where(user_id: params[:user].id).where(target_id: params[:target].id).where(target_type: params[:target].class.to_s).first + + if review + review.description = params[:description] + review.rating = params[:rating] + review.save + else + review = Review.create(params) + end + + review + end def self.create(params) review = Review.new review.target = params[:target] @@ -81,7 +114,7 @@ module JamRuby def reduce ReviewSummary.transaction do - ReviewSummary.where(target_type: target_type, target_id: target_id).destroy_all + ReviewSummary.where(target_type: target_type, target_id: target_id).delete_all Review.select("target_id, target_type AS target_type, AVG(rating) as avg_rating, count(*) as review_count, SUM(CASE WHEN rating>=3.0 THEN 1 ELSE 0 END) AS pos_count") .where("deleted_at IS NULL") @@ -89,15 +122,22 @@ module JamRuby .group("target_type, target_id") .each do |r| wilson_score = Review.ci_lower_bound(r.pos_count, r.review_count) - ReviewSummary.create!( + + summary = ReviewSummary.create( target_id: r.target_id, target_type: r.target_type, avg_rating: r.avg_rating, wilson_score: wilson_score, review_count: r.review_count ) + if summary.errors.any? + puts "review summary unable to be created #{summary.errors.inspect}" + raise "review summary unable to be created #{summary.errors.inspect}" + end end end + + return true end end end \ No newline at end of file diff --git a/ruby/lib/jam_ruby/models/review_summary.rb b/ruby/lib/jam_ruby/models/review_summary.rb index fb3833f5d..b0aef4711 100644 --- a/ruby/lib/jam_ruby/models/review_summary.rb +++ b/ruby/lib/jam_ruby/models/review_summary.rb @@ -5,7 +5,7 @@ module JamRuby validates :avg_rating, presence:true, numericality: true validates :review_count, presence:true, numericality: {only_integer: true} - validates :wilson_score, presence:true, numericality: {greater_than:0, less_than:1} + validates :wilson_score, presence:true, numericality: {greater_than_or_equal_to:0, less_than_or_equal_to:1} validates :target_id, presence:true, uniqueness:true class << self diff --git a/ruby/lib/jam_ruby/models/user.rb b/ruby/lib/jam_ruby/models/user.rb index 85c9cd061..2421a5c3c 100644 --- a/ruby/lib/jam_ruby/models/user.rb +++ b/ruby/lib/jam_ruby/models/user.rb @@ -2113,11 +2113,11 @@ module JamRuby end def has_rated_teacher(teacher) - teacher_rating(teacher).count > 0 + teacher_rating(teacher) end def has_rated_student(student) - student_rating(student).count > 0 + Review.where(target_id: student.id).where(target_type: "JamRuby::User").count > 0 end def teacher_rating(teacher) @@ -2126,9 +2126,11 @@ module JamRuby end Review.where(target_id: teacher.id).where(target_type: teacher.class.to_s) end - - def student_rating(student) - Review.where(target_id: student.id).where(target_type: "JamRuby::User") + 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 has_rated_student(student) @@ -2140,7 +2142,7 @@ module JamRuby end def ratings_url - "#{APP_CONFIG.external_root_url}/client?selected=ratings#/profile/teacher/#{id}" + "#{APP_CONFIG.external_root_url}/client?tile=ratings#/profile/teacher/#{id}" end def student_ratings_url diff --git a/web/app/assets/javascripts/profile.js b/web/app/assets/javascripts/profile.js index 7e42a4747..01ef7cd00 100644 --- a/web/app/assets/javascripts/profile.js +++ b/web/app/assets/javascripts/profile.js @@ -1,985 +1,1007 @@ (function (context, $) { - "use strict"; - - context.JK = context.JK || {}; - context.JK.ProfileScreen = function (app) { - var logger = context.JK.logger; - var userId; - var user = null; - var userDefer = null; - var rest = context.JK.Rest(); - var decrementedFriendCountOnce = false; - var sentFriendRequest = false; - var textMessageDialog = null; - var feed = null; - var player = null; - var profileUtils = context.JK.ProfileUtils; - - var NOT_SPECIFIED_TEXT = 'Not specified'; - - var $screen = $('#user-profile'); - - var $biography = $screen.find('#biography'); - - // musical experience - var $instruments = $screen.find('.instruments-holder'); - var $musicianStatus = $screen.find('#musician-status'); - var $genres = $screen.find('#genres'); - var $concertCount = $screen.find('#concert-count'); - var $studioCount = $screen.find('#studio-count'); - - // performance samples - var $noSamples = $screen.find('.no-samples'); - var $jamkazamSamples = $screen.find('.jamkazam-samples'); - var $soundCloudSamples = $screen.find('.soundcloud-samples'); - var $youTubeSamples = $screen.find('.youtube-samples'); - - // online presence - - var $userWebsite = $screen.find('.user-website'); - var $soundCloudPresence = $screen.find('.soundcloud-presence'); - var $reverbNationPresence = $screen.find('.reverbnation-presence'); - var $bandCampPresence = $screen.find('.bandcamp-presence'); - var $fandalismPresence = $screen.find('.fandalism-presence'); - var $youTubePresence = $screen.find('.youtube-presence'); - var $facebookPresence = $screen.find('.facebook-presence'); - var $twitterPresence = $screen.find('.twitter-presence'); - - // current interests - var $noInterests = $screen.find('#no-interests'); - var $paidGigSection = $screen.find('#paid-gigs'); - var $paidGigDetails = $screen.find('#paid-gig-details'); - - var $freeGigSection = $screen.find('#free-gigs'); - var $freeGigDetails = $screen.find('#free-gig-details'); - - var $cowritingSection = $screen.find('#cowriting'); - var $cowritingDetails = $screen.find('#cowriting-details'); - - var $traditionalBandSection = $screen.find('#traditional-band'); - var $traditionalBandDetails = $screen.find('#traditional-band-details'); - - var $virtualBandSection = $screen.find('#virtual-band'); - var $virtualBandDetails = $screen.find('#virtual-band-details'); - - // tabs - var $aboutLink = $screen.find('#about-link'); - var $aboutContent = $screen.find('#about-content'); - - var $historyLink = $screen.find('#history-link'); - var $historyContent = $screen.find('#history-content'); - - var $bandsLink = $screen.find('#bands-link'); - var $bandsContent = $screen.find('#bands-content'); - - var $socialLink = $screen.find('#social-link'); - var $socialContent = $screen.find('#social-content'); - - var $favoritesLink = $screen.find('#favorites-link'); - var $favoritesContent = $screen.find('#favorites-content'); - - // stats - var $friendStats = $screen.find('#friend-stats'); - var $followerStats = $screen.find('#follower-stats'); - var $sessionStats = $screen.find('#session-stats'); - var $recordingStats = $screen.find('#recording-stats'); - var $followingStats = $screen.find('#following-stats'); - var $favoriteStats = $screen.find('#favorite-stats'); - - // miscellaneous - var $userName = $screen.find('#username'); - var $avatar = $screen.find('#avatar'); - var $typeLabel = $screen.find('#type-label'); - var $location = $screen.find('#location'); - var $age = $screen.find('#age'); - - // buttons - var $profileActions = $screen.find('.profile-actions') - var $btnEdit = $screen.find('.edit-profile-btn'); - var $btnTeacherProfileEdit = $screen.find('.edit-teacher-profile-btn'); - var $btnTeacherProfileView = $screen.find('.view-teacher-profile-btn'); - var $btnAddFriend = $screen.find('#btn-add-friend'); - var $btnFollowUser = $screen.find('#btn-follow-user'); - var $btnMessageUser = $screen.find('#btn-message-user'); - var $btnEditBio = $screen.find(".add-bio"); - var $btnAddRecordings = $screen.find('.add-recordings'); - var $btnAddSites = $screen.find('.add-sites'); - var $btnAddInterests = $screen.find('.add-interests'); - var $btnAddExperiences = $screen.find('.add-experiences') - - // social - var $socialLeft = $screen.find('.profile-social-left'); - var $socialFriends = $screen.find('#social-friends'); - var $socialFollowings = $screen.find('#social-followings'); - var $socialFollowers = $screen.find('#social-followers'); - - var instrument_logo_map = context.JK.getInstrumentIconMap24(); - - function beforeShow(data) { - userId = data.id; - feed.setUser(userId); - } - - function afterShow(data) { - initUser(); - resetForm(); - renderAllStats(); - } - - function beforeHide(data) { - feed.setUser(null); - } - - function resetForm() { - //$instruments.empty(); - - $aboutContent.show(); - $historyContent.hide(); - $bandsContent.hide(); - $socialContent.hide(); - $favoritesContent.hide(); - - $('.profile-nav a.active').removeClass('active'); - $aboutLink.addClass('active'); - } - - function initUser() { - user = null; - decrementedFriendCountOnce = false; - sentFriendRequest = false; - userDefer = rest.getUserProfile({id: userId, show_teacher:true}) - .done(function (response) { - user = response; - configureUserType(); - renderActive(); - renderAllStats(); - }) - .fail(function (jqXHR) { - if (jqXHR.status >= 500) { - context.JK.fetchUserNetworkOrServerFailure(); - } - else if (jqXHR.status == 404) { - context.JK.entityNotFound("User"); - } - else { - app.ajaxError(arguments); - } - }); - } - - function isMusician() { - return user.musician; - } - - function isTeacher() { - return user.teacher; - } - - function isCurrentUser() { - return userId === context.JK.currentUserId; - } - - function configureUserType() { - if (isMusician()) { - $historyLink.show(); - $bandsLink.show(); - $instruments.show(); - $sessionStats.show(); - $recordingStats.show(); - // $followingStats.hide(); - // $favoriteStats.hide(); - $socialLeft.show(); - $typeLabel.text('musician'); - $location.text('Location'); - } else { - $historyLink.hide(); - $bandsLink.hide(); - $instruments.hide(); - $sessionStats.hide(); - $recordingStats.hide(); - // $followingStats.show(); - // $favoriteStats.show(); - $socialLeft.hide(); - $typeLabel.text('fan'); - $location.text('Presence'); - } - - if (isCurrentUser()) { - $profileActions.show() - $btnEdit.show(); - $btnTeacherProfileEdit.show(); - if(isTeacher()) { - $btnTeacherProfileView.show(); - } - else { - $btnTeacherProfileView.hide(); - } - $btnAddFriend.hide(); - $btnFollowUser.hide(); - $btnMessageUser.hide(); - } else { - configureFriendFollowersControls(); - - $profileActions.hide(); - $btnEdit.hide(); - $btnTeacherProfileEdit.hide(); - $btnTeacherProfileView.show(); - $btnAddFriend.show(); - $btnFollowUser.show(); - $btnMessageUser.show(); - } - } - - function configureFriendFollowersControls() { - // wire up Add Friend click - configureFriendButton(); - - // wire up Follow click - configureFollowingButton(); - } - - /****************** MAIN PORTION OF SCREEN *****************/ - // events for main screen - function events() { - // wire up panel clicks -- these need to check deferred because they can't be hidden when in an invalid state - $aboutLink.click(function () { - renderTabDeferred(renderAbout) - }); - - $historyLink.click(function () { - renderTabDeferred(renderHistory) - }); - - $bandsLink.click(function () { - renderTabDeferred(renderBands) - }); - - $socialLink.click(function () { - renderTabDeferred(renderSocial) - }); - - $favoritesLink.click(function () { - renderTabDeferred(renderFavorites) - }); - - // this doesn't need deferred because it's only shown when valid - $btnAddFriend.click(handleFriendChange); - $btnFollowUser.click(handleFollowingChange); - $btnMessageUser.click(handleMessageMusician); - - // Hook up soundcloud player: - $soundCloudSamples.off("click", "a.sound-cloud-playable") .on("click", "a.sound-cloud-playable", playSoundCloudFile) - - $btnEdit.click(function(e) { - e.preventDefault() - window.ProfileActions.startProfileEdit(null, false) - return false; - }) - $btnTeacherProfileEdit.click(function(e) { - e.preventDefault() - window.ProfileActions.startTeacherEdit(null, false) - return false; - }) - $btnTeacherProfileView.click(function(e) { - e.preventDefault() - context.location = '/client#/profile/teacher/' + context.JK.currentUserId; - return false; - }) - $btnEditBio.click(function(e) { - e.preventDefault() - window.ProfileActions.startProfileEdit(null, true) - return false; - }) - $btnAddRecordings.click(function(e) { - e.preventDefault() - window.ProfileActions.startProfileEdit('samples', true) - return false; - }) - $btnAddSites.click(function(e) { - e.preventDefault() - window.ProfileActions.startProfileEdit('samples', true) - return false; - }) - $btnAddInterests.click(function(e) { - e.preventDefault() - window.ProfileActions.startProfileEdit('interests', true) - return false; - }); - $btnAddExperiences.click(function(e) { - e.preventDefault() - window.ProfileActions.startProfileEdit('experience', true) - return false; - }) - } - - function playSoundCloudFile(e) { - e.preventDefault(); - var url = $(this).attr("soundcloud_url") - var cap = $(this).text() - player.initialize(url, cap); - app.layout.showDialog('sound-cloud-player-dialog'); - return false; - } - - function handleFriendChange(evt) { - if (isFriend()) { - removeFriend(evt); - } else { - sendFriendRequest(evt); - } - return false; - } - - function handleFollowingChange(evt) { - if (isFollowing()) { - removeFollowing(false, userId); - } else { - addFollowing(); - } - return false; - } - - function handleMessageMusician(evt) { - app.layout.showDialog('text-message', { d1: userId }); - return false; - } - - function sendFriendRequest(evt) { - evt.stopPropagation(); - setFriend(true); // TODO: you aren't a friend yet. just a request to be one really there are 3 states here. - sentFriendRequest = true; - rest.sendFriendRequest(app, userId, friendRequestCallback); - } - - function removeFriend(evt) { - evt.stopPropagation(); - - rest.removeFriend({friend_id: userId}) - .done(function () { - updateFriendCount(-1); - setFriend(false); - configureFriendButton(); - }) - .fail(app.ajaxError); - } - - function isFriend() { - return user.is_friend; - } - - function setFriend(isFriend) { - user.is_friend = isFriend; - } - - function friendRequestCallback() { - configureFriendButton(); - } - - function configureFriendButton() { - if (isFriend()) { - $btnAddFriend.text('DISCONNECT'); - } else { - $btnAddFriend.text('CONNECT'); - } - } - - function addFollowing() { - - rest.addFollowing({user_id: userId}) - .done(function () { - updateFollowingCount(1); - setFollowing(true); - configureFollowingButton(); - context.JK.GA.trackJKSocial(context.JK.GA.Categories.jkFollow, isMusician() ? context.JK.GA.JKSocialTargets.musician : context.JK.GA.JKSocialTargets.fan); - }) - .fail(app.ajaxError); - } - - function removeFollowing(isBand, id) { - rest.removeFollowing(id) - .done(function () { - if (!isBand) { - updateFollowingCount(-1); - setFollowing(false); - configureFollowingButton(); - } - else { - updateBandFollowingCount(id, -1); // refresh stats - configureBandFollowingButton(false, id); - } - }) - .fail(app.ajaxError); - } - - function isFollowing() { - return user.is_following; - } - - function setFollowing(isFollowing) { - user.is_following = isFollowing; - } - - function configureFollowingButton() { - - if (isFollowing()) { - $btnFollowUser.text('UNFOLLOW'); - } else { - $btnFollowUser.text('FOLLOW'); - } - } - - function configureEditProfileButton() { - $btnFollowUser.click(addFollowing); - } - - // refreshes the currently active tab - function renderActive() { - if ($aboutLink.hasClass('active')) { - renderAbout(); - } - else if ($historyLink.hasClass('active')) { - renderHistory(); - } - else if ($bandsLink.hasClass('active')) { - renderBands(); - } - else if ($socialLink.hasClass('active')) { - renderSocial(); - } - else if ($favoritesLink.hasClass('active')) { - renderFavorites(); - } - } - - function renderTabDeferred(tabRenderer) { - userDefer - .done(function () { - tabRenderer(); - }) - .fail(function () { - // try again - initUser(); - }) - } - - function hideElements(elements) { - $.each(elements, function(index, val) { - val.hide(); - }); - } - - /****************** ABOUT TAB *****************/ - function renderAbout() { - //$instruments.empty(); - - $aboutContent.show(); - $historyContent.hide(); - $bandsContent.hide(); - $socialContent.hide(); - $favoritesContent.hide(); - - $('.profile-nav a.active').removeClass('active'); - $aboutLink.addClass('active'); - } - - function renderAllStats() { - - if (!isCurrentUser()) { - $btnEditBio.hide(); - $btnAddRecordings.hide(); - $btnAddSites.hide(); - $btnAddInterests.hide(); - } - - if (user && $userName) { - renderNameLocationStats(); - renderBio(); - renderMusicalExperience(); - renderPerformanceSamples(); - renderOnlinePresence(); - renderInterests(); - } - } - - function renderNameLocationStats() { - // name - $userName.html(user.name); - - // avatar - $avatar.attr('src', context.JK.resolveAvatarUrl(user.photo_url)); - - // location - $location.html(user.location); - - $age.html(user.age ? user.age + " years old" : ""); + "use strict"; + + context.JK = context.JK || {}; + context.JK.ProfileScreen = function (app) { + var logger = context.JK.logger; + var userId; + var user = null; + var userDefer = null; + var rest = context.JK.Rest(); + var decrementedFriendCountOnce = false; + var sentFriendRequest = false; + var textMessageDialog = null; + var feed = null; + var player = null; + var profileUtils = context.JK.ProfileUtils; + var EVENTS = context.JK.EVENTS; + + var NOT_SPECIFIED_TEXT = 'Not specified'; + + var $screen = $('#user-profile'); + + var $biography = $screen.find('#biography'); + + // musical experience + var $instruments = $screen.find('.instruments-holder'); + var $musicianStatus = $screen.find('#musician-status'); + var $genres = $screen.find('#genres'); + var $concertCount = $screen.find('#concert-count'); + var $studioCount = $screen.find('#studio-count'); + + // performance samples + var $noSamples = $screen.find('.no-samples'); + var $jamkazamSamples = $screen.find('.jamkazam-samples'); + var $soundCloudSamples = $screen.find('.soundcloud-samples'); + var $youTubeSamples = $screen.find('.youtube-samples'); + + // online presence + + var $userWebsite = $screen.find('.user-website'); + var $soundCloudPresence = $screen.find('.soundcloud-presence'); + var $reverbNationPresence = $screen.find('.reverbnation-presence'); + var $bandCampPresence = $screen.find('.bandcamp-presence'); + var $fandalismPresence = $screen.find('.fandalism-presence'); + var $youTubePresence = $screen.find('.youtube-presence'); + var $facebookPresence = $screen.find('.facebook-presence'); + var $twitterPresence = $screen.find('.twitter-presence'); + + // current interests + var $noInterests = $screen.find('#no-interests'); + var $paidGigSection = $screen.find('#paid-gigs'); + var $paidGigDetails = $screen.find('#paid-gig-details'); + + var $freeGigSection = $screen.find('#free-gigs'); + var $freeGigDetails = $screen.find('#free-gig-details'); + + var $cowritingSection = $screen.find('#cowriting'); + var $cowritingDetails = $screen.find('#cowriting-details'); + + var $traditionalBandSection = $screen.find('#traditional-band'); + var $traditionalBandDetails = $screen.find('#traditional-band-details'); + + var $virtualBandSection = $screen.find('#virtual-band'); + var $virtualBandDetails = $screen.find('#virtual-band-details'); + + // tabs + var $aboutLink = $screen.find('#about-link'); + var $aboutContent = $screen.find('#about-content'); + + var $historyLink = $screen.find('#history-link'); + var $historyContent = $screen.find('#history-content'); + + var $bandsLink = $screen.find('#bands-link'); + var $bandsContent = $screen.find('#bands-content'); + + var $socialLink = $screen.find('#social-link'); + var $socialContent = $screen.find('#social-content'); + + var $favoritesLink = $screen.find('#favorites-link'); + var $favoritesContent = $screen.find('#favorites-content'); // stats - var text = user.friend_count > 1 || user.friend_count === 0 ? " Friends" : " Friend"; - $friendStats.html('' + user.friend_count + '' + text); + var $friendStats = $screen.find('#friend-stats'); + var $followerStats = $screen.find('#follower-stats'); + var $sessionStats = $screen.find('#session-stats'); + var $recordingStats = $screen.find('#recording-stats'); + var $followingStats = $screen.find('#following-stats'); + var $favoriteStats = $screen.find('#favorite-stats'); - text = user.follower_count > 1 || user.follower_count === 0 ? " Followers" : " Follower"; - $followerStats.html('' + user.follower_count + '' + text); + // miscellaneous + var $userName = $screen.find('#username'); + var $avatar = $screen.find('#avatar'); + var $typeLabel = $screen.find('#type-label'); + var $location = $screen.find('#location'); + var $age = $screen.find('#age'); - if (isMusician()) { - text = user.session_count > 1 || user.session_count === 0 ? " Sessions" : " Session"; - $sessionStats.html(user.session_count + text); + // buttons + var $profileActions = $screen.find('.profile-actions') + var $btnEdit = $screen.find('.edit-profile-btn'); + var $btnTeacherProfileEdit = $screen.find('.edit-teacher-profile-btn'); + var $btnTeacherProfileView = $screen.find('.view-teacher-profile-btn'); + var $btnAddFriend = $screen.find('#btn-add-friend'); + var $btnFollowUser = $screen.find('#btn-follow-user'); + var $btnMessageUser = $screen.find('#btn-message-user'); + var $btnEditBio = $screen.find(".add-bio"); + var $btnAddRecordings = $screen.find('.add-recordings'); + var $btnAddSites = $screen.find('.add-sites'); + var $btnAddInterests = $screen.find('.add-interests'); + var $btnAddExperiences = $screen.find('.add-experiences') - text = user.recording_count > 1 || user.recording_count === 0 ? " Recordings" : " Recording"; - $recordingStats.html(user.recording_count + text); - } else { - text = " Following"; - $followingStats.html(user.following_count + text); - text = user.favorite_count > 1 || user.favorite_count === 0 ? " Favorites" : " Favorite"; - $favoriteStats.html(user.favorite_count + text); - } - } + // social + var $socialLeft = $screen.find('.profile-social-left'); + var $socialFriends = $screen.find('#social-friends'); + var $socialFollowings = $screen.find('#social-followings'); + var $socialFollowers = $screen.find('#social-followers'); - function renderBio() { - $biography.html(user.biography ? user.biography : NOT_SPECIFIED_TEXT); - if (isCurrentUser()) { - $btnEditBio.show(); - } else { - $btnEditBio.hide(); - } - } + var instrument_logo_map = context.JK.getInstrumentIconMap24(); - function renderMusicalExperience() { - profileUtils.renderMusicalExperience(user, $screen, isCurrentUser()) - } - - function renderPerformanceSamples() { - profileUtils.renderPerformanceSamples(user, $screen, isCurrentUser()) - } - - function renderOnlinePresence() { - profileUtils.renderOnlinePresence(user, $screen, isCurrentUser()) - } - - function renderInterests() { - // current interests - if (isCurrentUser()) { - $btnAddInterests.show(); - } - else { - $btnAddInterests.hide(); + function beforeShow(data) { + userId = data.id; + feed.setUser(userId); } - var noInterests = !user.paid_sessions && !user.free_sessions && !user.cowriting && !user.virtual_band && !user.traditional_band; - if (noInterests) { - $noInterests.show(); - $paidGigSection.hide(); - $freeGigSection.hide(); - $cowritingSection.hide(); - $traditionalBandSection.hide(); - $virtualBandSection.hide(); - } else { - $noInterests.hide(); + function afterShow(data) { + initUser(); + resetForm(); + renderAllStats(); - // paid sessions - if (user.paid_sessions) { - $paidGigSection.show(); + autoShowRatingDialogIfNeeded(); + } - var genreList = profileUtils.paidSessionGenreList(user.genres); - $paidGigDetails.find("ul").html(""); - $paidGigDetails.find("ul").append('
  • Genre(s): ' + (genreList.length > 0 ? genreList : NOT_SPECIFIED_TEXT) + '
  • '); + function autoShowRatingDialogIfNeeded() { - var hourlyRate = user.paid_sessions_hourly_rate; - $paidGigDetails.find("ul").append('
  • Hourly rate = ' + (hourlyRate ? hourlyRate : NOT_SPECIFIED_TEXT) + '
  • '); + if ($.QueryString['selected']) { + var rewrite = true + app.layout.showDialog('rate-user-dialog', {d1: "student_" + userId}).one(EVENTS.DIALOG_CLOSED, function (e, data) { + if (!data.canceled) { - var dailyRate = user.paid_sessions_daily_rate; - $paidGigDetails.find("ul").append('
  • Day rate = ' + (dailyRate ? dailyRate : NOT_SPECIFIED_TEXT) + '
  • '); + } + }) + } + + if (rewrite) { + if (window.history.replaceState) {//ie9 proofing + window.history.replaceState({}, "", "/client#/profile/teacher/#{e.id}") + } + } + } + + function beforeHide(data) { + feed.setUser(null); + } + + function resetForm() { + //$instruments.empty(); + + $aboutContent.show(); + $historyContent.hide(); + $bandsContent.hide(); + $socialContent.hide(); + $favoritesContent.hide(); + + $('.profile-nav a.active').removeClass('active'); + $aboutLink.addClass('active'); + } + + function initUser() { + user = null; + decrementedFriendCountOnce = false; + sentFriendRequest = false; + userDefer = rest.getUserProfile({id: userId, show_teacher: true}) + .done(function (response) { + user = response; + configureUserType(); + renderActive(); + renderAllStats(); + }) + .fail(function (jqXHR) { + if (jqXHR.status >= 500) { + context.JK.fetchUserNetworkOrServerFailure(); + } + else if (jqXHR.status == 404) { + context.JK.entityNotFound("User"); + } + else { + app.ajaxError(arguments); + } + }); + } + + function isMusician() { + return user.musician; + } + + function isTeacher() { + return user.teacher; + } + + function isCurrentUser() { + return userId === context.JK.currentUserId; + } + + function configureUserType() { + if (isMusician()) { + $historyLink.show(); + $bandsLink.show(); + $instruments.show(); + $sessionStats.show(); + $recordingStats.show(); + // $followingStats.hide(); + // $favoriteStats.hide(); + $socialLeft.show(); + $typeLabel.text('musician'); + $location.text('Location'); } else { + $historyLink.hide(); + $bandsLink.hide(); + $instruments.hide(); + $sessionStats.hide(); + $recordingStats.hide(); + // $followingStats.show(); + // $favoriteStats.show(); + $socialLeft.hide(); + $typeLabel.text('fan'); + $location.text('Presence'); + } + + if (isCurrentUser()) { + $profileActions.show() + $btnEdit.show(); + $btnTeacherProfileEdit.show(); + if (isTeacher()) { + $btnTeacherProfileView.show(); + } + else { + $btnTeacherProfileView.hide(); + } + $btnAddFriend.hide(); + $btnFollowUser.hide(); + $btnMessageUser.hide(); + } else { + configureFriendFollowersControls(); + + $profileActions.hide(); + $btnEdit.hide(); + $btnTeacherProfileEdit.hide(); + $btnTeacherProfileView.show(); + $btnAddFriend.show(); + $btnFollowUser.show(); + $btnMessageUser.show(); + } + } + + function configureFriendFollowersControls() { + // wire up Add Friend click + configureFriendButton(); + + // wire up Follow click + configureFollowingButton(); + } + + /****************** MAIN PORTION OF SCREEN *****************/ + // events for main screen + function events() { + // wire up panel clicks -- these need to check deferred because they can't be hidden when in an invalid state + $aboutLink.click(function () { + renderTabDeferred(renderAbout) + }); + + $historyLink.click(function () { + renderTabDeferred(renderHistory) + }); + + $bandsLink.click(function () { + renderTabDeferred(renderBands) + }); + + $socialLink.click(function () { + renderTabDeferred(renderSocial) + }); + + $favoritesLink.click(function () { + renderTabDeferred(renderFavorites) + }); + + // this doesn't need deferred because it's only shown when valid + $btnAddFriend.click(handleFriendChange); + $btnFollowUser.click(handleFollowingChange); + $btnMessageUser.click(handleMessageMusician); + + // Hook up soundcloud player: + $soundCloudSamples.off("click", "a.sound-cloud-playable").on("click", "a.sound-cloud-playable", playSoundCloudFile) + + $btnEdit.click(function (e) { + e.preventDefault() + window.ProfileActions.startProfileEdit(null, false) + return false; + }) + $btnTeacherProfileEdit.click(function (e) { + e.preventDefault() + window.ProfileActions.startTeacherEdit(null, false) + return false; + }) + $btnTeacherProfileView.click(function (e) { + e.preventDefault() + context.location = '/client#/profile/teacher/' + context.JK.currentUserId; + return false; + }) + $btnEditBio.click(function (e) { + e.preventDefault() + window.ProfileActions.startProfileEdit(null, true) + return false; + }) + $btnAddRecordings.click(function (e) { + e.preventDefault() + window.ProfileActions.startProfileEdit('samples', true) + return false; + }) + $btnAddSites.click(function (e) { + e.preventDefault() + window.ProfileActions.startProfileEdit('samples', true) + return false; + }) + $btnAddInterests.click(function (e) { + e.preventDefault() + window.ProfileActions.startProfileEdit('interests', true) + return false; + }); + $btnAddExperiences.click(function (e) { + e.preventDefault() + window.ProfileActions.startProfileEdit('experience', true) + return false; + }) + } + + function playSoundCloudFile(e) { + e.preventDefault(); + var url = $(this).attr("soundcloud_url") + var cap = $(this).text() + player.initialize(url, cap); + app.layout.showDialog('sound-cloud-player-dialog'); + return false; + } + + function handleFriendChange(evt) { + if (isFriend()) { + removeFriend(evt); + } else { + sendFriendRequest(evt); + } + return false; + } + + function handleFollowingChange(evt) { + if (isFollowing()) { + removeFollowing(false, userId); + } else { + addFollowing(); + } + return false; + } + + function handleMessageMusician(evt) { + app.layout.showDialog('text-message', {d1: userId}); + return false; + } + + function sendFriendRequest(evt) { + evt.stopPropagation(); + setFriend(true); // TODO: you aren't a friend yet. just a request to be one really there are 3 states here. + sentFriendRequest = true; + rest.sendFriendRequest(app, userId, friendRequestCallback); + } + + function removeFriend(evt) { + evt.stopPropagation(); + + rest.removeFriend({friend_id: userId}) + .done(function () { + updateFriendCount(-1); + setFriend(false); + configureFriendButton(); + }) + .fail(app.ajaxError); + } + + function isFriend() { + return user.is_friend; + } + + function setFriend(isFriend) { + user.is_friend = isFriend; + } + + function friendRequestCallback() { + configureFriendButton(); + } + + function configureFriendButton() { + if (isFriend()) { + $btnAddFriend.text('DISCONNECT'); + } else { + $btnAddFriend.text('CONNECT'); + } + } + + function addFollowing() { + + rest.addFollowing({user_id: userId}) + .done(function () { + updateFollowingCount(1); + setFollowing(true); + configureFollowingButton(); + context.JK.GA.trackJKSocial(context.JK.GA.Categories.jkFollow, isMusician() ? context.JK.GA.JKSocialTargets.musician : context.JK.GA.JKSocialTargets.fan); + }) + .fail(app.ajaxError); + } + + function removeFollowing(isBand, id) { + rest.removeFollowing(id) + .done(function () { + if (!isBand) { + updateFollowingCount(-1); + setFollowing(false); + configureFollowingButton(); + } + else { + updateBandFollowingCount(id, -1); // refresh stats + configureBandFollowingButton(false, id); + } + }) + .fail(app.ajaxError); + } + + function isFollowing() { + return user.is_following; + } + + function setFollowing(isFollowing) { + user.is_following = isFollowing; + } + + function configureFollowingButton() { + + if (isFollowing()) { + $btnFollowUser.text('UNFOLLOW'); + } else { + $btnFollowUser.text('FOLLOW'); + } + } + + function configureEditProfileButton() { + $btnFollowUser.click(addFollowing); + } + + // refreshes the currently active tab + function renderActive() { + if ($aboutLink.hasClass('active')) { + renderAbout(); + } + else if ($historyLink.hasClass('active')) { + renderHistory(); + } + else if ($bandsLink.hasClass('active')) { + renderBands(); + } + else if ($socialLink.hasClass('active')) { + renderSocial(); + } + else if ($favoritesLink.hasClass('active')) { + renderFavorites(); + } + } + + function renderTabDeferred(tabRenderer) { + userDefer + .done(function () { + tabRenderer(); + }) + .fail(function () { + // try again + initUser(); + }) + } + + function hideElements(elements) { + $.each(elements, function (index, val) { + val.hide(); + }); + } + + /****************** ABOUT TAB *****************/ + function renderAbout() { + //$instruments.empty(); + + $aboutContent.show(); + $historyContent.hide(); + $bandsContent.hide(); + $socialContent.hide(); + $favoritesContent.hide(); + + $('.profile-nav a.active').removeClass('active'); + $aboutLink.addClass('active'); + } + + function renderAllStats() { + + if (!isCurrentUser()) { + $btnEditBio.hide(); + $btnAddRecordings.hide(); + $btnAddSites.hide(); + $btnAddInterests.hide(); + } + + if (user && $userName) { + renderNameLocationStats(); + renderBio(); + renderMusicalExperience(); + renderPerformanceSamples(); + renderOnlinePresence(); + renderInterests(); + } + } + + function renderNameLocationStats() { + // name + $userName.html(user.name); + + // avatar + $avatar.attr('src', context.JK.resolveAvatarUrl(user.photo_url)); + + // location + $location.html(user.location); + + $age.html(user.age ? user.age + " years old" : ""); + + // stats + var text = user.friend_count > 1 || user.friend_count === 0 ? " Friends" : " Friend"; + $friendStats.html('' + user.friend_count + '' + text); + + text = user.follower_count > 1 || user.follower_count === 0 ? " Followers" : " Follower"; + $followerStats.html('' + user.follower_count + '' + text); + + if (isMusician()) { + text = user.session_count > 1 || user.session_count === 0 ? " Sessions" : " Session"; + $sessionStats.html(user.session_count + text); + + text = user.recording_count > 1 || user.recording_count === 0 ? " Recordings" : " Recording"; + $recordingStats.html(user.recording_count + text); + } else { + text = " Following"; + $followingStats.html(user.following_count + text); + text = user.favorite_count > 1 || user.favorite_count === 0 ? " Favorites" : " Favorite"; + $favoriteStats.html(user.favorite_count + text); + } + } + + function renderBio() { + $biography.html(user.biography ? user.biography : NOT_SPECIFIED_TEXT); + if (isCurrentUser()) { + $btnEditBio.show(); + } else { + $btnEditBio.hide(); + } + } + + function renderMusicalExperience() { + profileUtils.renderMusicalExperience(user, $screen, isCurrentUser()) + } + + function renderPerformanceSamples() { + profileUtils.renderPerformanceSamples(user, $screen, isCurrentUser()) + } + + function renderOnlinePresence() { + profileUtils.renderOnlinePresence(user, $screen, isCurrentUser()) + } + + function renderInterests() { + // current interests + if (isCurrentUser()) { + $btnAddInterests.show(); + } + else { + $btnAddInterests.hide(); + } + + var noInterests = !user.paid_sessions && !user.free_sessions && !user.cowriting && !user.virtual_band && !user.traditional_band; + if (noInterests) { + $noInterests.show(); $paidGigSection.hide(); - } - - // free sessions - if (user.free_sessions) { - $freeGigSection.show(); - $freeGigDetails.find("ul").html(""); - var genreList = profileUtils.freeSessionGenreList(user.genres); - $freeGigDetails.find("ul").append('
  • Genre(s): ' + (genreList.length > 0 ? genreList : NOT_SPECIFIED_TEXT) + '
  • '); - } else { $freeGigSection.hide(); - } - - // cowriting - if (user.cowriting) { - $cowritingSection.show(); - $cowritingDetails.find("ul").html(""); - var genreList = profileUtils.cowritingGenreList(user.genres); - $cowritingDetails.find("ul").append('
  • Genre(s): ' + (genreList.length > 0 ? genreList : NOT_SPECIFIED_TEXT) + '
  • '); - - var purpose = user.cowriting_purpose; - $cowritingDetails.find("ul").append('
  • Purpose: ' + (purpose ? profileUtils.cowritingPurposeMap[purpose] : NOT_SPECIFIED_TEXT) + '
  • '); - } else { $cowritingSection.hide(); - } - - // traditional bands - if (user.traditional_band) { - $traditionalBandSection.show(); - $traditionalBandDetails.find("ul").html(""); - var genreList = profileUtils.traditionalBandGenreList(user.genres); - $traditionalBandDetails.find("ul").append('
  • Genre(s): ' + (genreList.length > 0 ? genreList : NOT_SPECIFIED_TEXT) + '
  • '); - - var commitment = user.traditional_band_commitment; - $traditionalBandDetails.find("ul").append('
  • Commitment: ' + (commitment ? profileUtils.bandCommitmentMap[commitment] : NOT_SPECIFIED_TEXT) + '
  • '); - - var canTour = user.traditional_band_touring; - var canTourResponse = canTour ? "Yes" : (canTour === false ? "No" : NOT_SPECIFIED_TEXT); - $traditionalBandDetails.find("ul").append('
  • Touring: ' + canTourResponse + '
  • '); - } else { $traditionalBandSection.hide(); - } - - // virtual band - if (user.virtual_band) { - $virtualBandSection.show(); - $virtualBandDetails.find("ul").html(""); - var genreList = profileUtils.virtualBandGenreList(user.genres); - $virtualBandDetails.find("ul").append('
  • Genre(s): ' + (genreList.length > 0 ? genreList : NOT_SPECIFIED_TEXT) + '
  • '); - - var commitment = user.virtual_band_commitment; - $virtualBandDetails.find("ul").append('
  • Commitment: ' + (commitment ? profileUtils.bandCommitmentMap[commitment] : NOT_SPECIFIED_TEXT) + '
  • '); - } else { $virtualBandSection.hide(); + } else { + $noInterests.hide(); + + // paid sessions + if (user.paid_sessions) { + $paidGigSection.show(); + + var genreList = profileUtils.paidSessionGenreList(user.genres); + $paidGigDetails.find("ul").html(""); + $paidGigDetails.find("ul").append('
  • Genre(s): ' + (genreList.length > 0 ? genreList : NOT_SPECIFIED_TEXT) + '
  • '); + + var hourlyRate = user.paid_sessions_hourly_rate; + $paidGigDetails.find("ul").append('
  • Hourly rate = ' + (hourlyRate ? hourlyRate : NOT_SPECIFIED_TEXT) + '
  • '); + + var dailyRate = user.paid_sessions_daily_rate; + $paidGigDetails.find("ul").append('
  • Day rate = ' + (dailyRate ? dailyRate : NOT_SPECIFIED_TEXT) + '
  • '); + } else { + $paidGigSection.hide(); + } + + // free sessions + if (user.free_sessions) { + $freeGigSection.show(); + $freeGigDetails.find("ul").html(""); + var genreList = profileUtils.freeSessionGenreList(user.genres); + $freeGigDetails.find("ul").append('
  • Genre(s): ' + (genreList.length > 0 ? genreList : NOT_SPECIFIED_TEXT) + '
  • '); + } else { + $freeGigSection.hide(); + } + + // cowriting + if (user.cowriting) { + $cowritingSection.show(); + $cowritingDetails.find("ul").html(""); + var genreList = profileUtils.cowritingGenreList(user.genres); + $cowritingDetails.find("ul").append('
  • Genre(s): ' + (genreList.length > 0 ? genreList : NOT_SPECIFIED_TEXT) + '
  • '); + + var purpose = user.cowriting_purpose; + $cowritingDetails.find("ul").append('
  • Purpose: ' + (purpose ? profileUtils.cowritingPurposeMap[purpose] : NOT_SPECIFIED_TEXT) + '
  • '); + } else { + $cowritingSection.hide(); + } + + // traditional bands + if (user.traditional_band) { + $traditionalBandSection.show(); + $traditionalBandDetails.find("ul").html(""); + var genreList = profileUtils.traditionalBandGenreList(user.genres); + $traditionalBandDetails.find("ul").append('
  • Genre(s): ' + (genreList.length > 0 ? genreList : NOT_SPECIFIED_TEXT) + '
  • '); + + var commitment = user.traditional_band_commitment; + $traditionalBandDetails.find("ul").append('
  • Commitment: ' + (commitment ? profileUtils.bandCommitmentMap[commitment] : NOT_SPECIFIED_TEXT) + '
  • '); + + var canTour = user.traditional_band_touring; + var canTourResponse = canTour ? "Yes" : (canTour === false ? "No" : NOT_SPECIFIED_TEXT); + $traditionalBandDetails.find("ul").append('
  • Touring: ' + canTourResponse + '
  • '); + } else { + $traditionalBandSection.hide(); + } + + // virtual band + if (user.virtual_band) { + $virtualBandSection.show(); + $virtualBandDetails.find("ul").html(""); + var genreList = profileUtils.virtualBandGenreList(user.genres); + $virtualBandDetails.find("ul").append('
  • Genre(s): ' + (genreList.length > 0 ? genreList : NOT_SPECIFIED_TEXT) + '
  • '); + + var commitment = user.virtual_band_commitment; + $virtualBandDetails.find("ul").append('
  • Commitment: ' + (commitment ? profileUtils.bandCommitmentMap[commitment] : NOT_SPECIFIED_TEXT) + '
  • '); + } else { + $virtualBandSection.hide(); + } } } - } - /****************** SOCIAL TAB *****************/ - function renderSocial() { - $socialFriends.empty(); - $socialFollowings.empty(); - $socialFollowers.empty(); + /****************** SOCIAL TAB *****************/ + function renderSocial() { + $socialFriends.empty(); + $socialFollowings.empty(); + $socialFollowers.empty(); - $aboutContent.hide(); - $historyContent.hide(); - $bandsContent.hide(); - $socialContent.show(); - $favoritesContent.hide(); + $aboutContent.hide(); + $historyContent.hide(); + $bandsContent.hide(); + $socialContent.show(); + $favoritesContent.hide(); - $('.profile-nav a.active').removeClass('active'); - $socialLink.addClass('active'); + $('.profile-nav a.active').removeClass('active'); + $socialLink.addClass('active'); - bindSocial(); - } + bindSocial(); + } - function bindSocial() { - if (isMusician()) { - // FRIENDS - rest.getFriends({id: userId}) + function bindSocial() { + if (isMusician()) { + // FRIENDS + rest.getFriends({id: userId}) + .done(function (response) { + if (response && response.length > 0) { + $.each(response, function (index, val) { + var template = $('#template-profile-social').html(); + var friendHtml = context.JK.fillTemplate(template, { + userId: val.id, + hoverAttributeId: "user-id", + hoverAction: val.musician ? "musician" : "fan", + avatar_url: context.JK.resolveAvatarUrl(val.photo_url), + userName: val.name, + location: val.location, + type: "Friends" + }); + + $socialFriends.append(friendHtml); + }); + } + else { + $socialFriends.html(' '); + } + context.JK.bindHoverEvents(); + }) + .fail(app.ajaxError) + } + + rest.getFollowings({id: userId}) .done(function (response) { if (response && response.length > 0) { $.each(response, function (index, val) { var template = $('#template-profile-social').html(); - var friendHtml = context.JK.fillTemplate(template, { + var followingHtml = context.JK.fillTemplate(template, { userId: val.id, - hoverAttributeId: "user-id", - hoverAction: val.musician ? "musician" : "fan", + hoverAttributeId: val.type === "user" ? "user-id" : "band-id", + hoverAction: val.type === "user" ? (val.musician ? "musician" : "fan") : "band", avatar_url: context.JK.resolveAvatarUrl(val.photo_url), userName: val.name, - location: val.location, - type: "Friends" + location: val.location }); - $socialFriends.append(friendHtml); + $socialFollowings.append(followingHtml); }); } else { - $socialFriends.html(' '); + $socialFollowings.html(' '); } context.JK.bindHoverEvents(); }) - .fail(app.ajaxError) - } + .fail(app.ajaxError); - rest.getFollowings({id: userId}) - .done(function (response) { - if (response && response.length > 0) { + rest.getFollowers({id: userId}) + .done(function (response) { $.each(response, function (index, val) { var template = $('#template-profile-social').html(); - var followingHtml = context.JK.fillTemplate(template, { + var followerHtml = context.JK.fillTemplate(template, { userId: val.id, - hoverAttributeId: val.type === "user" ? "user-id" : "band-id", - hoverAction: val.type === "user" ? (val.musician ? "musician" : "fan") : "band", + hoverAttributeId: "user-id", + hoverAction: val.musician ? "musician" : "fan", avatar_url: context.JK.resolveAvatarUrl(val.photo_url), userName: val.name, location: val.location }); - $socialFollowings.append(followingHtml); + $socialFollowers.append(followerHtml); }); - } - else { - $socialFollowings.html(' '); - } - context.JK.bindHoverEvents(); - }) - .fail(app.ajaxError); - - rest.getFollowers({id: userId}) - .done(function (response) { - $.each(response, function (index, val) { - var template = $('#template-profile-social').html(); - var followerHtml = context.JK.fillTemplate(template, { - userId: val.id, - hoverAttributeId: "user-id", - hoverAction: val.musician ? "musician" : "fan", - avatar_url: context.JK.resolveAvatarUrl(val.photo_url), - userName: val.name, - location: val.location - }); - - $socialFollowers.append(followerHtml); - }); - context.JK.bindHoverEvents(); - }) - .fail(app.ajaxError); - } - - /****************** HISTORY TAB *****************/ - function renderHistory() { - $aboutContent.hide(); - $historyContent.show(); - $bandsContent.hide(); - $socialContent.hide(); - $favoritesContent.hide(); - - $('.profile-nav a.active').removeClass('active'); - $historyLink.addClass('active'); - - bindHistory(); - } - - function bindHistory() { - feed.refresh(); - } - - /****************** BANDS TAB *****************/ - function renderBands() { - $bandsContent.empty(); - - $aboutContent.hide(); - $historyContent.hide(); - $bandsContent.show(); - $socialContent.hide(); - $favoritesContent.hide(); - - $('.profile-nav a.active').removeClass('active'); - $bandsLink.addClass('active'); - - bindBands(); - } - - function bindBands() { - - rest.getBands({id: userId}) - .done(function (response) { - if ((!response || response.length === 0) && isCurrentUser()) { - var noBandHtml = $('#template-no-bands').html(); - $bandsContent.html(noBandHtml); - } - else { - addMoreBandsLink(); - - $.each(response, function (index, val) { - var isBandMember = false; - - // build band member HTML - var musicianHtml = ''; - if (val.musicians) { - for (var i = 0; i < val.musicians.length; i++) { - var musician = val.musicians[i]; - var instrumentLogoHtml = ''; - if (musician.instruments) { - for (var j = 0; j < musician.instruments.length; j++) { - var instrument = musician.instruments[j]; - var inst = '/assets/content/icon_instrument_default24.png'; - var toolTip = ''; - if (instrument.instrument_id in instrument_logo_map) { - inst = instrument_logo_map[instrument.instrument_id].asset; - toolTip = instrument.instrument_id; - } - instrumentLogoHtml += ' '; - } - } - if (!isBandMember) - isBandMember = musician.id === context.JK.currentUserId; - - // this template is in _findSession.html.erb - var musicianTemplate = $('#template-musician-info').html(); - musicianHtml += context.JK.fillTemplate(musicianTemplate, { - userId: musician.id, - avatar_url: context.JK.resolveAvatarUrl(musician.photo_url), - profile_url: "/client#/profile/" + musician.id, - musician_name: musician.name, - instruments: instrumentLogoHtml, - more_link: '' - }); - } - } - var template = $('#template-profile-bands').html(); - var bandHtml = context.JK.fillTemplate(template, { - bandId: val.id, - biography: val.biography, - profile_url: "/client#/bandProfile/" + val.id, - band_edit_url: "/client#/band/setup/" + val.id + '/step0', - band_member_url: "/client#/band/setup/" + val.id + '/step4', - avatar_url: context.JK.resolveBandAvatarUrl(val.photo_url), - name: val.name, - location: val.location, - genres: formatGenres(val.genres), - follower_count: val.follower_count, - recording_count: val.recording_count, - session_count: val.session_count, - musicians: musicianHtml - }); - - $bandsContent.append(bandHtml); - - $('.profile-band-link-member-true').each(function(idx) { - isBandMember ? $(this).show() : $(this).hide(); - }); - $('.profile-band-link-member-false').each(function(idx) { - isBandMember ? $(this).hide() : $(this).show(); - }); - - // wire up Band Follow button click handler - configureBandFollowingButton(val.is_following, val.id); - }); - - if (response.length >= 3) { - addMoreBandsLink(); - } - } - context.JK.bindHoverEvents(); - }) - .fail(app.ajaxError); - } - - function addMoreBandsLink() { - if (isCurrentUser()) { - var moreBandsHtml = $('#template-more-bands').html(); - $bandsContent.append(moreBandsHtml); + context.JK.bindHoverEvents(); + }) + .fail(app.ajaxError); } - } - function formatGenres(genres) { - var formattedGenres = ''; - if (genres) { - for (var i = 0; i < genres.length; i++) { - var genre = genres[i]; - formattedGenres += genre.description; - if (i < genres.length - 1) { - formattedGenres += ', '; - } + /****************** HISTORY TAB *****************/ + function renderHistory() { + $aboutContent.hide(); + $historyContent.show(); + $bandsContent.hide(); + $socialContent.hide(); + $favoritesContent.hide(); + + $('.profile-nav a.active').removeClass('active'); + $historyLink.addClass('active'); + + bindHistory(); + } + + function bindHistory() { + feed.refresh(); + } + + /****************** BANDS TAB *****************/ + function renderBands() { + $bandsContent.empty(); + + $aboutContent.hide(); + $historyContent.hide(); + $bandsContent.show(); + $socialContent.hide(); + $favoritesContent.hide(); + + $('.profile-nav a.active').removeClass('active'); + $bandsLink.addClass('active'); + + bindBands(); + } + + function bindBands() { + + rest.getBands({id: userId}) + .done(function (response) { + if ((!response || response.length === 0) && isCurrentUser()) { + var noBandHtml = $('#template-no-bands').html(); + $bandsContent.html(noBandHtml); + } + else { + addMoreBandsLink(); + + $.each(response, function (index, val) { + var isBandMember = false; + + // build band member HTML + var musicianHtml = ''; + if (val.musicians) { + for (var i = 0; i < val.musicians.length; i++) { + var musician = val.musicians[i]; + var instrumentLogoHtml = ''; + if (musician.instruments) { + for (var j = 0; j < musician.instruments.length; j++) { + var instrument = musician.instruments[j]; + var inst = '/assets/content/icon_instrument_default24.png'; + var toolTip = ''; + if (instrument.instrument_id in instrument_logo_map) { + inst = instrument_logo_map[instrument.instrument_id].asset; + toolTip = instrument.instrument_id; + } + instrumentLogoHtml += ' '; + } + } + if (!isBandMember) + isBandMember = musician.id === context.JK.currentUserId; + + // this template is in _findSession.html.erb + var musicianTemplate = $('#template-musician-info').html(); + musicianHtml += context.JK.fillTemplate(musicianTemplate, { + userId: musician.id, + avatar_url: context.JK.resolveAvatarUrl(musician.photo_url), + profile_url: "/client#/profile/" + musician.id, + musician_name: musician.name, + instruments: instrumentLogoHtml, + more_link: '' + }); + } + } + var template = $('#template-profile-bands').html(); + var bandHtml = context.JK.fillTemplate(template, { + bandId: val.id, + biography: val.biography, + profile_url: "/client#/bandProfile/" + val.id, + band_edit_url: "/client#/band/setup/" + val.id + '/step0', + band_member_url: "/client#/band/setup/" + val.id + '/step4', + avatar_url: context.JK.resolveBandAvatarUrl(val.photo_url), + name: val.name, + location: val.location, + genres: formatGenres(val.genres), + follower_count: val.follower_count, + recording_count: val.recording_count, + session_count: val.session_count, + musicians: musicianHtml + }); + + $bandsContent.append(bandHtml); + + $('.profile-band-link-member-true').each(function (idx) { + isBandMember ? $(this).show() : $(this).hide(); + }); + $('.profile-band-link-member-false').each(function (idx) { + isBandMember ? $(this).hide() : $(this).show(); + }); + + // wire up Band Follow button click handler + configureBandFollowingButton(val.is_following, val.id); + }); + + if (response.length >= 3) { + addMoreBandsLink(); + } + } + context.JK.bindHoverEvents(); + }) + .fail(app.ajaxError); + } + + function addMoreBandsLink() { + if (isCurrentUser()) { + var moreBandsHtml = $('#template-more-bands').html(); + $bandsContent.append(moreBandsHtml); } } - return formattedGenres; - } - function updateFriendCount(value) { - if (!decrementedFriendCountOnce && !sentFriendRequest) { - decrementedFriendCountOnce = true; - var friendCount = $('#profile-friend-stats span.friend-count'); - friendCount.text(value + parseInt(friendCount.text())); + function formatGenres(genres) { + var formattedGenres = ''; + if (genres) { + for (var i = 0; i < genres.length; i++) { + var genre = genres[i]; + formattedGenres += genre.description; + if (i < genres.length - 1) { + formattedGenres += ', '; + } + } + } + return formattedGenres; } - } - function updateFollowingCount(value) { - var $followingCount = $('#follower-stats span.follower-count'); - $followingCount.text(value + parseInt($followingCount.text())); - } - - function updateBandFollowingCount(bandId, value) { - var $bandFollowing = $('div[band-id="' + bandId + '"].profile-bands span.follower-count'); - $bandFollowing.text(value + parseInt($bandFollowing.text())); - } - - function addBandFollowing(evt) { - evt.stopPropagation(); - var bandId = $(this).parent().parent().parent().parent().attr('band-id'); - - var newFollowing = {}; - newFollowing.band_id = bandId; - - rest.addFollowing(newFollowing) - .done(function (response) { - updateBandFollowingCount(bandId, 1); // increase counter - configureBandFollowingButton(true, bandId); - context.JK.GA.trackJKSocial(context.JK.GA.Categories.jkFollow, context.JK.GA.JKSocialTargets.band); - }) - .fail(app.ajaxError); - } - - function configureBandFollowingButton(following, bandId) { - var $btnFollowBand = $('div[band-id=' + bandId + ']', '#bands-content').find('#btn-follow-band'); - $btnFollowBand.unbind("click"); - - if (following) { - $btnFollowBand.text('UNFOLLOW'); - $btnFollowBand.click(function (evt) { - removeFollowing(true, bandId); - evt.stopPropagation(); - return false; - }); - } else { - $btnFollowBand.text('FOLLOW'); - $btnFollowBand.click(addBandFollowing); + function updateFriendCount(value) { + if (!decrementedFriendCountOnce && !sentFriendRequest) { + decrementedFriendCountOnce = true; + var friendCount = $('#profile-friend-stats span.friend-count'); + friendCount.text(value + parseInt(friendCount.text())); + } } - } - /****************** FAVORITES TAB *****************/ - function renderFavorites() { - $aboutContent.hide(); - $historyContent.hide(); - $bandsContent.hide(); - $socialContent.hide(); - $favoritesContent.show(); + function updateFollowingCount(value) { + var $followingCount = $('#follower-stats span.follower-count'); + $followingCount.text(value + parseInt($followingCount.text())); + } - $('.profile-nav a.active').removeClass('active'); - $favoritesLink.addClass('active'); + function updateBandFollowingCount(bandId, value) { + var $bandFollowing = $('div[band-id="' + bandId + '"].profile-bands span.follower-count'); + $bandFollowing.text(value + parseInt($bandFollowing.text())); + } - bindFavorites(); - } + function addBandFollowing(evt) { + evt.stopPropagation(); + var bandId = $(this).parent().parent().parent().parent().attr('band-id'); + + var newFollowing = {}; + newFollowing.band_id = bandId; + + rest.addFollowing(newFollowing) + .done(function (response) { + updateBandFollowingCount(bandId, 1); // increase counter + configureBandFollowingButton(true, bandId); + context.JK.GA.trackJKSocial(context.JK.GA.Categories.jkFollow, context.JK.GA.JKSocialTargets.band); + }) + .fail(app.ajaxError); + } + + function configureBandFollowingButton(following, bandId) { + var $btnFollowBand = $('div[band-id=' + bandId + ']', '#bands-content').find('#btn-follow-band'); + $btnFollowBand.unbind("click"); + + if (following) { + $btnFollowBand.text('UNFOLLOW'); + $btnFollowBand.click(function (evt) { + removeFollowing(true, bandId); + evt.stopPropagation(); + return false; + }); + } else { + $btnFollowBand.text('FOLLOW'); + $btnFollowBand.click(addBandFollowing); + } + } + + /****************** FAVORITES TAB *****************/ + function renderFavorites() { + $aboutContent.hide(); + $historyContent.hide(); + $bandsContent.hide(); + $socialContent.hide(); + $favoritesContent.show(); + + $('.profile-nav a.active').removeClass('active'); + $favoritesLink.addClass('active'); + + bindFavorites(); + } - function bindFavorites() { - } + function bindFavorites() { + } - function initializeFeed() { + function initializeFeed() { - var $scroller = $screen.find('.content-body-scroller#user-profile-feed-scroller'); - var $content = $screen.find('.feed-content#user-profile-feed-entry-list'); - var $noMoreFeeds = $screen.find('#user-profile-end-of-feeds-list'); - var $refresh = $screen.find('.btn-refresh-entries'); - var $sortFeedBy = $screen.find('#feed_order_by'); - var $includeDate = $screen.find('#feed_date'); - var $includeType = $screen.find('#feed_show'); + var $scroller = $screen.find('.content-body-scroller#user-profile-feed-scroller'); + var $content = $screen.find('.feed-content#user-profile-feed-entry-list'); + var $noMoreFeeds = $screen.find('#user-profile-end-of-feeds-list'); + var $refresh = $screen.find('.btn-refresh-entries'); + var $sortFeedBy = $screen.find('#feed_order_by'); + var $includeDate = $screen.find('#feed_date'); + var $includeType = $screen.find('#feed_show'); - feed = new context.JK.Feed(app); - feed.initialize($screen, $scroller, $content, $noMoreFeeds, $refresh, $sortFeedBy, $includeDate, $includeType, {time_range: 'all'}); - } + feed = new context.JK.Feed(app); + feed.initialize($screen, $scroller, $content, $noMoreFeeds, $refresh, $sortFeedBy, $includeDate, $includeType, {time_range: 'all'}); + } - function initialize(textMessageDialogInstance) { - textMessageDialog = textMessageDialogInstance; - var screenBindings = { - 'beforeShow': beforeShow, - 'afterShow': afterShow, - 'beforeHide' : beforeHide - }; - app.bindScreen('profile', screenBindings); - events(); - initializeFeed(); - player = new context.JK.SoundCloudPlayerDialog(app); - } + function initialize(textMessageDialogInstance) { + textMessageDialog = textMessageDialogInstance; + var screenBindings = { + 'beforeShow': beforeShow, + 'afterShow': afterShow, + 'beforeHide': beforeHide + }; + app.bindScreen('profile', screenBindings); + events(); + initializeFeed(); + player = new context.JK.SoundCloudPlayerDialog(app); + } - this.initialize = initialize; - this.beforeShow = beforeShow; - this.afterShow = afterShow; - return this; - }; + this.initialize = initialize; + this.beforeShow = beforeShow; + this.afterShow = afterShow; + return this; + }; -})(window, jQuery); \ No newline at end of file + }) +(window, jQuery); \ No newline at end of file diff --git a/web/app/assets/javascripts/react-components/AccountPaymentHistoryScreen.js.jsx.coffee b/web/app/assets/javascripts/react-components/AccountPaymentHistoryScreen.js.jsx.coffee index 13a6d8178..5bc85d3f4 100644 --- a/web/app/assets/javascripts/react-components/AccountPaymentHistoryScreen.js.jsx.coffee +++ b/web/app/assets/javascripts/react-components/AccountPaymentHistoryScreen.js.jsx.coffee @@ -49,7 +49,6 @@ profileUtils = context.JK.ProfileUtils @root = $(@getDOMNode()) @endOfList = @root.find('.end-of-payments-list') @contentBodyScroller = @root - @root = $(@getDOMNode()) @iCheckify() componentDidUpdate: (prevProps, prevState) -> diff --git a/web/app/assets/javascripts/react-components/RateUserDialog.js.jsx.coffee b/web/app/assets/javascripts/react-components/RateUserDialog.js.jsx.coffee index 889210ed4..79a3f895a 100644 --- a/web/app/assets/javascripts/react-components/RateUserDialog.js.jsx.coffee +++ b/web/app/assets/javascripts/react-components/RateUserDialog.js.jsx.coffee @@ -2,10 +2,19 @@ context = window @RateUserDialog = React.createClass({ - mixins: [Reflux.listenTo(@AppStore, "onAppInit")] + mixins: [ICheckMixin, + Reflux.listenTo(@AppStore, "onAppInit")] teacher: false - parseId:(id) -> + getInitialState: () -> + { + id: null, + type: null, + student: null, + teacher: null, + rating: null, + } + parseId: (id) -> if !id? {id: null, type: null} else @@ -17,17 +26,25 @@ context = window beforeShow: (args) -> logger.debug("RateUserDialog.beforeShow", args.d1) - @firstName = '' - @lastName = '' - @email = '' + parsed = @parseId(args.d1) - @setState({target: null}) + @setState({student: null, teacher: null, type: parsed.type, id: parsed.id, rating: null}) + + rest.getUserDetail({id: parsed.id}).done((response) => @userLookupDone(response)).fail((jqXHR) => @userLookupFail(jqXHR)) - rest.getUserDetail({id: args.d1}).done((response) => @userLookupDone(response)).fail((jqXHR) => @userLookupFail(jqXHR)) afterHide: () -> + isRatingTeacher: () -> + !@isRatingStudent() + + isRatingStudent: () -> + @state.type == 'student' + userLookupDone: (response) -> - @setState({target: response}) + if @isRatingTeacher() + @setState({teacher: response}) + else + @setState({student: response}) userLookupFail: (jqXHR) -> @app.ajaxError(jqXHR, null, null) @@ -38,50 +55,121 @@ context = window 'afterHide': @afterHide }; - @app.bindDialog('rate-user', dialogBindings); + @app.bindDialog('rate-user-dialog', dialogBindings); + checkboxChanged: (e) -> + $target = $(e.target) + @setState({rating: $target.val()}) componentDidMount: () -> + @checkboxes = [{selector: 'input[name="rating"]', stateKey: 'rating'}] + @root = $(@getDOMNode()) - getInitialState: () -> - {inviteErrors: null} + @iCheckify() + + componentDidUpdate: () -> + @iCheckify() + + descriptionChanged: (e) -> + @setState({description: $(e.target).val()}) doCancel: (e) -> e.preventDefault() - @app.layout.closeDialog('rate-user', true); + @app.layout.cancelDialog('rate-user-dialog'); doRating: (e) -> e.preventDefault() - rest.createReview({id: target}) + if @disabled() + return - createDone:(response) -> - context.SchoolActions.addInvitation(@state.teacher, response) - context.JK.Banner.showNotice("invitation sent", "Your invitation has been sent!") - @app.layout.closeDialog('invite-school-user') + if @isRatingTeacher() + data = + { + target_id: @state.id + target_type: 'JamRuby::Teacher' + } + else + data = + { + target_id: @state.id, + target_type: 'JamRuby::User', + } - createFail: (jqXHR) -> + data.rating = @state.rating + data.description = @state.description + rest.createReview(data).done((response) => @createReviewDone(response)).fail((jqXHR) => @createReviewFail(jqXHR)) + createReviewDone: (response) -> + if @isRatingTeacher() + context.JK.Banner.showNotice("teacher rated", "Thank you for taking the time to provide your feedback.") + else + context.JK.Banner.showNotice("student rated", "Thank you for taking the time to provide your feedback.") + + @app.layout.closeDialog('rate-user-dialog') + + createReviewFail: (jqXHR) -> handled = false if jqXHR.status == 422 - errors = JSON.parse(jqXHR.responseText) - @setState({inviteErrors: errors}) - handled = true + response = JSON.parse(jqXHR.responseText) + if response.errors.target? + @app.layout.notify({title: "not allowed", text: "you can not rate someone until you have had a lesson with them"}) + handled = true if !handled @app.ajaxError(jqXHR, null, null) - render: () -> + disabled: () -> + !@state.rating? || (!@state.teacher? && !@state.student?) - if @state.user?.teacher? + render: () -> + submitClasses = classNames({'button-orange': true, disabled: @disabled()}) + if @isRatingTeacher() title = 'Rate Teacher' - help = `

    Please rate this teacher based on your experience with them.

    ` + help = `

    Please rate this teacher based on your experience with them:

    ` + descriptionPrompt = `

    Please help other students by explaining what you like or don’t like about this teacher:

    ` + choices = + `
    +
    + +
    +
    + +
    +
    + +
    +
    + +
    +
    + +
    +
    ` else title = 'Rate Student' - help = `

    Please rate this student based on your experience with them.

    ` - + help = `

    Please rate this student based on your experience with them:

    ` + descriptionPrompt = `

    Please help other teachers by explaining what you like or don’t like about this student:

    ` + choices = + `
    +
    + +
    +
    + +
    +
    + +
    +
    + +
    +
    + +
    +
    ` `
    @@ -93,9 +181,17 @@ context = window {help} + {choices} + +
    + {descriptionPrompt} + +
    +
    CANCEL - SUBMIT RATING + SUBMIT RATING
    ` diff --git a/web/app/assets/javascripts/react-components/SessionLeaveBtn.js.jsx.coffee b/web/app/assets/javascripts/react-components/SessionLeaveBtn.js.jsx.coffee index a11467e65..6286a0bbf 100644 --- a/web/app/assets/javascripts/react-components/SessionLeaveBtn.js.jsx.coffee +++ b/web/app/assets/javascripts/react-components/SessionLeaveBtn.js.jsx.coffee @@ -4,16 +4,9 @@ context = window onLeave: (e) -> e.preventDefault() - @rateSession() SessionActions.leaveSession.trigger({location: '/client#/home'}) - rateSession: () -> - unless @rateSessionDialog? - @rateSessionDialog = new context.JK.RateSessionDialog(context.JK.app); - @rateSessionDialog.initialize(); - - @rateSessionDialog.showDialog(); render: () -> ` diff --git a/web/app/assets/javascripts/react-components/TeacherProfile.js.jsx.coffee b/web/app/assets/javascripts/react-components/TeacherProfile.js.jsx.coffee index bed688d7b..25ac26c0d 100644 --- a/web/app/assets/javascripts/react-components/TeacherProfile.js.jsx.coffee +++ b/web/app/assets/javascripts/react-components/TeacherProfile.js.jsx.coffee @@ -1,6 +1,7 @@ context = window rest = context.JK.Rest() logger = context.JK.logger +EVENTS = context.JK.EVENTS; SubjectStore = context.SubjectStore InstrumentStore = context.InstrumentStore @@ -117,8 +118,20 @@ proficiencyDescriptionMap = { @visible = true logger.debug("TeacherProfile: afterShow") @setState({userId: e.id, user: null}) + @updateProfileInfo(e.id) + + if $.QueryString['tile']? + rewrite = true + @setState({selected: $.QueryString['tile']}) + + if rewrite + if window.history.replaceState #ie9 proofing + window.history.replaceState({}, "", "/client#/profile/teacher/#{e.id}") + + + updateProfileInfo: (id) -> rest.getUserDetail({ - id: e.id, + id: id, show_teacher: true, show_profile: true }).done((response) => @userDetailDone(response)).fail(@app.ajaxError) @@ -549,6 +562,12 @@ proficiencyDescriptionMap = { {this.musicSamples(user, teacher)} ` + rateTeacher: (e) -> + @app.layout.showDialog('rate-user-dialog', {d1: "teacher_#{@state.user.id}"}).one(EVENTS.DIALOG_CLOSED, (e, data) => + if !data.canceled + @updateProfileInfo(@state.userId) + ) + ratings: () -> user = @state.user teacher = user.teacher @@ -581,7 +600,8 @@ proficiencyDescriptionMap = { `

    Ratings & Reviews

    -

    {user.first_name} Summary Rating:
    ({reviewCount})

    +

    {user.first_name} Summary Rating:
    ({reviewCount})
    RATE TEACHER

    + {reviews}
    ` 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 2964025de..0bf3cda13 100644 --- a/web/app/assets/javascripts/react-components/mixins/ICheckMixin.js.coffee +++ b/web/app/assets/javascripts/react-components/mixins/ICheckMixin.js.coffee @@ -21,11 +21,15 @@ teacherActions = window.JK.Actions.Teacher $candidate = @root.find(selector) + @iCheckIgnore = true if $candidate.attr('type') == 'radio' - $found = @root.find(selector + '[value="' + choice + '"]') - $found.iCheck('check').attr('checked', true) + if choice? + $found = @root.find(selector + '[value="' + choice + '"]') + $found.iCheck('check').attr('checked', true) + else + $candidate.iCheck('uncheck').attr('checked', false) else if choice $candidate.iCheck('check').attr('checked', true); @@ -54,5 +58,5 @@ teacherActions = window.JK.Actions.Teacher if @checkboxChanged? @checkboxChanged(e) else - logger.warn("no checkbox changed implemented") + logger.error("no checkbox changed defined") } \ No newline at end of file diff --git a/web/app/assets/javascripts/react-components/stores/SessionStore.js.coffee b/web/app/assets/javascripts/react-components/stores/SessionStore.js.coffee index def7bfe56..0d00065b1 100644 --- a/web/app/assets/javascripts/react-components/stores/SessionStore.js.coffee +++ b/web/app/assets/javascripts/react-components/stores/SessionStore.js.coffee @@ -1072,6 +1072,19 @@ ConfigureTracksActions = @ConfigureTracksActions @sessionUtils.SessionPageLeave() + if @currentSession?.lesson_session? + if context.JK.currentUserId == @currentSession.lesson_session.teacher_id + @app.layout.showDialog('rate-user-dialog', {d1: 'student_' + @currentSession.lesson_session.student_id}) + else + @app.layout.showDialog('rate-user-dialog', {d1: 'teacher_' + @currentSession.lesson_session.student_id}) + + else + unless @rateSessionDialog? + @rateSessionDialog = new context.JK.RateSessionDialog(context.JK.app); + @rateSessionDialog.initialize(); + + @rateSessionDialog.showDialog(); + leaveSession: () -> if !@joinDeferred? || @joinDeferred?.state() == 'resolved' diff --git a/web/app/assets/stylesheets/client/react-components/TeacherProfile.css.scss b/web/app/assets/stylesheets/client/react-components/TeacherProfile.css.scss index 66c256f58..2f0412533 100644 --- a/web/app/assets/stylesheets/client/react-components/TeacherProfile.css.scss +++ b/web/app/assets/stylesheets/client/react-components/TeacherProfile.css.scss @@ -225,6 +225,12 @@ color:$ColorTextTypical; } + .rate-teacher-btn { + margin-left: 36px; + top: -2px; + position: relative; + } + .review { border-width:1px 0 0 0; border-color:$ColorTextTypical; diff --git a/web/app/assets/stylesheets/dialogs/rateUserDialog.css.scss b/web/app/assets/stylesheets/dialogs/rateUserDialog.css.scss new file mode 100644 index 000000000..2d3a6606c --- /dev/null +++ b/web/app/assets/stylesheets/dialogs/rateUserDialog.css.scss @@ -0,0 +1,52 @@ +@import "client/common"; + +#rate-user-dialog { + width: 600px; + max-height:600px; + + h2 { + color:white; + margin-bottom:10px; + font-size:16px; + } + .dialog-inner { + width: auto; + height:calc(100% - 29px) + } + + .field { + margin-bottom:10px; + } + + input { + display:inline-block; + } + label { + display:inline-block; + } + .iradio_minimal { + display:inline-block; + margin-right: 5px; + top: 4px; + } + + textarea { + width:100%; + height:80px; + margin:0; + } + + div[data-react-class="RateUserDialog"] { + + } + .field.description { + margin-bottom:20px; + h2 { + margin-top: 20px; + } + } + .actions { + float:right; + margin:0 -13px 30px 0; + } +} \ No newline at end of file diff --git a/web/app/controllers/api_reviews_controller.rb b/web/app/controllers/api_reviews_controller.rb index dcdd8d3b0..99480b9c0 100644 --- a/web/app/controllers/api_reviews_controller.rb +++ b/web/app/controllers/api_reviews_controller.rb @@ -15,7 +15,21 @@ class ApiReviewsController < ApiController # Create a review: def create - @review = Review.create(params) + target = User.find(params['target_id']) + if params[:target_type] == 'JamRuby::Teacher' + target = target.teacher + end + + params[:target] = target + params[:user] = current_user + + @review = Review.create_or_update(params) + + puts "@review.errors #{@review.errors.inspect}" + if @review.errors.any? + respond_with_model(@review) + return + end end # List reviews matching targets for given review summary: diff --git a/web/app/views/dialogs/_dialogs.html.haml b/web/app/views/dialogs/_dialogs.html.haml index ae4d9e5fb..4c0ed3f1d 100644 --- a/web/app/views/dialogs/_dialogs.html.haml +++ b/web/app/views/dialogs/_dialogs.html.haml @@ -53,3 +53,4 @@ = render 'dialogs/chatDialog' = render 'dialogs/cancelLessonDialog' = render 'dialogs/rescheduleLessonDialog' += render 'dialogs/rateUserDialog' diff --git a/web/app/views/dialogs/_rateUserDialog.html.slim b/web/app/views/dialogs/_rateUserDialog.html.slim new file mode 100644 index 000000000..111c3916d --- /dev/null +++ b/web/app/views/dialogs/_rateUserDialog.html.slim @@ -0,0 +1,2 @@ +.dialog.dialog-overlay-sm.top-parent layout='dialog' layout-id='rate-user-dialog' id='rate-user-dialog' + = react_component 'RateUserDialog', {} diff --git a/web/config/environments/development.rb b/web/config/environments/development.rb index f8042d0ce..0113ea09a 100644 --- a/web/config/environments/development.rb +++ b/web/config/environments/development.rb @@ -107,4 +107,5 @@ SampleApp::Application.configure do config.vst_enabled = true config.verify_email_enabled = true + config.jamclass_enabled = true end diff --git a/web/config/environments/test.rb b/web/config/environments/test.rb index e0ad3315c..00e39413b 100644 --- a/web/config/environments/test.rb +++ b/web/config/environments/test.rb @@ -115,5 +115,6 @@ SampleApp::Application.configure do :secret_key => 'sk_test_OkjoIF7FmdjunyNsdVqJD02D', :source_customer => 'cus_88Vp44SLnBWMXq' } + config.jamclass_enabled = true end