merged teacher search

This commit is contained in:
Seth Call 2016-01-28 13:55:17 -06:00
parent 50e2090f25
commit 641a553dcc
34 changed files with 1306 additions and 153 deletions

View File

@ -1,40 +1,35 @@
ActiveAdmin.register_page "Monthly Stats" do
menu :parent => 'Reports'
distinct_users = MusicSession.select([:month, :count]).find_by_sql("select date_trunc('month', msuh.created_at)::date as month, count(distinct(user_id)) from music_sessions_user_history msuh group by month order by month desc;")
total_session = MusicSession.select([:month, :count]).find_by_sql("select date_trunc('month', ms.created_at)::date as month, count(id) from music_sessions ms where started_at is not null group by month order by month desc;")
total_jamtrack_sessions = MusicSession.select([:month, :count]).find_by_sql("select date_trunc('month', jts.created_at)::date as month, count(distinct(music_session_id)) from jam_track_sessions jts where session_type = 'session' group by month order by month desc;")
total_webplayer_sessions = MusicSession.select([:month, :count]).find_by_sql("select date_trunc('month', jts.created_at)::date as month, count(id) from jam_track_sessions jts where session_type = 'browser' group by month order by month desc;")
distinct_jamtrack_users = MusicSession.select([:month, :count]).find_by_sql("select date_trunc('month', jts.created_at)::date as month, count(distinct(user_id)) from jam_track_sessions jts group by month order by month desc;")
content :title => "Month Stats" do
content :title => "Monthly Stats" do
h2 "Distinct Users Playing in Sessions"
table_for distinct_users do
table_for MusicSession.select([:month, :count]).find_by_sql("select date_trunc('month', msuh.created_at)::date as month, count(distinct(user_id)) from music_sessions_user_history msuh group by month order by month desc;") do
column "Month", Proc.new { |row| Date.parse(row.month).strftime('%B %Y') }
column "Users", :count
end
endF
h2 "Music Sessions"
table_for total_session do
table_for MusicSession.select([:month, :count]).find_by_sql("select date_trunc('month', ms.created_at)::date as month, count(id) from music_sessions ms where started_at is not null group by month order by month desc;") do
column "Month", Proc.new { |row| Date.parse(row.month).strftime('%B %Y') }
column "Sessions", :count
end
h2 "Distinct Users Who Played with a JamTrack"
table_for distinct_jamtrack_users do
table_for MusicSession.select([:month, :count]).find_by_sql("select date_trunc('month', jts.created_at)::date as month, count(distinct(user_id)) from jam_track_sessions jts group by month order by month desc;") do
column "Month", Proc.new { |row| Date.parse(row.month).strftime('%B %Y') }
column "Users", :count
end
h2 "Music Sessions with JamTracks Played"
table_for total_jamtrack_sessions do
table_for MusicSession.select([:month, :count]).find_by_sql("select date_trunc('month', jts.created_at)::date as month, count(distinct(music_session_id)) from jam_track_sessions jts where session_type = 'session' group by month order by month desc;") do
column "Month", Proc.new { |row| Date.parse(row.month).strftime('%B %Y') }
column "Sessions", :count
end
h2 "JamTrack Web Player Sessions"
table_for total_webplayer_sessions do
table_for MusicSession.select([:month, :count]).find_by_sql("select date_trunc('month', jts.created_at)::date as month, count(id) from jam_track_sessions jts where session_type = 'browser' group by month order by month desc;") do
column "Month", Proc.new { |row| Date.parse(row.month).strftime('%B %Y') }
column "Sessions", :count
end

View File

