VRFS-3036 building out band search filter features, refactoring musician search filter

This commit is contained in:
Jonathan Kolyer 2015-05-18 04:00:12 +00:00
parent 6fb07d8a31
commit 737367b016
19 changed files with 658 additions and 413 deletions

View File

@ -1,12 +1,16 @@
module JamRuby
class BandSearch < BaseSearch
cattr_accessor :jschema, :search_meta
attr_accessor :user_counters
KEY_BAND_SEARCH_TYPE = 'band_search_type'
KEY_BAND_TYPE = 'band_type'
KEY_PLAY_COMMIT = 'play_commit'
KEY_TOUR_OPTION = 'tour_option'
KEY_PERF_SAMPLES = 'perform_samples'
KEY_HIRE_MAX_COST = 'max_cost'
KEY_HIRE_FREE = 'free_gigs'
BAND_SEARCH_TYPE_VALS = %W{ to_join to_hire }
BAND_SEARCH_TYPES = {
@ -20,6 +24,13 @@ module JamRuby
SORT_VALS[1] => 'Latency to Me',
}
HIRE_SORT_VALS = %W{ distance price_asc price_desc }
HIRE_SORT_ORDERS = {
HIRE_SORT_VALS[0] => 'Distance to Me',
HIRE_SORT_VALS[1] => 'Gig Minimum Price (Low to High)',
HIRE_SORT_VALS[2] => 'Gig Minimum Price (High to Low)',
}
BAND_TYPE_VALS = [ANY_VAL_STR,
GenrePlayer::VIRTUAL_BAND,
GenrePlayer::TRADITIONAL_BAND,
@ -52,19 +63,37 @@ module JamRuby
TOUR_OPTION_VALS[1] => 'No',
}
JSON_SCHEMA = BaseSearch::JSON_SCHEMA.merge({
KEY_BAND_SEARCH_TYPE => BAND_SEARCH_TYPES[0],
KEY_BAND_TYPE => BAND_TYPE_VALS[0],
KEY_PLAY_COMMIT => PLAY_COMMIT_VALS[0],
KEY_TOUR_OPTION => TOUR_OPTION_VALS[0],
})
PERF_SAMPLES_VALS = TOUR_OPTION_VALS.clone
PERF_SAMPLES = TOUR_OPTIONS.clone
SEARCH_FILTER_META = BaseSearch::SEARCH_FILTER_META.merge({
sort_order: { keys: self::SORT_VALS, map: self::SORT_ORDERS },
band_type: { keys: BAND_TYPE_VALS, map: BAND_TYPES },
play_commit: { keys: PLAY_COMMIT_VALS, map: PLAY_COMMITS },
tour_option: { keys: TOUR_OPTION_VALS, map: TOUR_OPTIONS }
})
def self.json_schema
return @@jschema if @@jschema
@@jschema = {
BAND_SEARCH_TYPE_VALS[0] => BaseSearch.json_schema.merge({
KEY_BAND_TYPE => BAND_TYPE_VALS[0],
KEY_PLAY_COMMIT => PLAY_COMMIT_VALS[0],
KEY_TOUR_OPTION => TOUR_OPTION_VALS[0],
}),
BAND_SEARCH_TYPE_VALS[1] => {
KEY_SORT_ORDER => self::HIRE_SORT_VALS[0],
KEY_GENRES => [],
KEY_SKILL => self::SKILL_VALS[0].to_s,
KEY_GIGS => self::GIG_COUNTS[0].to_s,
KEY_PERF_SAMPLES => self::PERF_SAMPLES[0].to_s,
KEY_HIRE_MAX_COST => 0,
KEY_HIRE_FREE => 0,
},
}
end
def self.search_filter_meta
return @@search_meta if @@search_meta
@@search_meta = {
BAND_SEARCH_TYPE_VALS[0] => super(self.json_schema[BAND_SEARCH_TYPE_VALS[0]]),
BAND_SEARCH_TYPE_VALS[1] => super(self.json_schema[BAND_SEARCH_TYPE_VALS[1]],
{ keys: HIRE_SORT_VALS, map: HIRE_SORT_ORDERS }),
}
end
def self.search_target_class
User
@ -155,7 +184,7 @@ module JamRuby
end
def is_blank?
self.data_blob == JSON_SCHEMA
self.data_blob == self.class.json_schema
end
def description
@ -168,5 +197,39 @@ module JamRuby
str
end
def reset_filter(subtype, data=nil)
data ||= self.class.json_schema[subtype]
dblob = self.data_blob
dblob[subtype] = data
self.data_blob = dblob
self.save
end
def reset_search_results(subtype=BAND_SEARCH_TYPE_VALS[0])
reset_filter(subtype)
search_results_page(subtype)
end
def self.search_filter_json(user, subtype=BAND_SEARCH_TYPE_VALS[0])
self.user_search_filter(user).json[subtype]
end
def search_results_page(subtype=BAND_SEARCH_TYPE_VALS[0], filter=nil, page=1)
if filter
reset_filter(subtype, filter)
else
filter = self.data_blob[subtype]
end
rel = do_search(filter)
@page_number = [page.to_i, 1].max
rel = rel.paginate(:page => @page_number, :per_page => self.class::PER_PAGE)
rel = self.search_includes(rel)
@page_count = rel.total_pages
process_results_page(rel.all)
end
end
end

View File

