Show quick info template in React Schedule component

27 Jan 202324 minutes to read

This demo showcases the quick popups for cells and appointments with the customized templates.

import * as React from 'react';
import * as ReactDOM from 'react-dom';
import { ScheduleComponent, ResourcesDirective, ResourceDirective, Day, Week, WorkWeek, Month, Agenda, MonthAgenda, Inject } from '@syncfusion/ej2-react-schedule';
import { extend, Internationalization } from '@syncfusion/ej2-base';
import { DropDownListComponent } from '@syncfusion/ej2-react-dropdowns';
import { TextBoxComponent } from '@syncfusion/ej2-react-inputs';
import { ButtonComponent } from '@syncfusion/ej2-react-buttons';
import { ScheduleData } from './datasource';
function App() {
    let eventTypeObj;
    let titleObj;
    let notesObj;
    let scheduleObj;
    const intl = new Internationalization();
    const roomData = [
        { Name: 'Jammy', Id: 1, Capacity: 20, Color: '#ea7a57', Type: 'Conference' },
        { Name: 'Tweety', Id: 2, Capacity: 7, Color: '#7fa900', Type: 'Cabin' },
        { Name: 'Nestle', Id: 3, Capacity: 5, Color: '#5978ee', Type: 'Cabin' },
        { Name: 'Phoenix', Id: 4, Capacity: 15, Color: '#fec200', Type: 'Conference' },
        { Name: 'Mission', Id: 5, Capacity: 25, Color: '#df5286', Type: 'Conference' },
        { Name: 'Hangout', Id: 6, Capacity: 10, Color: '#00bdae', Type: 'Cabin' },
        { Name: 'Rick Roll', Id: 7, Capacity: 20, Color: '#865fcf', Type: 'Conference' },
        { Name: 'Rainbow', Id: 8, Capacity: 8, Color: '#1aaa55', Type: 'Cabin' },
        { Name: 'Swarm', Id: 9, Capacity: 30, Color: '#df5286', Type: 'Conference' },
        { Name: 'Photogenic', Id: 10, Capacity: 25, Color: '#710193', Type: 'Conference' }
    ];
    const scheduleData = extend([], ScheduleData, null, true);
    function getResourceData(data) {
        const resources = scheduleObj.getResourceCollections().slice(-1)[0];
        const resourceData = resources.dataSource.filter((resource) => resource.Id === data.RoomId)[0];
        return resourceData;
    }
    function getHeaderStyles(data) {
        if (data.elementType === 'cell') {
            return { alignItems: 'center', color: '#919191' };
        }
        else {
            const resourceData = getResourceData(data);
            return { background: resourceData.Color, color: '#FFFFFF' };
        }
    }
    function getHeaderTitle(data) {
        return (data.elementType === 'cell') ? 'Add Appointment' : 'Appointment Details';
    }
    function getHeaderDetails(data) {
        return intl.formatDate(data.StartTime, { type: 'date', skeleton: 'full' }) + ' (' +
            intl.formatDate(data.StartTime, { skeleton: 'hm' }) + ' - ' +
            intl.formatDate(data.EndTime, { skeleton: 'hm' }) + ')';
    }
    function getEventType(data) {
        const resourceData = getResourceData(data);
        return resourceData.Name;
    }
    function buttonClickActions(e) {
        const quickPopup = scheduleObj.element.querySelector('.e-quick-popup-wrapper');
        const getSlotData = () => {
            const cellDetails = scheduleObj.getCellDetails(scheduleObj.getSelectedElements());
            const addObj = {};
            addObj.Id = scheduleObj.getEventMaxID();
            addObj.Subject = titleObj.value;
            addObj.StartTime = new Date(+cellDetails.startTime);
            addObj.EndTime = new Date(+cellDetails.endTime);
            addObj.Description = notesObj.value;
            addObj.RoomId = eventTypeObj.value;
            return addObj;
        };
        if (e.target.id === 'add') {
            const addObj = getSlotData();
            scheduleObj.addEvent(addObj);
        }
        else if (e.target.id === 'delete') {
            const eventDetails = scheduleObj.activeEventData.event;
            let currentAction = 'Delete';
            if (eventDetails.RecurrenceRule) {
                currentAction = 'DeleteOccurrence';
            }
            scheduleObj.deleteEvent(eventDetails, currentAction);
        }
        else {
            const isCellPopup = quickPopup.firstElementChild.classList.contains('e-cell-popup');
            const eventDetails = isCellPopup ? getSlotData() :
                scheduleObj.activeEventData.event;
            let currentAction = isCellPopup ? 'Add' : 'Save';
            if (eventDetails.RecurrenceRule) {
                currentAction = 'EditOccurrence';
            }
            scheduleObj.openEditor(eventDetails, currentAction, true);
        }
        scheduleObj.closeQuickInfoPopup();
    }
    function headerTemplate(props) {
        return (<div className="quick-info-header">
        <div className="quick-info-header-content" style={getHeaderStyles(props)}>
          <div className="quick-info-title">{getHeaderTitle(props)}</div>
          <div className="duration-text">{getHeaderDetails(props)}</div>
        </div>
      </div>);
    }
    function contentTemplate(props) {
        return (<div className="quick-info-content">
        {props.elementType === 'cell' ?
                <div className="e-cell-content">
            <div className="content-area">
              <TextBoxComponent id="title" ref={(textbox) => titleObj = textbox} placeholder="Title"/>
            </div>
            <div className="content-area">
              <DropDownListComponent id="eventType" ref={(ddl) => eventTypeObj = ddl} dataSource={roomData} fields= placeholder="Choose Type" index={0} popupHeight="200px"/>
            </div>
            <div className="content-area">
              <TextBoxComponent id="notes" ref={(textbox) => notesObj = textbox} placeholder="Notes"/>
            </div>
          </div>
                :
                    <div className="event-content">
            <div className="meeting-type-wrap">
              <label>Subject</label>:
              <span>{props.Subject}</span>
            </div>
            <div className="meeting-subject-wrap">
              <label>Type</label>:
              <span>{getEventType(props)}</span>
            </div>
            <div className="notes-wrap">
              <label>Notes</label>:
              <span>{props.Description}</span>
            </div>
          </div>}
      </div>);
    }
    function footerTemplate(props) {
        return (<div className="quick-info-footer">
        {props.elementType == "cell" ?
                <div className="cell-footer">
            <ButtonComponent id="more-details" cssClass='e-flat' content="More Details" onClick={buttonClickActions.bind(this)}/>
            <ButtonComponent id="add" cssClass='e-flat' content="Add" isPrimary={true} onClick={buttonClickActions.bind(this)}/>
          </div>
                :
                    <div className="event-footer">
            <ButtonComponent id="delete" cssClass='e-flat' content="Delete" onClick={buttonClickActions.bind(this)}/>
            <ButtonComponent id="more-details" cssClass='e-flat' content="More Details" isPrimary={true} onClick={buttonClickActions.bind(this).bind(this)}/>
          </div>}
      </div>);
    }
    return (<div className='schedule-control-section'>
      <div className='col-lg-12 control-section'>
        <div className='control-wrapper'>
          <ScheduleComponent id="schedule" cssClass='quick-info-template' ref={(schedule) => scheduleObj = schedule} height="650px" selectedDate={new Date(2020, 0, 9)} eventSettings= quickInfoTemplates=>
            <ResourcesDirective>
              <ResourceDirective field='RoomId' title='Room Type' name='MeetingRoom' textField='Name' idField='Id' colorField='Color' dataSource={roomData}></ResourceDirective>
            </ResourcesDirective>
            <Inject services={[Day, Week, WorkWeek, Month, Agenda, MonthAgenda]}/>
          </ScheduleComponent>
        </div>
      </div>
    </div>);
}
;
const root = ReactDOM.createRoot(document.getElementById('schedule'));
root.render(<App />);
import * as React from 'react';
import * as ReactDOM from 'react-dom';
import {
  ScheduleComponent, ResourcesDirective, ResourceDirective, Day, Week, WorkWeek, Month,
  Agenda, MonthAgenda, Inject, ResourcesModel, CellClickEventArgs, CurrentAction
} from '@syncfusion/ej2-react-schedule';
import { extend, Internationalization } from '@syncfusion/ej2-base';
import { DropDownListComponent } from '@syncfusion/ej2-react-dropdowns';
import { TextBoxComponent } from '@syncfusion/ej2-react-inputs';
import { ButtonComponent } from '@syncfusion/ej2-react-buttons';
import { ScheduleData } from './datasource';

