context = window
MIX_MODES = context.JK.MIX_MODES
@JamTrackSearchScreen = React.createClass({
mixins: [Reflux.listenTo(@AppStore,"onAppInit"), Reflux.listenTo(@UserStore,"onUserChanged")]
LIMIT: 10
instrument_logo_map: context.JK.getInstrumentIconMap24()
input: null
MAX_ARTIST_SHOW: 3
filterOption:() ->
true
render: () ->
searchText = if @state.first_search then 'SEARCH' else 'SEARCH AGAIN'
uiJamTracks = []
for jamtrack in @state.jamtracks
trackRow = context._.clone(jamtrack)
trackRow.track_cnt = jamtrack.tracks.length
trackRow.tracks = []
# if an instrument is selected by the user, then re-order any jam tracks with a matching instrument to the top
###instrument = @instrument.val()
if instrument?
jamtrack.tracks.sort((a, b) =>
aWeight = @computeWeight(a, instrument)
bWeight = @computeWeight(b, instrument)
return aWeight - bWeight
)
###
for track in jamtrack.tracks
if track.track_type == 'Master' || track.track_type == 'Track'
trackRow.tracks.push(track)
if track.track_type == 'Master'
track.instrument_desc = "Master"
else if track.track_type == 'Track'
inst = '../assets/content/icon_instrument_default24.png'
if track.instrument?
if track.instrument.id in @instrument_logo_map
inst = @instrument_logo_map[track.instrument.id].asset
track.instrument_desc = track.instrument.description
track.instrument_url = inst
if track.part != ''
track.instrument_desc += ' (' + track.part + ')'
trackRow.free_state = if (@state.is_free && jamtrack.allow_free) then 'free' else 'non-free'
trackRow.is_free = @state.is_free && jamtrack.allow_free
uiJamTracks.push trackRow
artists = []
artistsShown = 0
for artist in @state.artists
if @state.show_all_artists || artistsShown < @MAX_ARTIST_SHOW
artists.push `
`
artistsShown += 1
artists.push `No matching artists
` if artists.length == 0
if !@state.show_all_artists && @state.artists.length > @MAX_ARTIST_SHOW
artists.push ``
else if @state.show_all_artists
artists.push ``
jamtracks = []
for jamtrack in uiJamTracks
jamtrackPricesClasses = { "jamtrack-price" : true }
jamtrackPricesClasses[jamtrack.free_state] = true
jamtrackPricesClasses = classNames(jamtrackPricesClasses)
tracks = []
for track in jamtrack.tracks
tracks.push ``
actionBtn = null
if jamtrack.purchased
if jamtrack.can_download
actionBtn = `PURCHASED`
else
priceNotice = `$ {Number(jamtrack.upgrade_price).toFixed(2)}
`
actionBtn = ``
else if jamtrack.is_free
actionBtn = `GET IT FREE!`
else if jamtrack.added_cart
actionBtn = `ALREADY IN CART`
else
priceNotice = `$ {jamtrack.price}
`
fullPriceNotice = `$ {jamtrack.download_price}
`
actionBtn = ``
availabilityNotice = null
if jamtrack.sales_region==context.JK.AVAILABILITY_US
availabilityNotice =
`
This JamTrack available only to US customers.
why?
`
jamtracks.push `
|
"{jamtrack.name}"
Songwriters:
{jamtrack.songwriter}
Publishers:
{jamtrack.publisher}
Genres:
{jamtrack.genres.join(', ')}
Version:
{jamtrack.recording_type}
|
{tracks}
|
{actionBtn}
{availabilityNotice}
|
`
#jamtracks.push `No matching JamTracks
` if jamtracks.length == 0
searchClasses = classNames({
"button-orange" : true,
"search-btn" : true,
"disabled" : @state.searching
})
artistSection = null
jamTracksSection = null
if @state.type == 'user-input'
if @state.searching
jamtracksHeader = "searching..."
else
jamtracksHeader = "search results: #{@state.count} jamtracks"
else if @state.type == 'artist-select'
jamtracksHeader = "search results: jamtracks for artist \"#{@state.artist}\""
else if @state.type == 'song-select'
jamtracksHeader = "search results: jamtrack \"#{@state.song}\""
else
throw "unknown search type #{@state.type}"
if !@state.first_search
# only show the artists links if the user typed the results
if @state.type == 'user-input'
artistSection =
`
search results: artists
{artists}
`
jamTracksSection =
`
| JAMTRACK |
TRACKS INCLUDED / PREVIEW |
SHOP |
{jamtracks}
No more JamTracks
`
options = {}
searchValue = if @state.search == 'SEPARATOR' then '' else window.JamTrackSearchInput
`
Download JamTracks catalog
or
{artistSection}
{jamTracksSection}
`
clearResults:() ->
@setState({currentPage: 0, next: null, show_all_artists: false, artists:[], jamtracks:[], type: 'user-input', searching:false, artist: null, song:null, is_free: @user.show_free_jamtrack, first_search: true})
getInitialState: () ->
{search: '', type: 'user-input', artists:[], jamtracks:[], show_all_artists: false, currentPage: 0, next: null, searching: false, first_search: true, count: 0, is_free: context.JK.currentUserFreeJamTrack}
onArtistClick: (artist, e) ->
e.preventDefault()
@search('artist-select', artist)
onSelectChange: (val) ->
return false unless val?
search_type
if val.indexOf('ARTIST=') == 0
search_type = 'artist-select'
artist = val['ARTIST='.length..-1]
@search(search_type, artist)
else if val.indexOf('SONG=') == 0
search_type = 'song-select'
song = val['SONG='.length..-1]
@search(search_type, song)
else
@logger.debug("user selected separator")
# this is to signal to the component that the separator was selected, and it has code in render to negate the selection
setTimeout((() =>
@setState({search:val})
), 1)
return false
onSelectBlur: (e) ->
#@logger.debug("blur time")
#@search()
showAllArtists: () ->
@setState({show_all_artists: true})
hideExtraArtists: () ->
@setState({show_all_artists: false})
defaultQuery:(extra) ->
query =
per_page: @LIMIT
page: @state.currentPage + 1
sort_by: 'jamtrack'
if @state.next
query.since = @state.next
$.extend(query, extra)
userSearch: (e) ->
e.preventDefault()
@search('user-input', window.JamTrackSearchInput)
search: (search_type, input) ->
return if @state.searching
return unless input?
window.JamTrackSearchInput = input
$root = $(@getDOMNode())
# disable scroll watching now that we've started a new search
#@logger.debug("disabling infinite scroll")
$root.find('.content-body-scroller').off('scroll')
$root.find('.end-of-jamtrack-list').hide()
artistSearch = {limit:100}
if search_type == 'artist-select'
# the user wants to see just artists matching thes exact name
artistSearch.artist = input
else
# the user wants to see anything sort of matching input
artistSearch.artist_search = input
if input?
@rest.getJamTrackArtists(artistSearch)
.done((response) =>
@setState({artists:response.artists})
# we have to make sure the query starts from page 1, and no 'next' from previous causes a 'since' to show up
query = @defaultQuery({page: 1})
delete query.since
@logger.debug("Search type", search_type)
if search_type == 'artist-select'
query.artist = input # works like exact match
else if search_type == 'song-select'
query.song = input # works as exact match
else
query.search = input # works with tsv
@rest.getJamTracks(query)
.done((response) =>
@setState({jamtracks: response.jamtracks, next: response.next, searching: false, first_search: false, currentPage: 1, count: response.count})
)
.fail((jqXHR) =>
@app.notifyServerError jqXHR, 'Search Unavailable'
@setState({searching: false, first_search: false})
)
)
.fail((jqXHR) =>
@app.notifyServerError jqXHR, 'Search Unavailable'
@setState({searching: false, first_search: false})
)
@setState({currentPage: 0, next: null, artists: [], jamtracks:[], searching: true, artist: input, song: input, type: search_type, search:input, count:0})
getOptions: (input, callback) =>
#@logger.debug("getOptions input #{input}", this)
# sigh. ugly global
window.JamTrackSearchInput = input
if !input? || input.length == 0
callback(null, {options: [], complete: false})
return
@rest.autocompleteJamTracks({match:input, limit:5})
.done((autocomplete) =>
options = []
for artist in autocomplete.artists
options.push { value: "ARTIST=#{artist.original_artist}", label: "Artist: #{artist.original_artist}" }
if options.length > 0 && autocomplete.songs.length > 0
options.push { value: 'SEPARATOR', label: "---------------"}
for jamtrack in autocomplete.songs
options.push { value: "SONG=#{jamtrack.name}", label: "Song: #{jamtrack.name}" }
callback(null, {options: options, complete: false})
)
artistNavSelected: (e) ->
e.preventDefault()
@search('artist-select', $(e.target).attr('data-artist'))
componentDidMount: () ->
#@logger.debug("componentDidMount")
componentDidUpdate: ( ) ->
$root = $(this.getDOMNode())
$scroller = $root.find('.content-body-scroller')
for jamTrack in @state.jamtracks
jamtrackElement = $root.find("tbody .jamtrack-record[data-jamtrack-id=\"#{jamTrack.id}\"]")
alreadyRegistered = jamtrackElement.data('registered')
unless alreadyRegistered
jamtrackElement.data('jamTrack', jamTrack)
jamtrackElement.data('registered', true)
jamtrackElement.data('expanded', true)
@handleExpanded(jamtrackElement)
@registerEvents(jamtrackElement)
if @state.next == null
$scroller = $root.find('.content-body-scroller')
# if we less results than asked for, end searching
#$scroller.infinitescroll 'pause'
#@logger.debug("disabling infinite scroll")
$scroller.off('scroll')
if @state.currentPage == 1 and @state.jamtracks.length == 0
$root.find('.end-of-jamtrack-list').text('No JamTracks found matching your search').show()
@logger.debug("JamTrackSearch: empty search")
else if @state.currentPage > 0
@logger.debug("end of search")
$noMoreJamtracks = $root.find('.end-of-jamtrack-list').text('No more JamTracks').show()
# there are bugs with infinitescroll not removing the 'loading'.
# it's most noticeable at the end of the list, so whack all such entries
else
@registerInfiniteScroll($scroller)
registerInfiniteScroll:($scroller) ->
@logger.debug("registering infinite scroll")
$scroller.off('scroll')
$scroller.on('scroll', () =>
# be sure to not fire off many refreshes when user hits the bottom
return if @refreshing
if $scroller.scrollTop() + $scroller.innerHeight() + 100 >= $scroller[0].scrollHeight
$scroller.append('... Loading more JamTracks ...
')
@refreshing = true
@setState({searching: true})
@logger.debug("refreshing more jamtracks for infinite scroll")
@rest.getJamTracks(@defaultQuery({search:@state.search}))
.done((json) =>
@setState({jamtracks: @state.jamtracks.concat(json.jamtracks), next: json.next, first_search: false, currentPage: @state.currentPage + 1, count: json.count})
)
.always(() =>
$scroller.find('.infinite-scroll-loader-2').remove()
@refreshing = false
@setState({searching: false})
)
)
playJamtrack:(e) ->
e.preventDefault()
addToCartJamtrack:(e) ->
e.preventDefault()
$target = $(e.target)
params = id: $target.attr('data-jamtrack-id')
params.variant = $target.attr('data-variant')
isFree = $(e.target).is('.is_free')
@rest.addJamtrackToShoppingCart(params).done((response) =>
console.log("added item to shopping cart. fast_redeem? " + response.fast_redeem)
if response.fast_reedem
if context.JK.currentUserId?
context.location = '/client#/redeemComplete'
else
context.location = '/client#/redeemSignup'
else
context.location = '/client#/shoppingCart'
).fail(((jqxhr) =>
handled = false
if jqxhr.status == 422
body = JSON.parse(jqxhr.responseText)
if body.errors && body.errors.base
handled = true
context.JK.Banner.showAlert("You can not have a mix of free and non-free items in your shopping cart.
If you want to add this new item to your shopping cart, then clear out all current items by clicking on the shopping cart icon and clicking 'delete' next to each item.")
if !handled
@app.ajaxError(arguments[0], arguments[1], arguments[2])
))
licenseUSWhy:(e) ->
e.preventDefault()
@app.layout.showDialog 'jamtrack-availability-dialog'
registerEvents:($parent) ->
$parent.find('.play-button').on 'click', @playJamtrack
$parent.find('.jamtrack-add-cart').on 'click', @addToCartJamtrack
$parent.find('.license-us-why').on 'click', @licenseUSWhy
$parent.find('.jamtrack-detail-btn').on 'click', @toggleExpanded
$parent.find('.jamtrack-variant-help').on 'click', @showVariantHelp
$parent.find('.jamtrack-upgrade-help').on 'click', @showUpgradeHelp
showVariantHelp: (e) ->
$screen = $('#jamtrackSearch')
e.preventDefault()
context.JK.HelpBubbleHelper.jamtrackVariants($(e.target), $screen)
showUpgradeHelp: (e) ->
$screen = $('#jamtrackSearch')
e.preventDefault()
context.JK.HelpBubbleHelper.jamtrackUpgrade($(e.target), $screen)
toggleExpanded:(e) ->
e.preventDefault()
jamtrackRecord = $(e.target).parents('.jamtrack-record')
@handleExpanded(jamtrackRecord)
handleExpanded:(trackElement) ->
jamTrack = trackElement.data('jamTrack')
expanded = trackElement.data('expanded')
expand = !expanded
trackElement.data('expanded', expand)
detailArrow = trackElement.find('.jamtrack-detail-btn')
if expand
trackElement.find('.extra').removeClass('hidden')
detailArrow.html('hide tracks ')
for track in jamTrack.tracks
trackElement.find("[data-jamtrack-track-id='#{track.id}']").removeClass('hidden')
else
trackElement.find('.extra').addClass('hidden')
detailArrow.html('show all tracks ')
count = 0
for track in jamTrack.tracks
if count < 6
trackElement.find("[data-jamtrack-track-id='#{track.id}']").removeClass('hidden')
else
trackElement.find("[data-jamtrack-track-id='#{track.id}']").addClass('hidden')
count++
afterShow: (data) ->
@setFilterFromURL()
setFilterFromURL:() ->
performSearch = false
if $.QueryString['artist']?
performSearch = true
@search('artist-select', $.QueryString['artist'])
else if $.QueryString['song']?
performSearch = true
@search('song-select', $.QueryString['song'])
else if $.QueryString['search']?
performSearch = true
@search('user-input', $.QueryString['search'])
else
# check if someone has requested a search for us as we transition to this screen
search = context.JamTrackStore.checkRequestedSearch()
if search?
performSearch = true
@search(search.searchType, search.searchData)
else
if !@state.first_search
@search(@state.type, window.JamTrackSearchInput)
if performSearch
if window.history.replaceState #ie9 proofing
window.history.replaceState({}, "", "/client#/jamtrack/search")
beforeShow: () ->
onAppInit: (@app) ->
window.JamTrackSearchInput = '' # need to be not null; otherwise react-select chokes
@EVENTS = context.JK.EVENTS
@rest = context.JK.Rest()
@logger = context.JK.logger
screenBindings =
'beforeShow': @beforeShow
'afterShow': @afterShow
@app.bindScreen('jamtrack/search', screenBindings)
onUserChanged: (userState) ->
@user = userState?.user
@setState({is_free: @user?.show_free_jamtrack})
})