@ -43,27 +43,31 @@ module JamRuby
3 => 'Expert',
}
JSON_SCHEMA = {
KEY_SORT_ORDER => self::SORT_VALS[0],
KEY_INSTRUMENTS => [],
KEY_GENRES => [],
KEY_SKILL => self::SKILL_VALS[0].to_s,
KEY_GIGS => self::GIG_COUNTS[0].to_s,
}
def self.json_schema
{
KEY_SORT_ORDER => self::SORT_VALS[0],
KEY_INSTRUMENTS => [],
KEY_GENRES => [],
KEY_SKILL => self::SKILL_VALS[0].to_s,
KEY_GIGS => self::GIG_COUNTS[0].to_s,
}
end
JSON_SCHEMA_KEYS = self::JSON_SCHEMA.keys
MULTI_VALUE_KEYS = self::JSON_SCHEMA.collect { |kk,vv| vv.is_a?(Array) ? kk : nil }.compact
SINGLE_VALUE_KEYS = self::JSON_SCHEMA.keys - self::MULTI_VALUE_KEYS
SEARCH_FILTER_META = {
per_page: self::PER_PAGE,
filter_keys: {
keys: self::JSON_SCHEMA_KEYS,
multi: self::MULTI_VALUE_KEYS,
single: self::SINGLE_VALUE_KEYS,
},
sort_order: { keys: self::SORT_VALS, map: self::SORT_ORDERS },
}
def self.search_filter_meta(jschema=nil, sort_order=nil)
jschema ||= self.json_schema
schema_keys = jschema.keys
sort_order ||= { keys: self::SORT_VALS, map: self::SORT_ORDERS }
multi_keys = jschema.collect { |kk,vv| vv.is_a?(Array) ? kk : nil }.compact
{
per_page: self::PER_PAGE,
filter_keys: {
keys: schema_keys,
multi: multi_keys,
single: schema_keys - multi_keys,
},
sort_order: sort_order
}
end
RESULT_FOLLOW = :follows
RESULT_FRIEND = :friends
@ -88,7 +92,7 @@ module JamRuby
def self.create_search(user)
ms = self.new
ms.user = user
ms.data_blob = self::JSON_SCHEMA
ms.data_blob = self.json_schema
ms.save!
ms
end
@ -169,7 +173,7 @@ module JamRuby
end
def reset_filter
self.data_blob = self.class::JSON_SCHEMA
self.data_blob = self.class.json_schema
self.save
end
@ -183,7 +187,7 @@ module JamRuby
end
def is_blank?
self.data_blob == self.class::JSON_SCHEMA
self.data_blob == self.class.json_schema
end
def description

View File

@ -1,6 +1,7 @@
module JamRuby
class MusicianSearch < BaseSearch
cattr_accessor :jschema, :search_meta
attr_accessor :user_counters
KEY_STUDIOS = 'studio_sessions'
@ -47,16 +48,22 @@ module JamRuby
INTEREST_VALS[5] => 'Co-Writing'
}
JSON_SCHEMA = BaseSearch::JSON_SCHEMA.merge({
KEY_INTERESTS => INTEREST_VALS[0],
KEY_STUDIOS => STUDIO_COUNTS[0].to_s,
KEY_AGES => []
})
def self.json_schema
return @@jschema if @@jschema
@@jschema = BaseSearch.json_schema.merge({
KEY_INTERESTS => INTEREST_VALS[0],
KEY_STUDIOS => STUDIO_COUNTS[0].to_s,
KEY_AGES => []
})
end
SEARCH_FILTER_META = BaseSearch::SEARCH_FILTER_META.merge({
interests: { keys: INTEREST_VALS, map: INTERESTS },
ages: { keys: AGE_COUNTS, map: AGES }
})
def self.search_filter_meta
return @@search_meta if @@search_meta
@@search_meta = super.merge({
interests: { keys: INTEREST_VALS, map: INTERESTS },
ages: { keys: AGE_COUNTS, map: AGES }
})
end
def self.search_target_class
User
@ -226,7 +233,7 @@ module JamRuby
end
def is_blank?
self.data_blob == JSON_SCHEMA
self.data_blob == self.class.json_schema
end
def description

View File

@ -169,6 +169,7 @@ module JamRuby
has_many :performance_samples, :class_name => "JamRuby::PerformanceSample", :foreign_key=> 'player_id'
has_one :musician_search, :class_name => 'JamRuby::MusicianSearch'
has_one :band_search, :class_name => 'JamRuby::BandSearch'
before_save :create_remember_token, :if => :should_validate_password?
before_save :stringify_avatar_info , :if => :updating_avatar

View File

