VRFS-4050 - countdown timer
This commit is contained in:
parent
30aec92512
commit
6f9d39ef16
|
|
@ -419,7 +419,7 @@ SQL
|
|||
end
|
||||
|
||||
connection.join_the_session(music_session, as_musician, tracks, user, audio_latency, video_sources)
|
||||
JamRuby::MusicSessionUserHistory.join_music_session(user.id, music_session.id)
|
||||
JamRuby::MusicSessionUserHistory.join_music_session(user.id, music_session.id, client_id)
|
||||
# connection.music_session_id = music_session.id
|
||||
# connection.as_musician = as_musician
|
||||
# connection.joining_session = true
|
||||
|
|
|
|||
|
|
@ -447,6 +447,10 @@ module JamRuby
|
|||
music_session.creator
|
||||
end
|
||||
|
||||
def student_id
|
||||
music_session.creator.id
|
||||
end
|
||||
|
||||
def self.index(user, params = {})
|
||||
limit = params[:per_page]
|
||||
limit ||= 100
|
||||
|
|
|
|||
|
|
@ -69,7 +69,7 @@ module JamRuby
|
|||
|
||||
# spec: https://jamkazam.atlassian.net/wiki/display/PS/Product+Specification+-+JamClass#ProductSpecification-JamClass-TeacherReceives&RespondstoLessonBookingRequest
|
||||
|
||||
if !force && (music_session.session_removed_at.nil? && !((music_session.scheduled_start + (lesson_session.duration * 60)) < Time.now))
|
||||
if !force && (!((music_session.scheduled_start + (lesson_session.duration * 60)) < Time.now))
|
||||
reason = SESSION_ONGOING
|
||||
bill = false
|
||||
else
|
||||
|
|
@ -98,8 +98,17 @@ module JamRuby
|
|||
student = JOINED_LATE
|
||||
bill = true
|
||||
end
|
||||
else
|
||||
if teacher_analysis[:no_show]
|
||||
teacher = NO_SHOW
|
||||
elsif !teacher_analysis[:joined_on_time]
|
||||
teacher = JOINED_LATE
|
||||
elsif !teacher_analysis[:waited_correctly]
|
||||
teacher = MINIMUM_TIME_NOT_MET
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
|
||||
if reason.nil?
|
||||
|
|
|
|||
|
|
@ -40,9 +40,9 @@ module JamRuby
|
|||
end
|
||||
|
||||
def self.save(music_session_id, user_id, client_id, tracks)
|
||||
return true if 0 < self.where(:music_session_id => music_session_id,
|
||||
:user_id => user_id,
|
||||
:client_id => client_id).count
|
||||
return true if 0 < self.where(:music_session_id => music_session_id,
|
||||
:user_id => user_id,
|
||||
:client_id => client_id).where('session_removed_at is NULL').count
|
||||
session_user_history = MusicSessionUserHistory.new
|
||||
session_user_history.music_session_id = music_session_id
|
||||
session_user_history.user_id = user_id
|
||||
|
|
@ -60,10 +60,12 @@ module JamRuby
|
|||
(end_time - self.created_at) / 60.0
|
||||
end
|
||||
|
||||
def self.join_music_session(user_id, session_id)
|
||||
def self.join_music_session(user_id, session_id, client_id)
|
||||
hist = self
|
||||
.where(:user_id => user_id)
|
||||
.where(:music_session_id => session_id)
|
||||
.where(:client_id => client_id)
|
||||
.where('session_removed_at IS NULL')
|
||||
.limit(1)
|
||||
.first
|
||||
hist.start_history if hist
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ describe LessonSessionAnalyser do
|
|||
Timecop.freeze((lesson.music_session.scheduled_start + lesson.duration * 60) + 1)
|
||||
|
||||
analysis = LessonSessionAnalyser.analyse(lesson)
|
||||
analysis[:reason].should eql LessonSessionAnalyser::NEITHER_SHOW
|
||||
analysis[:reason].should eql LessonSessionAnalyser::TEACHER_FAULT
|
||||
analysis[:student].should eql nil
|
||||
analysis[:bill].should be false
|
||||
|
||||
|
|
@ -47,8 +47,7 @@ describe LessonSessionAnalyser do
|
|||
start = lesson.scheduled_start
|
||||
end_time = lesson.scheduled_start + (60 * lesson.duration)
|
||||
uh2 = FactoryGirl.create(:music_session_user_history, user: teacher, history: music_session, created_at: start, session_removed_at: end_time)
|
||||
lesson.music_session.session_removed_at = end_time
|
||||
lesson.music_session.save!
|
||||
Timecop.travel(end_time + 1)
|
||||
|
||||
|
||||
analysis = LessonSessionAnalyser.analyse(lesson)
|
||||
|
|
@ -67,6 +66,36 @@ describe LessonSessionAnalyser do
|
|||
together[:session_time].should eql 0
|
||||
end
|
||||
|
||||
it "student joined 1 min before start time, is waiting for 12 minutes" do
|
||||
lesson = testdrive_lesson(user, teacher)
|
||||
music_session = lesson.music_session
|
||||
|
||||
# create some bogus, super-perfect teacher/student times
|
||||
start = lesson.scheduled_start
|
||||
end_time = lesson.scheduled_start + (60 * lesson.duration)
|
||||
uh2 = FactoryGirl.create(:music_session_user_history, user: user, history: music_session, created_at: start - 60, session_removed_at: nil)
|
||||
|
||||
Timecop.freeze(start + 11 * 60)
|
||||
|
||||
analysis = LessonSessionAnalyser.analyse(lesson, true)
|
||||
analysis[:reason].should eql LessonSessionAnalyser::TEACHER_FAULT
|
||||
analysis[:teacher].should eql LessonSessionAnalyser::NO_SHOW
|
||||
analysis[:student].should be_nil
|
||||
analysis[:bill].should be false
|
||||
|
||||
student = analysis[:student_analysis]
|
||||
student[:joined_on_time].should be true
|
||||
student[:joined_late].should be false
|
||||
student[:waited_correctly].should be true
|
||||
student[:initial_waiting_pct].should eql 1.0
|
||||
student[:potential_waiting_time].should eql 600.0
|
||||
|
||||
student[:session_time].should eql (11 * 60).to_f
|
||||
|
||||
together = analysis[:together_analysis]
|
||||
together[:session_time].should eql 0
|
||||
end
|
||||
|
||||
it "teacher joined on time, waited, student joined late" do
|
||||
lesson = testdrive_lesson(user, teacher)
|
||||
music_session = lesson.music_session
|
||||
|
|
@ -78,8 +107,7 @@ describe LessonSessionAnalyser do
|
|||
uh1 = FactoryGirl.create(:music_session_user_history, user: user, history: music_session, created_at: late_start, session_removed_at: late_start + 4 * 60)
|
||||
uh2 = FactoryGirl.create(:music_session_user_history, user: teacher, history: music_session, created_at: start, session_removed_at: end_time)
|
||||
|
||||
lesson.music_session.session_removed_at = end_time
|
||||
lesson.music_session.save!
|
||||
Timecop.travel(end_time + 1)
|
||||
|
||||
|
||||
analysis = LessonSessionAnalyser.analyse(lesson)
|
||||
|
|
@ -117,8 +145,7 @@ describe LessonSessionAnalyser do
|
|||
analysis = LessonSessionAnalyser.analyse(lesson)
|
||||
analysis[:reason].should eql LessonSessionAnalyser::SESSION_ONGOING
|
||||
|
||||
lesson.music_session.session_removed_at = end_time
|
||||
lesson.music_session.save!
|
||||
Timecop.travel(end_time + 1)
|
||||
|
||||
analysis = LessonSessionAnalyser.analyse(lesson)
|
||||
analysis[:reason].should eql LessonSessionAnalyser::SUCCESS
|
||||
|
|
|
|||
|
|
@ -237,7 +237,7 @@
|
|||
}, opts.animationDuration);
|
||||
});
|
||||
|
||||
var broadcastWidth = findCardLayout.width + feedCardLayout.width;
|
||||
var broadcastWidth = findCardLayout.width + feedCardLayout.width; //+ opts.gridPadding * 2;
|
||||
|
||||
layoutBroadcast(broadcastWidth, findCardLayout.left);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,16 +3,38 @@ context = window
|
|||
@InLessonBroadcast = React.createClass({
|
||||
displayName: 'In Lesson Broadcast'
|
||||
|
||||
displayTime: (minuteOffset = 0) ->
|
||||
untilTime = @props.lessonSession.until
|
||||
getTimeRemaining: (t) ->
|
||||
|
||||
if t < 0
|
||||
t = -t
|
||||
|
||||
seconds = Math.floor( (t/1000) % 60 );
|
||||
minutes = Math.floor( (t/1000/60) % 60 );
|
||||
hours = Math.floor( (t/(1000*60*60)) % 24 );
|
||||
days = Math.floor( t/(1000*60*60*24) );
|
||||
|
||||
return {
|
||||
'total': t,
|
||||
'days': days,
|
||||
'hours': hours,
|
||||
'minutes': minutes,
|
||||
'seconds': seconds
|
||||
};
|
||||
|
||||
|
||||
displayTime: () ->
|
||||
if @props.lessonSession.initialWindow
|
||||
# offset time by 10 minutes to get the 'you need to wait message' in
|
||||
untilTime = @getTimeRemaining(@props.lessonSession.until.total + (10 * 60 * 1000))
|
||||
else
|
||||
untilTime = @props.lessonSession.until
|
||||
timeString = ''
|
||||
if untilTime.days != 0
|
||||
timeString += "#{untilTime.days} days, "
|
||||
if untilTime.hours != 0 || timeString.length > 0
|
||||
timeString += "#{untilTime.hours} hours, "
|
||||
if untilTime.minutes != 0 || timeString.length > 0
|
||||
timeString += "#{untilTime.minutes + minuteOffset} minutes, "
|
||||
timeString += "#{untilTime.minutes} minutes, "
|
||||
if untilTime.seconds != 0 || timeString.length > 0
|
||||
timeString += "#{untilTime.seconds} seconds"
|
||||
|
||||
|
|
@ -39,14 +61,14 @@ context = window
|
|||
else if @props.lessonSession.initialWindow
|
||||
content = `<div className="message">
|
||||
<p>You need to wait in this session for</p>
|
||||
<p className="time">{this.displayTime(10)}</p>
|
||||
<p className="time">{this.displayTime()}</p>
|
||||
<p>to allow time for your teacher to join you. If you leave before this timer reaches zero, and your teacher joins this session, you will be marked absent and charged for the lesson.</p>
|
||||
</div>`
|
||||
else if @props.lessonSession.teacherFault
|
||||
if @props.lessonSession.teacherPresent?
|
||||
content = `<div className="message">
|
||||
<p>You may now leave the session. However, if you choose to stay in the session with the teacher, after 5 minutes together the session will be considered a success, and you will be billed.</p>
|
||||
<p>If the two of you do not spend at least 5 minutes together in the session, your teacher will be marked absent and penalized for missing the lesson. You will not be charged for this lesson.</p>
|
||||
<p>Because your teacher was late, you may now leave the session. However, if you choose to stay in the session with the teacher, after 5 minutes together the session will be considered a success, and you will be billed.</p>
|
||||
<p>If the two of you do not spend at least 5 minutes together in the session, your teacher will be marked absent and penalized for missing the lesson, and you will not be charged for this lesson.</p>
|
||||
</div>`
|
||||
else
|
||||
content = `<div className="message">
|
||||
|
|
|
|||
|
|
@ -22,20 +22,29 @@ BroadcastStore = Reflux.createStore(
|
|||
|
||||
onAppInit: (@app) ->
|
||||
|
||||
|
||||
getTimeRemaining: (endtime) ->
|
||||
t = Date.parse(endtime) - new Date().getTime()
|
||||
seconds = Math.floor( (t/1000) % 60 );
|
||||
minutes = Math.floor( (t/1000/60) % 60 );
|
||||
hours = Math.floor( (t/(1000*60*60)) % 24 );
|
||||
days = Math.floor( t/(1000*60*60*24) );
|
||||
t = new Date(endtime).getTime() - new Date().getTime()
|
||||
|
||||
originalT = t
|
||||
|
||||
if t < 0
|
||||
seconds = Math.ceil( (t/1000) % 60 );
|
||||
minutes = Math.ceil( (t/1000/60) % 60 );
|
||||
hours = Math.ceil( (t/(1000*60*60)) % 24 );
|
||||
days = Math.ceil( t/(1000*60*60*24) );
|
||||
else
|
||||
seconds = Math.floor( (t/1000) % 60 );
|
||||
minutes = Math.floor( (t/1000/60) % 60 );
|
||||
hours = Math.floor( (t/(1000*60*60)) % 24 );
|
||||
days = Math.floor( t/(1000*60*60*24) );
|
||||
|
||||
return {
|
||||
'total': t,
|
||||
'days': days,
|
||||
'hours': hours,
|
||||
'minutes': minutes,
|
||||
'seconds': seconds
|
||||
};
|
||||
'total': originalT,
|
||||
'days': days,
|
||||
'hours': hours,
|
||||
'minutes': minutes,
|
||||
'seconds': seconds
|
||||
};
|
||||
|
||||
lessonTick: () ->
|
||||
@timeManagement()
|
||||
|
|
@ -47,10 +56,10 @@ BroadcastStore = Reflux.createStore(
|
|||
lessonSession.until = @getTimeRemaining(lessonSession.scheduled_start)
|
||||
if lessonSession.until.total < 0
|
||||
# we are past the start time
|
||||
if lessonSession.until.total < 10 * 60 * 1000 # 10 minutes
|
||||
lessonSession.initialWindow = false
|
||||
else
|
||||
if lessonSession.until.total > -(10 * 60 * 1000) # 10 minutes
|
||||
lessonSession.initialWindow = true
|
||||
else
|
||||
lessonSession.initialWindow = false
|
||||
lessonSession.beforeSession = false
|
||||
else
|
||||
# we are before the due time
|
||||
|
|
@ -90,7 +99,7 @@ BroadcastStore = Reflux.createStore(
|
|||
|
||||
@session = session
|
||||
currentSession = session.session
|
||||
if currentSession? && currentSession.lesson_session? && session.inSession()
|
||||
if currentSession? && currentSession.lesson_session? && session.inSession() && currentSession.lesson_session.student_id == context.JK.currentUserId
|
||||
|
||||
@currentSession = currentSession
|
||||
|
||||
|
|
@ -106,6 +115,7 @@ BroadcastStore = Reflux.createStore(
|
|||
|
||||
@currentLesson = lessonSession
|
||||
@timeManagement()
|
||||
logger.debug("BroadcastStore: currentLesson until: ", @currentLesson.until, lessonSession.scheduled_start)
|
||||
if !@currentLessonTimer?
|
||||
@currentLessonTimer = setInterval((() => @lessonTick()), 1000)
|
||||
@changed()
|
||||
|
|
@ -135,7 +145,10 @@ BroadcastStore = Reflux.createStore(
|
|||
if @currentLesson?
|
||||
@currentLesson.teacherFault = @teacherFault
|
||||
@currentLesson.teacherPresent = @session.findParticipantByUserId(@currentLesson.teacher_id)
|
||||
this.trigger(@currentLesson)
|
||||
if @currentLesson.teacherPresent?
|
||||
this.trigger(null)
|
||||
else
|
||||
this.trigger(@currentLesson)
|
||||
else
|
||||
this.trigger(@broadcast)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,13 +1,17 @@
|
|||
@import 'client/common';
|
||||
|
||||
[data-react-class="BroadcastHolder"] {
|
||||
#broadcast-notification-holder{
|
||||
position:absolute;
|
||||
min-height:60px;
|
||||
top:62px;
|
||||
bottom:0;
|
||||
}
|
||||
|
||||
[data-react-class="BroadcastHolder"] {
|
||||
position:relative;
|
||||
min-height: 125px;
|
||||
bottom: 60px;
|
||||
@include border_box_sizing;
|
||||
|
||||
.broadcast-notification {
|
||||
position:absolute;
|
||||
border-width:1px;
|
||||
border-color:$ColorScreenPrimary;
|
||||
border-style:solid;
|
||||
|
|
@ -17,7 +21,6 @@
|
|||
left:0;
|
||||
top:0;
|
||||
overflow:hidden;
|
||||
margin-left:60px;
|
||||
@include border_box_sizing;
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -41,7 +41,8 @@ class ApiLessonSessionsController < ApiController
|
|||
response = {message: 'not admin'}
|
||||
render :json => response, :status => 422
|
||||
else
|
||||
time = Time.zone.local_to_utc(Time.now + params[:minutes].to_i * 60)
|
||||
# time = Time.zone.local_to_utc(Time.now + params[:minutes].to_i * 60)
|
||||
time = Time.current + params[:minutes].to_i * 60
|
||||
@lesson_session.music_session.scheduled_start = time
|
||||
@lesson_session.music_session.save!
|
||||
render :json => {}, :status => 200
|
||||
|
|
|
|||
|
|
@ -75,7 +75,7 @@ else
|
|||
}
|
||||
|
||||
child(lesson_session: :lesson_session) {
|
||||
attributes :id, :scheduled_start, :status, :teacher_id, :success, :duration
|
||||
attributes :id, :scheduled_start, :status, :teacher_id, :success, :duration, :student_id
|
||||
}
|
||||
|
||||
# only show join_requests if the current_user is in the session
|
||||
|
|
|
|||
|
|
@ -9,8 +9,11 @@
|
|||
<a layout-link="session-settings">SS</a>
|
||||
-->
|
||||
|
||||
|
||||
<%= render "users/user_dropdown" %>
|
||||
|
||||
<%= react_component 'BroadcastHolder', {} %>
|
||||
|
||||
|
||||
<!-- Templates -->
|
||||
<script type="text/template" id="template-search-section">
|
||||
|
|
|
|||
|
|
@ -9,7 +9,6 @@
|
|||
<div class="dialog-overlay op70" style="display:none; width:100%; height:100%; z-index:99;"></div>
|
||||
|
||||
<%= render "header" %>
|
||||
<%= react_component 'BroadcastHolder', {} %>
|
||||
<%= render "home" %>
|
||||
<%= render "footer" %>
|
||||
<%= render "paginator" %>
|
||||
|
|
|
|||
Loading…
Reference in New Issue