@ -33,110 +33,201 @@ module JamRuby
default_scope { includes(:genres) }
class << self
def save_teacher(user, params)
teacher = build_teacher(user, params)
teacher.save
teacher
def self.index(user, params = {})
limit = params[:per_page]
limit ||= 20
limit = limit.to_i
query = User.joins(:teacher)
instruments = params[:instruments]
if instruments && !instruments.blank? && instruments.length > 0
query = query.joins("inner JOIN teachers_instruments AS tinst ON tinst.teacher_id = teachers.id")
.where("tinst.instrument_id IN (?)", instruments)
end
def build_teacher(user, params)
# ensure person creating this Teacher is a Musician
unless user && user.musician?
raise JamPermissionError, "must be a musician"
end
teacher = user.teacher
teacher ||= user.build_teacher()
teacher.user = user
teacher.website = params[:website] if params.key?(:website)
teacher.biography = params[:biography] if params.key?(:biography)
teacher.introductory_video = params[:introductory_video] if params.key?(:introductory_video)
teacher.introductory_video = params[:introductory_video] if params.key?(:introductory_video)
teacher.years_teaching = params[:years_teaching] if params.key?(:years_teaching)
teacher.years_playing = params[:years_playing] if params.key?(:years_playing)
teacher.teaches_age_lower = params[:teaches_age_lower] if params.key?(:teaches_age_lower)
teacher.teaches_age_upper = params[:teaches_age_upper] if params.key?(:teaches_age_upper)
teacher.website = params[:website] if params.key?(:website)
teacher.biography = params[:biography] if params.key?(:biography)
teacher.teaches_beginner = params[:teaches_beginner] if params.key?(:teaches_beginner)
teacher.teaches_intermediate = params[:teaches_intermediate] if params.key?(:teaches_intermediate)
teacher.teaches_advanced = params[:teaches_advanced] if params.key?(:teaches_advanced)
teacher.prices_per_lesson = params[:prices_per_lesson] if params.key?(:prices_per_lesson)
teacher.prices_per_month = params[:prices_per_month] if params.key?(:prices_per_month)
teacher.lesson_duration_30 = params[:lesson_duration_30] if params.key?(:lesson_duration_30)
teacher.lesson_duration_45 = params[:lesson_duration_45] if params.key?(:lesson_duration_45)
teacher.lesson_duration_60 = params[:lesson_duration_60] if params.key?(:lesson_duration_60)
teacher.lesson_duration_90 = params[:lesson_duration_90] if params.key?(:lesson_duration_90)
teacher.lesson_duration_120 = params[:lesson_duration_120] if params.key?(:lesson_duration_120)
teacher.price_per_lesson_30_cents = params[:price_per_lesson_30_cents] if params.key?(:price_per_lesson_30_cents)
teacher.price_per_lesson_45_cents = params[:price_per_lesson_45_cents] if params.key?(:price_per_lesson_45_cents)
teacher.price_per_lesson_60_cents = params[:price_per_lesson_60_cents] if params.key?(:price_per_lesson_60_cents)
teacher.price_per_lesson_90_cents = params[:price_per_lesson_90_cents] if params.key?(:price_per_lesson_90_cents)
teacher.price_per_lesson_120_cents = params[:price_per_lesson_120_cents] if params.key?(:price_per_lesson_120_cents)
teacher.price_per_month_30_cents = params[:price_per_month_30_cents] if params.key?(:price_per_month_30_cents)
teacher.price_per_month_45_cents = params[:price_per_month_45_cents] if params.key?(:price_per_month_45_cents)
teacher.price_per_month_60_cents = params[:price_per_month_60_cents] if params.key?(:price_per_month_60_cents)
teacher.price_per_month_90_cents = params[:price_per_month_90_cents] if params.key?(:price_per_month_90_cents)
teacher.price_per_month_120_cents = params[:price_per_month_120_cents] if params.key?(:price_per_month_120_cents)
# Many-to-many relations:
if params.key?(:genres)
genres = params[:genres]
genres = [] if genres.nil?
teacher.genres = genres.collect{|genre_id| Genre.find(genre_id)}
end
if params.key?(:instruments)
instruments = params[:instruments]
instruments = [] if instruments.nil?
teacher.instruments = instruments.collect{|instrument_id| Instrument.find(instrument_id)}
end
if params.key?(:subjects)
subjects = params[:subjects]
subjects = [] if subjects.nil?
teacher.subjects = subjects.collect{|subject_id| Subject.find(subject_id)}
end
if params.key?(:languages)
languages = params[:languages]
languages = [] if languages.nil?
teacher.languages = languages.collect{|language_id| Language.find(language_id)}
end
# Experience:
[:teaching, :education, :award].each do |experience_type|
key = "experiences_#{experience_type}".to_sym
if params.key?(key)
list = params[key]
list = [] if list.nil?
experiences = list.collect do |exp|
TeacherExperience.new(
name: exp[:name],
experience_type: experience_type,
organization: exp[:organization],
start_year: exp[:start_year],
end_year: exp[:end_year]
)
end # collect
# we blindly destroy/recreate on every resubmit
previous = teacher.send("#{key.to_s}")
previous.destroy_all
# Dynamically call the appropriate method (just setting the
# value doesn't result in the behavior we need)
teacher.send("#{key.to_s}=", experiences)
end # if
end # do
# How to validate:
teacher.validate_introduction = !!params[:validate_introduction]
teacher.validate_basics = !!params[:validate_basics]
teacher.validate_pricing = !!params[:validate_pricing]
teacher
subjects = params[:subjects]
if subjects && !subjects.blank? && subjects.length > 0
query = query.joins("inner JOIN teachers_subjects AS tsubjs ON tsubjs.teacher_id = teachers.id")
.where('tsubjs.subject_id IN (?)', subjects)
end
genres = params[:genres]
if genres && !genres.blank? && genres.length > 0
query = query.joins("inner JOIN teachers_genres AS tgenres ON tgenres.teacher_id = teachers.id")
.where('tgenres.genre_id IN (?)', genres)
end
country = params[:country]
if country && country.length > 0
query = query.where(country: country)
end
region = params[:region]
if region && region.length > 0
query = query.where(state: region)
end
languages = params[:languages]
if languages && !languages.blank? && languages.length > 0
query= query.joins("inner JOIN teachers_languages AS tlang ON tlang.teacher_id = teachers.id")
.where('tlang.language_id IN (?)', languages)
end
years_teaching = params[:years_teaching].to_i
if years_teaching && years_teaching > 0
query = query.where('years_teaching >= ?', years_teaching)
end
teaches_beginner = params[:teaches_beginner]
teaches_intermediate = params[:teaches_intermediate]
teaches_advanced = params[:teaches_advanced]
if teaches_beginner || teaches_intermediate || teaches_advanced
clause = ''
if teaches_beginner
clause << 'teaches_beginner = true'
end
if teaches_intermediate
if clause.length > 0
clause << ' OR '
end
clause << 'teaches_intermediate = true'
end
if teaches_advanced
if clause.length > 0
clause << ' OR '
end
clause << 'teaches_advanced = true'
end
query = query.where(clause)
end
student_age = params[:student_age].to_i
if student_age && student_age > 0
query = query.where("teaches_age_lower <= ? AND (CASE WHEN teaches_age_upper = 0 THEN true ELSE teaches_age_upper >= ? END)", student_age, student_age)
end
current_page = params[:page].nil? ? 1 : params[:page].to_i
next_page = current_page + 1
# will_paginate gem
query = query.paginate(:page => current_page, :per_page => limit)
if query.length == 0 # no more results
{ query: query, next_page: nil}
elsif query.length < limit # no more results
{ query: query, next_page: nil}
else
{ query: query, next_page: next_page }
end
end
def self.save_teacher(user, params)
teacher = build_teacher(user, params)
teacher.save
teacher
end
def self.build_teacher(user, params)
# ensure person creating this Teacher is a Musician
unless user && user.musician?
raise JamPermissionError, "must be a musician"
end
teacher = user.teacher
teacher ||= user.build_teacher()
teacher.user = user
teacher.website = params[:website] if params.key?(:website)
teacher.biography = params[:biography] if params.key?(:biography)
teacher.introductory_video = params[:introductory_video] if params.key?(:introductory_video)
teacher.introductory_video = params[:introductory_video] if params.key?(:introductory_video)
teacher.years_teaching = params[:years_teaching] if params.key?(:years_teaching)
teacher.years_playing = params[:years_playing] if params.key?(:years_playing)
teacher.teaches_age_lower = params[:teaches_age_lower] if params.key?(:teaches_age_lower)
teacher.teaches_age_upper = params[:teaches_age_upper] if params.key?(:teaches_age_upper)
teacher.website = params[:website] if params.key?(:website)
teacher.biography = params[:biography] if params.key?(:biography)
teacher.teaches_beginner = params[:teaches_beginner] if params.key?(:teaches_beginner)
teacher.teaches_intermediate = params[:teaches_intermediate] if params.key?(:teaches_intermediate)
teacher.teaches_advanced = params[:teaches_advanced] if params.key?(:teaches_advanced)
teacher.prices_per_lesson = params[:prices_per_lesson] if params.key?(:prices_per_lesson)
teacher.prices_per_month = params[:prices_per_month] if params.key?(:prices_per_month)
teacher.lesson_duration_30 = params[:lesson_duration_30] if params.key?(:lesson_duration_30)
teacher.lesson_duration_45 = params[:lesson_duration_45] if params.key?(:lesson_duration_45)
teacher.lesson_duration_60 = params[:lesson_duration_60] if params.key?(:lesson_duration_60)
teacher.lesson_duration_90 = params[:lesson_duration_90] if params.key?(:lesson_duration_90)
teacher.lesson_duration_120 = params[:lesson_duration_120] if params.key?(:lesson_duration_120)
teacher.price_per_lesson_30_cents = params[:price_per_lesson_30_cents] if params.key?(:price_per_lesson_30_cents)
teacher.price_per_lesson_45_cents = params[:price_per_lesson_45_cents] if params.key?(:price_per_lesson_45_cents)
teacher.price_per_lesson_60_cents = params[:price_per_lesson_60_cents] if params.key?(:price_per_lesson_60_cents)
teacher.price_per_lesson_90_cents = params[:price_per_lesson_90_cents] if params.key?(:price_per_lesson_90_cents)
teacher.price_per_lesson_120_cents = params[:price_per_lesson_120_cents] if params.key?(:price_per_lesson_120_cents)
teacher.price_per_month_30_cents = params[:price_per_month_30_cents] if params.key?(:price_per_month_30_cents)
teacher.price_per_month_45_cents = params[:price_per_month_45_cents] if params.key?(:price_per_month_45_cents)
teacher.price_per_month_60_cents = params[:price_per_month_60_cents] if params.key?(:price_per_month_60_cents)
teacher.price_per_month_90_cents = params[:price_per_month_90_cents] if params.key?(:price_per_month_90_cents)
teacher.price_per_month_120_cents = params[:price_per_month_120_cents] if params.key?(:price_per_month_120_cents)
# Many-to-many relations:
if params.key?(:genres)
genres = params[:genres]
genres = [] if genres.nil?
teacher.genres = genres.collect{|genre_id| Genre.find(genre_id)}
end
if params.key?(:instruments)
instruments = params[:instruments]
instruments = [] if instruments.nil?
teacher.instruments = instruments.collect{|instrument_id| Instrument.find(instrument_id)}
end
if params.key?(:subjects)
subjects = params[:subjects]
subjects = [] if subjects.nil?
teacher.subjects = subjects.collect{|subject_id| Subject.find(subject_id)}
end
if params.key?(:languages)
languages = params[:languages]
languages = [] if languages.nil?
teacher.languages = languages.collect{|language_id| Language.find(language_id)}
end
# Experience:
[:teaching, :education, :award].each do |experience_type|
key = "experiences_#{experience_type}".to_sym
if params.key?(key)
list = params[key]
list = [] if list.nil?
experiences = list.collect do |exp|
TeacherExperience.new(
name: exp[:name],
experience_type: experience_type,
organization: exp[:organization],
start_year: exp[:start_year],
end_year: exp[:end_year]
)
end # collect
# we blindly destroy/recreate on every resubmit
previous = teacher.send("#{key.to_s}")
previous.destroy_all
# Dynamically call the appropriate method (just setting the
# value doesn't result in the behavior we need)
teacher.send("#{key.to_s}=", experiences)
end # if
end # do
# How to validate:
teacher.validate_introduction = !!params[:validate_introduction]
teacher.validate_basics = !!params[:validate_basics]
teacher.validate_pricing = !!params[:validate_pricing]
teacher
end
def offer_pricing