@ -1,257 +0,0 @@
(function(context,$) {
"use strict";
context.JK = context.JK || {};
context.JK.FindBandScreen = function(app) {
var logger = context.JK.logger;
var bands = {};
var bandList;
var instrument_logo_map = context.JK.getInstrumentIconMap24();
var did_show_band_page = false;
var page_num=1, page_count=0;
var helpBubble = context.JK.HelpBubbleHelper;
var $screen = $('#bands-screen');
var $results = $screen.find('#band-filter-results');
function loadBands(queryString) {
// squelch nulls and undefines
queryString = !!queryString ? queryString : "";
$.ajax({
type: "GET",
url: "/api/search.json?" + queryString,
success: afterLoadBands,
error: app.ajaxError
});
}
function search() {
did_show_band_page = true;
var queryString = 'srch_b=1&page='+page_num+'&';
// order by
var orderby = $('#band_order_by').val();
if (typeof orderby != 'undefined' && orderby.length > 0) {
queryString += "orderby=" + orderby + '&';
}
// genre filter
var genre = $('#band_genre').val();
if (typeof genre != 'undefined' && !(genre === '')) {
queryString += "genre=" + genre + '&';
}
// distance filter
var query_param = $('#band_query_distance').val();
if (query_param !== null && query_param.length > 0) {
var matches = query_param.match(/(\d+)/);
if (0 < matches.length) {
var distance = matches[0];
queryString += "distance=" + distance + '&';
}
}
loadBands(queryString);
}
function refreshDisplay() {
clearResults();
search();
}
function afterLoadBands(mList) {
// display the 'no bands' banner if appropriate
var $noBandsFound = $('#bands-none-found');
bandList = mList;
if(bandList.length == 0) {
$noBandsFound.show();
bands = [];
}
else {
$noBandsFound.hide();
bands = bandList['bands'];
if (!(typeof bands === 'undefined')) {
$('#band-filter-city').text(bandList['city']);
if (0 == page_count) {
page_count = bandList['page_count'];
}
renderBands();
}
}
}
function renderBands() {
var ii, len;
var mTemplate = $('#template-find-band-row').html();
var pTemplate = $('#template-band-player-info').html();
var aTemplate = $('#template-band-action-btns').html();
var eTemplate = $('#template-band-edit-btns').html();
var bVals, bb, renderings='';
var instr_logos, instr;
var players, playerVals, aPlayer, isMember;
for (ii=0, len=bands.length; ii < len; ii++) {
bb = bands[ii];
instr_logos = '';
players = '';
playerVals = {};
isMember = false;
for (var jj=0, ilen=bb['players'].length; jj<ilen; jj++) {
var toolTip = '';
aPlayer = bb['players'][jj];
var player_instrs = '';
var iter_pinstruments = aPlayer['instruments'].split(',');
for (var kk=0, klen=iter_pinstruments.length; kk<klen; kk++) {
var pinstr = iter_pinstruments[kk];
var toolTip = '';
if (pinstr in instrument_logo_map) {
instr = instrument_logo_map[pinstr].asset;
toolTip = pinstr;
}
player_instrs += '<img src="' + instr + '" title="' + toolTip + '"/>';
}
if (!isMember) {
isMember = aPlayer.user_id == context.JK.currentUserId;
}
playerVals = {
user_id: aPlayer.user_id,
player_name: aPlayer.name,
profile_url: '/client#/profile/' + aPlayer.user_id,
avatar_url: context.JK.resolveAvatarUrl(aPlayer.photo_url),
player_instruments: player_instrs
};
players += context.JK.fillTemplate(pTemplate, playerVals);
}
var actionVals, band_actions;
if (isMember) {
actionVals = {
profile_url: "/client#/bandProfile/" + bb.id,
band_edit_url: "/client#/band/setup/" + bb.id + '/step1',
band_member_url: "/client#/band/setup/" + bb.id + '/step2'
};
band_actions = context.JK.fillTemplate(eTemplate, actionVals);
} else {
actionVals = {
profile_url: "/client#/bandProfile/" + bb.id,
button_follow: bb['is_following'] ? '' : 'button-orange',
button_message: 'button-orange'
};
band_actions = context.JK.fillTemplate(aTemplate, actionVals);
}
var bgenres = '';
for (jj=0, ilen=bb['genres'].length; jj<ilen; jj++) {
bgenres += bb['genres'][jj]['description'] + '<br />';
}
bgenres += '<br />';
bVals = {
avatar_url: context.JK.resolveBandAvatarUrl(bb.photo_url),
profile_url: "/client#/bandProfile/" + bb.id,
band_name: bb.name,
band_location: bb.city + ', ' + bb.state,
genres: bgenres,
instruments: instr_logos,
biography: bb['biography'],
follow_count: bb['follow_count'],
recording_count: bb['recording_count'],
session_count: bb['session_count'],
band_id: bb['id'],
band_player_template: players,
band_action_template: band_actions
};
var $rendering = $(context.JK.fillTemplate(mTemplate, bVals))
var $offsetParent = $results.closest('.content');
var data = {entity_type: 'band'};
var options = {positions: ['top', 'bottom', 'right', 'left'], offsetParent: $offsetParent};
context.JK.helpBubble($('.follower-count', $rendering), 'follower-count', data, options);
context.JK.helpBubble($('.recording-count', $rendering), 'recording-count', data, options);
context.JK.helpBubble($('.session-count', $rendering), 'session-count', data, options);
$results.append($rendering);
}
$('.search-m-follow').on('click', followBand);
context.JK.bindHoverEvents();
}
function beforeShow(data) {
}
function afterShow(data) {
if (!did_show_band_page) {
refreshDisplay();
}
}
function clearResults() {
bands = {};
$('#band-filter-results').empty();
page_num = 1;
page_count = 0;
}
function followBand(evt) {
// if the band is already followed, remove the button-orange class, and prevent
// the link from working
if (0 == $(this).closest('.button-orange').size()) return false;
$(this).click(function(ee) {ee.preventDefault();});
evt.stopPropagation();
var newFollowing = {};
newFollowing.band_id = $(this).parent().data('band-id');
var url = "/api/users/" + context.JK.currentUserId + "/followings";
$.ajax({
type: "POST",
dataType: "json",
contentType: 'application/json',
url: url,
data: JSON.stringify(newFollowing),
processData: false,
success: function(response) {
// remove the orange look to indicate it's not selectable
// @FIXME -- this will need to be tweaked when we allow unfollowing
$('div[data-band-id='+newFollowing.band_id+'] .search-m-follow').removeClass('button-orange').addClass('button-grey');
},
error: app.ajaxError(arguments)
});
}
function events() {
$('#band_query_distance').change(refreshDisplay);
$('#band_genre').change(refreshDisplay);
$('#band_order_by').change(refreshDisplay);
$('#band-filter-results').closest('.content-body-scroller').bind('scroll', function() {
if ($(this).scrollTop() + $(this).innerHeight() >= $(this)[0].scrollHeight) {
if (page_num < page_count) {
page_num += 1;
search();
}
}
});
}
function initialize() {
var screenBindings = {
'beforeShow': beforeShow,
'afterShow': afterShow
};
app.bindScreen('bands', screenBindings);
events();
}
this.initialize = initialize;
this.renderBands = renderBands;
this.afterShow = afterShow;
this.clearResults = clearResults;
return this;
}
})(window,jQuery);

