client/app/bundles/course/lesson-plan/reducers/utils.js
import moment from 'lib/moment';
/**
* Adds a new attribute itemTypeKey to the lesson plan item.
* itemTypeKey has two functions:
* 1. It serves as key for the visibilityByType hash
* 2. It is used as the display string for the 'type' of the item.
*/
export function generateTypeKey(item) {
return {
...item,
itemTypeKey: item.lesson_plan_item_type.join(': '),
};
}
/**
* Converts the visibility settings received from the backend into a hash keyed by
* itemTypeKey (as generated by generateTypeKey above).
*
* Example:
*
* Each setting is a hash like { setting_key: ['Standard Assessment', 'Tab 2'], visible: false }.
*
* This becomes the visibilitySetting hash { 'Standard Assessment: Tab 2': false } where the key
* is in the same format as itemTypeKey.
*/
export function generateVisibilitySettings(visibilitySettings) {
const newVisibilitySettings = {};
visibilitySettings.forEach((setting) => {
newVisibilitySettings[setting.setting_key.join(': ')] = setting.visible;
});
return newVisibilitySettings;
}
function sortByStartAt(a, b) {
const aStartAt = moment(a.start_at);
if (aStartAt.isAfter(b.start_at)) {
return 1;
}
if (aStartAt.isBefore(b.start_at)) {
return -1;
}
return 0;
}
/**
* Groups lesson plan items under their respective milestones.
* An item falls under a milestone if the milestone is the latest milestone
* to have an earlier start_at date-time than the item.
* Items that precedes all milestones are grouped with an empty milestone.
* Items are sorted by startAt, then itemTypeKey, then title.
*
* @param {Array} items
* @param {Array} milestones
* @return {Array.<{ milestone: Object, items: Array }>}
*/
export function groupItemsUnderMilestones(items, milestones) {
const sortedMilestones = [...milestones].sort(sortByStartAt);
const sortedItems = [...items].sort((a, b) => {
const startAtSortResult = sortByStartAt(a, b);
if (startAtSortResult !== 0) {
return startAtSortResult;
}
const itemTypeSortResult = a.itemTypeKey.localeCompare(b.itemTypeKey);
if (itemTypeSortResult !== 0) {
return itemTypeSortResult;
}
return a.title.localeCompare(b.title);
});
const groups = [];
const group = { id: null, milestone: null, items: [] };
// Adds current group to groups and resets group
const addGroup = () => {
if (group.items.length > 0 || group.milestone) {
const milestoneId = group.milestone ? group.milestone.id : 'ungrouped';
group.id = `milestone-group-${milestoneId}`;
groups.push({ ...group });
group.id = null;
group.milestone = null;
group.items = [];
}
};
sortedMilestones.forEach((milestone) => {
// Group items that come before the current milestone under the previous milestone
while (
sortedItems.length > 0 &&
moment(sortedItems[0].start_at).isBefore(milestone.start_at)
) {
group.items.push(sortedItems.shift());
}
// Finalize the group, then start a new group with the current milestone
addGroup();
group.milestone = milestone;
});
// The remaining items belong with the last milestone
group.items = group.items.concat(sortedItems);
addGroup();
return groups;
}
/**
* Generates a hash that indicates the visibility of each item type, e.g. :
* { "Training: Extra": false, "Recitation": true }
* as read from the given visibilitySettings.
*
* All other items are visible by default.
*
* @param {Array} items
* @param {{itemTypeKey: Boolean}} visibilitySettings keyed by itemTypeKey
* @return {Object}
*/
export function initializeVisibility(items, visibilitySettings) {
const itemTypes = new Set(items.map((item) => item.itemTypeKey));
const visibility = {};
itemTypes.forEach((itemType) => {
const hasVisibilitySetting = Object.prototype.hasOwnProperty.call(
visibilitySettings,
itemType,
);
visibility[itemType] = hasVisibilitySetting
? visibilitySettings[itemType]
: true;
});
return visibility;
}