function App() {
  let eventTypeObj: DropDownListComponent;
  let titleObj: TextBoxComponent;
  let notesObj: TextBoxComponent;
  let scheduleObj: ScheduleComponent;
  const intl: Internationalization = new Internationalization();
  const roomData: { [key: string]: Object }[] = [
    { Name: 'Jammy', Id: 1, Capacity: 20, Color: '#ea7a57', Type: 'Conference' },
    { Name: 'Tweety', Id: 2, Capacity: 7, Color: '#7fa900', Type: 'Cabin' },
    { Name: 'Nestle', Id: 3, Capacity: 5, Color: '#5978ee', Type: 'Cabin' },
    { Name: 'Phoenix', Id: 4, Capacity: 15, Color: '#fec200', Type: 'Conference' },
    { Name: 'Mission', Id: 5, Capacity: 25, Color: '#df5286', Type: 'Conference' },
    { Name: 'Hangout', Id: 6, Capacity: 10, Color: '#00bdae', Type: 'Cabin' },
    { Name: 'Rick Roll', Id: 7, Capacity: 20, Color: '#865fcf', Type: 'Conference' },
    { Name: 'Rainbow', Id: 8, Capacity: 8, Color: '#1aaa55', Type: 'Cabin' },
    { Name: 'Swarm', Id: 9, Capacity: 30, Color: '#df5286', Type: 'Conference' },
    { Name: 'Photogenic', Id: 10, Capacity: 25, Color: '#710193', Type: 'Conference' }
  ];
  const scheduleData: Object[] = extend([], ScheduleData, null, true) as Object[];
  function getResourceData(data: { [key: string]: Object }): { [key: string]: Object } {
    const resources: ResourcesModel = scheduleObj.getResourceCollections().slice(-1)[0];
    const resourceData: { [key: string]: Object } = (resources.dataSource as Object[]).filter((resource: { [key: string]: Object }) =>
      resource.Id === data.RoomId)[0] as { [key: string]: Object };
    return resourceData;
  }

  function getHeaderStyles(data: { [key: string]: Object }): Object {
    if (data.elementType === 'cell') {
      return { alignItems: 'center', color: '#919191' };
    } else {
      const resourceData: { [key: string]: Object } = getResourceData(data);
      return { background: resourceData.Color, color: '#FFFFFF' };
    }
  }

  function getHeaderTitle(data: { [key: string]: Object }): string {
    return (data.elementType === 'cell') ? 'Add Appointment' : 'Appointment Details';
  }

  function getHeaderDetails(data: { [key: string]: Date }): string {
    return intl.formatDate(data.StartTime, { type: 'date', skeleton: 'full' }) + ' (' +
      intl.formatDate(data.StartTime, { skeleton: 'hm' }) + ' - ' +
      intl.formatDate(data.EndTime, { skeleton: 'hm' }) + ')';

  }

  function getEventType(data: { [key: string]: string }): string {
    const resourceData: { [key: string]: Object } = getResourceData(data);
    return resourceData.Name as string;
  }

  function buttonClickActions(e: Event) {
    const quickPopup: HTMLElement = scheduleObj.element.querySelector('.e-quick-popup-wrapper') as HTMLElement;
    const getSlotData: Function = (): { [key: string]: Object } => {
      const cellDetails: CellClickEventArgs = scheduleObj.getCellDetails(scheduleObj.getSelectedElements());
      const addObj: { [key: string]: Object } = {};
      addObj.Id = scheduleObj.getEventMaxID();
      addObj.Subject = titleObj.value;
      addObj.StartTime = new Date(+cellDetails.startTime);
      addObj.EndTime = new Date(+cellDetails.endTime);
      addObj.Description = notesObj.value;
      addObj.RoomId = eventTypeObj.value;
      return addObj;
    };
    if ((e.target as HTMLElement).id === 'add') {
      const addObj: { [key: string]: Object } = getSlotData();
      scheduleObj.addEvent(addObj);
    } else if ((e.target as HTMLElement).id === 'delete') {
      const eventDetails: { [key: string]: Object } = scheduleObj.activeEventData.event as { [key: string]: Object };
      let currentAction: CurrentAction = 'Delete';
      if (eventDetails.RecurrenceRule) {
        currentAction = 'DeleteOccurrence';
      }
      scheduleObj.deleteEvent(eventDetails, currentAction);
    } else {
      const isCellPopup: boolean = (quickPopup.firstElementChild as HTMLElement).classList.contains('e-cell-popup');
      const eventDetails: { [key: string]: Object } = isCellPopup ? getSlotData() :
        scheduleObj.activeEventData.event as { [key: string]: Object };
      let currentAction: CurrentAction = isCellPopup ? 'Add' : 'Save';
      if (eventDetails.RecurrenceRule) {
        currentAction = 'EditOccurrence';
      }
      scheduleObj.openEditor(eventDetails, currentAction, true);
    }
    scheduleObj.closeQuickInfoPopup();
  }

  function headerTemplate(props: { [key: string]: Date }): JSX.Element {
    return (
      <div className="quick-info-header">
        <div className="quick-info-header-content" style={getHeaderStyles(props)}>
          <div className="quick-info-title">{getHeaderTitle(props)}</div>
          <div className="duration-text">{getHeaderDetails(props)}</div>
        </div>
      </div>
    );
  }

  function contentTemplate(props: { [key: string]: string }): JSX.Element {
    return (
      <div className="quick-info-content">
        {props.elementType === 'cell' ?
          <div className="e-cell-content">
            <div className="content-area">
              <TextBoxComponent id="title" ref={(textbox: TextBoxComponent) => titleObj = textbox} placeholder="Title" />
            </div>
            <div className="content-area">
              <DropDownListComponent id="eventType" ref={(ddl: DropDownListComponent) => eventTypeObj = ddl} dataSource={roomData}
                fields= placeholder="Choose Type" index={0} popupHeight="200px" />
            </div>
            <div className="content-area">
              <TextBoxComponent id="notes" ref={(textbox: TextBoxComponent) => notesObj = textbox} placeholder="Notes" />
            </div>
          </div>
          :
          <div className="event-content">
            <div className="meeting-type-wrap">
              <label>Subject</label>:
              <span>{props.Subject}</span>
            </div>
            <div className="meeting-subject-wrap">
              <label>Type</label>:
              <span>{getEventType(props)}</span>
            </div>
            <div className="notes-wrap">
              <label>Notes</label>:
              <span>{props.Description}</span>
            </div>
          </div>
        }
      </div>
    );
  }

  function footerTemplate(props: { [key: string]: Object }): JSX.Element {
    return (
      <div className="quick-info-footer">
        {props.elementType == "cell" ?
          <div className="cell-footer">
            <ButtonComponent id="more-details" cssClass='e-flat' content="More Details" onClick={buttonClickActions.bind(this)} />
            <ButtonComponent id="add" cssClass='e-flat' content="Add" isPrimary={true} onClick={buttonClickActions.bind(this)} />
          </div>
          :
          <div className="event-footer">
            <ButtonComponent id="delete" cssClass='e-flat' content="Delete" onClick={buttonClickActions.bind(this)} />
            <ButtonComponent id="more-details" cssClass='e-flat' content="More Details" isPrimary={true} onClick={buttonClickActions.bind(this).bind(this)} />
          </div>
        }
      </div>
    );
  }

  return (
    <div className='schedule-control-section'>
      <div className='col-lg-12 control-section'>
        <div className='control-wrapper'>
          <ScheduleComponent id="schedule" cssClass='quick-info-template' ref={(schedule: ScheduleComponent) => scheduleObj = schedule} height="650px"
            selectedDate={new Date(2020, 0, 9)} eventSettings= quickInfoTemplates=>
            <ResourcesDirective>
              <ResourceDirective field='RoomId' title='Room Type' name='MeetingRoom' textField='Name' idField='Id'
                colorField='Color' dataSource={roomData}></ResourceDirective>
            </ResourcesDirective>
            <Inject services={[Day, Week, WorkWeek, Month, Agenda, MonthAgenda]} />
          </ScheduleComponent>
        </div>
      </div>
    </div>
  );

};
const root = ReactDOM.createRoot(document.getElementById('schedule'));
root.render(<App />);
<!DOCTYPE html>
<html lang="en">

    <head>
        <title>Syncfusion React Schedule</title>
        <meta charset="utf-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <meta name="description" content="Essential JS 2 for React Components" />
        <meta name="author" content="Syncfusion" />
        <link href="https://cdn.syncfusion.com/ej2/20.4.48/ej2-base/styles/material.css" rel="stylesheet" />
        <link href="https://cdn.syncfusion.com/ej2/20.4.48/ej2-react-buttons/styles/material.css" rel="stylesheet" />
        <link href="https://cdn.syncfusion.com/ej2/20.4.48/ej2-react-calendars/styles/material.css" rel="stylesheet" />
        <link href="https://cdn.syncfusion.com/ej2/20.4.48/ej2-react-dropdowns/styles/material.css" rel="stylesheet" />
        <link href="https://cdn.syncfusion.com/ej2/20.4.48/ej2-react-inputs/styles/material.css" rel="stylesheet" />
        <link href="https://cdn.syncfusion.com/ej2/20.4.48/ej2-react-navigations/styles/material.css" rel="stylesheet" />
        <link href="https://cdn.syncfusion.com/ej2/20.4.48/ej2-react-popups/styles/material.css" rel="stylesheet" />    
        <link href="https://cdn.syncfusion.com/ej2/20.4.48/ej2-react-schedule/styles/material.css" rel="stylesheet" />
        <link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet" />
        <script src="https://cdnjs.cloudflare.com/ajax/libs/systemjs/0.19.38/system.js"></script>
        <link href="index.css" rel="stylesheet" /> 
        <script src="systemjs.config.js"></script>
         <style>
            #loader {
                color: #008cff;
                height: 40px;
                left: 45%;
                position: absolute;
                top: 45%;
                width: 30%;
            }
        </style>
    <script src="https://cdn.syncfusion.com/ej2/syncfusion-helper.js" type ="text/javascript"></script>
</head>
    
    <body>
            <div id='schedule'>
                <div id='loader'>Loading....</div>
            </div>
    </body>
    
    </html>