View File

@ -1639,6 +1639,19 @@
});
}
function getBandSearchFilter(query) {
var qarg = query === undefined ? '' : query;
return $.get("/api/search/bands.json?"+qarg);
}
function postBandSearchFilter(query) {
return $.ajax({
type: "POST",
url: "/api/search/bands.json",
data: query
});
}
function getMount(options) {
var id = getId(options);
return $.ajax({
@ -1852,6 +1865,8 @@
this.addRecordingTimeline = addRecordingTimeline;
this.getMusicianSearchFilter = getMusicianSearchFilter;
this.postMusicianSearchFilter = postMusicianSearchFilter;
this.getBandSearchFilter = getBandSearchFilter;
this.postBandSearchFilter = postBandSearchFilter;
this.playJamTrack = playJamTrack;
this.createSignupHint = createSignupHint;
this.createAlert = createAlert;
@ -1860,4 +1875,4 @@
};
})(window,jQuery);
})(window,jQuery);

View File

@ -31,12 +31,6 @@ context.JK.BaseSearchFilter = class BaseSearchFilter
this.registerResultsPagination()
@screen.find('#btn-'+@searchType+'-search-builder').on 'click', =>
this.showBuilder()
@screen.find('#btn-'+@searchType+'-search-reset').on 'click', =>
this.resetFilter()
afterShow: () =>
@screen.find('#'+@searchType+'-search-filter-results').show()
@screen.find('#'+@searchType+'-search-filter-builder').hide()
@ -50,6 +44,9 @@ context.JK.BaseSearchFilter = class BaseSearchFilter
afterHide: () =>
@resultsListContainer.empty()
searchMetaData: () =>
@searchMeta
renderSearchFilter: () =>
$.when(@restGet()).done (sFilter) =>
this.loadSearchFilter(sFilter)
@ -69,8 +66,8 @@ context.JK.BaseSearchFilter = class BaseSearchFilter
_populateSelectIdentifier: (identifier) =>
elem = $ '#'+@searchType+'-search-filter-builder select[name='+identifier+']'
struct = @searchMeta[identifier]['map']
keys = @searchMeta[identifier]['keys']
struct = this.searchMetaData()[identifier]['map']
keys = this.searchMetaData()[identifier]['keys']
this._populateSelectWithKeys(struct, @searchFilter[identifier], keys, elem)
_populateSelectWithInt: (sourceStruct, selection, element) =>
@ -171,13 +168,19 @@ context.JK.BaseSearchFilter = class BaseSearchFilter
getUserFilterResults: () =>
if this.willSearch(true)
@restGet('results=true').done(this.didSearch)
this.doRestGet()
doRestGet: (query) =>
query2 = 'results=true&'
unless (typeof query == "undefined")
query2 += query
@restGet(query2).done(this.didSearch)
performSearch: () =>
if this.willSearch(true)
$.each @searchMeta.filter_keys.single, (index, key) =>
$.each this.searchMetaData().filter_keys.single, (index, key) =>
@searchFilter[key] = this._builderSelectValue(key)
$.each @searchMeta.filter_keys.multi, (index, key) =>
$.each this.searchMetaData().filter_keys.multi, (index, key) =>
@searchFilter[key] = this._builderSelectMultiValue(key)
@restPost({ filter: JSON.stringify(@searchFilter), page: @pageNumber }).done(this.didSearch)
@ -239,6 +242,10 @@ context.JK.MusicianSearchFilter = class MusicianSearchFilter extends BaseSearchF
init: (app) =>
super(app)
@screen.find('#btn-'+@searchType+'-search-builder').on 'click', =>
this.showBuilder()
@screen.find('#btn-'+@searchType+'-search-reset').on 'click', =>
this.resetFilter()
renderSearchFilter: () =>
super()
@ -293,8 +300,8 @@ context.JK.MusicianSearchFilter = class MusicianSearchFilter extends BaseSearchF
_populateAges: () =>
@screen.find('#search-filter-ages').empty()
ages_map = @searchMeta['ages']['map']
$.each @searchMeta['ages']['keys'], (index, key) =>
ages_map = this.searchMetaData()['ages']['map']
$.each this.searchMetaData()['ages']['keys'], (index, key) =>
ageTemplate = @screen.find('#template-search-filter-setup-ages').html()
selected = ''
ageLabel = ages_map[key]
@ -491,3 +498,148 @@ context.JK.MusicianSearchFilter = class MusicianSearchFilter extends BaseSearchF
registerResultsPagination: () =>
super()
context.JK.BandSearchFilter = class BandSearchFilter extends BaseSearchFilter
constructor: () ->
super()
@searchType = 'band'
@searchTypeS = @searchType+'s'
@restGet = @rest.getBandSearchFilter
@restPost = @rest.postBandSearchFilter
@searchMeta = gon.band_search_meta
@searchSubType = 'to_join'
init: (app) =>
super(app)
@screen.find('#btn-'+@searchType+'-search-builder-to_join').on 'click', =>
this.showBuilderToJoin()
@screen.find('#btn-'+@searchType+'-search-builder-to_hire').on 'click', =>
this.showBuilderToHire()
showBuilderToJoin: () =>
@searchSubType = 'to_join'
this.showBuilder()
showBuilderToHire: () =>
@searchSubType = 'to_hire'
this.showBuilder()
searchMetaData: () =>
@searchMeta[@searchSubType]
renderSearchFilter: () =>
super()
_searchFilterArgsToJoin: () =>
args =
tour_option: @searchFilter.data_blob.tour_option
skill_level: @searchFilter.data_blob.skill_level
play_commit: @searchFilter.data_blob.play_commit
band_type: @searchFilter.data_blob.band_type
concert_gigs: @searchFilter.data_blob.concert_gigs
_searchFilterArgsToHire: () =>
args =
skill_level: @searchFilter.data_blob.skill_level
concert_gigs: @searchFilter.data_blob.concert_gigs
perform_samples: @searchFilter.data_blob.perform_samples
max_cost: @searchFilter.data_blob.max_cost
free_gigs: @searchFilter.data_blob.free_gigs
_populateSearchFilterToJoin: () =>
this._populateInstruments()
this._populateSkill()
this._populateGigs()
this._populateBandType()
this._populatePlayCommit()
this._populateTourOption()
_populateSearchFilterToHire: () =>
loadSearchFilter: (sFilter) =>
super(sFilter)
@searchFilter = JSON.parse(sFilter)
switch @searchSubType
when 'to_join' then args = _searchFilterArgsToJoin()
when 'to_hire' then args = _searchFilterArgsToHire()
template = context.JK.fillTemplate(@screen.find('#template-band-search-filter-'+@searchSubType).html(), args)
content_root = @screen.find('#band-search-filter-builder')
content_root.html template
@screen.find('#btn-perform-band-search').on 'click', =>
this.performSearch()
@screen.find('#btn-band-search-cancel').on 'click', =>
this.cancelFilter()
this._populateGenres()
this._populateSortOrder()
switch @searchSubType
when 'to_join' then _populateSearchFilterToJoin()
when 'to_hire' then _populateSearchFilterToHire()
_populateSortOrder: () =>
this._populateSelectIdentifier('sort_order')
_populateGenres: () =>
super()
_populateInstruments: () =>
super()
willSearch: (reload) =>
super(reload)
didSearch: (response) =>
super(response)
resetFilter: () =>
super()
cancelFilter: () =>
super()
doRestGet: (query) =>
super('subtype='+@searchSubType)
performSearch: () =>
super()
renderResultsHeader: () =>
super()
renderResultsPage: () =>
super()
this.renderResultsHeader() if @pageNumber == 1
bands = @searchResults.bands
len = bands.length
if 0 == len
@screen.find('#band-search-filter-results-list-blank').show()
@screen.find('#band-search-filter-results-list-blank').html('No results found')
return
else
@screen.find('#band-search-filter-results-list-blank').hide()
_bindMessageBand: () =>
_bindFriendBand: () =>
_bindFollowBand: () =>
_formatLocation: (band) ->
friendRequestCallback: (user_id)=>
# TODO:
paginate: () =>
super()
registerResultsPagination: () =>
super()