View File

@ -94,6 +94,10 @@ FactoryGirl.define do
end
end
factory :teacher, :class => JamRuby::Teacher do
association :user, factory: :user
end
factory :musician_instrument, :class => JamRuby::MusicianInstrument do
instrument { JamRuby::Instrument.find('electric guitar') }
proficiency_level 1

View File

@ -12,12 +12,177 @@ describe Teacher do
let(:instrument1) { FactoryGirl.create(:instrument, :description => 'a great instrument')}
let(:instrument2) { FactoryGirl.create(:instrument, :description => 'an ok instrument')}
describe "index" do
it "no params" do
teacher = FactoryGirl.create(:teacher)
teachers = Teacher.index(nil)[:query]
teachers.length.should eq 1
teachers[0].should eq(teacher.user)
end
it "instruments" do
teacher = FactoryGirl.create(:teacher)
teachers = Teacher.index(nil, {instruments: ['acoustic guitar']})[:query]
teachers.length.should eq 0
teacher.instruments << Instrument.find('acoustic guitar')
teacher.save!
teachers = Teacher.index(nil, {instruments: ['acoustic guitar']})[:query]
teachers.length.should eq 1
teachers[0].should eq(teacher.user)
teacher.instruments << Instrument.find('electric guitar')
teacher.save!
teachers = Teacher.index(nil, {instruments: ['acoustic guitar']})[:query]
teachers.length.should eq 1
teachers[0].should eq(teacher.user)
end
it "subjects" do
teacher = FactoryGirl.create(:teacher)
teachers = Teacher.index(nil, {subjects: ['music-theory']})[:query]
teachers.length.should eq 0
teacher.subjects << Subject.find('music-theory')
teacher.save!
teachers = Teacher.index(nil, {subjects: ['music-theory']})[:query]
teachers.length.should eq 1
teachers[0].should eq(teacher.user)
end
it "genres" do
teacher = FactoryGirl.create(:teacher)
teachers = Teacher.index(nil, {genres: ['ambient']})[:query]
teachers.length.should eq 0
teacher.genres << Genre.find('ambient')
teacher.save!
teachers = Teacher.index(nil, {genres: ['ambient']})[:query]
teachers.length.should eq 1
teachers[0].should eq(teacher.user)
end
it "languages" do
teacher = FactoryGirl.create(:teacher)
teachers = Teacher.index(nil, {languages: ['EN']})[:query]
teachers.length.should eq 0
teacher.languages << Language.find('EN')
teacher.save!
teachers = Teacher.index(nil, {languages: ['EN']})[:query]
teachers.length.should eq 1
teachers[0].should eq(teacher.user)
end
it "country" do
teacher = FactoryGirl.create(:teacher)
teachers = Teacher.index(nil, {country: 'DO'})[:query]
teachers.length.should eq 0
teacher.user.country = 'DO'
teacher.user.save!
teachers = Teacher.index(nil, {country: 'DO'})[:query]
teachers.length.should eq 1
teachers[0].should eq(teacher.user)
end
it "region" do
teacher = FactoryGirl.create(:teacher)
teachers = Teacher.index(nil, {region: 'HE'})[:query]
teachers.length.should eq 0
teacher.user.state = 'HE'
teacher.user.save!
teachers = Teacher.index(nil, {region: 'HE'})[:query]
teachers.length.should eq 1
teachers[0].should eq(teacher.user)
end
it "years_teaching" do
teacher = FactoryGirl.create(:teacher, years_teaching: 5)
teachers = Teacher.index(nil, {years_teaching: 10})[:query]
teachers.length.should eq 0
teachers = Teacher.index(nil, {years_teaching: 2})[:query]
teachers.length.should eq 1
teachers[0].should eq(teacher.user)
end
it "teaches beginner/intermediate/advanced" do
teacher = FactoryGirl.create(:teacher)
teachers = Teacher.index(nil, {teaches_beginner: true})[:query]
teachers.length.should eq 0
teacher.teaches_beginner = true
teacher.save!
teachers = Teacher.index(nil, {teaches_beginner: true})[:query]
teachers.length.should eq 1
teachers[0].should eq(teacher.user)
teachers = Teacher.index(nil, {teaches_intermediate: true})[:query]
teachers.length.should eq 0
teachers = Teacher.index(nil, {teaches_beginner: true, teaches_intermediate: true})[:query]
teachers.length.should eq 1
teachers[0].should eq(teacher.user)
teachers = Teacher.index(nil, {teaches_beginner: true, teaches_intermediate: true, teaches_advanced: true})[:query]
teachers.length.should eq 1
teachers[0].should eq(teacher.user)
end
it "student_age" do
teacher = FactoryGirl.create(:teacher)
teachers = Teacher.index(nil, {student_age: 5})[:query]
teachers.length.should eq 1
teacher.teaches_age_lower = 5
teacher.save!
teachers = Teacher.index(nil, {student_age: 5})[:query]
teachers.length.should eq 1
teachers[0].should eq(teacher.user)
teacher.teaches_age_lower = 6
teacher.save!
teachers = Teacher.index(nil, {student_age: 5})[:query]
teachers.length.should eq 0
teacher.teaches_age_lower = 4
teacher.teaches_age_upper = 6
teacher.save!
teachers = Teacher.index(nil, {student_age: 5})[:query]
teachers.length.should eq 1
teachers[0].should eq(teacher.user)
teacher.teaches_age_lower = 0
teacher.teaches_age_upper = 5
teacher.save!
teachers = Teacher.index(nil, {student_age: 5})[:query]
teachers.length.should eq 1
teachers[0].should eq(teacher.user)
teacher.teaches_age_lower = 0
teacher.teaches_age_upper = 6
teacher.save!
teachers = Teacher.index(nil, {student_age: 5})[:query]
teachers.length.should eq 1
teachers[0].should eq(teacher.user)
teacher.teaches_age_lower = 0
teacher.teaches_age_upper = 4
teacher.save!
teachers = Teacher.index(nil, {student_age: 5})[:query]
teachers.length.should eq 0
end
end
BIO = "Once a man learned a guitar."
GOOD_YOUTUBE_URL = "http://youtube.com/watch?v=1234567890"
describe "can create" do
it "a simple teacher" do
teacher = Teacher.new
teacher.user = user;
teacher.user = user
teacher.biography = BIO
teacher.introductory_video = GOOD_YOUTUBE_URL
teacher.save.should be_true

