Show reserved names in agenda view with better scheduler

closes CNVS-32183

Test Plan:
  - Set up an appointment group and limit the signups to 6 students
  - Add students to the appointment group
  - As a teacher, look at the agenda view
  - It should show all the students like:
     "Banner, Bruce; Lang, Scott; Parker, Peter; Rogers, Steve; Stark, Tony"
    when there are 5 or fewer people signed up
  - When there are more than 5 is should look like:
     "Banner, Bruce; Lang, Scott; Parker, Peter; Rogers, Steve; Stark, Tony; and more..."
  - Please note that it should also convey the status of the appointment group as a
    whole prior to listing attendees.  For instance, X more available should show
    whenever there are still slots remaining or Filled when all the slots are
    taken
     - If no one has reserved any slots it should show "X Available"
       rather than "X more available"
Change-Id: I00e85bf0886a9105abdb1d7bb8d08fe60e0b9f62
Reviewed-on: https://gerrit.instructure.com/91303
Tested-by: Jenkins
Reviewed-by: Steven Burnett <sburnett@instructure.com>
QA-Review: Heath Hales <hhales@instructure.com>
Product-Review: Clay Diffrient <cdiffrient@instructure.com>
This commit is contained in:
Clay Diffrient 2016-09-26 12:35:18 -06:00
parent eabe8f26a2
commit 484025dee6
3 changed files with 85 additions and 8 deletions

View File