View File

@ -350,4 +350,36 @@
label {
margin-bottom:2px;
}
}
#musicians-screen {
.builder-section {
padding: 10px;
margin-bottom: 20px;
}
#bands-filter-to-join {
.builder-section {
padding: 10px;
margin-bottom: 20px;
}
.col-left {
float: left;
width: 50%;
margin-left: auto;
margin-right: auto;
}
.col-right {
float: right;
width: 50%;
margin-left: auto;
margin-right: auto;
}
}
}

View File

@ -7,7 +7,7 @@ class ApiSearchController < ApiController
def index
if 1 == params[Search::PARAM_MUSICIAN].to_i || 1 == params[Search::PARAM_BAND].to_i
query = params.clone
query = parasobj.clone
query[:remote_ip] = request.remote_ip
if 1 == query[Search::PARAM_MUSICIAN].to_i
@search = Search.musician_filter(query, current_user)
@ -32,13 +32,35 @@ class ApiSearchController < ApiController
end
elsif request.post?
ms = MusicianSearch.user_search_filter(current_user)
sobj = MusicianSearch.user_search_filter(current_user)
filter = params[:filter]
if filter == 'reset'
@search = ms.reset_search_results
@search = sobj.reset_search_results
else
json = JSON.parse(filter, :create_additions => false)
@search = ms.search_results_page(json, [params[:page].to_i, 1].max)
@search = sobj.search_results_page(json, [params[:page].to_i, 1].max)
end
respond_with @search, responder: ApiResponder, status: 201, template: 'api_search/index'
end
end
def bands
if request.get?
if params[:results]
@search = BandSearch.user_search_filter(current_user).search_results_page(params[:subtype])
respond_with @search, responder: ApiResponder, status: 201, template: 'api_search/index'
else
render :json => BandSearch.search_filter_json(current_user, params[:subtype]), :status => 200
end
elsif request.post?
sobj = BandSearch.user_search_filter(current_user)
filter = params[:filter]
if filter == 'reset'
@search = sobj.reset_search_results(params[:subtype])
else
json = JSON.parse(filter, :create_additions => false)
@search = sobj.search_results_page(json, [params[:page].to_i, 1].max)
end
respond_with @search, responder: ApiResponder, status: 201, template: 'api_search/index'
end