View File

@ -95,13 +95,13 @@ end
config.before(:suite) do
DatabaseCleaner.strategy = :transaction
DatabaseCleaner.clean_with(:deletion, {pre_count: true, reset_ids:false, :except => %w[gift_card_types instruments genres icecast_server_groups jamcompany jamisp geoipblocks geoipisp geoiplocations cities regions countries generic_state spatial_ref_sys] })
DatabaseCleaner.clean_with(:deletion, {pre_count: true, reset_ids:false, :except => %w[gift_card_types instruments languages subjects genres icecast_server_groups jamcompany jamisp geoipblocks geoipisp geoiplocations cities regions countries generic_state spatial_ref_sys] })
end
config.around(:each) do |example|
# set no_transaction: true as metadata on your test to use deletion strategy instead
if example.metadata[:no_transaction]
DatabaseCleaner.strategy = :deletion, {pre_count: true, reset_ids:false, :except => %w[gift_card_types instruments genres icecast_server_groups jamcompany jamisp geoipblocks geoipisp geoiplocations cities regions countries generic_state spatial_ref_sys] }
DatabaseCleaner.strategy = :deletion, {pre_count: true, reset_ids:false, :except => %w[gift_card_types instruments languages subjects genres icecast_server_groups jamcompany jamisp geoipblocks geoipisp geoiplocations cities regions countries generic_state spatial_ref_sys] }
else
DatabaseCleaner.strategy = :transaction
end

View File

