context = window
rest = context.JK.Rest()
logger = context.JK.logger
EVENTS = context.JK.EVENTS;
SubjectStore = context.SubjectStore
InstrumentStore = context.InstrumentStore
LanguageStore = context.LanguageStore
GenreStore = context.GenreStore
UserStore = context.UserStore
AppStore = context.AppStore
ProfileActions = context.ProfileActions
profileUtils = context.JK.ProfileUtils
proficiencyCssMap = {
"1": "proficiency-beginner",
"2": "proficiency-intermediate",
"3": "proficiency-expert"
};
proficiencyDescriptionMap = {
"1": "BEGINNER",
"2": "INTERMEDIATE",
"3": "EXPERT"
};
@TeacherProfile = React.createClass({
mixins: [
PostProcessorMixin,
Reflux.listenTo(AppStore, "onAppInit"),
Reflux.listenTo(UserStore, "onUserChanged"),
Reflux.listenTo(SubjectStore, "onSubjectsChanged"),
Reflux.listenTo(GenreStore, "onGenresChanged"),
Reflux.listenTo(InstrumentStore, "onInstrumentsChanged"),
Reflux.listenTo(LanguageStore, "onLanguagesChanged")
]
TILE_ABOUT: 'about'
TILE_EXPERIENCE: 'experience'
TILE_SAMPLES: 'samples'
TILE_RATINGS: 'ratings'
TILE_PRICES: 'prices'
visible: false
profileClipboard: null
TILES: ['about', 'experience', 'samples', 'ratings', 'prices']
onAppInit: (@app) ->
@app.bindScreen('profile/teacher', {beforeShow: @beforeShow, afterShow: @afterShow, beforeHide: @beforeHide})
onSubjectsChanged: () ->
@setState({subjects: true})
onInstrumentsChanged: () ->
@setState({instruments: true})
onGenresChanged: () ->
@setState({genres: true})
onLanguagesChanged: () ->
@setState({languages: true})
componentDidMount: () ->
@root = $(@getDOMNode())
@screen = $('#teacher-profile')
@starbox()
@clipboard()
componentDidUpdate:() ->
@starbox()
context.JK.popExternalLinks(@root)
@clipboard()
clipboard: () ->
$profileLink = @root.find('.copy-profile-link')
if $profileLink.length > 0 && !@profileClipboard?
# mount it
@profileClipboard = new Clipboard($profileLink.get(0), {
text: =>
return context.JK.makeAbsolute('/client#/teacher/profile/' + @state.user.id)
})
else if $profileLink.length == 0 && @profileClipboard?
@profileClipboard.destroy()
@profileClipboard = null
starbox:() ->
$ratings = @root.find('.ratings-box')
$ratings.each((i, value) =>
$element = $(value)
rating = $element.attr('data-ratings')
rating = parseFloat(rating)
#$element.starbox('destroy')
$element.starbox({
average: rating,
changeable: false,
autoUpdateAverage: false,
ghosting: false
}).show()
)
userDetailDone: (response) ->
if response.id == @state.userId
console.log("teacher markup", response)
@postProcessUser(response)
@setState({user: response, isSelf: response.id == context.JK.currentUserId})
else
logger.debug("ignoring userDetailDone", response.id, @state.userId)
@showSideBubbleWhenReady()
showSideBubbleWhenReady: () ->
if @user? && @state.user?
if @visible
setTimeout((() => (
if @visible
@showSideBubble()
)), 5000)
beforeHide: (e) ->
@visible = false
@hideSideBubble();
logger.debug("TeacherProfile: beforeHide")
ProfileActions.viewTeacherProfileDone()
beforeShow: (e) ->
logger.debug("TeacherProfile: beforeShow")
afterShow: (e) ->
UserActions.refresh()
@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: id,
show_teacher: true,
show_profile: true
}).done((response) => @userDetailDone(response)).fail(@app.ajaxError)
showSideBubble: () ->
# :remaining_test_drives, :can_buy_test_drive?
if @state.user?['same_school_with_student']
@showBuyNormalLessonBubble()
else if @user['jamclass_credits'] > 0
@showUseRemainingJamClassCreditsBubble()
else
if @state.user?['has_booked_test_drive_with_student']
@showBuyNormalLessonBubble()
else
if @user['remaining_test_drives'] > 0
@showUseRemainingTestDrivesBubble()
else if @user['can_buy_test_drive?']
@showBuyTestDriveBubble()
else
@showBuyNormalLessonBubble()
hideSideBubble: () ->
if @screen.btOff
@screen.btOff()
showUseRemainingTestDrivesBubble: ( ) ->
context.JK.HelpBubbleHelper.showUseRemainingTestDrives(@screen, @screen, @user, (() => @useRemainingTestDrives()))
showUseRemainingJamClassCreditsBubble: ( ) ->
context.JK.HelpBubbleHelper.showUseRemainingJamClassCreditsBubble(@screen, @screen, @user, (() => @useRemainingTestDrives()))
showBuyTestDriveBubble: () ->
context.JK.HelpBubbleHelper.showBuyTestDrive(@screen, @screen, @user, (() => @buyTestDrive()))
showBuyNormalLessonBubble: () ->
context.JK.HelpBubbleHelper.showBuyNormalLesson(@screen, @screen, @state.user, (() => @buyNormalLesson()))
useRemainingTestDrives: () ->
window.location.href = "/client#/jamclass/book-lesson/test-drive_#{@state.user.id}"
buyTestDrive: () ->
window.location.href = "/client#/jamclass/test-drive-selection/#{@state.user.id}"
buyNormalLesson: () ->
window.location.href = "/client#/jamclass/book-lesson/normal_#{@state.user.id}"
getInitialState: () ->
{
userId: null,
user: null,
selected: 'about' ,
isSelf: false,
subjects: false,
instruments: false,
genres: false,
languages: false
}
onUserChanged: (userState) ->
@user = userState?.user
@showSideBubbleWhenReady()
editProfile: (selected, e) ->
e.preventDefault()
logger.debug("edit profile requested for state " + selected)
ProfileActions.startTeacherEdit(selected, true)
editMusicProfile: (selected, e) ->
e.preventDefault()
logger.debug("edit music profile requested " + selected)
ProfileActions.startProfileEdit(selected, true)
editProfileLink: (text, selected) ->
if @state.isSelf
`{text}`
editMusicProfileLink: (text, selected) ->
if @state.isSelf
`{text}`
editTeacherProfile: (e) ->
e.preventDefault()
ProfileActions.startTeacherEdit(null, false)
teacherBio: (user, teacher) ->
if teacher.biography?
biography = teacher.biography
else
biography = 'No bio defined yet'
biography = biography.replace(/\n/g, "
")
# make button available only if this is the current user viewing
if @state.userId == @user?.id
copyUrlToClipboard = `
COPY PROFILE URL TO CLIPBOARD
`
`
{copyUrlToClipboard}
Teacher Profile {this.editProfileLink('edit profile', 'introduction')}
`
getYoutubeId:(url) ->
regExp = /^.*(youtu.be\/|v\/|u\/\w\/|embed\/|watch\?v=|\&v=)([^#\&\?]*).*/
match = url.match(regExp)
if match && match[2].length >= 9
return match[2]
else
return 'unknown'
sampleVideo: (user, teacher) ->
if teacher.introductory_video? && teacher.introductory_video.length > 0
videoUrl = teacher.introductory_video
# http://stackoverflow.com/a/21607897
embedId = @getYoutubeId(videoUrl)
embedUrl = "//www.youtube.com/embed/#{embedId}"
video = `
`
return ``
teachesInfo: (user, teacher) ->
teachesInfo = []
instruments = teacher.instruments.map((id) -> InstrumentStore.display(id))
instrumentData = instruments.join(', ')
teachesInfo.push(`
| Instruments |
{instrumentData} |
`)
subjects = teacher.subjects.map((id) -> SubjectStore.display(id))
subjectsData = subjects.join(', ')
teachesInfo.push(`
| Subjects |
{subjectsData} |
`)
genres = teacher.genres.map((id) -> GenreStore.display(id))
genresData = genres.join(', ')
teachesInfo.push(`
| Genres |
{genresData} |
`)
levels = []
if teacher.teaches_beginner
levels.push('Beginner')
if teacher.teaches_intermediate
levels.push('Intermediate')
if teacher.teaches_advanced
levels.push('Advanced')
levelsData = levels.join(', ')
teachesInfo.push(`
| Levels |
{levelsData} |
`)
ageData = '?'
if teacher.teaches_age_lower == 0 && teacher.teaches_age_upper == 0
ageData = 'Any'
else if teacher.teaches_age_lower != 0 && teacher.teaches_age_upper != 0
ageData = "#{teacher.teaches_age_lower} to #{teacher.teaches_age_upper}"
else if teacher.teaches_age_lower == 0
ageData = "Age #{teacher.teaches_age_upper} and younger"
else if teacher.teaches_age_upper == 0
ageData = "Ages #{teacher.teaches_age_lower} and up"
teachesInfo.push(`
| Ages |
{ageData} |
`)
languages = teacher.languages.map((id) -> LanguageStore.display(id))
languagesData = languages.join(', ')
teachesInfo.push(`
| Languages |
{languagesData} |
`)
`
{this.state.user.first_name} Teaches {this.editProfileLink('edit teaching', 'basics')}
`
musicianBio: (user, teacher) ->
if user.biography?
musicianBio = user.biography
else
musicianBio = 'None specified.'
musicianBio = musicianBio.replace(/\n/g, "
")
`
Musical Profile {this.editMusicProfileLink('update bio', '')}
`
plays: (user, teacher) ->
if user.profile.concert_count > 0
gigs = "Has played #{profileUtils.gigMap[user.profile.concert_count]} concert gigs"
else
gigs = "Has played an unknown # of concert gigs"
if user.profile.studio_session_count > 0
studioSessions = "Has played #{profileUtils.gigMap[user.profile.studio_session_count]} studio sessions"
else
studioSessions = "Has played an unknown # of studio sessions"
gigTable =
``
display_instruments = []
for instrument in user.instruments
description = InstrumentStore.display(instrument.instrument_id)
proficiency = instrument.proficiency_level;
instrument_icon_url = context.JK.getInstrumentIcon256(instrument.instrument_id);
display_instruments.push(`
{description}
{proficiencyDescriptionMap[proficiency]}
`)
`
{this.state.user.first_name} Plays {this.editMusicProfileLink('update instruments', 'experience')}
{display_instruments}
{gigTable}
`
createPresence: (className, url, img) ->
``
onlinePresences: (user, teacher) ->
online_presences = user.profile.online_presences
presences = []
if user.profile.website
# make sure website is rooted
website = user.profile.website
if website.indexOf('http') == -1
website = 'http://' + website
presences.push(@createPresence("user-website", website, "/assets/content/website-logo.png"))
matches = profileUtils.soundCloudPresences(online_presences)
if matches.length > 0
presences.push(@createPresence("soundcloud", "http://www.soundcloud.com/#{matches[0].username}",
"/assets/content/soundcloud-logo.png"))
matches = profileUtils.reverbNationPresences(online_presences)
if matches.length > 0
presences.push(@createPresence("reverbnation", "http://www.reverbnation.com/#{matches[0].username}",
"/assets/content/reverbnation-logo.png"))
matches = profileUtils.bandCampPresences(online_presences)
if matches.length > 0
presences.push(@createPresence("bandcamp", 'http://' + matches[0].username + '.bandcamp.com/',
"/assets/content/bandcamp-logo.png"))
matches = profileUtils.fandalismPresences(online_presences)
if matches.length > 0
presences.push(@createPresence("fandalism", 'http://www.fandalism.com/' + matches[0].username,
"/assets/content/fandalism-logo.png"))
matches = profileUtils.youTubePresences(online_presences)
if matches.length > 0
presences.push(@createPresence("youtube", 'http://www.youtube.com/' + matches[0].username,
"/assets/content/youtube-logo.png"))
matches = profileUtils.facebookPresences(online_presences)
if matches.length > 0
presences.push(@createPresence("facebook", 'http://www.facebook.com/' + matches[0].username,
"/assets/content/facebook-logo.png"))
matches = profileUtils.twitterPresences(online_presences)
if matches.length > 0
presences.push(@createPresence("twitter", 'http://www.twitter.com/' + matches[0].username,
"/assets/content/twitter-logo.png"))
if presences.length == 0
presences = `None specified
`
`
Online Presence {this.editMusicProfileLink('update presence', 'samples')}
{presences}
`
about: () ->
user = @state.user
teacher = user.teacher
`
{this.sampleVideo(user, teacher)}
{this.teacherBio(user, teacher)}
{this.teachesInfo(user, teacher)}
{this.musicianBio(user, teacher)}
{this.plays(user, teacher)}
{this.onlinePresences(user, teacher)}
`
experiences: (title, attr, update, user, teacher) ->
teachingExperiences = []
for teachingExperience, i in teacher['experiences_' + attr]
years = ''
if teachingExperience.start_year > 0
if teachingExperience.end_year && teachingExperience.end_year > 0
years = "#{teachingExperience.start_year} - #{teachingExperience.end_year}"
else
years = "#{teachingExperience.start_year} - Present"
teachingExperiences.push(`
{years}
{teachingExperience.name}
{teachingExperience.organization}
`)
if update?
updateLink = this.editProfileLink('update ' + update, 'experience')
if teachingExperiences.length == 0
teachingExperiences = `None specified
`
`
{title} {updateLink}
{teachingExperiences}
`
sampleClicked: (e) ->
e.preventDefault()
context.JK.popExternalLink($(e.target).attr('href'))
musicSamples: (user, teacher) ->
performance_samples = user.profile.performance_samples
jamkazamSamples = []
samples = profileUtils.jamkazamSamples(performance_samples);
for sample in samples
jamkazamSamples.push(`{sample.claimed_recording.name}`)
soundCloudSamples= []
samples = profileUtils.soundCloudSamples(performance_samples);
for sample in samples
soundCloudSamples.push(`{sample.description}`)
youTubeSamples = []
samples = profileUtils.youTubeSamples(performance_samples);
for sample in samples
youTubeSamples.push(`{sample.description}`)
sampleJsx = []
if jamkazamSamples.length > 0
sampleJsx.push(`

{jamkazamSamples}
`)
if soundCloudSamples.length > 0
sampleJsx.push(`

{soundCloudSamples}
`)
if youTubeSamples.length > 0
sampleJsx.push(`

{youTubeSamples}
`)
`
Performance Samples {this.editMusicProfileLink('update samples', 'samples')}
{sampleJsx}
`
experience: () ->
user = @state.user
teacher = user.teacher
`
{this.experiences('Teaching Experience', 'teaching', 'experience', user, teacher)}
{this.experiences('Music Education', 'education', null, user, teacher)}
{this.experiences('Music Awards', 'award', null, user, teacher)}
`
samples: () ->
user = @state.user
teacher = user.teacher
`
{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
summary = teacher.review_summary || {avg_rating: 0, review_count: 0}
if summary.review_count == 1
reviewCount = '1 review'
else
reviewCount = summary.review_count + ' reviews'
reviews = []
for review in teacher.recent_reviews
photo_url = review.user.photo_url
if !photo_url?
photo_url = '/assets/shared/avatar_generic.png'
name = `{review.user.name}
`
reviews.push(`
{name}
{context.JK.formatDateShort(review.created_at)}
`)
`
Ratings & Reviews
{user.first_name} Summary Rating:
({reviewCount})
RATE TEACHER
{reviews}
`
prices: () ->
user = @state.user
teacher = user.teacher
rows = []
for minutes in [30, 45, 60, 90, 120]
lesson_price = teacher["price_per_lesson_#{minutes}_cents"]
monthly_price = teacher["price_per_month_#{minutes}_cents"]
duration_enabled = teacher["lesson_duration_#{minutes}"]
if duration_enabled && teacher.prices_per_lesson && lesson_price? && lesson_price > 0
lessonPriceFormatted = '$ ' + (lesson_price / 100).toFixed(2)
else
lessonPriceFormatted = 'N/A'
if duration_enabled && teacher.prices_per_month && monthly_price? && monthly_price > 0
monthlyPriceFormatted = '$ ' + (monthly_price / 100).toFixed(2)
else
monthlyPriceFormatted = 'N/A'
rows.push(`| {minutes + " Minutes"} | {lessonPriceFormatted} | {monthlyPriceFormatted} |
`)
`
Lesson Prices {this.editProfileLink('update prices', 'pricing')}
| LESSON LENGTH | PRICE PER LESSON | PRICE PER MONTH |
{rows}
`
mainContent: () ->
if @state.selected == @TILE_ABOUT
@about()
else if @state.selected == @TILE_EXPERIENCE
@experience()
else if @state.selected == @TILE_SAMPLES
@samples()
else if @state.selected == @TILE_RATINGS
@ratings()
else if @state.selected == @TILE_PRICES
@prices()
profileLeft: () ->
if this.state.user.age?
age = `{this.state.user.age} years old
`
else
age = null
backgroundCheck = null
backgroundCheckAt = @state.user?.teacher?.background_check_at
if backgroundCheckAt
backgroundCheck =
`
Background Check:
{context.JK.formatDateShort(new Date(backgroundCheckAt))}

`
`
{this.state.user.city}
{this.state.user.state}
{this.state.user.country}
{age}
Last Signed In:
{"very recently"}
{backgroundCheck}
`
copyProfileLink: (e) ->
e.preventDefault()
@app.layout.notify({
title: 'Teacher Profile Link Copied',
text: "Your clipboard now has a link to this teacher that you can share with anyone."
})
selectionMade: (selection, e) ->
e.preventDefault()
@setState({selected: selection})
createTileLink: (i, tile) ->
active = this.state.selected == tile
classes = classNames({last: i == @TILES.length - 1, activeTile: active})
return ``
onCustomBack: (customBack, e) ->
e.preventDefault()
context.location = customBack
render: () ->
if @state.user?
avatar = context.JK.resolveAvatarUrl(@state.user.photo_url);
if @state.user?
if @state.user.teacher?
mainContent = @mainContent()
profileLeft = @profileLeft()
else
if context.JK.currentUserId? && @state.user?.id == context.JK.currentUserId
noTeacherProfile = ``
else
noTeacherProfile = `This user has no teacher profile.
`
mainContent = `
{noTeacherProfile}
`
else
noTeacherProfile = ``
mainContent = `
{noTeacherProfile}
`
if ProfileStore.customBack
actionButtons = ``
profileSelections = []
for tile, i in @TILES
profileSelections.push(@createTileLink(i, tile, profileSelections))
profileNav = `
{profileSelections}
`
`
{actionButtons}
{profileNav}
{profileLeft}
{mainContent}
`
})