View File

@ -69,7 +69,12 @@ class SpikesController < ApplicationController
end
def musician_search_filter
# gon.musician_search_meta = MusicianSearch::SEARCH_FILTER_META
# gon.musician_search_meta = MusicianSearch.search_filter_meta
render :layout => 'web'
end
def band_search_filter
gon.band_search_meta = BandSearch.search_filter_meta
render :layout => 'web'
end

View File

@ -67,8 +67,8 @@ module ClientHelper
gon.ftue_network_test_duration = Rails.application.config.ftue_network_test_duration
gon.ftue_network_test_max_clients = Rails.application.config.ftue_network_test_max_clients
gon.ftue_maximum_gear_latency = Rails.application.config.ftue_maximum_gear_latency
gon.musician_search_meta = MusicianSearch::SEARCH_FILTER_META
gon.band_search_meta = BandSearch::SEARCH_FILTER_META
gon.musician_search_meta = MusicianSearch.search_filter_meta
gon.band_search_meta = BandSearch.search_filter_meta
# is this the native client or browser?
@nativeClient = is_native_client?

View File

@ -58,6 +58,40 @@ if @search.is_a?(MusicianSearch)
last_jam_audio_latency(musician)
end
}
elsif @search.is_a?(BandSearch)
node :page_count do |foo|
@search.page_count
end
child(:results => :bands) {
attributes :id, :name, :city, :state, :country, :photo_url, :biography, :logo_url, :website
node :is_following do |band|
@search.is_follower?(band)
end
node :biography do |band|
band.biography.nil? ? "" : band.biography
end
child :genres => :genres do
attributes :genre_id, :description
end
child :users => :players do |pl|
node :user_id do |uu| uu.id end
node :photo_url do |uu| uu.photo_url end
node :name do |uu| uu.name end
node :instruments do |uu| uu.instruments.map(&:id).join(',') end
end
node :follow_count do |band| @search.follow_count(band) end
node :recording_count do |band| @search.record_count(band) end
node :session_count do |band| @search.session_count(band) end
}
else
if @search.session_invite_search?

View File

@ -0,0 +1,94 @@
.content-body-scroller
div#band-search-filter-builder.content-wrapper
div#band-search-filter-results.content-wrapper
div#band-search-filter-results-header
a#btn-band-search-builder-to_join.button-orange href="#" SEARCH FOR BAND TO JOIN
a#btn-band-search-reset-to_hire.button-grey href="#" SEARCH FOR BAND TO HIRE
div#band-search-filter-description
div.clearall
div#band-search-filter-spinner.spinner-large
div#band-search-filter-results-wrapper
div#band-search-filter-results-list-blank
div#band-search-filter-results-list.content-wrapper
div.paginate-wait
Fetching more results...
div.spinner-small
script#template-band-search-filter-to_join type="text/template"
#bands-filter-to_join
#band-search-filter-builder-top.builder-section
.col-left
h2 search bands
.col-right.builder-sort-order
.text-label Sort Results By:
select.easydropdown name="sort_order"
option selected="selected" value="{sort_order}" {sort_order}
.clearall
#band-search-filter-builder-middle1.builder-section
.col-left
.field
label for="search-filter-genres" Genres:
.search-filter-setup-genres.band-setup-genres
table#search-filter-genres cellpadding="10" cellspacing="6" width="100%"
.col-right
.field
label for="search-filter-instruments"
| Instruments &amp; Skill Level:
.search-filter-setup-instruments.band-setup-genres.builder-instruments
table#search-filter-instruments cellpadding="10" cellspacing="6" width="100%"
.clearall
#band-search-filter-builder-middle2.builder-section
.col-left
.field.builder-selector
label Type:
select.easydropdown name="band_type"
option selected="selected" value="{band_type}" {band_type}
.field.builder-selector
label Play Commitment:
select.easydropdown name="play_commit"
option selected="selected" value="{play_commit}" {play_commit}
.col-right
.field.builder-selector
label Status:
select.easydropdown name="skill_level"
option selected="selected" value="{skill_level}" {skill_level}
.field.builder-selector
label Concert Gigs Played:
select.easydropdown name="concert_gigs"
option selected="selected" value="{concert_gigs}" {concert_gigs}
.field.builder-selector
label Touring Option:
select.easydropdown name="tour_option"
option selected="selected" value="{tour_option}" {tour_option}
.clearall
.clearall
#band-search-filter-builder-bottom.builder-section.builder-action-buttons
.col-right
a#btn-perform-band-search.builder-button.button-orange href="#" SEARCH
a#btn-band-search-cancel.builder-button.button-grey href="#" CANCEL
script#template-search-filter-setup-instrument type="text/template"
tr data-instrument-id="{id}"
td <input type="checkbox" {checked} />{description}
td align="right" width="50%"
select.proficiency_selector name="proficiency"
option value="1" Beginner
option value="2" Intermediate
option value="3" Expert
script#template-search-filter-setup-genres type="text/template"
tr
td <input value="{id}" {checked} type="checkbox" />{description}
/! Session Row Template
script#template-search-band-row type="text/template"