@ -1974,6 +1974,15 @@
});
}
function searchTeachers(query) {
return $.ajax({
type: "GET",
url: "/api/teachers?" + $.param(query),
dataType: "json",
contentType: 'application/json'
});
}
function getMusicianSearchFilter(query) {
var qarg = query === undefined ? '' : query;
return $.get("/api/search/musicians.json?"+qarg);
@ -2286,6 +2295,7 @@
this.updateBillingInfo = updateBillingInfo;
this.placeOrder = placeOrder;
this.searchMusicians = searchMusicians;
this.searchTeachers = searchTeachers;
this.resendBandInvitation = resendBandInvitation;
this.getMount = getMount;
this.createSourceChange = createSourceChange;

View File

@ -18,6 +18,9 @@
//= require ./react-components/stores/MixerStore
//= require ./react-components/stores/ConfigureTracksStore
//= require ./react-components/stores/JamTrackStore
//= require ./react-components/stores/LocationStore
//= require ./react-components/stores/TeacherSearchStore
//= require ./react-components/stores/TeacherSearchResultsStore
//= require ./react-components/stores/SessionNotificationStore
//= require ./react-components/stores/MediaPlaybackStore
//= require ./react-components/stores/BrowserMediaPlaybackStore

View File

@ -4,11 +4,15 @@ logger = context.JK.logger
@AgeRangeList = React.createClass({
ages: [0, 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,25,30,35,40,45,50,55,60,65,70,75,80,85,90,95,100]
agesJsx: []
propTypes: {
onItemChanged: React.PropTypes.func.isRequired
}
componentDidMount: () ->
componentWillMount: () ->
@agesJsx = []
for age in @ages
@agesJsx.push(`<option value={age}>{age == 0 ? 'Any' : age}</option>`)
@agesJsx.push(`<option key={age} value={age}>{age == 0 ? 'Any' : age}</option>`)
getInitialState: () ->
{selectedAge:@props.selectedAge}

View File

@ -6,6 +6,13 @@ logger = context.JK.logger
mixins: [Reflux.listenTo(@GenreStore,"onGenresChanged")]
propTypes: {
onItemChanged: React.PropTypes.func.isRequired
}
getDefaultProps: () ->
selectedGenres: []
getInitialState:() ->
{genres: []}

View File

@ -6,6 +6,13 @@ logger = context.JK.logger
mixins: [Reflux.listenTo(@InstrumentStore,"onInstrumentsChanged")]
propTypes: {
onItemChanged: React.PropTypes.func.isRequired
}
getDefaultProps: () ->
selectedInstruments: []
getInitialState: () ->
{instruments: []}

View File

@ -6,6 +6,13 @@ logger = context.JK.logger
mixins: [Reflux.listenTo(@LanguageStore,"onLanguagesChanged")]
propTypes: {
onItemChanged: React.PropTypes.func.isRequired
}
getDefaultProps: () ->
selectedLanguages: []
getInitialState: () ->
{languages: []}

View File

@ -0,0 +1,62 @@
context = window
rest = window.JK.Rest()
logger = context.JK.logger
@SelectLocation = React.createClass({
mixins: [Reflux.listenTo(@LocationStore,"onLocationsChanged")]
propTypes: {
onItemChanged: React.PropTypes.func.isRequired
}
getInitialState:() ->
{selectedCountry: null, countries:{US: {name: 'United States', region: null}}}
onLocationsChanged: (countries) ->
@setState({countries: countries})
onCountryChanged: (e) ->
val = $(e.target).val()
@changed(val, null)
@setState({selectedCountry: val, selectedRegion: null })
if val?
LocationActions.selectCountry(val)
onRegionChanged: (e) ->
val = $(e.target).val()
@changed(@state.selectedCountry, val)
@setState({selectedRegion: val })
changed: (country, region) ->
if country == ''
country = null
if region == ''
region = null
@props.onItemChanged(country, region)
render: () ->
countries = [`<option value="">Any</option>`]
for countryId, countryInfo of @state.countries
countries.push(`<option value={countryId}>{countryInfo.name}</option>`)
country = @state.countries[@state.selectedCountry]
regions = [`<option value="">Any</option>`]
if country? && country.regions
for region in country.regions
regions.push(`<option value={region.id}>{region.name}</option>`)
disabled = regions.length == 1
`<div className="SelectLocation">
<h3>Country:</h3>
<select name="countries" onChange={this.onCountryChanged} value={this.state.selectedCountry}>{countries}</select>
<h3>State/Region:</h3>
<select name="regions" disabled={disabled} onChange={this.onRegionChanged} value={this.state.selectedRegion}>{regions}</select>
</div>`
})

View File

@ -6,6 +6,13 @@ logger = context.JK.logger
mixins: [Reflux.listenTo(@SubjectStore,"onSubjectsChanged")]
propTypes: {
onItemChanged: React.PropTypes.func.isRequired
}
getDefaultProps: () ->
selectedSubjects: []
getInitialState:() ->
{subjects: []}

View File

@ -78,7 +78,7 @@ logger = context.JK.logger
errors = []
if this.state.errors?
for error in this.state.errors
errors.push(error)
errors.push(`<span>{error}</span>`)
`<div className="TeacherExperienceEditableList react-component">
<form className="teacher-experience-teaching-form">

View File

@ -9,6 +9,7 @@ LanguageStore = context.LanguageStore
GenreStore = context.GenreStore
UserStore = context.UserStore
AppStore = context.AppStore
ProfileActions = context.ProfileActions
profileUtils = context.JK.ProfileUtils
@ -44,7 +45,7 @@ proficiencyDescriptionMap = {
TILES: ['about', 'experience', 'samples', 'ratings', 'prices']
onAppInit: (@app) ->
@app.bindScreen('profile/teacher', {beforeShow: @beforeShow, afterShow: @afterShow})
@app.bindScreen('profile/teacher', {beforeShow: @beforeShow, afterShow: @afterShow, beforeHide: @beforeHide})
onSubjectsChanged: () ->
@setState({subjects: true})
@ -83,15 +84,21 @@ proficiencyDescriptionMap = {
)
beforeShow: (e) ->
userDetailDone: (response) ->
if response.id == @state.userId
@setState({user: response, isSelf: response.id == context.JK.currentUserId})
else
logger.debug("ignoring userDetailDone", response.id, @state.userId)
beforeHide: (e) ->
logger.debug("TeacherProfile: beforeHide")
ProfileActions.viewTeacherProfileDone()
beforeShow: (e) ->
logger.debug("TeacherProfile: beforeShow")
afterShow: (e) ->
logger.debug("TeacherProfile: afterShow")
@setState({userId: e.id, user: null})
rest.getUserDetail({
id: e.id,
@ -619,6 +626,10 @@ proficiencyDescriptionMap = {
return `<div key={i} className="profile-tile"><a className={classes} onClick={this.selectionMade.bind(this, tile)}>{tile}</a></div>`
onCustomBack: (customBack, e) ->
e.preventDefault()
context.location = customBack
render: () ->
if @state.user?
avatar = context.JK.resolveAvatarUrl(@state.user.photo_url);
@ -634,12 +645,10 @@ proficiencyDescriptionMap = {
{noTeacherProfile}
</div>`
editButton = `<a href="/client#/account/profile" className="button-orange edit-profile-btn hidden">EDIT PROFILE</a>`
actionButtons = `<div className="right hidden">
<a id="btn-add-friend" className="button-orange">ADD FRIEND</a>
<a id="btn-follow-user" className="button-orange">FOLLOW</a>
<a id="btn-message-user" className="button-orange">MESSAGE</a>
</div>`
if ProfileStore.customBack
actionButtons = `<div className="right profileNavActions">
<a className="button-orange" onClick={this.onCustomBack.bind(this, ProfileStore.customBack)}>{ProfileStore.customBackDisplay}</a>
</div>`
profileSelections = []
for tile, i in @TILES
@ -653,7 +662,6 @@ proficiencyDescriptionMap = {
<div className="user-header">
<h2 id="username"></h2>
{editButton}
</div>
{actionButtons}

View File

@ -0,0 +1,137 @@
context = window
rest = context.JK.Rest()
TeacherSearchActions = @TeacherSearchActions
LocationActions = @LocationActions
@TeacherSearchOptionsScreen = React.createClass({
mixins: [Reflux.listenTo(@AppStore, "onAppInit"), Reflux.listenTo(@UserStore, "onUserChanged"),
Reflux.listenTo(@TeacherSearchStore, "onTeacherSearchChanged")]
LIMIT: 20
getInitialState: () ->
{options: {}}
onAppInit: (@app) ->
@app.bindScreen('jamclass/searchOptions', {beforeShow: @beforeShow, afterShow: @afterShow})
beforeShow: (e) ->
LocationActions.load()
afterShow: (e) ->
onUserChanged: (@user) ->
onTeacherSearchChanged: (options) ->
@setState({options: options})
handleListChange: (listName, selectedObjects)->
logger.debug("handleListChange:", listName, selectedObjects)
options = @state.options
options[listName] = selectedObjects
@setState({options: options})
handleLocationChange: (country, region) ->
logger.debug("handleLocationChange #{country} #{region}")
options = @state.options
options['location'] = {country:country, region:region}
@setState({options: options})
onCancel: (e) ->
e.preventDefault()
window.history.go(-1)
onSearch: (e) ->
e.preventDefault()
TeacherSearchActions.search({searchOptions: @state.options})
levelChanged: (e) ->
purpose = $(e.target).attr('data-purpose')
checked = $(e.target).is(":checked")
logger.debug("levelChanged:", purpose, checked)
options = @state.options
options[purpose] = checked
@setState({options: options})
handleYearsTeaching: (e) ->
yearsTeaching = $(e.target).val()
logger.debug("years teaching:", yearsTeaching)
options = @state.options
options['years-teaching'] = yearsTeaching
@setState({options: options})
render: () ->
selectedAge = null
yearsTeaching = []
for yr in [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 15, 20, 25, 30, 40, 45, 50]
yearsTeaching.push(`<option value={yr}>{yr}</option>`)
`<div className="content-body-scroller">
<div className="screen-content">
<h2>search teachers</h2>
<div className="search-criteria">
<h3>Instruments Taught:</h3>
<InstrumentCheckBoxList onItemChanged={this.handleListChange} selectedInstruments={this.state.options.instruments}/>
</div>
<div className="search-criteria">
<h3>Music Subjects Taught:</h3>
<SubjectCheckBoxList onItemChanged={this.handleListChange} selectedSubjects={this.state.options.subjects}/>
</div>
<div className="search-criteria">
<h3>Genres Taught:</h3>
<GenreCheckBoxList onItemChanged={this.handleListChange} selectedGenres={this.state.options.genres}/>
</div>
<div className="search-criteria">
<h3>Languages Spoken:</h3>
<LanguageCheckBoxList onItemChanged={this.handleListChange} selectedLanguages={this.state.options.languages}/>
</div>
<br className="clearall"/>
<div className="search-criteria">
<div className="student-levels-taught">
<h3>Student Levels Taught:</h3>
<div className="teaching-level beginner-level">
<input name="beginner-level" type="checkbox" data-purpose="teaches_beginner" onChange={this.levelChanged} checked={this.state.options.teaches_beginner}></input>
<label for="beginner-level">Beginner</label>
</div>
<div className="teaching-level intermediate-level">
<input name="intermediate-level" type="checkbox" data-purpose="teaches_intermediate" onChange={this.levelChanged} checked={this.state.options.teaches_intermediate}></input>
<label for="intermediate-level">Intermediate</label>
</div>
<div className="teaching-level advanced-level">
<input name="advanced-level" type="checkbox" data-purpose="teaches_advanced" onChange={this.levelChanged} checked={this.state.options.teaches_advanced}></input>
<label for="advanced-level">Advanced</label>
</div>
</div>
</div>
<div className="search-criteria">
<h3>Student Ages Taught:</h3>
<AgeRangeList selectedAge={selectedAge} objectName="ages-taught" onItemChanged={this.handleListChange} selectedAge={this.state.options['ages-taught']} />
<h3 className="years-teaching-header">Years Teaching Experience:</h3>
<select name="years-teaching" onChange={this.handleYearsTeaching} value={this.state.options['years-teaching']}>
<option value=''>Any</option>
{yearsTeaching}
</select>
</div>
<div className="search-criteria">
<SelectLocation onItemChanged={this.handleLocationChange}/>
</div>
</div>
<div className="actions">
<a className="button-grey" onClick={this.onCancel}>CANCEL</a>
<a className="button-orange" onClick={this.onSearch}>SEARCH</a>
</div>
</div>`
})

View File

@ -0,0 +1,184 @@
context = window
rest = context.JK.Rest()
TeacherSearchStore = @TeacherSearchStore
TeacherSearchActions = @TeacherSearchActions
TeacherSearchResultsActions = @TeacherSearchResultsActions
LocationActions = @LocationActions
InstrumentStore = @InstrumentStore
SubjectStore = @SubjectStore
GenreStore = @GenreStore
LanguageStore = @LanguageStore
ProfileActions = @ProfileActions
@TeacherSearchScreen = React.createClass({
# Reflux.listenTo(@TeacherSearchStore, "onTeacherSearchChanged"),
mixins: [Reflux.listenTo(@AppStore, "onAppInit"), Reflux.listenTo(@UserStore, "onUserChanged"),
Reflux.listenTo(@TeacherSearchResultsStore, "onTeacherSearchResultsStore")]
LIMIT: 20
visible: false
getInitialState: () ->
{searchOptions: {}, results: []}
onAppInit: (@app) ->
@app.bindScreen('teachers/search', {beforeShow: @beforeShow, afterShow: @afterShow, afterHide: @afterHide})
beforeShow: (e) ->
@visible = true
afterShow: (e) ->
@visible = false
#@setState(TeacherSearchStore.getState())
TeacherSearchResultsActions.reset()
afterHide: (e) ->
onUserChanged: (@user) ->
#onTeacherSearchChanged: (options) ->
# if @visible
# @setState(options)
componentDidMount: () ->
@root = $(@getDOMNode())
@resultsNode = @root.find('.results')
componentDidUpdate: () ->
@resultsNode.find('.teacher-bio').each((index, element) => (
$this = $(element)
if !$this.data('dotdotdot')
$this.dotdotdot({
after: "a.readmore"
})
))
onTeacherSearchResultsStore: (results) ->
@setState(results)
moreAboutTeacher: (user, e) ->
e.preventDefault()
ProfileActions.viewTeacherProfile(user, '/client#/teachers/search', 'BACK TO TEACHER SEARCH')
bookTestDrive: (e) ->
e.preventDefault()
bookNormalLesson: (e) ->
e.preventDefault()
bookFreeLesson: (e) ->
e.preventDefault()
readMore: (e) ->
e.preventDefault()
target = $(e.target)
teacherBio = target.closest('.teacher-bio')
teacherBio.css('height', 'auto')
target.trigger( 'destroy.dot' );
teacherBio.css('height', 'auto')
createSearchDescription: () ->
searchOptions = TeacherSearchStore.getState().searchOptions
summary = ''
instruments = searchOptions.instruments
if instruments? && instruments.length > 0
if instruments.length == 1
bit = "Instrument = #{InstrumentStore.display(instruments[0])}"
else
instruments.length > 1
bit = "Instruments = #{InstrumentStore.display(instruments[0])}..."
summary += " #{bit}"
subjects = searchOptions.subjects
if subjects? && subjects.length > 0
if subjects.length == 1
bit = "Subject = #{SubjectStore.display(subjects[0])}"
else
subjects.length > 1
bit = "Subjects = #{SubjectStore.display(subjects[0])}..."
summary += " #{bit}"
genres = searchOptions.genres
if genres? && genres.length > 0
if genres.length == 1
bit = "Genre = #{GenreStore.display(genres[0])}"
else
genres.length > 1
bit = "Genres = #{GenreStore.display(genres[0])}..."
summary += " #{bit}"
languages = searchOptions.languages
if languages? && languages.length > 0
if languages.length == 1
bit = "Genre = #{LanguageStore.display(languages[0])}"
else
languages.length > 1
bit = "Genres = #{LanguageStore.display(languages[0])}..."
summary += " #{bit}"
if summary.length == 0
summary = 'all teachers'
summary
render: () ->
searchDesc = @createSearchDescription()
resultsJsx = []
for user in @state.results
photo_url = user.photo_url
if !photo_url?
photo_url = '/assets/shared/avatar_generic.png'
bio = user.teacher.biography
if !bio?
bio = 'No bio'
resultsJsx.push(`<div key={user.id} className="teacher-search-result">
<div className="user-avatar">
<div className="avatar small">
<img src={photo_url} />
</div>
<div className="user-name">
{user.name}
</div>
</div>
<div className="user-info">
<div className="teacher-bio">
{bio}
<a className="readmore" onClick={this.readMore}>more</a>
</div>
<div className="teacher-actions">
<a className="button-orange" onClick={this.moreAboutTeacher.bind(this, user)}>MORE ABOUT THIS TEACHER</a>
<a className="button-orange" onClick={this.bookTestDrive}>BOOK TESTDRIVE LESSON</a>
<a className="button-orange" onClick={this.bookFreeLesson}>BOOK FREE LESSON</a>
<a className="button-orange" onClick={this.bookNormalLesson}>BOOK NORMAL LESSON</a>
</div>
</div>
<br className="clearall" />
</div>`)
`<div className="content-body-scroller">
<div className="screen-content">
<div className="header">
<a href="" onClick={alert.bind('not yet')}>LESSONS HOME</a>&nbsp;:&nbsp;
<a href="/client#/jamclass/searchOptions" >TEACHERS SEARCH</a>&nbsp;:&nbsp;
<span className="search-results-options">
<span className="results-text">SEARCH RESULTS / </span>
<span className="search-summary">{searchDesc}</span>
</span>
</div>
<div className="results">
{resultsJsx}
</div>
</div>
</div>`
})

View File

@ -0,0 +1,7 @@
context = window
@LocationActions = Reflux.createActions({
load: {}
selectCountry: {}
})

View File

@ -9,4 +9,6 @@ context = window
cancelProfileEdit: {}
doneProfileEdit: {}
editProfileNext: {}
viewTeacherProfile: {}
viewTeacherProfileDone: {}
})

View File

@ -0,0 +1,7 @@
context = window
@TeacherSearchActions = Reflux.createActions({
updateOptions: {}
search: {}
})

View File

@ -0,0 +1,6 @@
context = window
@TeacherSearchResultsActions = Reflux.createActions({
reset: {}
})

View File

@ -0,0 +1,74 @@
$ = jQuery
context = window
rest = window.JK.Rest()
logger = context.JK.logger
@LocationStore = Reflux.createStore(
{
listenables: @LocationActions
countries: {}
init: ->
# Register with the app store to get @app
this.listenTo(context.AppStore, this.onAppInit)
changed: () ->
@trigger(@countries)
onSelectCountry: (country) ->
@loadRegions(country)
onLoad: () ->
# avoid double-loads
if Object.keys(@countries).length == 0
rest.getCountries().done ((response) =>
countries = response.countriesx
if Object.keys(@countries).length == 0
for country in countries
name = country.countryname
if !name?
name = country.countrycode
@countries[country.countrycode] = {name: name, regions:null}
@loadRegions('US')
)
loadRegions: (loadForCountry) ->
if loadForCountry == null
return
country = @countries[loadForCountry]
if !country?
logger.warn("country is null in searching for: " + loadForCountry)
return
regions = country.regions
# avoid double-loads
if regions == null
rest.getRegions({country: loadForCountry}).done ((countriesRegions) =>
regions = country.regions
if regions == null
regions = []
country.regions = regions
if regions.length > 0
return
for region in countriesRegions.regions
id = region.region
name = region.name
if !name?
name = region.region
regions.push({id: id, name: name})
@changed()
)
onAppInit: (@app) ->
}
)

View File

@ -8,6 +8,8 @@ ProfileActions = @ProfileActions
{
listenables: ProfileActions
customBack: null
customBackDisplay: null
returnNav: null
solo: false
@ -95,6 +97,16 @@ ProfileActions = @ProfileActions
@solo = false
else
context.location = "/client#/account/profile/" + step
onViewTeacherProfile: (user, customBack, customBackDisplay) ->
@customBack = customBack
@customBackDisplay = customBackDisplay
context.location = "/client#/profile/teacher/#{user.id}"
onViewTeacherProfileDone: () ->
@customBack = null
@customBackDisplay = null
}
)

View File

@ -0,0 +1,66 @@
$ = jQuery
context = window
logger = context.JK.logger
rest = context.JK.Rest()
TeacherSearchResultsActions = @TeacherSearchResultsActions
@TeacherSearchResultsStore = Reflux.createStore(
{
listenables: TeacherSearchResultsActions
results: []
page: 1
limit: 20
init: ->
# Register with the app store to get @app
this.listenTo(context.AppStore, this.onAppInit)
onAppInit: (app) ->
@app = app
onReset: () ->
@results = []
@changed()
query = @createQuery()
rest.searchTeachers(query)
.done((response) =>
@next = response.next
@results.push.apply(@results, response.entries)
@changed()
)
.fail((jqXHR, textStatus, errorMessage) =>
@app.ajaxError(jqXHR, textStatus, errorMessage)
)
getState: () ->
({results: @results})
changed:() ->
@trigger(@getState())
createQuery: () ->
searchOptions = context.TeacherSearchStore.getState().searchOptions
query = {}
query.page = @page
query.limit = @limit
query.instruments = searchOptions.instruments
query.subjects = searchOptions.subjects
query.genres = searchOptions.genres
query.languages = searchOptions.languages
query.teaches_beginner = searchOptions.teaches_beginner
query.teaches_intermediate = searchOptions.teaches_intermediate
query.teaches_advanced = searchOptions.teaches_advanced
query.student_age = searchOptions['ages-taught']
query.years_teaching = searchOptions['years-teaching']
query.country = searchOptions.location?.country
query.region = searchOptions.location?.region
query
}
)

View File

@ -0,0 +1,38 @@
$ = jQuery
context = window
logger = context.JK.logger
rest = context.JK.Rest()
TeacherSearchActions = @TeacherSearchActions
@TeacherSearchStore = Reflux.createStore(
{
listenables: TeacherSearchActions
searchOptions: {}
viewingTeacher: null
init: ->
# Register with the app store to get @app
this.listenTo(context.AppStore, this.onAppInit)
onAppInit: (app) ->
@app = app
onUpdateOptions: (options) ->
@searchOptions = options
onSearch: (searchOptions) ->
@searchOptions = searchOptions
@changed()
window.location = "/client#/teachers/search"
getState: () ->
({searchOptions: @searchOptions})
changed:() ->
@trigger(@getState())
}
)

View File

@ -172,6 +172,10 @@
}
.years {float:right}
}
.profileNavActions {
margin-right: -3px;
}
.ratings-block {
h3 {

View File

@ -0,0 +1,109 @@
@import "client/common";
#teacherSearch {
div[data-react-class="TeacherSearchScreen"] {
height:100%;
}
.screen-content {
padding:20px;
}
.header {
height:20px;
margin-bottom:10px;
a {
font-size:16px;
text-decoration:underline;
}
.search-results-options {
font-size:16px;
color:$ColorTextTypical;
}
}
a.readmore {
display:none;
}
.search-summary {
font-size:11px;
}
.teacher-search-result {
@include border_box_sizing;
clear:both;
position:relative;
margin-bottom:10px;
width:100%;
min-width:600px;
background-color:#242323;
color:$ColorTextTypical;
//height:110px;
padding:10px;
}
.user-info {
@include border_box_sizing;
width: calc(100% - 150px);
//padding:12px 10px 10px;
min-width:450px;
float:right;
}
.teacher-bio {
@include border_box_sizing;
height:50px;
width:100%;
margin-bottom:16px;
font-size:12px;
}
.teacher-actions {
a {
font-size:12px;
&:nth-of-type(1) {
margin-left:2px;
}
}
}
.user-avatar {
text-align:center;
float:left;
width:150px;
}
.avatar {
display:inline-block;
padding:1px;
width:48px;
height:48px;
background-color:#ed4818;
margin:10px 0 0 0;
-webkit-border-radius:24px;
-moz-border-radius:24px;
border-radius:24px;
float:none;
}
.avatar img {
width: 48px;
height: 48px;
-webkit-border-radius:24px;
-moz-border-radius:24px;
border-radius:24px;
}
.user-name {
text-align:center;
display:block;
margin-top:8px;
clear:both;
}
.actions {
float: right;
width: 100%;
text-align: right;
padding-right: 31px;
margin-bottom: 20px;
}
}

View File

@ -0,0 +1,93 @@
@import "client/common";
#teacherSearchOptions {
div[data-react-class="TeacherSearchOptionsScreen"] {
height:100%;
}
.search-criteria {
.checkbox-scroller {
height:100px;
margin-top:0;
}
min-width:200px;
width:25%;
@include border_box_sizing;
float:left;
padding: 0 10px;
margin-bottom:30px;
&:first-child {
padding-left:0;
}
&:last-child {
padding-right:0;
}
h3 {
color: #FFFFFF;
font-size: 14px;
font-weight: 400;
margin-bottom: 8px;
}
}
.screen-content {
padding:20px;
}
.actions {
float: right;
width: 100%;
text-align: right;
padding-right: 31px;
margin-bottom: 20px;
}
h2 {
color: #FFFFFF;
font-size: 23px;
font-weight: 400;
margin-bottom:20px;
padding-left:10px;
}
select {
@include border_box_sizing;
width: 100%;
max-width:200px;
}
.SelectLocation {
select[name="countries"] {
//margin-top: 6px;
margin-bottom: 30px;
}
}
select[name="years-teaching"] {
//margin-top: 6px;
margin-bottom: 30px;
}
.student-levels-taught {
.teaching-level {
margin-bottom:10px;
}
label {
display:inline-block;
}
input {
display:inline-block;
margin-right:10px;
}
.beginner-level {
margin-top:10px;
}
}
.years-teaching-header {
margin-top:30px;
}
}

