UNPKG

@oveasoft/planning

Version:

An AngularJS planning component

304 lines (257 loc) 9.98 kB
import './ovaPlanning.scss'; import template from './ovaPlanning.template.html'; import moment from 'moment'; import _ from 'lodash'; // import uuid from 'uuid'; import angular from 'angular'; import { MomentHelper } from './../classes/moment.helper'; import { Configuration } from './../classes/configuration.class'; import { Debugger } from './../classes/debugger.class'; /** * @module ova-planning * @class OvaPlanningComponent * @name OvaPlanningComponent * @property {Array<Object>} appointments * @property {Object} config * @property {moment.Moment} currentWeek * * Days: * 0 to 6 * | FR | Lundi to Dimanche | * | EN | Sunday to Saturday | */ class OvaPlanningComponent { constructor () { this.informations = {}; this.week = ['0', '1', '2', '3', '4', '5', '6']; /** * Exclude days from the week according to the configuration 'excludedDays' key. * @private */ this._excludeDays = () => { _.remove(this.week, day => _.find(this.config.excludedDays, exclude => exclude === day)); if (this.week.length <= 0) { throw new Error(`[ova-planning] The week does not contain any days. Did you have excluded all days of the week ?`); } }; } $onInit () { this.oldAppointments = angular.copy(this.appointments); // Set the momentJs local. moment.locale(this.config.momentLocale); // Merge configuration with default configuration. this.config = new Configuration(this.config); this.oldConfig = angular.copy(this.config); this.Debugger = new Debugger(this.config.debug); this.Debugger.output('OvaPlanning $onInit'); this.buildView(); } switchView () { this.config.viewer = this.config.viewer === 'month' ? 'week' : 'month'; this.buildView(); } buildView () { this.informations = {}; switch (this.config.viewer) { case 'month': this.buildMonthView(); break; case 'week': // Exclude days from the week. this._excludeDays(); // Build the chronoline. this.buildChronoline(); // Calculate the first week. this.buildWeek(); break; case 'trimester': this.buildTrimesterView(); break; default: return null; } } buildTrimesterView () { this.labels = []; this.cols = []; const past = this.config.views.trimester.range.past; const future = this.config.views.trimester.range.future; this.columnType = this.config.views.trimester.columnType; const now = moment(this.config.currentWeek); const firstCol = moment(now).subtract(past, this.columnType); const lastCol = moment(now).add(future, this.columnType); for (let i = moment(firstCol); i.isSameOrBefore(lastCol); i.add(1, this.columnType)) { const data = []; if (angular.isFunction(this.config.views.trimester.labels)) { this.labels.push(this.config.views.trimester.labels(i)); } else { this.labels.push(`${i.get(this.columnType)}`); } if (angular.isArray(this.appointments)) { let events = angular.copy(this.appointments); events.forEach(event => { const eventDate = _.get(event, this.config.datePath); if (moment(eventDate).isSame(i, this.columnType)) { data.push(event); } }); } this.cols.push({ date: moment(i), data: data }); } } buildMonthView () { this.days = []; this.labels = []; this.range = []; const startOfWeek = moment().startOf('week'); const endOfWeek = moment().endOf('week'); for (let i = startOfWeek; i.isBefore(endOfWeek); i.add(1, 'day')) { if (this.config.excludedDays.indexOf(i.day().toString()) < 0) { this.labels.push(i.format('dddd')); } } for (let i = moment(this.config.currentWeek); i.isBefore(moment(this.config.currentWeek).add(this.config.views.month.weeksPerView.current, 'weeks')); i.add(1, 'week')) { let days = []; let currentDate = moment(this.config.currentWeek).week(i.week()); let cursor = moment(currentDate).startOf('week'); let lastDayOfWeek = moment(currentDate).endOf('week'); while (cursor.isBefore(lastDayOfWeek)) { if (this.config.excludedDays.indexOf(cursor.day().toString()) >= 0) { cursor.add(1, 'day'); continue; } let data = []; _.forEach(this.appointments, appointment => { if (moment(_.get(appointment, this.config.datePath)).isSame(cursor, 'day')) { data.push(appointment); } }); days.push({ date: moment(cursor), data: data }); cursor.add(1, 'day'); } this.range.push({ week: i.get('week'), days: days }); } } /** * Use to zoom in/out a week * @param {Number} week */ collapseToWeek (week) { if ((moment(this.config.currentWeek).week() === week) && this.config.views.month.weeksPerView.current === 1) { this.config.views.month.weeksPerView.current = this.config.views.month.weeksPerView.default; this.config.currentWeek = moment(this.previousWeek); this.config.onChangeWeek(this.config.currentWeek); } else { this.previousWeek = this.config.currentWeek; this.config.views.month.weeksPerView.current = 1; this.config.currentWeek = moment().week(week); } } /** * Push data to information object. * @param {*} data * @param {string} key * @memberof OvaPlanningComponent */ pushToInformations (data, key) { if (!this.informations.hasOwnProperty(key)) { this.informations[key] = []; } this.informations[key].push(data); } rebuild () { this.informations = {}; this.buildView(); this.oldConfig = angular.copy(this.config); } $doCheck () { // _.map(this.appointments, appointment => (appointment.$$id = uuid())); if (!angular.equals(this.config.currentWeek, this.oldConfig.currentWeek) || !angular.equals(this.config.viewer, this.oldConfig.viewer)) { this.Debugger.output(`The configuration changed.`, 'log'); this.rebuild(); } else if (!angular.equals(this.appointments, this.oldAppointments)) { this.informations = {}; this.buildView(); this.oldAppointments = angular.copy(this.appointments); } } /** * Push an item in the Chronoline. * @param {String} date * @param {Boolean} display */ pushToChronoline (date, display = false) { this.chronoLine.push({ date, display }); } /** * Build the week to be displayed. */ buildWeek () { this.days = []; let firstDayOfWeek = moment(this.config.currentWeek).startOf('week'); let lastDayOfWeek = moment(this.config.currentWeek).endOf('week'); while (firstDayOfWeek.isBefore(lastDayOfWeek)) { if (this.config.excludedDays.indexOf(firstDayOfWeek.day().toString()) < 0) { let dayItem = this.buildDay(firstDayOfWeek.day().toString()); this.days.push(dayItem); } firstDayOfWeek.add(1, 'day'); } this.config.onLoad(this.informations); } /** * Return the moment object of the given day index for the current week. * @param dayIndex * @returns {{date: moment.Moment, slots: Array}} */ buildDay (dayIndex) { const date = moment(this.config.currentWeek).day(dayIndex).startOf('day'); return { date: date, data: _.filter(this.appointments, appointment => _.get(appointment, this.config.datePath, false) && (moment(_.get(appointment, this.config.datePath, false)).isSame(date, 'day'))) }; } /** * Build the Chronoline. * This is the first column at the left of the table, it's a legend that display the slots hour for each line. */ buildChronoline () { this.chronoLine = []; _.each(this.config.slot, (slotRanges) => { let startingHour = MomentHelper.buildSlot(undefined, slotRanges[0]); let endingHour = MomentHelper.buildSlot(undefined, slotRanges[1]); // We put the first hour in the array. this.pushToChronoline(startingHour.format('HH:mm'), true); // Then we fill the array every $config.slotInterval while (startingHour.isBefore(endingHour)) { let item = startingHour.add(this.config.slotInterval, 'minutes'); if (item.isAfter(endingHour)) { this.pushToChronoline(endingHour.format('HH:mm'), true); } else { this.pushToChronoline(item.format('HH:mm'), true); } } }); } previous (step = 'week') { this.config.currentWeek.subtract(1, step); this.config.onChangeWeek(this.config.currentWeek); this.buildView(); } next (step = 'week') { this.config.currentWeek.add(1, step); this.config.onChangeWeek(this.config.currentWeek); this.buildView(); } } export default { controller: OvaPlanningComponent, template, bindings: { config: '=', appointments: '=' } };