UNPKG

@microsoft/mgt

Version:
428 lines • 16.2 kB
/** * ------------------------------------------------------------------------------------------- * Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the MIT License. * See License in the project root for license information. * ------------------------------------------------------------------------------------------- */ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; return c > 3 && r && Object.defineProperty(target, key, r), r; }; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; import { customElement, html, property } from 'lit-element'; import { Providers } from '../../Providers'; import { ProviderState } from '../../providers/IProvider'; import { styles } from './mgt-agenda-css'; import '../../styles/fabric-icon-font'; import { prepScopes } from '../../utils/GraphHelpers'; import { getDayOfWeekString, getMonthString } from '../../utils/Utils'; import '../mgt-person/mgt-person'; import { MgtTemplatedComponent } from '../templatedComponent'; /** * Web Component which represents events in a user or group calendar. * * @export * @class MgtAgenda * @extends {MgtTemplatedComponent} */ let MgtAgenda = class MgtAgenda extends MgtTemplatedComponent { constructor() { super(); /** * allows developer to define agenda to group events by day. * @type {Boolean} */ this.groupByDay = false; /** * sets number of days until endate, 3 is the default * @type {number} */ this.days = 3; this._firstUpdated = false; /** * determines if agenda component is still loading details. * @type {boolean} */ this._loading = true; this.onResize = this.onResize.bind(this); } /** * Array of styles to apply to the element. The styles should be defined * using the `css` tag function. */ static get styles() { return styles; } /** * Invoked when the element is first updated. Implement to perform one time * work on the element after update. * * Setting properties inside this method will trigger the element to update * again after this update cycle completes. * * * @param _changedProperties Map of changed properties with old values */ firstUpdated() { this._firstUpdated = true; Providers.onProviderUpdated(() => this.loadData()); this.loadData(); } /** * Determines width available if resize is necessary, adds onResize event listener to window * * @memberof MgtAgenda */ connectedCallback() { this._isNarrow = this.offsetWidth < 600; super.connectedCallback(); window.addEventListener('resize', this.onResize); } /** * Removes onResize event listener from window * * @memberof MgtAgenda */ disconnectedCallback() { window.removeEventListener('resize', this.onResize); super.disconnectedCallback(); } /** * Synchronizes property values when attributes change. * * @param {*} name * @param {*} oldValue * @param {*} newValue * @memberof MgtAgenda */ attributeChangedCallback(name, oldValue, newValue) { if (oldValue !== newValue && (name === 'date' || name === 'days' || name === 'group-id')) { this.events = null; this.loadData(); } super.attributeChangedCallback(name, oldValue, newValue); } /** * Invoked on each update to perform rendering tasks. This method must return a lit-html TemplateResult. * Setting properties inside this method will not trigger the element to update * * @returns * @memberof MgtAgenda */ render() { this._isNarrow = this.offsetWidth < 600; return html ` <div class="agenda ${this._isNarrow ? 'narrow' : ''}"> ${this.renderAgenda()} </div> `; } onResize() { this._isNarrow = this.offsetWidth < 600; } loadData() { return __awaiter(this, void 0, void 0, function* () { if (this.events) { return; } if (!this._firstUpdated) { return; } const p = Providers.globalProvider; if (p && p.state === ProviderState.SignedIn) { this._loading = true; if (this.eventQuery) { try { const tokens = this.eventQuery.split('|'); let scope; let query; if (tokens.length > 1) { query = tokens[0].trim(); scope = tokens[1].trim(); } else { query = this.eventQuery; } let request = yield p.graph.client.api(query); if (scope) { request = request.middlewareOptions(prepScopes(scope)); } const results = yield request.get(); if (results && results.value) { this.events = results.value; } // tslint:disable-next-line: no-empty } catch (e) { } } else { const start = this.date ? new Date(this.date) : new Date(); start.setHours(0, 0, 0, 0); const end = new Date(start.getTime()); end.setDate(start.getDate() + this.days); try { this.events = yield p.graph.getEvents(start, end, this.groupId); } catch (error) { // noop - possible error with graph } } this._loading = false; } else if (p && p.state === ProviderState.Loading) { this._loading = true; } else { this._loading = false; } }); } renderAgenda() { if (this._loading) { return this.renderTemplate('loading', null) || this.renderLoading(); } if (this.events && this.events.length) { const events = this.showMax && this.showMax > 0 ? this.events.slice(0, this.showMax) : this.events; const renderedTemplate = this.renderTemplate('default', { events }); if (renderedTemplate) { return renderedTemplate; } if (this.groupByDay) { const grouped = {}; // tslint:disable-next-line: prefer-for-of for (let i = 0; i < events.length; i++) { const header = this.getDateHeaderFromDateTimeString(events[i].start.dateTime); grouped[header] = grouped[header] || []; grouped[header].push(events[i]); } return html ` <div class="agenda grouped ${this._isNarrow ? 'narrow' : ''}"> ${Object.keys(grouped).map(header => html ` <div class="group"> ${this.renderTemplate('header', { header }, 'header-' + header) || html ` <div class="header" aria-label="${header}">${header}</div> `} ${this.renderListOfEvents(grouped[header])} </div> `)} </div> `; } return this.renderListOfEvents(events); } else { return this.renderTemplate('no-data', null) || html ``; } } renderListOfEvents(events) { return html ` <ul class="agenda-list"> ${events.map(event => html ` <li @click=${() => this.eventClicked(event)}> ${this.renderTemplate('event', { event }, event.id) || this.renderEvent(event)} </li> `)} </ul> `; } renderLoading() { return html ` <div class="event"> <div class="event-time-container"> <div class="event-time-loading loading-element"></div> </div> <div class="event-details-container"> <div class="event-subject-loading loading-element"></div> <div class="event-location-container"> <div class="event-location-icon-loading loading-element"></div> <div class="event-location-loading loading-element"></div> </div> <div class="event-location-container"> <div class="event-attendee-loading loading-element"></div> <div class="event-attendee-loading loading-element"></div> <div class="event-attendee-loading loading-element"></div> </div> </div> </div> `; } renderEvent(event) { return html ` <div class="event"> <div class="event-time-container"> <div class="event-time" aria-label="${this.getEventTimeString(event)}">${this.getEventTimeString(event)}</div> </div> <div class="event-details-container"> <div class="event-subject">${event.subject}</div> ${this.renderLocation(event)} ${this.renderAttendies(event)} </div> ${this.templates['event-other'] ? html ` <div class="event-other-container"> ${this.renderTemplate('event-other', { event }, event.id + '-other')} </div> ` : ''} </div> `; // <div class="event-duration">${this.getEventDuration(event)}</div> } renderLocation(event) { if (!event.location.displayName) { return null; } return html ` <div class="event-location-container"> <svg width="10" height="13" viewBox="0 0 10 13" fill="none" xmlns="http://www.w3.org/2000/svg"> <path fill-rule="evenodd" clip-rule="evenodd" d="M4.99989 6.49989C4.15159 6.49989 3.46143 5.81458 3.46143 4.97224C3.46143 4.12965 4.15159 3.44434 4.99989 3.44434C5.84845 3.44434 6.53835 4.12965 6.53835 4.97224C6.53835 5.81458 5.84845 6.49989 4.99989 6.49989Z" stroke="black" /> <path fill-rule="evenodd" clip-rule="evenodd" d="M8.1897 7.57436L5.00029 12L1.80577 7.56765C0.5971 6.01895 0.770299 3.47507 2.17681 2.12383C2.93098 1.39918 3.93367 1 5.00029 1C6.06692 1 7.06961 1.39918 7.82401 2.12383C9.23075 3.47507 9.40372 6.01895 8.1897 7.57436Z" stroke="black" /> </svg> <div class="event-location" aria-label="${event.location.displayName}">${event.location.displayName}</div> </div> `; } renderAttendies(event) { if (!event.attendees.length) { return null; } return html ` <mgt-people class="event-attendees" .people=${event.attendees.map(attendee => ({ displayName: attendee.emailAddress.name, emailAddresses: [attendee.emailAddress] }))} ></mgt-people> `; } eventClicked(event) { this.fireCustomEvent('eventClick', { event }); } getEventTimeString(event) { if (event.isAllDay) { return 'ALL DAY'; } const start = this.prettyPrintTimeFromDateTime(new Date(event.start.dateTime)); const end = this.prettyPrintTimeFromDateTime(new Date(event.end.dateTime)); return `${start} - ${end}`; } prettyPrintTimeFromDateTime(date) { date.setMinutes(date.getMinutes() - date.getTimezoneOffset()); let hours = date.getHours(); const minutes = date.getMinutes(); const ampm = hours >= 12 ? 'PM' : 'AM'; hours = hours % 12; hours = hours ? hours : 12; const minutesStr = minutes < 10 ? '0' + minutes : minutes; return `${hours}:${minutesStr} ${ampm}`; } getDateHeaderFromDateTimeString(dateTimeString) { const date = new Date(dateTimeString); date.setMinutes(date.getMinutes() - date.getTimezoneOffset()); const dayIndex = date.getDay(); const monthIndex = date.getMonth(); const day = date.getDate(); const year = date.getFullYear(); return `${getDayOfWeekString(dayIndex)}, ${getMonthString(monthIndex)} ${day}, ${year}`; } getEventDuration(event) { let dtStart = new Date(event.start.dateTime); const dtEnd = new Date(event.end.dateTime); const dtNow = new Date(); let result = ''; if (dtNow > dtStart) { dtStart = dtNow; } const diff = dtEnd.getTime() - dtStart.getTime(); const durationMinutes = Math.round(diff / 60000); if (durationMinutes > 1440 || event.isAllDay) { result = Math.ceil(durationMinutes / 1440) + 'd'; } else if (durationMinutes > 60) { result = Math.round(durationMinutes / 60) + 'h'; const leftoverMinutes = durationMinutes % 60; if (leftoverMinutes) { result += leftoverMinutes + 'm'; } } else { result = durationMinutes + 'm'; } return result; } }; __decorate([ property({ attribute: 'events' }) ], MgtAgenda.prototype, "events", void 0); __decorate([ property({ attribute: 'group-by-day', reflect: true, type: Boolean }) ], MgtAgenda.prototype, "groupByDay", void 0); __decorate([ property({ attribute: 'date', reflect: true, type: String }) ], MgtAgenda.prototype, "date", void 0); __decorate([ property({ attribute: 'days', reflect: true, type: Number }) ], MgtAgenda.prototype, "days", void 0); __decorate([ property({ attribute: 'event-query', type: String }) ], MgtAgenda.prototype, "eventQuery", void 0); __decorate([ property({ attribute: 'show-max', type: Number }) ], MgtAgenda.prototype, "showMax", void 0); __decorate([ property({ attribute: 'group-id', type: String }) ], MgtAgenda.prototype, "groupId", void 0); __decorate([ property({ attribute: false }) ], MgtAgenda.prototype, "_isNarrow", void 0); __decorate([ property({ attribute: false }) ], MgtAgenda.prototype, "_loading", void 0); MgtAgenda = __decorate([ customElement('mgt-agenda') ], MgtAgenda); export { MgtAgenda }; //# sourceMappingURL=mgt-agenda.js.map