import * as React from 'react' ; import * as ReactDOM from 'react-dom' ; import { BaseDialog , IDialogConfiguration } from '@microsoft/sp-dialog' ; import { autobind , DatePicker , PrimaryButton , CommandButton , TextField , Label , Dropdown , DropdownMenuItemType , IDropdownOption , DialogFooter , DialogContent } from 'office-ui-fabric-react' ; import { DateTimePicker } from './DateTimePicker' ; import { ExtensionContext } from '@microsoft/sp-extension-base' ; import { Dialog } from '@microsoft/sp-dialog' ; import { MSGraphClient } from '@microsoft/sp-client-preview' ; import styles from './ScheduleMeetingDialog.module.scss' ; import * as strings from 'DiscussNowCommandSetStrings' ; interface IScheduleMeetingDialogContentProps { fileName : string ; filePath : string ; close : ( ) => void ; submit : ( subject : string , meetingDateTime : Date , duration : number ) => void ; } interface IScheduleMeetingDialogContentState { subject : string ; dateTime : Date ; duration : number ; } class ScheduleMeetingDialogContent extends React . Component < IScheduleMeetingDialogContentProps , IScheduleMeetingDialogContentState > { constructor ( props ) { super ( props ) ; this . state = { subject : this . props . fileName , dateTime : new Date ( ) , duration : 60 } ; } public render ( ) { return ( < div className = { styles . scheduleMeetingDialogRoot } > < DialogContent title = { strings . DiscussNowDialogTitle } subText = { strings . DiscussNowDialogDescription } onDismiss = { this . props . close } showCloseButton = { true } > < div className = { styles . scheduleMeetingDialogContent } > < div className = "ms-Grid" > < div className = "ms-Grid-row" > < div className = "ms-Grid-col ms-u-sm12 ms-u-md12 ms-u-lg12" > < TextField label = { strings . ScheduleMeetingSubjectLabel } required = { true } value = { this . state . subject } onChanged = { this . _onChangedSubject } onGetErrorMessage = { this . _getErrorMessageSubject } / > < /div> < /div> < div className = "ms-Grid-row" > < div className = "ms-Grid-col ms-u-sm12 ms-u-md12 ms-u-lg12" > < DateTimePicker showTime = { true } includeSeconds = { false } isRequired = { true } dateLabel = { strings . ScheduleMeetingDateLabel } hoursLabel = { strings . ScheduleMeetingHoursLabel } hoursValidationError = { strings . ScheduleMeetingHoursValidationError } minutesLabel = { strings . ScheduleMeetingMinutesLabel } minutesValidationError = { strings . ScheduleMeetingMinutesValidationError } onChanged = { this . _onChangedScheduledDateTime } / > < /div> < /div> < div className = "ms-Grid-row" > < div className = "ms-Grid-col ms-u-sm12 ms-u-md12 ms-u-lg12" > < Dropdown label = { strings . ScheduleMeetingDurationLabel } defaultSelectedKey = '60' options = { [ { key : '30' , text : '30 minutes' } , { key : '60' , text : '1 hour' } , { key : '90' , text : '1 hour and 30 minutes' } , { key : '120' , text : '2 hours' } , ] } onChanged = { this . _onChangedScheduleDuration } / > < /div> < /div> < /div> < /div> < DialogFooter > < CommandButton text = 'Cancel' title = 'Cancel' onClick = { this . props . close } / > < PrimaryButton text = 'OK' title = 'OK' onClick = { ( ) => { this . props . submit ( this . state . subject , this . state . dateTime , this . state . duration ) ; } } /> < /DialogFooter> < /DialogContent> < /div>); } @ autobind private _onChangedSubject ( newValue ) { this . setState ( { subject : newValue , } ) ; } private _getErrorMessageSubject ( value ) { return ( value == null || value . length == 0 || value . length >= 10 ) ? '' : `${ strings . ScheduleMeetingSubjectValidationErrorMessage } ${ value . length }.` ; } @ autobind private _onChangedScheduledDateTime ( newValue ) { this . setState ( { dateTime : newValue , } ) ; } @ autobind private _onChangedScheduleDuration ( option , index ? ) { const duration = Number ( option . key ) ; this . setState ( { duration : duration } ) ; } } export default class ScheduleMeetingDialog extends BaseDialog { public fileName : string ; public filePath : string ; public context : ExtensionContext ; public render ( ) { ReactDOM . render ( < ScheduleMeetingDialogContent fileName = { this . fileName } filePath = { this . filePath } close = { this . close } submit = { this . _submit } / > , this . domElement ) ; } public getConfig ( ) { return { isBlocking : false } ; } @ autobind private async _submit ( subject , dateTime , duration ) { let response = null ; const startDateTimeISO = dateTime . toISOString ( ) ; let addMinutes = 0 ; let addHours = 0 ; switch ( duration ) { case 30 : addMinutes = 30 ; break ; case 60 : addHours = 1 ; break ; case 90 : addHours = 1 ; addMinutes = 30 ; break ; case 120 : addHours = 2 ; break ; default : break ; } let endDateTime = new Date ( startDateTimeISO ) ; endDateTime . setHours ( dateTime . getHours ( ) + addHours ) ; endDateTime . setMinutes ( dateTime . getMinutes ( ) + addMinutes ) ; const endDateTimeISO = endDateTime . toISOString ( ) ; const groupId = this . context . pageContext . legacyPageContext . groupId ; if ( groupId ) { const newMeetingRequest = { body : { content : "Let's discuss about this document: ${this.filePath}" , contentType : "Text" } , subject : subject , start : { dateTime : startDateTimeISO , timeZone : "UTC" } , end : { dateTime : endDateTimeISO , timeZone : "UTC" } } ; const graphClient = this . context . serviceScope . consume ( MSGraphClient . serviceKey ) ; response = await graphClient . api ( `groups/${ groupId }/calendar/events` ) . version ( "v1.0" ) . post ( newMeetingRequest ) ; } if ( response && response . id ) { Dialog . alert ( `Meeting "${ subject }" has been successfully created.` ) ; } else { Dialog . alert ( `Failed to create meeting "${ subject }"!` ) ; } this . close ( ) ; } }