posa2wip
This commit is contained in:
parent
eb89ea0a43
commit
3117c7ed3e
|
|
@ -366,4 +366,5 @@ rails4_migration.sql
|
|||
non_free_jamtracks.sql
|
||||
retailers.sql
|
||||
second_ed.sql
|
||||
second_ed_v2.sql
|
||||
second_ed_v2.sql
|
||||
retailers_v2.sql
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
ALTER TABLE lesson_bookings ADD COLUMN posa_card_id VARCHAR(64);
|
||||
ALTER TABLE jam_track_rights ADD COLUMN posa_card_id VARCHAR(64);
|
||||
ALTER TABLE lesson_package_purchases ADD COLUMN posa_card_id VARCHAR(64);
|
||||
|
|
@ -1038,7 +1038,20 @@ module JamRuby
|
|||
|
||||
@user = lesson_session.student
|
||||
email = @student.email
|
||||
subject = "You have used #{@student.used_test_drives} of #{@student.total_test_drives} TestDrive lesson credits"
|
||||
|
||||
|
||||
if lesson_session.posa_card
|
||||
@total_credits = @student.total_posa_credits
|
||||
@used_credits = @student.used_posa_credits
|
||||
@remaining_credits = @student.jamclass_credits
|
||||
else
|
||||
@total_credits = @student.total_test_drives
|
||||
@used_credits = @student.used_test_drives
|
||||
@remaining_credits = @student.remaining_test_drives
|
||||
end
|
||||
|
||||
subject = "You have used #{@used_credits} of #{@total_credits} TestDrive lesson credits"
|
||||
|
||||
unique_args = {:type => "student_test_drive_success"}
|
||||
|
||||
sendgrid_category "Notification"
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
<% provide(:title, "You have used #{@student.used_test_drives} of #{@student.total_test_drives} TestDrive lesson credits") %>
|
||||
<% provide(:title, "You have used #{@used_credits} of #{@total_credits} TestDrive lesson credits") %>
|
||||
<% provide(:photo_url, @teacher.resolved_photo_url) %>
|
||||
|
||||
<% content_for :note do %>
|
||||
|
|
@ -7,7 +7,7 @@
|
|||
</p>
|
||||
|
||||
<p>We hope you enjoyed your JamClass lesson today with <%= @teacher.name %>. You have
|
||||
used <%= @student.used_test_drives %> TestDrive credits, and you have <%= @student.remaining_test_drives %>
|
||||
used <%= @used_credits %> TestDrive credits, and you have <%= @remaining_credits %>
|
||||
remaining TestDrive lesson(s) available. If you haven’t booked your next TestDrive lesson,
|
||||
<a href="<%= User.search_url %>" style="color:#fc0">click here</a> to search our teachers and get your next
|
||||
lesson lined up today!</p>
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
You have used <%= @student.used_test_drives %> of <%= @student.total_test_drives %> TestDrive lesson credits.
|
||||
You have used <%= @used_credits %> of <%= @total_credits %> TestDrive lesson credits.
|
||||
|
||||
<% if @student.has_rated_teacher(@teacher) %>
|
||||
Also, please rate your teacher at <%= @teacher.ratings_url %> now for today’s lesson to help other students in the community find the best instructors.
|
||||
|
|
|
|||
|
|
@ -221,7 +221,12 @@ module JamRuby
|
|||
if is_single_free?
|
||||
user.remaining_free_lessons = user.remaining_free_lessons - 1
|
||||
elsif is_test_drive?
|
||||
user.remaining_test_drives = user.remaining_test_drives - 1
|
||||
if posa_card
|
||||
user.jamclass_credits = user.jamclass_credits - 1
|
||||
else
|
||||
user.remaining_test_drives = user.remaining_test_drives - 1
|
||||
end
|
||||
|
||||
end
|
||||
user.save(validate: false)
|
||||
end
|
||||
|
|
@ -762,7 +767,17 @@ module JamRuby
|
|||
lesson_booking.payment_style = payment_style
|
||||
lesson_booking.description = description
|
||||
lesson_booking.status = STATUS_REQUESTED
|
||||
lesson_booking.test_drive_package_choice = test_drive_package_choice
|
||||
if lesson_type == LESSON_TYPE_TEST_DRIVE
|
||||
# if the user has any jamclass credits, then we should get their most recent posa purchase
|
||||
if user.jamclass_credits > 0
|
||||
lesson_booking.posa_card = most_recent_posa_purchase.posa_card
|
||||
else
|
||||
# otherwise, it's a normal test drive, and we should honor test_drive_package_choice if specified
|
||||
lesson_booking.test_drive_package_choice = test_drive_package_choice
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
if lesson_booking.teacher && lesson_booking.teacher.teacher.school
|
||||
lesson_booking.school = lesson_booking.teacher.teacher.school
|
||||
end
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ module JamRuby
|
|||
belongs_to :teacher, class_name: "JamRuby::User"
|
||||
belongs_to :lesson_booking, class_name: "JamRuby::LessonBooking"
|
||||
belongs_to :lesson_payment_charge, class_name: "JamRuby::LessonPaymentCharge", foreign_key: :charge_id
|
||||
belongs_to :posa_card, class_name: "JamRuby::PosaCard", foreign_key: :posa_card_id
|
||||
has_one :lesson_session, class_name: "JamRuby::LessonSession", dependent: :destroy
|
||||
has_many :teacher_distributions, class_name: "JamRuby::TeacherDistribution"
|
||||
|
||||
|
|
@ -30,6 +31,10 @@ module JamRuby
|
|||
|
||||
def validate_test_drive
|
||||
if user
|
||||
# if this is a posa card purchase, we won't stop it from getting created
|
||||
if posa_card_id
|
||||
return
|
||||
end
|
||||
if lesson_package_type.is_test_drive? && !user.can_buy_test_drive?
|
||||
errors.add(:user, "can not buy test drive right now because you have already purchased it within the last year")
|
||||
end
|
||||
|
|
@ -56,6 +61,11 @@ module JamRuby
|
|||
end
|
||||
|
||||
def add_test_drives
|
||||
if posa_card_id
|
||||
#user.jamclass_credits incremented in posa_card.rb
|
||||
return
|
||||
end
|
||||
|
||||
if self.lesson_package_type.is_test_drive?
|
||||
new_test_drives = user.remaining_test_drives + lesson_package_type.test_drive_count
|
||||
User.where(id: user.id).update_all(remaining_test_drives: new_test_drives)
|
||||
|
|
@ -75,17 +85,19 @@ module JamRuby
|
|||
lesson_payment_charge.amount_in_cents / 100.0
|
||||
end
|
||||
|
||||
def self.create(user, lesson_booking, lesson_package_type, year = nil, month = nil)
|
||||
def self.create(user, lesson_booking, lesson_package_type, year = nil, month = nil, posa_card = nil)
|
||||
purchase = LessonPackagePurchase.new
|
||||
purchase.user = user
|
||||
purchase.lesson_booking = lesson_booking
|
||||
purchase.teacher = lesson_booking.teacher if lesson_booking
|
||||
purchase.posa_card = posa_card
|
||||
|
||||
if year
|
||||
purchase.year = year
|
||||
purchase.month = month
|
||||
purchase.recurring = true
|
||||
|
||||
# this is for monthly
|
||||
if lesson_booking && lesson_booking.requires_teacher_distribution?(purchase)
|
||||
teacher_dist = TeacherDistribution.create_for_lesson_package_purchase(purchase, false)
|
||||
purchase.teacher_distributions << teacher_dist
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ module JamRuby
|
|||
@@log = Logging.logger[LessonSession]
|
||||
|
||||
delegate :sent_billing_notices, :last_billing_attempt_at, :billing_attempts, :billing_should_retry, :billed_at, :billing_error_detail, :billing_error_reason, :is_card_declined?, :is_card_expired?, :last_billed_at_date, :sent_billing_notices, to: :lesson_payment_charge, allow_nil: true
|
||||
delegate :is_test_drive?, :is_single_free?, :is_normal?, :approved_before?, :is_active?, :recurring, :is_monthly_payment?, :school_on_school?, :school_on_school_payment?, :no_school_on_school_payment?, :payment_if_school_on_school?, :scheduling_email, :teacher_school_emails, :school_and_teacher, :school_over_teacher, :school_and_teacher_ids, :school_over_teacher_ids, to: :lesson_booking
|
||||
delegate :is_test_drive?, :is_single_free?, :is_normal?, :approved_before?, :is_active?, :recurring, :is_monthly_payment?, :school_on_school?, :school_on_school_payment?, :no_school_on_school_payment?, :payment_if_school_on_school?, :scheduling_email, :teacher_school_emails, :school_and_teacher, :school_over_teacher, :school_and_teacher_ids, :school_over_teacher_ids, :posa_card, to: :lesson_booking
|
||||
delegate :pretty_scheduled_start, to: :music_session
|
||||
|
||||
|
||||
|
|
@ -581,8 +581,12 @@ module JamRuby
|
|||
lesson_session.slot = booking.default_slot
|
||||
lesson_session.assigned_student = booking.student
|
||||
lesson_session.user = booking.student
|
||||
if booking.is_test_drive? && booking.student.remaining_test_drives > 0
|
||||
lesson_session.lesson_package_purchase = booking.student.most_recent_test_drive_purchase
|
||||
if booking.is_test_drive?
|
||||
if booking.student.jamclass_credits > 0
|
||||
lesson_session.lesson_package_purchase = booking.student.most_recent_posa_purchase
|
||||
elsif booking.student.remaining_test_drives > 0
|
||||
lesson_session.lesson_package_purchase = booking.student.most_recent_test_drive_purchase
|
||||
end
|
||||
end
|
||||
lesson_session.save
|
||||
|
||||
|
|
@ -739,7 +743,11 @@ module JamRuby
|
|||
# 1st time this has ever been approved; there are other things we need to do
|
||||
|
||||
if lesson_package_purchase.nil? && lesson_booking.is_test_drive?
|
||||
self.lesson_package_purchase = student.most_recent_test_drive_purchase
|
||||
if student.jamclass_credits > 0
|
||||
self.lesson_package_purchase = student.most_recent_posa_purchase
|
||||
elsif student.remaining_test_drives > 0
|
||||
self.lesson_package_purchase = student.most_recent_test_drive_purchase
|
||||
end
|
||||
end
|
||||
|
||||
if self.save
|
||||
|
|
|
|||
|
|
@ -31,6 +31,18 @@ module JamRuby
|
|||
validate :must_be_activated
|
||||
validate :within_one_year
|
||||
|
||||
def credits
|
||||
if card_type == JAM_TRACKS_5
|
||||
5
|
||||
elsif card_type == JAM_TRACKS_10
|
||||
10
|
||||
elsif card_type == JAM_CLASS_4
|
||||
4
|
||||
else
|
||||
raise "unknown card type #{card_type}"
|
||||
end
|
||||
end
|
||||
|
||||
def already_activated
|
||||
if activated_at && activated_at_was && activated_at_changed?
|
||||
if retailer && retailer_id == retailer_id_was
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ module JamRuby
|
|||
validates_length_of :password, minimum: 6, maximum: 100, :if => :should_validate_password
|
||||
|
||||
after_create :create_affiliate
|
||||
before_save :stringify_avatar_info, :if => :updating_avatar
|
||||
# before_save :stringify_avatar_info, :if => :updating_avatar
|
||||
|
||||
def create_affiliate
|
||||
AffiliatePartner.create_from_retailer(self)
|
||||
|
|
@ -77,12 +77,12 @@ module JamRuby
|
|||
cropped_large_s3_path = cropped_large_fpfile["key"]
|
||||
|
||||
self.update_attributes(
|
||||
:original_fpfile => original_fpfile,
|
||||
:cropped_fpfile => cropped_fpfile,
|
||||
:cropped_large_fpfile => cropped_large_fpfile,
|
||||
:original_fpfile => original_fpfile.to_json,
|
||||
:cropped_fpfile => cropped_fpfile.to_json,
|
||||
:cropped_large_fpfile => cropped_large_fpfile.to_json,
|
||||
:cropped_s3_path => cropped_s3_path,
|
||||
:cropped_large_s3_path => cropped_large_s3_path,
|
||||
:crop_selection => crop_selection,
|
||||
:crop_selection => crop_selection.to_json,
|
||||
:photo_url => S3Util.url(aws_bucket, escape_filename(cropped_s3_path), :secure => true),
|
||||
:large_photo_url => S3Util.url(aws_bucket, escape_filename(cropped_large_s3_path), :secure => true)
|
||||
)
|
||||
|
|
@ -116,9 +116,9 @@ module JamRuby
|
|||
# so we need t oconvert it to JSON before storing it (otherwise it gets serialized as a ruby object)
|
||||
# later, when serving this data out to the REST API, we currently just leave it as a string and make a JSON capable
|
||||
# client parse it, because it's very rare when it's needed at all
|
||||
self.original_fpfile = original_fpfile.to_json if !original_fpfile.nil?
|
||||
self.cropped_fpfile = cropped_fpfile.to_json if !cropped_fpfile.nil?
|
||||
self.crop_selection = crop_selection.to_json if !crop_selection.nil?
|
||||
self.original_fpfile = original_fpfile.to_json if !original_fpfile.nil? && original_fpfile.class != String
|
||||
self.cropped_fpfile = cropped_fpfile.to_json if !cropped_fpfile.nil? && cropped_fpfile.class != String
|
||||
self.crop_selection = crop_selection.to_json if !crop_selection.nil? && crop_selection.class != String
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ module JamRuby
|
|||
validate :validate_avatar_info
|
||||
|
||||
after_create :create_affiliate
|
||||
before_save :stringify_avatar_info, :if => :updating_avatar
|
||||
#before_save :stringify_avatar_info, :if => :updating_avatar
|
||||
|
||||
def is_education?
|
||||
education
|
||||
|
|
@ -84,12 +84,12 @@ module JamRuby
|
|||
cropped_large_s3_path = cropped_large_fpfile["key"]
|
||||
|
||||
self.update_attributes(
|
||||
:original_fpfile => original_fpfile,
|
||||
:cropped_fpfile => cropped_fpfile,
|
||||
:cropped_large_fpfile => cropped_large_fpfile,
|
||||
:original_fpfile => original_fpfile.to_json,
|
||||
:cropped_fpfile => cropped_fpfile.to_json,
|
||||
:cropped_large_fpfile => cropped_large_fpfile.to_json,
|
||||
:cropped_s3_path => cropped_s3_path,
|
||||
:cropped_large_s3_path => cropped_large_s3_path,
|
||||
:crop_selection => crop_selection,
|
||||
:crop_selection => crop_selection.to_json,
|
||||
:photo_url => S3Util.url(aws_bucket, escape_filename(cropped_s3_path), :secure => true),
|
||||
:large_photo_url => S3Util.url(aws_bucket, escape_filename(cropped_large_s3_path), :secure => true)
|
||||
)
|
||||
|
|
|
|||
|
|
@ -219,7 +219,18 @@ module JamRuby
|
|||
teacher.teaches_test_drive = params[:teaches_test_drive] if params.key?(:teaches_test_drive)
|
||||
teacher.test_drives_per_week = params[:test_drives_per_week] if params.key?(:test_drives_per_week)
|
||||
teacher.test_drives_per_week = 10 if !params.key?(:test_drives_per_week) # default to 10 in absence of others
|
||||
teacher.school_id = params[:school_id] if params.key?(:school_id)
|
||||
if params.key?(:school_id)
|
||||
teacher.school_id = params[:school_id]
|
||||
if !teacher.joined_school_at
|
||||
teacher.joined_school_at = Time.now
|
||||
end
|
||||
end
|
||||
if params.key?(:retailer_id)
|
||||
teacher.retailer_id = params[:retailer_id]
|
||||
if !teacher.joined_retailer_at
|
||||
teacher.joined_retailer_at = Time.now
|
||||
end
|
||||
end
|
||||
|
||||
# How to validate:
|
||||
teacher.validate_introduction = !!params[:validate_introduction]
|
||||
|
|
|
|||
|
|
@ -1136,6 +1136,8 @@ module JamRuby
|
|||
teacher = options[:teacher]
|
||||
school_invitation_code = options[:school_invitation_code]
|
||||
school_id = options[:school_id]
|
||||
retailer_invitation_code = options[:retailer_invitation_code]
|
||||
retailer_id = options[:retailer_id]
|
||||
school_interest = options[:school_interest]
|
||||
education_interest = options[:education_interest]
|
||||
origin = options[:origin]
|
||||
|
|
@ -1144,6 +1146,7 @@ module JamRuby
|
|||
test_drive_package = TestDrivePackage.find_by_name(test_drive_package_details[:name]) if test_drive_package_details
|
||||
|
||||
school = School.find(school_id) if school_id
|
||||
retailer = School.find(retailer_id) if retailer_id
|
||||
user = User.new
|
||||
user.validate_instruments = true
|
||||
UserManager.active_record_transaction do |user_manager|
|
||||
|
|
@ -1158,6 +1161,16 @@ module JamRuby
|
|||
end
|
||||
end
|
||||
|
||||
if retailer_invitation_code
|
||||
retailer_invitation = RetailerInvitation.find_by_invitation_code(retailer_invitation_code)
|
||||
if retailer_invitation
|
||||
first_name ||= retailer_invitation.first_name
|
||||
last_name ||= retailer_invitation.last_name
|
||||
retailer_invitation.accepted = true
|
||||
retailer_invitation.save
|
||||
end
|
||||
end
|
||||
|
||||
user.first_name = first_name if first_name.present?
|
||||
user.last_name = last_name if last_name.present?
|
||||
user.email = email
|
||||
|
|
@ -1195,10 +1208,18 @@ module JamRuby
|
|||
user.affiliate_referral = school.affiliate_partner
|
||||
elsif user.is_a_teacher
|
||||
school = School.find_by_id(school_id)
|
||||
school_name = school ? school.name : 'a music school'
|
||||
user.teacher = Teacher.build_teacher(user, validate_introduction: true, biography: "Empty biography", school_id: school_id)
|
||||
user.affiliate_referral = school.affiliate_partner
|
||||
end
|
||||
elsif retailer_id.present?
|
||||
if user.is_a_student
|
||||
user.retailer_id = school_id
|
||||
user.affiliate_referral = retailer.affiliate_partner
|
||||
elsif user.is_a_teacher
|
||||
retailer = Retailer.find_by_id(retailer_id)
|
||||
user.teacher = Teacher.build_teacher(user, validate_introduction: true, biography: "Empty biography", retailer_id: retailer_id)
|
||||
user.affiliate_referral = retailer.affiliate_partner
|
||||
end
|
||||
else
|
||||
if user.is_a_teacher
|
||||
user.teacher = Teacher.build_teacher(user, validate_introduction: true, biography: "Empty biography")
|
||||
|
|
@ -2003,6 +2024,10 @@ module JamRuby
|
|||
remaining_test_drives > 0
|
||||
end
|
||||
|
||||
def has_posa_credits?
|
||||
jamclass_credits > 0
|
||||
end
|
||||
|
||||
def has_unprocessed_test_drives?
|
||||
!unprocessed_test_drive.nil?
|
||||
end
|
||||
|
|
@ -2185,6 +2210,10 @@ module JamRuby
|
|||
LessonBooking.unprocessed(self).where(lesson_type: LessonBooking::LESSON_TYPE_PAID).first
|
||||
end
|
||||
|
||||
def most_recent_posa_purchase
|
||||
lesson_purchases.where('lesson_package_type_id in (?)', LessonPackageType.test_drive_package_ids).where('posa_card_id is not null').order('created_at desc').first
|
||||
end
|
||||
|
||||
def most_recent_test_drive_purchase
|
||||
lesson_purchases.where('lesson_package_type_id in (?)', LessonPackageType.test_drive_package_ids).order('created_at desc').first
|
||||
end
|
||||
|
|
@ -2198,8 +2227,18 @@ module JamRuby
|
|||
end
|
||||
end
|
||||
|
||||
|
||||
def total_posa_credits
|
||||
purchase = most_recent_posa_purchase
|
||||
if purchase
|
||||
purchase.posa_card.credits
|
||||
else
|
||||
0
|
||||
end
|
||||
end
|
||||
|
||||
def test_drive_succeeded(lesson_session)
|
||||
if self.remaining_test_drives <= 0
|
||||
if (lesson_session.posa_card && self.jamclass_credits <= 0) || self.remaining_test_drives <= 0
|
||||
UserMailer.student_test_drive_lesson_done(lesson_session).deliver_now
|
||||
UserMailer.teacher_lesson_completed(lesson_session).deliver_now
|
||||
else
|
||||
|
|
@ -2211,7 +2250,13 @@ module JamRuby
|
|||
def test_drive_declined(lesson_session)
|
||||
# because we decrement test_drive credits as soon as you book, we need to bring it back now
|
||||
if lesson_session.lesson_booking.user_decremented
|
||||
self.remaining_test_drives = self.remaining_test_drives + 1
|
||||
if lesson_session.posa_card
|
||||
self.jamclass_credits = self.jamclass_credits + 1
|
||||
else
|
||||
self.remaining_test_drives = self.remaining_test_drives + 1
|
||||
|
||||
end
|
||||
|
||||
self.save(validate: false)
|
||||
end
|
||||
|
||||
|
|
@ -2221,7 +2266,12 @@ module JamRuby
|
|||
|
||||
if lesson_session.lesson_booking.user_decremented
|
||||
# because we decrement test_drive credits as soon as you book, we need to bring it back now
|
||||
self.remaining_test_drives = self.remaining_test_drives + 1
|
||||
if lesson_session.posa_card
|
||||
self.jamclass_credits = self.jamclass_credits + 1
|
||||
else
|
||||
self.remaining_test_drives = self.remaining_test_drives + 1
|
||||
end
|
||||
|
||||
self.save(validate: false)
|
||||
end
|
||||
UserMailer.teacher_test_drive_no_bill(lesson_session).deliver_now
|
||||
|
|
@ -2232,6 +2282,10 @@ module JamRuby
|
|||
total_test_drives - remaining_test_drives
|
||||
end
|
||||
|
||||
def used_posa_credits
|
||||
total_posa_credits - jamclass_credits
|
||||
end
|
||||
|
||||
def uncollectables(limit = 10)
|
||||
LessonPaymentCharge.where(user_id:self.id).order(:created_at).where('billing_attempts > 0').where(billed: false).limit(limit)
|
||||
end
|
||||
|
|
|
|||
|
|
@ -76,6 +76,7 @@
|
|||
isNativeClient: gon.isNativeClient,
|
||||
musician: context.JK.currentUserMusician,
|
||||
sales_count: userDetail.sales_count,
|
||||
owned_retailer_id: userDetail.owned_retailer_id,
|
||||
is_affiliate_partner: userDetail.is_affiliate_partner,
|
||||
affiliate_earnings: (userDetail.affiliate_earnings / 100).toFixed(2),
|
||||
affiliate_referral_count: userDetail.affiliate_referral_count,
|
||||
|
|
@ -146,6 +147,7 @@
|
|||
$("#account-content-scroller").on('click', '#account-payment-history-link', function(evt) {evt.stopPropagation(); navToPaymentHistory(); return false; } );
|
||||
$("#account-content-scroller").on('click', '#account-affiliate-partner-link', function(evt) {evt.stopPropagation(); navToAffiliates(); return false; } );
|
||||
$("#account-content-scroller").on('click', '#account-school-link', function(evt) {evt.stopPropagation(); navToSchool(); return false; } );
|
||||
$("#account-content-scroller").on('click', '#account-retailer-link', function(evt) {evt.stopPropagation(); navToRetailer(); return false; } );
|
||||
}
|
||||
|
||||
function renderAccount() {
|
||||
|
|
@ -208,6 +210,11 @@
|
|||
window.location = '/client#/account/school'
|
||||
}
|
||||
|
||||
function navToRetailer() {
|
||||
resetForm()
|
||||
window.location = '/client#/account/retailer'
|
||||
}
|
||||
|
||||
// handle update avatar event
|
||||
function updateAvatar(avatar_url) {
|
||||
var photoUrl = context.JK.resolveAvatarUrl(avatar_url);
|
||||
|
|
|
|||
|
|
@ -64,6 +64,7 @@
|
|||
$screen.find('select[name=skill_level]').val(userDetail.skill_level);
|
||||
$screen.find('select[name=concert_count]').val(userDetail.concert_count);
|
||||
$screen.find('select[name=studio_session_count]').val(userDetail.studio_session_count);
|
||||
context.JK.checkbox($instrumentSelector.find('input[type="checkbox"]'), true)
|
||||
}
|
||||
|
||||
function isUserInstrument(instrument, userInstruments) {
|
||||
|
|
@ -101,6 +102,8 @@
|
|||
});
|
||||
$userGenres.append(genreHtml);
|
||||
});
|
||||
|
||||
context.JK.checkbox($userGenres.find('input[type="checkbox"]'), true)
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -3,8 +3,8 @@ rest = context.JK.Rest()
|
|||
logger = context.JK.logger
|
||||
|
||||
AppStore = context.AppStore
|
||||
SchoolActions = context.RetailerActions
|
||||
SchoolStore = context.RetailerStore
|
||||
RetailerActions = context.RetailerActions
|
||||
RetailerStore = context.RetailerStore
|
||||
UserStore = context.UserStore
|
||||
|
||||
profileUtils = context.JK.ProfileUtils
|
||||
|
|
@ -31,7 +31,7 @@ profileUtils = context.JK.ProfileUtils
|
|||
onAppInit: (@app) ->
|
||||
@app.bindScreen('account/retailer', {beforeShow: @beforeShow, afterShow: @afterShow, beforeHide: @beforeHide})
|
||||
|
||||
onSchoolChanged: (retailerState) ->
|
||||
onRetailerChanged: (retailerState) ->
|
||||
@setState(retailerState)
|
||||
|
||||
onUserChanged: (userState) ->
|
||||
|
|
@ -57,6 +57,7 @@ profileUtils = context.JK.ProfileUtils
|
|||
beforeHide: (e) ->
|
||||
#ProfileActions.viewTeacherProfileDone()
|
||||
@screenVisible = false
|
||||
return true
|
||||
|
||||
beforeShow: (e) ->
|
||||
|
||||
|
|
@ -141,7 +142,7 @@ profileUtils = context.JK.ProfileUtils
|
|||
@app.ajaxError(jqXHR, null, null)
|
||||
|
||||
inviteTeacher: () ->
|
||||
@app.layout.showDialog('invite-school-user', {d1: true})
|
||||
@app.layout.showDialog('invite-retailer-user', {d1: true})
|
||||
|
||||
resendInvitation: (id, e) ->
|
||||
e.preventDefault()
|
||||
|
|
@ -169,13 +170,13 @@ profileUtils = context.JK.ProfileUtils
|
|||
|
||||
removeFromRetailer: (id, isTeacher, e) ->
|
||||
if isTeacher
|
||||
rest.deleteRetailerTeacher({id: this.state.retailer.id, teacher_id: id}).done((response) => @removeFromRetailerDone(response)).fail((jqXHR) => @removeFromSchoolFail(jqXHR))
|
||||
rest.deleteRetailerTeacher({id: this.state.retailer.id, teacher_id: id}).done((response) => @removeFromRetailerDone(response)).fail((jqXHR) => @removeFromRetailerFail(jqXHR))
|
||||
|
||||
removeFromRetailerDone: (retailer) ->
|
||||
context.JK.Banner.showNotice("User removed", "User was removed from your retailer.")
|
||||
context.RetailerActions.updateRetailer(retailer)
|
||||
|
||||
removeFromSchoolFail: (jqXHR) ->
|
||||
removeFromRetailerFail: (jqXHR) ->
|
||||
@app.ajaxError(jqXHR)
|
||||
|
||||
renderUser: (user, isTeacher) ->
|
||||
|
|
@ -217,7 +218,8 @@ profileUtils = context.JK.ProfileUtils
|
|||
|
||||
if this.state.retailer.teachers? && this.state.retailer.teachers.length > 0
|
||||
for teacher in this.state.retailer.teachers
|
||||
teachers.push(@renderUser(teacher.user, true))
|
||||
if teacher.user
|
||||
teachers.push(@renderUser(teacher.user, true))
|
||||
else
|
||||
teachers = `<p>No teachers</p>`
|
||||
|
||||
|
|
@ -248,61 +250,30 @@ profileUtils = context.JK.ProfileUtils
|
|||
@account()
|
||||
|
||||
account: () ->
|
||||
ownerEmail = this.state.school.owner.email
|
||||
correspondenceEmail = this.state.school.correspondence_email
|
||||
correspondenceDisabled = !@isSchoolManaged()
|
||||
|
||||
nameErrors = context.JK.reactSingleFieldErrors('name', @state.updateErrors)
|
||||
correspondenceEmailErrors = context.JK.reactSingleFieldErrors('correspondence_email', @state.updateErrors)
|
||||
nameClasses = classNames({name: true, error: nameErrors?, field: true})
|
||||
correspondenceEmailClasses = classNames({
|
||||
correspondence_email: true,
|
||||
error: correspondenceEmailErrors?,
|
||||
field: true
|
||||
})
|
||||
|
||||
cancelClasses = { "button-grey": true, "cancel" : true, disabled: this.state.updating }
|
||||
updateClasses = { "button-orange": true, "update" : true, disabled: this.state.updating }
|
||||
|
||||
`<div className="account-block info-block">
|
||||
<div className={nameClasses}>
|
||||
<label>School Name:</label>
|
||||
<label>Retailer Name:</label>
|
||||
<input type="text" name="name" value={this.nameValue()} onChange={this.nameChanged}/>
|
||||
{nameErrors}
|
||||
</div>
|
||||
<div className="field logo">
|
||||
<label>School Logo:</label>
|
||||
<AvatarEditLink target={this.state.school} target_type="school"/>
|
||||
<label>Retailer Logo:</label>
|
||||
<AvatarEditLink target={this.state.retailer} target_type="retailer"/>
|
||||
</div>
|
||||
|
||||
<h4>Management Preference</h4>
|
||||
|
||||
<div className="field scheduling_communication">
|
||||
<div className="scheduling_communication school">
|
||||
<input type="radio" name="scheduling_communication" readOnly={true} value="school"
|
||||
checked={this.isSchoolManaged()}/><label>School owner will manage scheduling of student lessons sourced
|
||||
by JamKazam</label>
|
||||
</div>
|
||||
<div className="scheduling_communication teacher">
|
||||
<input type="radio" name="scheduling_communication" readOnly={true} value="teacher"
|
||||
checked={!this.isSchoolManaged()}/><label>Teacher will manage scheduling of lessons</label>
|
||||
</div>
|
||||
</div>
|
||||
<div className={correspondenceEmailClasses}>
|
||||
<label>Correspondence Email:</label>
|
||||
<input type="text" name="correspondence_email" placeholder={ownerEmail} defaultValue={correspondenceEmail}
|
||||
disabled={correspondenceDisabled}/>
|
||||
|
||||
<div className="hint">All emails relating to lesson scheduling will go to this email if school owner manages
|
||||
scheduling.
|
||||
</div>
|
||||
{correspondenceEmailErrors}
|
||||
</div>
|
||||
|
||||
<h4>Payments</h4>
|
||||
|
||||
<div className="field stripe-connect">
|
||||
<StripeConnect purpose='school' user={this.state.user}/>
|
||||
<StripeConnect purpose='retailer' user={this.state.user}/>
|
||||
</div>
|
||||
|
||||
<div className="actions">
|
||||
|
|
@ -340,7 +311,7 @@ profileUtils = context.JK.ProfileUtils
|
|||
|
||||
agreement: () ->
|
||||
`<div className="agreement-block info-block">
|
||||
<p>The agreement between your music school and JamKazam is part of JamKazam's terms of service. You can find the
|
||||
<p>The agreement between your retailer and JamKazam is part of JamKazam's terms of service. You can find the
|
||||
complete terms of service <a href="/corp/terms" target="_blank">here</a>. And you can find the section that is
|
||||
most specific to the retailer terms <a href="/corp/terms" target="_blank">here</a>.</p>
|
||||
</div>`
|
||||
|
|
|
|||
|
|
@ -31,18 +31,28 @@ AvatarStore = context.AvatarStore
|
|||
render: () ->
|
||||
if this.props.target?.photo_url?
|
||||
|
||||
testStudentUrl = "/school/#{this.props.target.id}/student?preview=true"
|
||||
testTeacherUrl = "/school/#{this.props.target.id}/teacher?preview=true"
|
||||
target_type = this.props.target_type
|
||||
|
||||
testStudentUrl = "/#{target_type}/#{this.props.target.id}/student?preview=true"
|
||||
testTeacherUrl = "/#{target_type}/#{this.props.target.id}/teacher?preview=true"
|
||||
|
||||
if target_type == 'school'
|
||||
previewArea = `<div className="hint">See how it will look to
|
||||
<a href={testStudentUrl} target="_blank">students</a> and
|
||||
<a href={testTeacherUrl} target="_blank">teachers</a>
|
||||
</div>`
|
||||
else
|
||||
previewArea = `<div className="hint">See how it will look to
|
||||
<a href={testTeacherUrl} target="_blank">teachers</a>
|
||||
</div>`
|
||||
|
||||
|
||||
`<div className="avatar-edit-link">
|
||||
<img src={this.props.target.photo_url}></img>
|
||||
<br/>
|
||||
<a onClick={this.startUpdate}>change/update logo</a><br/>
|
||||
|
||||
<div className="hint">See how it will look to
|
||||
<a href={testStudentUrl} target="_blank">students</a> and
|
||||
<a href={testTeacherUrl} target="_blank">teachers</a>
|
||||
</div>
|
||||
{previewArea}
|
||||
</div>`
|
||||
else
|
||||
`<div className="avatar-edit-link">
|
||||
|
|
|
|||
|
|
@ -0,0 +1,147 @@
|
|||
context = window
|
||||
RetailerStore = context.RetailerStore
|
||||
|
||||
@InviteRetailerUserDialog = React.createClass({
|
||||
|
||||
mixins: [Reflux.listenTo(@AppStore, "onAppInit"), Reflux.listenTo(RetailerStore, "onRetailerChanged")]
|
||||
teacher: false
|
||||
|
||||
beforeShow: (args) ->
|
||||
logger.debug("InviteRetailerUserDialog.beforeShow", args.d1)
|
||||
@firstName = ''
|
||||
@lastName = ''
|
||||
@email = ''
|
||||
|
||||
@setState({inviteErrors: null, teacher: args.d1})
|
||||
afterHide: () ->
|
||||
|
||||
onRetailerChanged: (retailerState) ->
|
||||
@setState(retailerState)
|
||||
|
||||
onAppInit: (@app) ->
|
||||
dialogBindings = {
|
||||
'beforeShow': @beforeShow,
|
||||
'afterHide': @afterHide
|
||||
};
|
||||
|
||||
@app.bindDialog('invite-retailer-user', dialogBindings);
|
||||
|
||||
componentDidMount: () ->
|
||||
@root = $(@getDOMNode())
|
||||
|
||||
getInitialState: () ->
|
||||
{inviteErrors: null, retailer: null, sending: false}
|
||||
|
||||
doCancel: (e) ->
|
||||
e.preventDefault()
|
||||
@app.layout.closeDialog('invite-retailer-user', true);
|
||||
|
||||
doInvite: (e) ->
|
||||
e.preventDefault()
|
||||
|
||||
if this.state.sending
|
||||
console.log("sending already")
|
||||
return
|
||||
|
||||
|
||||
email = @root.find('input[name="email"]').val()
|
||||
lastName = @root.find('input[name="last_name"]').val()
|
||||
firstName = @root.find('input[name="first_name"]').val()
|
||||
retailer = context.RetailerStore.getState().retailer
|
||||
@setState({inviteErrors: null, sending: true})
|
||||
rest.createRetailerInvitation({
|
||||
id: retailer.id,
|
||||
as_teacher: this.state.teacher,
|
||||
email: email,
|
||||
last_name: lastName,
|
||||
first_name: firstName
|
||||
}).done((response) => @createDone(response)).fail((jqXHR) => @createFail(jqXHR))
|
||||
|
||||
createDone: (response) ->
|
||||
console.log("invitation added", response)
|
||||
@setState({inviteErrors:null, sending: false})
|
||||
context.RetailerActions.addInvitation(this.state.teacher, response)
|
||||
context.JK.Banner.showNotice("invitation sent", "Your invitation has been sent!")
|
||||
@app.layout.closeDialog('invite-retailer-user')
|
||||
|
||||
createFail: (jqXHR) ->
|
||||
handled = false
|
||||
|
||||
if jqXHR.status == 422
|
||||
errors = JSON.parse(jqXHR.responseText)
|
||||
@setState({inviteErrors: errors, sending: false})
|
||||
handled = true
|
||||
|
||||
if !handled
|
||||
@app.ajaxError(jqXHR, null, null)
|
||||
|
||||
|
||||
close: (e) ->
|
||||
e.preventDefault()
|
||||
@app.layout.closeDialog('invite-retailer-user');
|
||||
|
||||
|
||||
renderRetailer: () ->
|
||||
firstNameErrors = context.JK.reactSingleFieldErrors('first_name', @state.inviteErrors)
|
||||
lastNameErrors = context.JK.reactSingleFieldErrors('last_name', @state.inviteErrors)
|
||||
emailErrors = context.JK.reactSingleFieldErrors('email', @state.inviteErrors)
|
||||
|
||||
firstNameClasses = classNames({first_name: true, error: firstNameErrors?, field: true})
|
||||
lastNameClasses = classNames({last_name: true, error: lastNameErrors?, field: true})
|
||||
emailClasses = classNames({email: true, error: emailErrors?, field: true})
|
||||
sendInvitationClasses = classNames({'button-orange': true, disabled: this.state.sending})
|
||||
|
||||
if @state.teacher
|
||||
title = 'invite teacher'
|
||||
help = `<p>Send invitations to teachers who teach through your music store. When your teachers accept this invitation to create teacher accounts on JamKazam, you can easily send emails to customers who purchase online lessons pointing these customers to your preferred teachers from your store. </p>`
|
||||
else
|
||||
title = 'invite student'
|
||||
help = `<p>
|
||||
Shouldn't be here...
|
||||
</p>`
|
||||
|
||||
`<div>
|
||||
<div className="content-head">
|
||||
<img className="content-icon" src="/assets/content/icon_add.png" height={19} width={19}/>
|
||||
|
||||
<h1>{title}</h1>
|
||||
</div>
|
||||
<div className="dialog-inner">
|
||||
|
||||
{help}
|
||||
|
||||
<div className={firstNameClasses}>
|
||||
<label>First Name: </label>
|
||||
<input type="text" defaultValue={this.firstName} name="first_name"/>
|
||||
{firstNameErrors}
|
||||
</div>
|
||||
|
||||
<div className={lastNameClasses}>
|
||||
<label>Last Name: </label>
|
||||
<input type="text" defaultValue={this.lastName} name="last_name"/>
|
||||
{lastNameErrors}
|
||||
</div>
|
||||
|
||||
<div className={emailClasses}>
|
||||
<label>Email Name: </label>
|
||||
<input type="text" defaultValue={this.email} name="email"/>
|
||||
{emailErrors}
|
||||
</div>
|
||||
|
||||
<div className="actions">
|
||||
<a onClick={this.doCancel} className="button-grey">CANCEL</a>
|
||||
<a onClick={this.doInvite} className={sendInvitationClasses}>SEND INVITATION</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>`
|
||||
|
||||
render: () ->
|
||||
retailer = this.state.retailer
|
||||
|
||||
if !retailer?
|
||||
return `<div>no retailer</div>`
|
||||
|
||||
@renderRetailer()
|
||||
|
||||
|
||||
})
|
||||
|
|
@ -30,7 +30,7 @@ SchoolStore = context.SchoolStore
|
|||
@root = $(@getDOMNode())
|
||||
|
||||
getInitialState: () ->
|
||||
{inviteErrors: null, school: null}
|
||||
{inviteErrors: null, school: null, sending: false}
|
||||
|
||||
doCancel: (e) ->
|
||||
e.preventDefault()
|
||||
|
|
@ -39,11 +39,15 @@ SchoolStore = context.SchoolStore
|
|||
doInvite: (e) ->
|
||||
e.preventDefault()
|
||||
|
||||
if this.state.sending
|
||||
console.log("sending already")
|
||||
return
|
||||
|
||||
email = @root.find('input[name="email"]').val()
|
||||
lastName = @root.find('input[name="last_name"]').val()
|
||||
firstName = @root.find('input[name="first_name"]').val()
|
||||
school = context.SchoolStore.getState().school
|
||||
@setState({inviteErrors: null})
|
||||
@setState({inviteErrors: null, sending: true})
|
||||
rest.createSchoolInvitation({
|
||||
id: school.id,
|
||||
as_teacher: this.state.teacher,
|
||||
|
|
@ -54,6 +58,7 @@ SchoolStore = context.SchoolStore
|
|||
|
||||
createDone: (response) ->
|
||||
console.log("invitation added", response)
|
||||
@setState({inviteErrors:null, sending: false})
|
||||
context.SchoolActions.addInvitation(this.state.teacher, response)
|
||||
context.JK.Banner.showNotice("invitation sent", "Your invitation has been sent!")
|
||||
@app.layout.closeDialog('invite-school-user')
|
||||
|
|
@ -63,7 +68,7 @@ SchoolStore = context.SchoolStore
|
|||
|
||||
if jqXHR.status == 422
|
||||
errors = JSON.parse(jqXHR.responseText)
|
||||
@setState({inviteErrors: errors})
|
||||
@setState({inviteErrors: errors, sending: false})
|
||||
handled = true
|
||||
|
||||
if !handled
|
||||
|
|
@ -120,6 +125,7 @@ I'm writing to make you aware of a very interesting new option for private music
|
|||
firstNameClasses = classNames({first_name: true, error: firstNameErrors?, field: true})
|
||||
lastNameClasses = classNames({last_name: true, error: lastNameErrors?, field: true})
|
||||
emailClasses = classNames({email: true, error: emailErrors?, field: true})
|
||||
sendInvitationClasses = classNames({'button-orange': true, disabled: this.state.sending})
|
||||
|
||||
if @state.teacher
|
||||
title = 'invite teacher'
|
||||
|
|
@ -167,7 +173,7 @@ I'm writing to make you aware of a very interesting new option for private music
|
|||
|
||||
<div className="actions">
|
||||
<a onClick={this.doCancel} className="button-grey">CANCEL</a>
|
||||
<a onClick={this.doInvite} className="button-orange">SEND INVITATION</a>
|
||||
<a onClick={this.doInvite} className={sendInvitationClasses}>SEND INVITATION</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>`
|
||||
|
|
|
|||
|
|
@ -41,8 +41,12 @@ rest = new context.JK.Rest()
|
|||
|
||||
onPick: () ->
|
||||
|
||||
rest.generateSchoolFilePickerPolicy({id: @target.id})
|
||||
.done((filepickerPolicy) =>
|
||||
if @type == 'school'
|
||||
genpolicy = rest.generateSchoolFilePickerPolicy({id: @target.id})
|
||||
else if @type == 'retailer'
|
||||
genpolicy = rest.generateRetailerFilePickerPolicy({id: @target.id})
|
||||
|
||||
genpolicy.done((filepickerPolicy) =>
|
||||
@pickerOpen = true
|
||||
@changed()
|
||||
window.filepicker.setKey(gon.fp_apikey);
|
||||
|
|
@ -69,7 +73,7 @@ rest = new context.JK.Rest()
|
|||
.fail(@app.ajaxError)
|
||||
|
||||
afterImageUpload: (fpfile) ->
|
||||
logger.debug("afterImageUploaded")
|
||||
logger.debug("afterImageUploaded", typeof fpfile, fpfile)
|
||||
$.cookie('original_fpfile', JSON.stringify(fpfile));
|
||||
|
||||
@currentFpfile = fpfile
|
||||
|
|
@ -79,8 +83,12 @@ rest = new context.JK.Rest()
|
|||
@signFpfile()
|
||||
|
||||
signFpfile: () ->
|
||||
rest.generateSchoolFilePickerPolicy({ id: @target.id})
|
||||
.done((policy) => (
|
||||
if @type == 'school'
|
||||
genpolicy = rest.generateSchoolFilePickerPolicy({id: @target.id})
|
||||
else if @type == 'retailer'
|
||||
genpolicy = rest.generateRetailerFilePickerPolicy({id: @target.id})
|
||||
|
||||
genpolicy.done((policy) => (
|
||||
@signedCurrentFpfile = @currentFpfile.url + '?signature=' + policy.signature + '&policy=' + policy.policy;
|
||||
@changed()
|
||||
))
|
||||
|
|
@ -125,6 +133,8 @@ rest = new context.JK.Rest()
|
|||
|
||||
if @type == 'school'
|
||||
window.SchoolActions.refresh()
|
||||
if @type == 'retailer'
|
||||
window.RetailerActions.refresh()
|
||||
|
||||
@app.layout.closeDialog('upload-avatar')
|
||||
|
||||
|
|
@ -184,7 +194,10 @@ rest = new context.JK.Rest()
|
|||
@updatingAvatar = true
|
||||
@changed()
|
||||
|
||||
rest.deleteSchoolAvatar({id: @target.id}).done((response) => @deleteDone(response)).fail((jqXHR) => @deleteFail(jqXHR))
|
||||
if @type == 'school'
|
||||
rest.deleteSchoolAvatar({id: @target.id}).done((response) => @deleteDone(response)).fail((jqXHR) => @deleteFail(jqXHR))
|
||||
else if @type == 'retailer'
|
||||
rest.deleteRetailerAvatar({id: @target.id}).done((response) => @deleteDone(response)).fail((jqXHR) => @deleteFail(jqXHR))
|
||||
|
||||
deleteDone: (response) ->
|
||||
@currentFpfile = null
|
||||
|
|
@ -194,6 +207,8 @@ rest = new context.JK.Rest()
|
|||
@currentCropSelection = null
|
||||
if @type == 'school'
|
||||
window.SchoolActions.refresh()
|
||||
else if @type == 'retailer'
|
||||
window.RetailerActions.refresh()
|
||||
|
||||
@app.layout.closeDialog('upload-avatar');
|
||||
|
||||
|
|
@ -219,8 +234,12 @@ rest = new context.JK.Rest()
|
|||
logger.debug("Converting...");
|
||||
fpfile = @determineCurrentFpfile();
|
||||
|
||||
rest.generateSchoolFilePickerPolicy({ id: @target.id, handle: fpfile.url, convert: true })
|
||||
.done((filepickerPolicy) =>
|
||||
if @type == 'school'
|
||||
genpolicy = rest.generateSchoolFilePickerPolicy({ id: @target.id, handle: fpfile.url, convert: true })
|
||||
else if @type == 'retailer'
|
||||
genpolicy = rest.generateRetailerFilePickerPolicy({ id: @target.id, handle: fpfile.url, convert: true })
|
||||
|
||||
genpolicy.done((filepickerPolicy) =>
|
||||
window.filepicker.setKey(gon.fp_apikey)
|
||||
window.filepicker.convert(fpfile, {
|
||||
crop: [
|
||||
|
|
@ -243,8 +262,12 @@ rest = new context.JK.Rest()
|
|||
scale: (cropped) ->
|
||||
logger.debug("converting cropped");
|
||||
|
||||
rest.generateSchoolFilePickerPolicy({id: @target.id, handle: cropped.url, convert: true})
|
||||
.done((filepickerPolicy) => (
|
||||
if @type == 'school'
|
||||
genpolicy = rest.generateSchoolFilePickerPolicy({id: @target.id, handle: cropped.url, convert: true})
|
||||
else if @type == 'retailer'
|
||||
genpolicy = rest.generateRetailerFilePickerPolicy({id: @target.id, handle: cropped.url, convert: true})
|
||||
|
||||
genpolicy.done((filepickerPolicy) => (
|
||||
window.filepicker.convert(cropped, {
|
||||
height: @targetCropSize,
|
||||
width: @targetCropSize,
|
||||
|
|
@ -275,14 +298,24 @@ rest = new context.JK.Rest()
|
|||
|
||||
updateServer: (scaledLarger, scaled, cropped) ->
|
||||
logger.debug("converted and scaled final image %o", scaled);
|
||||
rest.updateSchoolAvatar({
|
||||
id: @target.id,
|
||||
original_fpfile: @determineCurrentFpfile(),
|
||||
cropped_fpfile: scaled,
|
||||
cropped_large_fpfile: scaledLarger,
|
||||
crop_selection: @selection
|
||||
})
|
||||
.done((response) => @updateAvatarSuccess(response))
|
||||
if @type == 'school'
|
||||
update = rest.updateSchoolAvatar({
|
||||
id: @target.id,
|
||||
original_fpfile: @determineCurrentFpfile(),
|
||||
cropped_fpfile: scaled,
|
||||
cropped_large_fpfile: scaledLarger,
|
||||
crop_selection: @selection
|
||||
})
|
||||
else if @type == 'retailer'
|
||||
update = rest.updateRetailerAvatar({
|
||||
id: @target.id,
|
||||
original_fpfile: @determineCurrentFpfile(),
|
||||
cropped_fpfile: scaled,
|
||||
cropped_large_fpfile: scaledLarger,
|
||||
crop_selection: @selection
|
||||
})
|
||||
|
||||
update.done((response) => @updateAvatarSuccess(response))
|
||||
.fail(@app.ajaxError)
|
||||
.always(() => (
|
||||
@updatingAvatar = false
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ rest = new context.JK.Rest()
|
|||
@teacherInvitations = response.entries
|
||||
@changed()
|
||||
|
||||
onAddInvitation: (invitation) ->
|
||||
onAddInvitation: (teacher, invitation) ->
|
||||
@teacherInvitations.push(invitation)
|
||||
@changed()
|
||||
|
||||
|
|
|
|||
|
|
@ -18,6 +18,8 @@ rest = new context.JK.Rest()
|
|||
redirect = '/client#/account/school'
|
||||
else if purpose == 'jamclass-home'
|
||||
redirect = '/client#/jamclass'
|
||||
else if purpose == 'retailer'
|
||||
redirect = '/client#/account/retailer'
|
||||
else
|
||||
throw "unknown purpose #{purpose}"
|
||||
|
||||
|
|
|
|||
|
|
@ -48,4 +48,39 @@
|
|||
margin-right: 3px;
|
||||
}
|
||||
}
|
||||
|
||||
.acct-prf-inst-ck {
|
||||
.icheckbox_minimal {
|
||||
margin-right: 8px;
|
||||
position: relative;
|
||||
top: 3px;
|
||||
}
|
||||
}
|
||||
|
||||
.acct-prf-inst-drdwn {
|
||||
select.proficiency_selector {
|
||||
color:black;
|
||||
}
|
||||
}
|
||||
|
||||
.user-genre-desc {
|
||||
|
||||
margin: 4px;
|
||||
padding: 4px;
|
||||
|
||||
.icheckbox_minimal {
|
||||
top: 4px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
span {
|
||||
vertical-align: middle;
|
||||
margin: 4px;
|
||||
padding: 4px;
|
||||
}
|
||||
}
|
||||
|
||||
.instrument_selector {
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,265 @@
|
|||
@import "client/common";
|
||||
|
||||
|
||||
#account-retailer {
|
||||
div[data-react-class="AccountRetailerScreen"] {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.profile-header {
|
||||
padding: 10px 30px !important;
|
||||
}
|
||||
|
||||
label {
|
||||
display: inline-block;
|
||||
min-width: 200px;
|
||||
}
|
||||
input {
|
||||
min-width:200px;
|
||||
}
|
||||
.hint {
|
||||
margin-left: 200px;
|
||||
font-size: 12px;
|
||||
font-style: italic;
|
||||
margin-top: 5px;
|
||||
}
|
||||
.iradio_minimal {
|
||||
display: inline-block;
|
||||
top: 4px;
|
||||
margin-right: 5px;
|
||||
}
|
||||
.field {
|
||||
margin-bottom: 30px;
|
||||
|
||||
&.stripe-connect {
|
||||
margin-bottom: 10px;
|
||||
label {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
}
|
||||
}
|
||||
.store-header {
|
||||
float: left;
|
||||
padding-top: 10px;
|
||||
font-size: 20px;
|
||||
font-weight: bold;
|
||||
}
|
||||
.profile-nav a {
|
||||
position: absolute;
|
||||
text-align: center;
|
||||
height: 100%;
|
||||
width: 98%;
|
||||
margin: 0 auto;
|
||||
padding: 11px 0 0 0;
|
||||
@include border-box_sizing;
|
||||
}
|
||||
|
||||
.profile-tile {
|
||||
width: 25%;
|
||||
float: left;
|
||||
@include border-box_sizing;
|
||||
height: 40px;
|
||||
position: relative;
|
||||
}
|
||||
.profile-body {
|
||||
padding-top: 100px;
|
||||
}
|
||||
.profile-photo {
|
||||
width: 16%;
|
||||
@include border-box_sizing;
|
||||
}
|
||||
.profile-nav {
|
||||
margin: 0;
|
||||
width: 84%;
|
||||
}
|
||||
.profile-wrapper {
|
||||
padding: 10px 20px
|
||||
}
|
||||
|
||||
.main-content {
|
||||
float: left;
|
||||
@include border-box_sizing;
|
||||
width: 84%;
|
||||
}
|
||||
|
||||
.info-block {
|
||||
min-height:400px;
|
||||
h3 {
|
||||
font-weight: bold;
|
||||
font-size: 18px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
h4 {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.section {
|
||||
margin-bottom: 40px;
|
||||
&.teachers {
|
||||
clear: both;
|
||||
}
|
||||
}
|
||||
|
||||
table.jamtable {
|
||||
font-size: 12px;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.stripe-connect {
|
||||
padding: 0;
|
||||
border: 0;
|
||||
background: transparent;
|
||||
outline:transparent;
|
||||
cursor:pointer;
|
||||
}
|
||||
|
||||
.actions {
|
||||
float: left;
|
||||
margin-top: 30px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
a.cancel {
|
||||
margin-left:3px;
|
||||
}
|
||||
|
||||
|
||||
.avatar-edit-link {
|
||||
display:inline-block;
|
||||
img {
|
||||
max-width:200px;
|
||||
}
|
||||
}
|
||||
|
||||
.avatar-edit-link {
|
||||
.hint {
|
||||
margin-left:0;
|
||||
}
|
||||
}
|
||||
|
||||
.column {
|
||||
width:50%;
|
||||
@include border_box_sizing;
|
||||
|
||||
h3 {
|
||||
float:left;
|
||||
}
|
||||
.invite-dialog {
|
||||
float:right;
|
||||
margin-right:2px;
|
||||
}
|
||||
&.column-left {
|
||||
float:left;
|
||||
padding-right:30px;
|
||||
|
||||
}
|
||||
&.column-right {
|
||||
float:right;
|
||||
padding-left:30px;
|
||||
}
|
||||
|
||||
.username {
|
||||
max-width:40%;
|
||||
font-size:16px;
|
||||
color:white;
|
||||
}
|
||||
table {
|
||||
width:100%;
|
||||
}
|
||||
td.description {
|
||||
font-size:16px;
|
||||
color: white;
|
||||
vertical-align: top;
|
||||
white-space: nowrap;
|
||||
}
|
||||
td.message {
|
||||
color: $ColorTextTypical;
|
||||
padding-left: 10px;
|
||||
vertical-align: top;
|
||||
text-align:right;
|
||||
}
|
||||
.detail-block {
|
||||
display:inline-block;
|
||||
font-size:12px;
|
||||
}
|
||||
.resend {
|
||||
float:left;
|
||||
}
|
||||
.delete {
|
||||
float:right;
|
||||
}
|
||||
.teacher-invites, .student-invites {
|
||||
margin-bottom: 20px;
|
||||
margin-top:40px;
|
||||
font-size:12px;
|
||||
min-height:40px;
|
||||
p {
|
||||
font-size:12px;
|
||||
}
|
||||
}
|
||||
.teachers, .students {
|
||||
margin-bottom:20px;
|
||||
}
|
||||
p {
|
||||
font-size:12px;
|
||||
margin-left:0;
|
||||
}
|
||||
.retailer-invitation {
|
||||
margin-bottom:20px;
|
||||
}
|
||||
}
|
||||
.retailer-user {
|
||||
margin-bottom:20px;
|
||||
|
||||
.avatar {
|
||||
position:absolute;
|
||||
padding:1px;
|
||||
width:32px;
|
||||
height:32px;
|
||||
background-color:#ed4818;
|
||||
margin:0;
|
||||
-webkit-border-radius:16px;
|
||||
-moz-border-radius:16px;
|
||||
border-radius:16px;
|
||||
float:none;
|
||||
}
|
||||
.avatar img {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
-webkit-border-radius:16px;
|
||||
-moz-border-radius:16px;
|
||||
border-radius:16px;
|
||||
}
|
||||
|
||||
.usersname {
|
||||
margin-left:56px;
|
||||
line-height:32px;
|
||||
vertical-align: middle;
|
||||
display: inline-block;
|
||||
|
||||
}
|
||||
|
||||
.just-name {
|
||||
display:block;
|
||||
}
|
||||
.just-email {
|
||||
position: relative;
|
||||
top: -14px;
|
||||
font-size:12px;
|
||||
}
|
||||
|
||||
.user-actions {
|
||||
float: right;
|
||||
line-height: 32px;
|
||||
height: 32px;
|
||||
vertical-align: middle;
|
||||
font-size:12px;
|
||||
}
|
||||
}
|
||||
p {
|
||||
font-size:12px;
|
||||
margin:0;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
@import "client/common";
|
||||
|
||||
#invite-retailer-user-dialog {
|
||||
width: 500px;
|
||||
|
||||
h3 {
|
||||
color:white;
|
||||
margin-bottom:20px;
|
||||
}
|
||||
.dialog-inner {
|
||||
width: auto;
|
||||
}
|
||||
|
||||
.actions {
|
||||
clear: both;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
p { margin-bottom:20px;}
|
||||
|
||||
label {
|
||||
width:150px;
|
||||
display:inline-block;
|
||||
}
|
||||
input {
|
||||
display:inline-block;
|
||||
width:250px;
|
||||
}
|
||||
|
||||
.field {
|
||||
margin-bottom:20px;
|
||||
}
|
||||
|
||||
textarea {
|
||||
height:500px;
|
||||
width:100%;
|
||||
margin-bottom:20px;
|
||||
}
|
||||
}
|
||||
|
|
@ -115,6 +115,8 @@ class ApiUsersController < ApiController
|
|||
teacher: params[:teacher],
|
||||
school_invitation_code: params[:school_invitation_code],
|
||||
school_id: params[:school_id],
|
||||
retailer_invitation_code: params[:retailer_invitation_code],
|
||||
retailer_id: params[:retailer_id],
|
||||
school_interest: params[:school_interest],
|
||||
education_interest: params[:education_interest],
|
||||
affiliate_referral_id: cookies[:affiliate_visitor],
|
||||
|
|
|
|||
|
|
@ -194,8 +194,25 @@
|
|||
<div class="right">
|
||||
<a id="account-school-link" href="#" class="button-orange">UPDATE</a>
|
||||
</div>
|
||||
<br clear="all" />
|
||||
{% } %}
|
||||
<br clear="all" />
|
||||
|
||||
{% if (data.owned_retailer_id) { %}
|
||||
<hr />
|
||||
<div class="account-left">
|
||||
<h2>retailer:</h2>
|
||||
</div>
|
||||
<div class="account-mid school">
|
||||
<div class="whitespace">
|
||||
<span class="retailer-info">Invite teachers, students, and manage your retailer settings.</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="right">
|
||||
<a id="account-retailer-link" href="#" class="button-orange">UPDATE</a>
|
||||
</div>
|
||||
<br clear="all" />
|
||||
{% } %}
|
||||
|
||||
|
||||
</div>
|
||||
<!-- end content wrapper -->
|
||||
|
|
|
|||
|
|
@ -84,8 +84,8 @@
|
|||
|
||||
<script type="text/template" id="account-profile-instrument">
|
||||
<tr data-instrument-id='{id}'>
|
||||
<td><input type="checkbox" {checked} />{description}</td>
|
||||
<td align="right" width="50%">
|
||||
<td class="acct-prf-inst-ck"><input type="checkbox" {checked} />{description}</td>
|
||||
<td align="right" width="50%" class="acct-prf-inst-drdwn">
|
||||
<select name="proficiency" class='proficiency_selector'>
|
||||
<option value="1">Beginner</option>
|
||||
<option value="2">Intermediate</option>
|
||||
|
|
@ -96,5 +96,5 @@
|
|||
</script>
|
||||
|
||||
<script type="text/template" id="template-user-setup-genres">
|
||||
<tr><td><input value="{id}" {checked} type="checkbox" />{description}</td></tr>
|
||||
<tr><td class="user-genre-desc"><input value="{id}" {checked} type="checkbox" /><span>{description}</span></td></tr>
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -50,6 +50,7 @@
|
|||
= render 'dialogs/tryTestDriveDialog'
|
||||
= render 'dialogs/uploadAvatarDialog'
|
||||
= render 'dialogs/inviteSchoolUserDialog'
|
||||
= render 'dialogs/inviteRetailerUserDialog'
|
||||
= render 'dialogs/chatDialog'
|
||||
= render 'dialogs/cancelLessonDialog'
|
||||
= render 'dialogs/rescheduleLessonDialog'
|
||||
|
|
|
|||
|
|
@ -0,0 +1,2 @@
|
|||
.dialog.dialog-overlay-sm.top-parent layout='dialog' layout-id='invite-retailer-user' id='invite-retailer-user-dialog'
|
||||
= react_component 'InviteRetailerUserDialog', {}
|
||||
|
|
@ -34,6 +34,8 @@ class UserManager < BaseManager
|
|||
teacher = options[:teacher]
|
||||
school_invitation_code = options[:school_invitation_code]
|
||||
school_id = options[:school_id]
|
||||
retailer_invitation_code = options[:retailer_invitation_code]
|
||||
retailer_id = options[:retailer_id]
|
||||
school_interest = options[:school_interest]
|
||||
education_interest = options[:education_interest]
|
||||
origin = options[:origin]
|
||||
|
|
@ -87,6 +89,8 @@ class UserManager < BaseManager
|
|||
teacher: teacher,
|
||||
school_invitation_code: school_invitation_code,
|
||||
school_id: school_id,
|
||||
retailer_invitation_code: retailer_invitation_code,
|
||||
retailer_id: retailer_id,
|
||||
school_interest: school_interest,
|
||||
education_interest: education_interest,
|
||||
origin: origin,
|
||||
|
|
|
|||
Loading…
Reference in New Issue