/**
 * -------------------------------------------------------------------------------------------
 * Copyright (c) Microsoft Corporation.  All Rights Reserved.  Licensed under the MIT License.
 * See License in the project root for license information.
 * -------------------------------------------------------------------------------------------
 */ import * as MicrosoftGraph from '@microsoft/microsoft-graph-types' ; import { customElement , html , property , TemplateResult } from 'lit-element' ; import { Providers , ProviderState , MgtTemplatedComponent , prepScopes } from '@microsoft/mgt-element' ; import '../../styles/style-helper' ; import { getDayOfWeekString , getMonthString } from '../../utils/Utils' ; import '../mgt-person/mgt-person' ; import { styles } from './mgt-agenda-css' ; import { getEventsPageIterator } from './mgt-agenda.graph' ; import { SvgIcon , getSvg } from '../../utils/SvgHelper' ; import { MgtPeople } from '../mgt-people/mgt-people' ; export class extends MgtTemplatedComponent fires cssprop cssprop cssprop cssprop cssprop cssprop cssprop cssprop cssprop cssprop cssprop cssprop cssprop cssprop @ customElement ( 'mgt-agenda' ) export class MgtAgenda extends MgtTemplatedComponent { /**
     * Array of styles to apply to the element. The styles should be defined
     * using the `css` tag function.
     */ static get styles ( ) { return styles ; } type { string } @ property ( { attribute : 'date' , type : String } ) public get date ( ) : string { return this . _date ; } public set date ( value ) { if ( this . _date === value ) { return ; } this . _date = value ; this . reloadState ( ) ; } type { string } @ property ( { attribute : 'group-id' , type : String } ) public get groupId ( ) : string { return this . _groupId ; } public set groupId ( value ) { if ( this . _groupId === value ) { return ; } this . _groupId = value ; this . reloadState ( ) ; } type { number } @ property ( { attribute : 'days' , type : Number } ) public get days ( ) : number { return this . _days ; } public set days ( value ) { if ( this . _days === value ) { return ; } this . _days = value ; this . reloadState ( ) ; } type { string } @ property ( { attribute : 'event-query' , type : String } ) public get eventQuery ( ) : string { return this . _eventQuery ; } public set eventQuery ( value ) { if ( this . _eventQuery === value ) { return ; } this . _eventQuery = value ; this . reloadState ( ) ; } type { MicrosoftGraph . Event [ ] } @ property ( { attribute : 'events' , type : Array } ) public events : MicrosoftGraph . Event [ ] ; type { number } @ property ( { attribute : 'show-max' , type : Number } ) public showMax : number ; type { boolean } @ property ( { attribute : 'group-by-day' , type : Boolean } ) public groupByDay : boolean ; type { string } @ property ( { attribute : 'preferred-timezone' , type : String } ) public get preferredTimezone ( ) : string { return this . _preferredTimezone ; } public set preferredTimezone ( value ) { if ( this . _preferredTimezone === value ) { return ; } this . _preferredTimezone = value ; this . reloadState ( ) ; } static return { * } memberof public static get requiredScopes ( ) : string [ ] { return [ ... new Set ( [ 'calendars.read' , ... MgtPeople . requiredScopes ] ) ] ; } type { boolean } @ property ( { attribute : false } ) private _isNarrow : boolean ; private _eventQuery : string ; private _days : number = 3 ; private _groupId : string ; private _date : string ; private _preferredTimezone : string ; constructor ( ) { super ( ) ; this . onResize = this . onResize . bind ( this ) ; } memberof public connectedCallback ( ) { this . _isNarrow = this . offsetWidth < 600 ; super . connectedCallback ( ) ; window . addEventListener ( 'resize' , this . onResize ) ; } memberof public disconnectedCallback ( ) { window . removeEventListener ( 'resize' , this . onResize ) ; super . disconnectedCallback ( ) ; } returns memberof public render ( ) { if ( ! this . events && this . isLoadingState ) { return this . renderLoading ( ) ; } if ( ! this . events || this . events . length === 0 ) { return this . renderNoData ( ) ; } 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 ; } this . _isNarrow = this . offsetWidth < 600 ; return html `
      <div dir=${ this . direction } class="agenda${ this . _isNarrow ? ' narrow' : '' }${ this . groupByDay ? ' grouped' : '' }">
        ${ this . groupByDay ? this . renderGroups ( events ) : this . renderEvents ( events ) }
        ${ this . isLoadingState ? this . renderLoading ( ) : html `` }
      </div>
    ` ; } memberof public async reload ( ) { this . events = await this . loadEvents ( ) ; } protected returns memberof protected renderLoading ( ) { return ( this . renderTemplate ( 'loading' , null ) || 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>
      ` ) ; } protected memberof protected clearState ( ) { this . events = null ; } protected returns { TemplateResult } memberof protected renderNoData ( ) { return this . renderTemplate ( 'no-data' , null ) || html `` ; } protected param { MicrosoftGraph . Event } event returns memberof protected renderEvent ( event ) { return html `
      <div class="event">
        <div class="event-time-container">
          <div tabindex=0 class="event-time" aria-label="${ this . getEventTimeString ( event ) }">${ this . getEventTimeString ( event ) }</div>
        </div>
        <div class="event-details-container">
          ${ this . renderTitle ( event ) } ${ this . renderLocation ( event ) } ${ this . renderAttendees ( event ) }
        </div>
        <div class="event-other-container">${ this . renderOther ( event ) }</div>
      </div>
    ` ; } protected param { Date } date returns memberof protected renderHeader ( header ) { return ( this . renderTemplate ( 'header' , { header } , 'header-' + header ) || html `
        <div tabindex=0 class="header" aria-label="${ header }">${ header }</div>
      ` ) ; } protected param { MicrosoftGraph . Event } event returns memberof protected renderTitle ( event ) { return html `
      <div tabindex=0 aria-label=${ event . subject } class="event-subject">${ event . subject }</div>
    ` ; } protected param { MicrosoftGraph . Event } event returns memberof protected renderLocation ( event ) { if ( ! event . location . displayName ) { return null ; } return html `
      <div class="event-location-container">
        <div class="event-location-icon">${ getSvg ( SvgIcon . OfficeLocation ) }</div>
        <div tabindex=0 class="event-location" aria-label="${ event . location . displayName }">${ event . location . displayName }</div>
      </div>
    ` ; } protected param { MicrosoftGraph . Event } event returns memberof protected renderAttendees ( event ) { if ( ! event . attendees . length ) { return null ; } return html `
      <mgt-people
        class="event-attendees"
        .peopleQueries=${ event . attendees . map ( attendee => { return attendee . emailAddress . address ; } ) }
      ></mgt-people>
    ` ; } protected param { MicrosoftGraph . Event } event returns memberof protected renderOther ( event ) { return this . hasTemplate ( 'event-other' ) ? html `
          ${ this . renderTemplate ( 'event-other' , { event } , event . id + '-other' ) }
        ` : null ; } protected param { MicrosoftGraph . Event [ ] } events returns { TemplateResult } memberof protected renderGroups ( events ) { const grouped = { } ; events . forEach ( event => { var eventDate = new Date ( event . start . dateTime ) ; var dateString = eventDate . toISOString ( ) . replace ( 'Z' , '' ) ; const header = this . getDateHeaderFromDateTimeString ( dateString ) ; grouped [ header ] = grouped [ header ] || [ ] ; grouped [ header ] . push ( event ) ; } ) ; return html `
      ${ Object . keys ( grouped ) . map ( header => html `
            <div class="group">${ this . renderHeader ( header ) } ${ this . renderEvents ( grouped [ header ] ) }</div>
          ` ) }
    ` ; } protected param { MicrosoftGraph . Event [ ] } events returns { TemplateResult } memberof protected renderEvents ( 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>
    ` ; } protected returns memberof protected async loadState ( ) { if ( this . events ) { return ; } const events = await this . loadEvents ( ) ; if ( events && events . length > 0 ) { this . events = events ; } } private async reloadState ( ) { this . events = null ; this . requestStateUpdate ( true ) ; } private onResize ( ) { this . _isNarrow = this . offsetWidth < 600 ; } private eventClicked ( event ) { this . fireCustomEvent ( 'eventClick' , { event } ) ; } private getEventTimeString ( event ) { if ( event . isAllDay ) { return 'ALL DAY' ; } let startString = event . start . dateTime ; if ( event . start . timeZone === 'UTC' ) { startString += 'Z' ; } let endString = event . end . dateTime ; if ( event . end . timeZone === 'UTC' ) { endString += 'Z' ; } const start = this . prettyPrintTimeFromDateTime ( new Date ( startString ) ) ; const end = this . prettyPrintTimeFromDateTime ( new Date ( endString ) ) ; return `${ start } - ${ end }` ; } private async loadEvents ( ) { const p = Providers . globalProvider ; let events = [ ] ; if ( p && p . state === ProviderState . SignedIn ) { const graph = p . graph . forComponent ( this ) ; 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 = await graph . api ( query ) ; if ( scope ) { request = request . middlewareOptions ( prepScopes ( scope ) ) ; } if ( this . preferredTimezone ) { request = request . header ( 'Prefer' , `outlook.timezone="${ this . preferredTimezone }"` ) ; } const results = await request . get ( ) ; if ( results && results . value ) { events = results . value ; } } 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 { const iterator = await getEventsPageIterator ( graph , start , end , this . groupId , this . preferredTimezone ) ; if ( iterator && iterator . value ) { events = iterator . value ; while ( iterator . hasNext ) { await iterator . next ( ) ; events = iterator . value ; } } } catch ( error ) { } } } return events ; } private prettyPrintTimeFromDateTime ( date ) { if ( ! this . preferredTimezone ) { 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 }` ; } private 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 }` ; } private 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 ; } }