View File

@ -1,13 +1,21 @@
class ApiTeachersController < ApiController
before_filter :api_signed_in_user, :except => [:index, :detail]
before_filter :api_signed_in_user, :except => [:index, :detail, :search]
before_filter :auth_teacher, :only => [:update, :delete]
before_filter :auth_user, :only => [:create, :update]
respond_to :json
def index
@teachers = Teacher.paginate(page: params[:page])
data = Teacher.index(current_user, params)
@show_profile = true
@show_teacher = true
@users = data[:query]
@next = data[:next_page]
render "api_teachers/index", :layout => nil
end
def detail

View File

@ -0,0 +1,11 @@
node :next do |page|
@next
end
node :entries do |page|
partial "api_users/show", object: @users
end
node :total_entries do |page|
@users.total_entries
end

View File

@ -3,19 +3,25 @@ object @user
attributes :id, :first_name, :last_name, :name, :city, :state, :country, :location, :online, :photo_url, :musician, :gender, :birth_date, :internet_service_provider, :friend_count, :liker_count, :like_count, :follower_count, :following_count,
:recording_count, :session_count, :biography, :favorite_count, :audio_latency, :upcoming_session_count, :age, :website, :skill_level, :reuse_card, :email_needs_verification
if @user.musician?
node :location do @user.location end
else
node :location do @user.online ? 'Online' : 'Offline' end
end
if @show_teacher && @user.teacher
node :teacher do
partial("api_teachers/detail", :object => @user.teacher)
node :location do |user|
if user.musician?
user.location
else
user.online ? 'Online' : 'Offline'
end
end
node :teacher do |user|
if @show_teacher && user.teacher
partial("api_teachers/detail", :object => user.teacher)
end
end
if @show_profile
node :profile do
partial("api_users/profile_show", :object => @user)
@ -23,7 +29,8 @@ if @show_profile
end
# give back more info if the user being fetched is yourself
if @user == current_user
if current_user && @user == current_user
attributes :email, :original_fpfile, :cropped_fpfile, :crop_selection, :session_settings, :show_whats_next, :show_whats_next_count, :subscribe_email, :auth_twitter, :new_notifications, :sales_count, :reuse_card, :purchased_jamtracks_count, :first_downloaded_client_at, :created_at, :first_opened_jamtrack_web_player, :gifted_jamtracks, :has_redeemable_jamtrack
node :geoiplocation do |user|
@ -43,34 +50,34 @@ if @user == current_user
user.mods_json
end
node :has_recurly_account do
@user.recurly_code == @user.id
node :has_recurly_account do |user|
user.recurly_code == user.id
end
node :is_affiliate_partner do
@user.affiliate_partner.present?
node :is_affiliate_partner do |user|
user.affiliate_partner.present?
end
node :affiliate_referral_count do
@user.affiliate_partner.try(:referral_user_count)
node :affiliate_referral_count do |user|
user.affiliate_partner.try(:referral_user_count)
end
node :affiliate_earnings do
@user.affiliate_partner.try(:cumulative_earnings_in_cents)
node :affiliate_earnings do |user|
user.affiliate_partner.try(:cumulative_earnings_in_cents)
end
elsif current_user
node :is_friend do |uu|
current_user.friends?(@user)
current_user.friends?(uu)
end
node :is_following do |uu|
current_user.following?(@user)
current_user.following?(uu)
end
node :is_liking do |uu|
current_user.likes?(@user)
current_user.likes?(uu)
end
node :pending_friend_request do |uu|
current_user.pending_friend_request?(@user)
current_user.pending_friend_request?(uu)
end
node :my_audio_latency do |user|
current_user.last_jam_audio_latency.round if current_user.last_jam_audio_latency

View File

@ -43,6 +43,8 @@
<%= render "clients/teachers/setup/experience" %>
<%= render "clients/teachers/setup/pricing" %>
<%= render "clients/teachers/profile/profile" %>
<%= render "clients/teachers/search/search_options" %>
<%= render "clients/teachers/search/search_results" %>
<%= render "users/feed_music_session_ajax" %>
<%= render "users/feed_recording_ajax" %>
<%= render "jamtrack_search" %>

View File

@ -0,0 +1,8 @@
#teacherSearchOptions.screen.secondary.no-login-required layout='screen' layout-id='jamclass/searchOptions'
.content
.content-head
.content-icon=image_tag("content/icon_account.png", height:20, width:27)
h1 jamclass
= render "screen_navigation"
.content-body
= react_component 'TeacherSearchOptionsScreen', {}

View File

@ -0,0 +1,8 @@
#teacherSearch.screen.secondary.no-login-required layout='screen' layout-id='teachers/search'
.content
.content-head
.content-icon=image_tag("content/icon_musicians.png", height:20, width:20)
h1 jamclass
= render "screen_navigation"
.content-body
= react_component 'TeacherSearchScreen', {}