2015-08-18 19:26:41 +00:00
context = window
MIX_MODES = context . JK . MIX_MODES
@JamTrackSearchScreen = React . createClass ( {
2015-11-13 13:12:58 +00:00
mixins: [ Reflux . listenTo ( @ AppStore , " onAppInit " ) , Reflux . listenTo ( @ UserStore , " onUserChanged " ) ]
2015-08-18 19:26:41 +00:00
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
2015-11-30 23:54:17 +00:00
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 + ' ) '
2015-08-18 19:26:41 +00:00
2016-08-03 01:46:15 +00:00
trackRow.free_state = if ( @ state . is_free && jamtrack . allow_free ) then ' free ' else ' non-free '
2015-08-18 19:26:41 +00:00
2016-08-03 01:46:15 +00:00
trackRow.is_free = @ state . is_free && jamtrack . allow_free
2015-08-18 19:26:41 +00:00
uiJamTracks . push trackRow
artists = [ ]
artistsShown = 0
for artist in @ state . artists
if @ state . show_all_artists || artistsShown < @ MAX_ARTIST_SHOW
artists . push ` < div key = { artist . original_artist } > < a className = " show-artist " onClick = { this . artistNavSelected } data - artist = { artist . original_artist } > { artist . original_artist } < / a > < / div > `
artistsShown += 1
artists . push ` < div key = " no-results " className = " no-results " > No matching artists < / div > ` if artists . length == 0
if ! @ state . show_all_artists && @ state . artists . length > @ MAX_ARTIST_SHOW
artists . push ` < div key = " show-hide-artists " > < a onClick = { this . showAllArtists } className = " show-hide-artists " > show all < div className = " details-arrow arrow-down " / > < / a > < / div > `
else if @ state . show_all_artists
artists . push ` < div key = " show-hide-artists " > < a onClick = { this . hideExtraArtists } className = " show-hide-artists " > hide artists < div className = " details-arrow arrow-up " / > < / a > < / div > `
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 ` < div className = " jamtrack-track hidden " key = { track . id } data - jamtrack - track - id = { track . id } >
< div className = " jamtrack-preview " >
< JamTrackPreview jamTrack = { jamtrack } jamTrackTrack = { track } options = { { master_shows_duration: true , color : ' gray ' } } / >
< div className = " clearall " / >
< / div >
< / div > `
actionBtn = null
2015-11-13 13:12:58 +00:00
if jamtrack . purchased
2017-02-05 20:42:51 +00:00
if jamtrack . can_download
actionBtn = ` < a className = " jamtrack-add-cart-disabled button-grey button-disabled " href = " javascript:void(0) " > PURCHASED < / a > `
else
priceNotice = ` < div className = { jamtrackPricesClasses } > $ { Number ( jamtrack . upgrade_price ) . toFixed ( 2 ) } < / div > `
actionBtn = ` < div >
< div className = " jamtrack-add-zone " >
{ priceNotice }
< a className = " jamtrack-add-cart button-orange " href = " # " data - jamtrack - id = { jamtrack . id } data - variant = " download " > UPGRADE TO FULL < / a >
< / div >
< a className = " jamtrack-upgrade-help " href = ' # ' > HELP < / a >
< / div > `
2015-11-13 13:12:58 +00:00
else if jamtrack . is_free
2017-02-05 20:42:51 +00:00
actionBtn = ` < a className = " jamtrack-add-cart button-orange is_free " href = " # " data - jamtrack - id = { jamtrack . id } data - variant = " full " > GET IT FREE ! < / a > `
2015-08-18 19:26:41 +00:00
else if jamtrack . added_cart
actionBtn = ` < a className = " jamtrack-add-cart-disabled button-grey button-disabled " href = " client # /shoppingCart " > ALREADY IN CART < / a > `
else
2017-02-05 20:42:51 +00:00
priceNotice = ` < div className = { jamtrackPricesClasses } > $ { jamtrack . price } < / div > `
fullPriceNotice = ` < div className = { jamtrackPricesClasses } > $ { jamtrack . download_price } < / div > `
actionBtn = ` < div >
< div className = " jamtrack-add-zone " >
{ priceNotice }
< a className = " jamtrack-add-cart button-orange " href = " # " data - jamtrack - id = { jamtrack . id } data - variant = " stream " > ADD TO CART < / a >
< / div >
< div className = " jamtrack-add-zone " >
{ fullPriceNotice }
< a className = " jamtrack-add-cart button-orange " href = " # " data - jamtrack - id = { jamtrack . id } data - variant = " full " > ADD TO CART ( FULL ) < / a >
< / div >
< a className = " jamtrack-variant-help " href = ' # ' > HELP < / a >
< / div > `
2015-08-18 19:26:41 +00:00
availabilityNotice = null
if jamtrack . sales_region == context . JK . AVAILABILITY_US
availabilityNotice =
` < div className = " jamtrack-license " >
This JamTrack available only to US customers . & nbsp ; & nbsp ; & nbsp ; & nbsp ;
< a className = " license-us-why " href = " # " > why ? < / a >
< / div > `
jamtracks . push ` < tr className = " jamtrack-record " key = { jamtrack . id } data - jamtrack - id = { jamtrack . id } >
< td className = " jamtrack-detail " >
< div className = " jamtrack-name " > " {jamtrack.name} " < / div >
2016-01-15 18:35:04 +00:00
< div className = " jamtrack-original-artist " > < a onClick = { this . onArtistClick . bind ( this , jamtrack . original_artist ) } > by { jamtrack . original_artist } < / a > < / div >
2015-08-18 19:26:41 +00:00
< br className = " clearall " / >
< div className = " clearall detail-label extra hidden song-writer " > Songwriters : < / div >
< div className = " detail-value extra hidden " > { jamtrack . songwriter } < / div >
< div className = " clearall detail-label extra hidden " > Publishers : < / div >
< div className = " detail-value extra hidden " > { jamtrack . publisher } < / div >
< div className = " clearall detail-label extra hidden " > Genres : < / div >
< div className = " detail-value extra hidden " > { jamtrack . genres . join ( ' , ' ) } < / div >
< div className = " clearall detail-label extra hidden " > Version : < / div >
< div className = " detail-value extra hidden " > { jamtrack . recording_type } < / div >
< / td >
< td className = " jamtrack-tracks " >
< div className = " detail-arrow " >
< div className = " jamtrack-detail-btn " >
show all tracks < a className = " details-arrow arrow-down " / >
< / div >
< / div >
{ tracks }
< / td >
< td className = " jamtrack-action " >
< div className = " jamtrack-action-container " >
< div className = " jamtrack-actions " >
{ actionBtn }
{ availabilityNotice }
< / div >
< / div >
< / td >
< / tr > `
#jamtracks.push `<div className="no-results">No matching JamTracks</div>` 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 =
` < div >
< h2 > search results: artists < / h2 >
< div className = " artist-results " >
{ artists }
< / div >
< / div > `
jamTracksSection =
` < div >
< h2 className = " jamtrack-results-header " > { jamtracksHeader } < a className = " back-to-jamtracks-home " href = " /client # /jamtrack " > back to jamtracks home < / a > < / h2 >
< table className = " generaltable jamtrack-table " >
< thead >
< tr >
< th className = " jamtrack-detail " > JAMTRACK < / th >
< th className = " jamtrack-tracks " > TRACKS INCLUDED / PREVIEW < / th >
< th className = " jamtrack-shop " > SHOP < / th >
< / tr >
< / thead >
< tbody className = " jamtrack-content " >
{ jamtracks }
< / tbody >
< / table >
< div className = " end-of-jamtrack-list end-of-list " > No more JamTracks < / div >
< / div > `
options = { }
searchValue = if @ state . search == ' SEPARATOR ' then ' ' else window . JamTrackSearchInput
` < div className = " JamTrackSearchScreen " >
< div className = " controls " >
< JamTrackAutoComplete onSearch = { this . search } / >
< button className = { searchClasses } name = " search " onClick = { this . userSearch } > { searchText } < / button >
2015-12-04 15:27:28 +00:00
< div className = " download-all " > Download JamTracks catalog < br / > < JamTrackCSVLink / > or < JamTrackPdfLink / > < / div >
2015-08-18 19:26:41 +00:00
< / div >
< div className = " content-body-scroller " >
{ artistSection }
{ jamTracksSection }
< / div >
< / div > `
clearResults : () ->
2015-11-13 13:12:58 +00:00
@ 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 } )
2015-08-18 19:26:41 +00:00
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 }
2016-01-15 18:35:04 +00:00
onArtistClick: (artist, e) ->
e . preventDefault ( )
@ search ( ' artist-select ' , artist )
2015-08-18 19:26:41 +00:00
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 ( )
2015-08-27 01:26:39 +00:00
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
2015-08-18 19:26:41 +00:00
if input ?
2015-08-27 01:26:39 +00:00
@ rest . getJamTrackArtists ( artistSearch )
2015-08-18 19:26:41 +00:00
. 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 '
2015-08-27 01:26:39 +00:00
query.artist = input # works like exact match
2015-08-18 19:26:41 +00:00
else if search_type == ' song-select '
2015-08-27 01:26:39 +00:00
query.song = input # works as exact match
2015-08-18 19:26:41 +00:00
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 } )
)
2016-12-15 18:47:08 +00:00
. fail ( (jqXHR) =>
2015-08-18 19:26:41 +00:00
@ app . notifyServerError jqXHR , ' Search Unavailable '
@ setState ( { searching: false , first_search: false } )
)
)
2016-12-15 18:47:08 +00:00
. fail ( (jqXHR) =>
2015-08-18 19:26:41 +00:00
@ 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 } \" ] " )
2015-08-20 19:49:07 +00:00
alreadyRegistered = jamtrackElement . data ( ' registered ' )
2015-08-18 19:26:41 +00:00
2015-08-20 19:49:07 +00:00
unless alreadyRegistered
jamtrackElement . data ( ' jamTrack ' , jamTrack )
jamtrackElement . data ( ' registered ' , true )
jamtrackElement . data ( ' expanded ' , true )
@ handleExpanded ( jamtrackElement )
@ registerEvents ( jamtrackElement )
2015-08-18 19:26:41 +00:00
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 ( ' <div class= " infinite-scroll-loader-2 " >... Loading more JamTracks ...</div> ' )
@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 ' )
2017-02-05 20:42:51 +00:00
params.variant = $target . attr ( ' data-variant ' )
2015-08-18 19:26:41 +00:00
isFree = $ ( e . target ) . is ( ' .is_free ' )
@ rest . addJamtrackToShoppingCart ( params ) . done ( (response) =>
2016-08-03 01:46:15 +00:00
console . log ( " added item to shopping cart. fast_redeem? " + response . fast_redeem )
if response . fast_reedem
if context . JK . currentUserId ?
context.location = ' /client # /redeemComplete '
2015-08-18 19:26:41 +00:00
else
context.location = ' /client # /redeemSignup '
2016-08-03 01:46:15 +00:00
else
context.location = ' /client # /shoppingCart '
2015-08-18 19:26:41 +00:00
2015-11-13 13:12:58 +00:00
) . 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.<br/><br/>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 ] )
) )
2015-08-18 19:26:41 +00:00
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
2017-02-05 20:42:51 +00:00
$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 )
2015-08-18 19:26:41 +00:00
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 <a class= " details-arrow arrow-up " ></a> ' )
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 <a class= " details-arrow arrow-down " ></a> ' )
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 )
2015-12-02 21:01:18 +00:00
else
if ! @ state . first_search
@ search ( @ state . type , window . JamTrackSearchInput )
2015-08-18 19:26:41 +00:00
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 )
2015-11-13 13:12:58 +00:00
onUserChanged: (userState) ->
@user = userState ? . user
@ setState ( { is_free: @ user ? . show_free_jamtrack } )
2015-08-18 19:26:41 +00:00
} )