@ -4,9 +4,10 @@ define [
'compiled/util/fcUtil'
'compiled/util/semanticDateRange'
'compiled/calendar/CommonEvent'
'compiled/util/natcompare'
'jquery.instructure_date_and_time'
'jquery.instructure_misc_helpers'
], (I18n, $, fcUtil, semanticDateRange, CommonEvent) ->
], (I18n, $, fcUtil, semanticDateRange, CommonEvent, natcompare) ->
deleteConfirmation = I18n.t('prompts.delete_event', "Are you sure you want to delete this event?")
@ -15,6 +16,7 @@ define [
super data, contextInfo, actualContextInfo
@eventType = 'calendar_event'
@appointmentGroupEventStatus = @calculateAppointmentGroupEventStatus()
@reservedUsers = @getListOfReservedPeople(5).join('; ')
@deleteConfirmation = deleteConfirmation
@deleteURL = contextInfo.calendar_event_url
@ -94,12 +96,29 @@ define [
calculateAppointmentGroupEventStatus: ->
status = I18n.t 'Available'
if @calendarEvent.available_slots > 0
status = I18n.t('%{availableSlots} Available', {availableSlots: @calendarEvent.available_slots})
if @calendarEvent.available_slots > 0 && @calendarEvent.child_events?.length
status = I18n.t('%{availableSlots} more available', {availableSlots: @calendarEvent.available_slots})
if @calendarEvent.available_slots == 0
status = I18n.t('Filled')
if @calendarEvent.reserved == true || (@calendarEvent.appointment_group_url && @calendarEvent.parent_event_id)
if @consideredReserved()
status = I18n.t('Reserved')
status
# Returns an array of sortable user names that have reserved this slot optionally
# limited to a certain number. The list is returned sorted naturally. If there
# are more than the limit 'and more...' will be appended.
getListOfReservedPeople: (limit) ->
return [] unless @calendarEvent.child_events?.length
names = @calendarEvent.child_events?.map((child_event) -> child_event.user?.sortable_name)
sorted = names.sort((a, b) => natcompare.strings(a, b))
if (limit)
sorted = sorted.slice(0, limit)
if @calendarEvent.child_events?.length > limit
sorted.push(I18n.t('and more...'))
sorted
# True if the slot should be considered reserved
consideredReserved: -> @calendarEvent.reserved == true || (@calendarEvent.appointment_group_url && @calendarEvent.parent_event_id)

View File

@ -18,7 +18,11 @@
<span class="screenreader-only">{{readableType}},</span>
<i class="icon-{{iconType}}"></i>
{{#if ../../meta.better_scheduler}}
{{#truncate title 60}}{{/truncate}} - {{appointmentGroupEventStatus}}
{{#if can_edit}}
{{#truncate title 60}}{{/truncate}} - {{appointmentGroupEventStatus}} {{#if reservedUsers }} - {{reservedUsers}} {{/if}}
{{else}}
{{#truncate title 60}}{{/truncate}} - {{appointmentGroupEventStatus}}
{{/if}}
{{else}}
{{#ifAll ../../../meta.displayAppointmentEvents isAppointmentGroupEvent}}
{{appointmentGroupEventStatus}}

View File

@ -4,22 +4,64 @@ define([
let calendarEvent;
const getFakeChildEvents = () => {
return [
{ user: {sortable_name: 'Stark, Tony'}},
{ user: {sortable_name: 'Parker, Peter'}},
{ user: {sortable_name: 'Rogers, Steve'}}
];
}
module('CommonEvent.CalendarEvent', {
setup () {
const data = {}
const contexts = ['course_1']
calendarEvent = new CalendarEvent(data, contexts)
const data = {
child_events: []
};
const contexts = ['course_1'];
calendarEvent = new CalendarEvent(data, contexts);
},
teardown () {
calendarEvent = null;
}
});
test('calculateAppointmentGroupEventStatus returns number of available slots string when more than 0', () => {
test('Constructor sets reservedUsers from child_events limited to 5 and joined by "; "', () => {
const data = {
child_events: getFakeChildEvents().concat([
{ user: {sortable_name: 'Banner, Bruce'}},
{ user: {sortable_name: 'Lang, Scott'}}
])
};
calendarEvent = new CalendarEvent(data, ['course_1']);
const expected = "Banner, Bruce; Lang, Scott; Parker, Peter; Rogers, Steve; Stark, Tony";
equal(calendarEvent.reservedUsers, expected);
});
test('Constructor sets reservedUsers from child_events limited to 5 and joined by "; " with "and more..." if more than 5', () => {
const data = {
child_events: getFakeChildEvents().concat([
{ user: {sortable_name: 'Banner, Bruce'}},
{ user: {sortable_name: 'Lang, Scott'}},
{ user: {sortable_name: 'Barton, Clint'}}
])
};
calendarEvent = new CalendarEvent(data, ['course_1']);
const expected = "Banner, Bruce; Barton, Clint; Lang, Scott; Parker, Peter; Rogers, Steve; and more...";
equal(calendarEvent.reservedUsers, expected);
});
test('calculateAppointmentGroupEventStatus returns number of available slots string when more than 0 and none are reserved', () => {
calendarEvent.calendarEvent.available_slots = 20;
equal(calendarEvent.calculateAppointmentGroupEventStatus(), '20 Available');
});
test('calculateAppointmentGroupEventStatus returns "X more available" when there are some reserved and some open', () => {
calendarEvent.calendarEvent.child_events = getFakeChildEvents();
calendarEvent.calendarEvent.available_slots = 17;
equal(calendarEvent.calculateAppointmentGroupEventStatus(), '17 more available');
})
test('calculateAppointmentGroupEventStatus gives "Filled" string when 0 available_slots', () => {
calendarEvent.calendarEvent.available_slots = 0;
equal(calendarEvent.calculateAppointmentGroupEventStatus(), 'Filled');
@ -37,5 +79,17 @@ define([
equal(calendarEvent.calculateAppointmentGroupEventStatus(), 'Reserved');
});
test('consideredReserved returns true when reserve should be shown', () => {
calendarEvent.calendarEvent.reserved = true;
ok(calendarEvent.consideredReserved(), 'true when reserved');
calendarEvent.calendarEvent.reserved = false;
calendarEvent.calendarEvent.appointment_group_url = 1;
calendarEvent.calendarEvent.parent_event_id = 30;
ok(calendarEvent.consideredReserved(), 'true with appointment_group_url and parent_event_id');
});
})