View File

@ -1,86 +0,0 @@
<!-- Band Screen -->
<%= content_tag(:div, :layout => 'screen', 'layout-id' => 'bands', :class => "screen secondary", :id => "bands-screen") do -%>
<%= content_tag(:div, :class => :content) do -%>
<%= content_tag(:div, :class => 'content-head') do -%>
<%= content_tag(:div, image_tag("content/icon_bands.png", {:height => 19, :width => 19}), :class => 'content-icon') %>
<%= content_tag(:h1, 'bands') %>
<%= render "screen_navigation" %>
<% end -%>
<%= content_tag(:div, :class => 'content-body') do -%>
<%= form_tag('', {:id => 'find-band-form', :class => 'inner-content'}) do -%>
<%= render(:partial => "web_filter", :locals => {:search_type => Search::PARAM_BAND}) %>
<%= content_tag(:div, :class => 'filter-body') do %>
<%= content_tag(:div, :class => 'content-body-scroller') do -%>
<%= content_tag(:div, content_tag(:div, '', :id => 'band-filter-results', :class => 'filter-results'), :class => 'content-wrapper') %>
<% end -%>
<% end -%>
<% end -%>
<% end -%>
<% end -%>
<% end -%>
<!-- Session Row Template -->
<script type="text/template" id="template-find-band-row"><!-- -->
<div class="profile-band-list-result band-list-result">
<div class="f11">
<div class="left" style="width:63px;margin-top:-12px;">
<!-- avatar -->
<div class="avatar-small"><img src="{avatar_url}" /></div>
</div>
<div class="right mband-players" style="width:265px; margin-top:-4px;">
<table class="musicians" cellpadding="0" cellspacing="5">{band_player_template}</table>
</div>
<div class="" style="margin-left: 63px; margin-right: 275px;margin-top: 12px;">
<div class="first-row" data-hint="top-row">
<div class="lcol left">
<!-- name & location -->
<div class="result-name">{band_name}</div>
<div class="result-location">{band_location}</div>
<br />
<div id="result_genres" class="nowrap mt10">{genres}</div>
</div>
<div class="whitespace">
<div class="biography">{biography}</div>
</div>
<div class="clearleft"></div>
</div>
<div class="button-row">
<div class="lcol stats left">
<span class="follower-count">{follow_count} <img src="../assets/content/icon_followers.png" width="22" height="12" align="absmiddle" style="margin-right:4px;"/></span>
<span class="recording-count">{recording_count} <img src="../assets/content/icon_recordings.png" width="12" height="13" align="absmiddle" style="margin-right:4px;"/></span>
<span class="session-count">{session_count} <img src="../assets/content/icon_session_tiny.png" width="12" height="12" align="absmiddle" /></span>
</div>
<div class="clearall"></div>
<div class="result-list-button-wrapper" data-band-id={band_id}>
{band_action_template}
</div>
<div class="clearall"></div>
</div>
</div>
</div>
</div>
</script>
<script type="text/template" id="template-band-action-btns">
<a href="{profile_url}" class="button-orange smallbutton">PROFILE</a>
<a href="#" class="{button_follow} smallbutton search-m-follow">FOLLOW</a>
</script>
<script type="text/template" id="template-band-edit-btns">
<a href="{profile_url}" class="button-orange smallbutton">PROFILE</a>
<a href="{band_edit_url}" class="button-orange smallbutton">EDIT BAND</a>
<a href="{band_member_url}" class="button-orange smallbutton">INVITE</a>
</script>
<script type="text/template" id="template-band-player-info">
<tr>
<td>
<a href="{profile_url}" user-id="{user_id}" hoveraction="musician" class="avatar-tiny"><img src="{avatar_url}" /></a>
</td>
<td style="padding: 0 4px;width:88px;">
<a user-id="{user_id}" hoveraction="musician" href="{profile_url}"><strong>{player_name}</strong></a>
</td>
<td class="instruments">{player_instruments}</td>
</tr>
</script>

View File

@ -0,0 +1,140 @@
#bands-screen.screen.secondary layout="screen" layout-id="bands"
.content
.content-head
.content-icon
img alt="Icon_bands" height="19" src="/assets/content/icon_bands.png" width="19" /
h1 bands
= render "screen_navigation"
.content-body
= render "clients/band_search_filter"
script#template-band-search-filter-to_join type="text/template"
#bands-filter-to_join
#band-search-filter-builder-top.builder-section
.col-left
h2 search bands
.col-right.builder-sort-order
.text-label Sort Results By:
select.easydropdown name="sort_order"
option selected="selected" value="{sort_order}" {sort_order}
.clearall
#band-search-filter-builder-middle1.builder-section
.col-left
.field
label for="search-filter-genres" Genres:
.search-filter-setup-genres.band-setup-genres
table#search-filter-genres cellpadding="10" cellspacing="6" width="100%"
.col-right
.field
label for="search-filter-instruments"
| Instruments &amp; Skill Level:
.search-filter-setup-instruments.band-setup-genres.builder-instruments
table#search-filter-instruments cellpadding="10" cellspacing="6" width="100%"
.clearall
#band-search-filter-builder-middle2.builder-section
.col-left
.field.builder-selector
label Type:
select.easydropdown name="band_type"
option selected="selected" value="{band_type}" {band_type}
.field.builder-selector
label Play Commitment:
select.easydropdown name="play_commit"
option selected="selected" value="{play_commit}" {play_commit}
.col-right
.field.builder-selector
label Status:
select.easydropdown name="skill_level"
option selected="selected" value="{skill_level}" {skill_level}
.field.builder-selector
label Concert Gigs Played:
select.easydropdown name="concert_gigs"
option selected="selected" value="{concert_gigs}" {concert_gigs}
.field.builder-selector
label Touring Option:
select.easydropdown name="tour_option"
option selected="selected" value="{tour_option}" {tour_option}
.clearall
.clearall
#band-search-filter-builder-bottom.builder-section.builder-action-buttons
.col-right
a#btn-perform-band-search.builder-button.button-orange href="#" SEARCH
a#btn-band-search-cancel.builder-button.button-grey href="#" CANCEL
/! Session Row Template
script#template-search-band-row type="text/template"
.profile-band-list-result.band-list-result
.f11
.left style="width:63px;margin-top:-12px;"
/! avatar
.avatar-small
img src="{avatar_url}" /
.right.mband-players style="width:265px; margin-top:-4px;"
table.musicians cellpadding="0" cellspacing="5"
| {band_player_template}
div style="margin-left: 63px; margin-right: 275px;margin-top: 12px;"
.first-row data-hint="top-row"
.lcol.left
/! name and location
.result-name
| {band_name}
.result-location
| {band_location}
br /
#result_genres.nowrap.mt10
| {genres}
.whitespace
.biography
| {biography}
.clearleft
.button-row
.lcol.stats.left
span.follower-count
| {follow_count}
img src="../assets/content/icon_followers.png" width="22" height="12" align="absmiddle" style="margin-right:4px;" /
span.recording-count
| {recording_count}
img src="../assets/content/icon_recordings.png" width="12" height="13" align="absmiddle" style="margin-right:4px;" /
span.session-count
| {session_count}
img src="../assets/content/icon_session_tiny.png" width="12" height="12" align="absmiddle" /
.clearall
.result-list-button-wrapper data-band-id="{band_id}"
| {band_action_template}
.clearall
script#template-search-band-action-btns type="text/template"
a.button-orange smallbutton href="{profile_url}"
PROFILE
a class="{button_follow} smallbutton search-m-follow" href="#"
FOLLOW
script#template-search-band-edit-btns type="text/template"
a href="{profile_url}" class="button-orange smallbutton"
PROFILE
a href="{band_edit_url}" class="button-orange smallbutton"
EDIT BAND
a href="{band_member_url}" class="button-orange smallbutton"
INVITE
script#template-search-band-player-info type="text/template"
tr
td
a.avatar-tiny href="{profile_url}" user-id="{user_id}" hoveraction="musician"
img src="{avatar_url}" /
td style="padding: 0 4px;width:88px"
a user-id="{user_id}" hoveraction="musician" href="{profile_url}"
strong
| {player_name}
td.instruments
| {player_instruments}

View File

@ -296,8 +296,10 @@
// var findMusicianScreen = new JK.FindMusicianScreen(JK.app);
//findMusicianScreen.initialize(JK.TextMessageDialogInstance);
var findBandScreen = new JK.FindBandScreen(JK.app);
findBandScreen.initialize();
var findBandScreen = new JK.BandSearchFilter();
findBandScreen.init(JK.app);
// var findBandScreen = new JK.FindBandScreen(JK.app);
// findBandScreen.initialize();
var sessionScreen = new JK.SessionScreen(JK.app);
sessionScreen.initialize(localRecordingsDialog, recordingFinishedDialog, JK.FriendSelectorDialogInstance);

View File

@ -0,0 +1,15 @@
= javascript_include_tag "profile_utils"
= javascript_include_tag "member_search_filter"
= stylesheet_link_tag "client/band"
#band_search_spike
= render "clients/band_search_filter"
javascript:
var initialized = false;
$(document).on('JAMKAZAM_READY', function(e, data) {
setTimeout(function() {
window.band_search_filter = new JK.BandSearchFilter();
band_search_filter.init();
band_search_filter.afterShow();
}, 1)
});

View File

@ -111,6 +111,7 @@ SampleApp::Application.routes.draw do
match '/site_validate', to: 'spikes#site_validate'
match '/recording_source', to: 'spikes#recording_source'
match '/musician_search_filter', to: 'spikes#musician_search_filter'
match '/band_search_filter', to: 'spikes#band_search_filter'
# junk pages
match '/help', to: 'static_pages#help'
@ -451,6 +452,7 @@ SampleApp::Application.routes.draw do
# search
match '/search' => 'api_search#index', :via => :get
match '/search/musicians' => 'api_search#musicians', :via => [:get, :post]
match '/search/bands' => 'api_search#bands', :via => [:get, :post]
# join requests
match '/join_requests/:id' => 'api_join_requests#show', :via => :get, :as => 'api_join_request_detail'

View File

@ -128,7 +128,7 @@ end
def make_band_members
Band.find_each do |bb|
User.order('RANDOM()').limit(4).each do |uu|
BandMusician.create!({:user_id => uu.id, :band_id => bb.id})
BandMusician.create({:user_id => uu.id, :band_id => bb.id})
end
end
end