DEV Community

Bryntum for Bryntum

Posted on • Originally published at bryntum.com

How to connect and sync Bryntum Scheduler to Microsoft Teams

Bryntum Scheduler is a modern, high-performance scheduling UI component built with pure Javascript. It can easily be used with React, Vue, or Angular. In this tutorial, we'll connect and sync Bryntum Scheduler to Microsoft Teams. We'll do the following:

  • Create a JavaScript app that a user can log into using their Microsoft 365 Developer Program account.
  • Use Microsoft Graph to get the user's Microsoft Teams shifts.
  • Display the Microsoft Teams shifts in Bryntum Scheduler.
  • Sync event changes in Bryntum Scheduler with the user's Microsoft Teams.

Bryntum - Microsoft Teams Shifts sync

Getting started

Clone the starter GitHub repository. The starter repository uses Vite, which is a development server and JavaScript bundler. You'll need Node.js version 14.18+ for Vite to work.

Now install the Vite dev dependency by running the following command:

npm install
Enter fullscreen mode Exit fullscreen mode

Run the local dev server using npm run dev and you’ll see a blank page. The dev server is configured to run on http://localhost:8080/ in the vite.config.js file. This will be needed for Microsoft 365 authentication later.

Let’s create our Bryntum Scheduler now.

Creating a scheduler using Bryntum

We'll install the Bryntum Scheduler component using npm. Follow step one of the Bryntum Scheduler setup guide to log into the Bryntum registry component.

Then initialize your application using the npm CLI npm init command:

npm init
Enter fullscreen mode Exit fullscreen mode

You will be asked a series of questions in the terminal; accept all the defaults by clicking Enter for each question.

Now follow step four of the Bryntum Scheduler setup guide to install Bryntum Scheduler.

Let’s import the Bryntum Scheduler component and give it some basic configuration. In the main.js file add the following lines:

import { Scheduler } from "@bryntum/scheduler/scheduler.module.js";
import "@bryntum/scheduler/scheduler.stockholm.css";

// get the current date
var today = new Date();

// get the day of the week
var day = today.getDay();

// get the date of the previous Sunday
var previousSunday = new Date(today);
previousSunday.setDate(today.getDate() - day);

// get the date of the following Saturday
var nextSaturday = new Date(today);
nextSaturday.setDate(today.getDate() + (6 - day));

const scheduler = new Scheduler({
    appendTo : "scheduler",

    startDate : previousSunday,
    endDate   : nextSaturday,
    viewPreset : 'dayAndWeek',

    resources : [
        { id : 1, name : 'Dan Stevenson' },
        { id : 2, name : 'Talisha Babin' }
    ],

    events : [
        { resourceId : 1, startDate : previousSunday, endDate : nextSaturday },
        { resourceId : 2, startDate : previousSunday, endDate : nextSaturday }
    ],

    columns : [
        { text : 'Name', field : 'name', width : 160 }
    ]
});
Enter fullscreen mode Exit fullscreen mode

We imported Bryntum Scheduler and the CSS for the Stockholm theme, which is one of five available themes. You can also create custom themes. You can read more about styling the scheduler here. We created a new Bryntum Scheduler instance and passed a configuration object into it. We added the scheduler to the DOM as a child of the <div> element with an id of "scheduler".

The scheduler can be set up to display specific dates on opening; here we set the startDate to the previous Sunday and endDate to the following Saturday in order to reflect the dates in the Microsoft Teams UI.

We passed in data inline to populate the scheduler resources and events stores for simplicity. You can learn more about working with data in the Bryntum docs. We have a resource for two individuals. Within the scheduler, there's an example "shift" event for each individual that runs for a week. If you run your dev server now, you'll see the events in Bryntum Scheduler:

Bryntum Scheduler with example event

Now let's learn how to retrieve a list of team shifts from a user’s Microsoft Teams using Microsoft Graph.

Gaining access to Microsoft Graph

We're going to register a Microsoft 365 application by creating an application registration in Azure Active Directory (Azure AD), which is an authentication service. We'll do this so that a user can sign into our app using their Microsoft 365 account. This will allow our app access to the data the user gives the app permission to access. A user will sign in using OAuth, which will send an access token to our app that will be stored in session storage. We'll then use the token to make authorized requests for Microsoft Teams data using Microsoft Graph. Microsoft Graph is a single endpoint REST API that enables you to access data from Microsoft 365 applications.

To use Microsoft Graph you'll need a Microsoft account and you'll need to join the Microsoft 365 Developer Program with that Microsoft account. When joining the Microsoft 365 Developer Program, you'll be asked what areas of Microsoft 365 development you’re interested in; select the Microsoft Graph option. Choose the closest data center region, create your admin username and password, then click "Continue". Next, select “Instant Sandbox” and click “Next”.

Setting up your Microsoft 365 developer sandbox

Now that you have successfully joined the Developer Program, you can get your admin email address in the dashboard window. We'll use it to create an application with Microsoft Azure.

ISetting up your Microsoft 365 developer sandbox

Creating an Azure AD app to connect to Microsoft 365

Let's register a Microsoft 365 application by creating an application registration in the Azure Active Directory admin portal. Sign in using the admin email address from your Microsoft 365 Developer Program account. Now follow these steps to create an Azure Active Directory application:

  1. In the menu, select "Azure Active Directory".
    Adzure AD setup - step 1

  2. Select "App registrations".
    Adzure AD setup - step 2

  3. Click "New registration" to create a new app registration.
    Adzure AD setup - step 3

  4. Give your app a name, select the "Single tenant" option, select "Single page application" for the redirect URI, and enter http://localhost:8080 for the redirect URL. Then click the "Register" button.
    Adzure AD setup - step 4

  5. After registering your application, take note of the Application (client) ID and the Directory (tenant) ID; you'll need these to set up authentication for your web app later.
    Adzure AD setup - step 5

Now we can create a JavaScript web app that can get user data using the Microsoft Graph API. The next step is to set up authentication within our web app.

Setting up Microsoft 365 authentication in the JavaScript app

To get data using the Microsoft Graph REST API, our app needs to prove that we're the owners of the app that we just created in Azure AD. Your application will get an access token from Azure AD and include it in each request to Microsoft Graph. After this is set up, users will be able to sign into your app using their Microsoft 365 account. This means that you won’t have to implement authentication in your app or maintain users' credentials.

Auth flow diagram

First we'll create the variables and functions we need for authentication and retrieving team shifts from Microsoft Teams. Then we'll add the Microsoft Authentication Library and Microsoft Graph SDK, which we'll need for authentication and using Microsoft Graph.

Create a file called auth.js in your project’s root directory and add the following code:

const msalConfig = {
  auth: {
    clientId: "<your-client-ID-here>",
    // comment out if you use a multi-tenant AAD app
    authority: "https://login.microsoftonline.com/<your-directory-ID-here>",
    redirectUri: "http://localhost:8080",
  },
}; 
Enter fullscreen mode Exit fullscreen mode

In the msalConfig variable, replace the value for clientID with the client ID that came with your Azure AD application and replace the authority value with your directory ID.

The following code will check permissions, create a Microsoft Authentication Library client, log a user in, and get the authentication token. Add it to the bottom of the file.

const msalRequest = { scopes: [] };
function ensureScope(scope) {
  if (
    !msalRequest.scopes.some((s) => s.toLowerCase() === scope.toLowerCase())
  ) {
    msalRequest.scopes.push(scope);
  }
}

// Initialize MSAL client
const msalClient = new msal.PublicClientApplication(msalConfig);

// Log the user in
async function signIn() {
  const authResult = await msalClient.loginPopup(msalRequest);
  sessionStorage.setItem("msalAccount", authResult.account.username);
}

async function getToken() {
  let account = sessionStorage.getItem("msalAccount");
  if (!account) {
    throw new Error(
      "User info cleared from session. Please sign out and sign in again."
    );
  }
  try {
    // First, attempt to get the token silently
    const silentRequest = {
      scopes: msalRequest.scopes,
      account: msalClient.getAccountByUsername(account),
    };

    const silentResult = await msalClient.acquireTokenSilent(silentRequest);
    return silentResult.accessToken;
  } catch (silentError) {
    // If silent requests fails with InteractionRequiredAuthError,
    // attempt to get the token interactively
    if (silentError instanceof msal.InteractionRequiredAuthError) {
      const interactiveResult = await msalClient.acquireTokenPopup(msalRequest);
      return interactiveResult.accessToken;
    } else {
      throw silentError;
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

The msalRequest variable stores the current Microsoft Authentication Library request. It initially contains an empty array of scopes. The list of permissions granted to your app is part of the access token. These are the scopes of the OAuth standard. When your app requests an access token from the Azure Active Directory, it needs to include a list of scopes. Each operation in Microsoft Graph has its own list of scopes. The list of the permissions required for each operation is available in the Microsoft Graph permissions reference.

Using Microsoft Graph to access a user's Teams shifts

Create a file called graph.js in the project’s root directory and add the following code:

const userTimeZone = Intl.DateTimeFormat().resolvedOptions().timeZone;

// Create an authentication provider
const authProvider = {
    getAccessToken: async () => {
        // Call getToken in auth.js
        return await getToken();
    }
};

// Initialize the Graph client
const graphClient = MicrosoftGraph.Client.initWithMiddleware({ authProvider });

async function getMembers() {
    ensureScope("TeamMember.Read.All");
    return await graphClient
    .api('/teams/<your-team-ID-here>/members')
    .get();
}

async function getAllShifts() {
    ensureScope("Schedule.Read.All");
    return await graphClient
    .api('/teams/<your-team-ID-here>/schedule/shifts')
    .header("Prefer", `outlook.timezone="${userTimeZone}"`)
    .get();
}
Enter fullscreen mode Exit fullscreen mode

We get the access token using the getToken method in the auth.js file. We then use the Microsoft Graph SDK (which we'll add later) to create a Microsoft Graph client that will handle Microsoft Graph API requests.

The getMembers function retrieves the team members from the team specified by a team ID. Find your team ID by navigating to your Microsoft Teams and copying the link from your team.

Teams ID

The team ID can be found in the link after groupid= and the first &.

Teams ID link

The getAllShifts function receives all the shifts within the team specified by the same ID. Make sure to replace <your-team-ID-here> in the code above with your team ID.

We use the ensureScope function to specify the permissions needed to access the team shifts data. We then call the "/teams/" endpoint using the graphClient API method to get the data from Microsoft Graph. The header method allows us to set our preferred time zone. Teams shifts dates are stored using UTC. We need to set the time zone for the returned Teams shifts start and end dates. This is done so that the correct event times are displayed in our Bryntum Scheduler. The value for the userTimeZone is defined in the first line of the code above.

Now let's add the user's Teams shifts to our Bryntum Scheduler.

Adding Microsoft Teams shifts to Bryntum Scheduler

Let's add the Microsoft 365 sign-in link and import the Microsoft Authentication Library and Microsoft Graph SDK. In the index.html file, replace the child elements of the <body> HTML element with the following elements:

  <main id="main-container" role="main" class="container">
    <div id="content" style="display: none">
      <div id="scheduler"></div>
    </div>
    <a id="signin" href="#">
      <img
        src="./images/ms-symbollockup_signin_light.png"
        alt="Sign in with Microsoft"
      />
    </a>
  </main>
  <script src="https://alcdn.msauth.net/browser/2.1.0/js/msal-browser.min.js"
    integrity="sha384-EmYPwkfj+VVmL1brMS1h6jUztl4QMS8Qq8xlZNgIT/luzg7MAzDVrRa2JxbNmk/e"
    crossorigin="anonymous"></script>
  <script src="https://cdn.jsdelivr.net/npm/@microsoft/microsoft-graph-client/lib/graph-js-sdk.js"></script>
  <script src="auth.js"></script>
  <script src="graph.js"></script>
  <script type = "module" src = "main.js"></script>
Enter fullscreen mode Exit fullscreen mode

Initially, our app will display the sign-in link only. When a user signs in, Bryntum Scheduler will be displayed.

In the main.js file, add the following line to store the "Sign in with Microsoft" link element object in a variable:

const signInButton = document.getElementById("signin");
Enter fullscreen mode Exit fullscreen mode

Now add the following function at the bottom of the file:

async function displayUI() {
    await signIn();

    // Hide login button and initial UI
    var signInButton = document.getElementById("signin");
    signInButton.style = "display: none";
    var content = document.getElementById("content");
    content.style = "display: block";

    var events = await getAllShifts();
    var members = await getMembers();
    members.value.forEach((member) => {
        var user = {id: member.userId, name: member.displayName, hasEvent : "Unassigned"};
        // append user to resources list
        scheduler.resourceStore.add(user);
    });
    events.value.forEach((event) => {
        var shift = {resourceId: event.userId, name: event.sharedShift.displayName, startDate: event.sharedShift.startDateTime, endDate: event.sharedShift.endDateTime, eventColor: event.sharedShift.theme, shiftId: event.id, iconCls: ""};

        scheduler.resourceStore.forEach((resource) => {
            if (resource.id == event.userId) {
                resource.hasEvent = "Assigned";
                resource.shiftId = event.id;
            }
        });

        // append shift to events list
        scheduler.eventStore.add(shift);
    });
  }

signInButton.addEventListener("click", displayUI);
export { displayUI };
Enter fullscreen mode Exit fullscreen mode

The displayUI function calls the signIn function in auth.js to sign the user in. Once the user is signed in, the sign-in link is hidden and Bryntum Scheduler is displayed. We use the getAllShifts function in the graph.js file to get the team shifts. We then use the retrieved Teams shifts to create events for Bryntum Scheduler and add them to the scheduler.eventStore store.

Each Teams shift has a unique id and when creating the shifts in Bryntum Scheduler we add this id in order to identify the corresponding shifts later on.

Similarly we use the getMembers function to get the team members and populate the scheduler.resourceStore with the team members.

We no longer need the inline data we created in the initial setup of our Scheduler, so remove these lines of code from the scheduler we defined in main.js.

    resources : [
        { id : 1, name : 'Dan Stevenson' },
        { id : 2, name : 'Talisha Babin' }
    ],

    events : [
        { resourceId : 1, startDate : previousSunday, endDate : nextSaturday },
        { resourceId : 2, startDate : previousSunday, endDate : nextSaturday }
    ],
Enter fullscreen mode Exit fullscreen mode

Now sign into Microsoft Teams using the admin email address from your Microsoft 365 Developer Program account and create some events for the following week, then click the "Share with team" button to share your shifts:

Microsoft Outlook events

Run your dev server using npm run dev and you'll see the sign-in link:

Sign in link

Sign in with the same admin email address that you used to log into Microsoft Teams:

Sign-in popup

You'll now see your Teams Shifts in your Bryntum Scheduler:

Bryntum Scheduler shifts

Next, we'll sync Teams with the scheduler by implementing CRUD functionality in our Bryntum Scheduler. Updates to Bryntum Scheduler will update the shifts in Microsoft Teams.

Implementing CRUD

Now that we have connected our scheduler to the Graph API, we'll implement the rest of the CRUD functionality by taking advantage of Microsoft Graph's post, patch, and delete methods, passing a query string where relevant.

Each of these functions requires your team ID so make sure to replace <your-team-ID-here> with the team ID you retrieved earlier.

Create events

In the graph.js file, add the following lines:

async function createShift(name, start, end, userId, color) {
    ensureScope("Schedule.ReadWrite.All");
    return await graphClient
    .api('/teams/<your-team-ID-here>/schedule/shifts')
    .post({
        "userId": userId,
        "sharedShift": {
            "displayName": name,
            "startDateTime": start,
            "endDateTime": end,
            "theme": color
        }
    });
}
Enter fullscreen mode Exit fullscreen mode

Here we create a function that will create a Teams shift with a user ID, name, start date, and end date collected from Bryntum Scheduler. The function is passed the appropriate scope and the new shift data is defined.

Update events

In the graph.js file, add the following function:

async function updateShift(id, userId, name, start, end, color) {
    ensureScope("Schedule.ReadWrite.All");
    return await graphClient
    .api(`/teams/<your-team-ID-here>/schedule/shifts/${id}`)
    .put({
        "userId": userId,
        "sharedShift": {
            "displayName": name,
            "startDateTime": start,
            "endDateTime": end,
            "theme": color
        }
    });
}
Enter fullscreen mode Exit fullscreen mode

The updateShift function will identify the appropriate Teams shift by id, and then it will use the new user ID, name, start date, and end date from Bryntum Scheduler to update the event. The function is passed the appropriate scope, and the new shift data is defined.

Delete events

In the graph.js file, add the following function:

async function deleteShift(id) {
    ensureScope("Schedule.ReadWrite.All");
    return await graphClient
    .api(`/teams/<your-team-ID-here>/schedule/shifts/${id}`)
    .delete();
}
Enter fullscreen mode Exit fullscreen mode

The deleteShift function will identify the appropriate Teams shift by id, and delete the event.

Listening for event data changes in Bryntum Scheduler

Next, we'll set the listeners for our Bryntum Scheduler so that it will know when the user updates the scheduler events.

Replace the definition of scheduler with the following code:

const scheduler = new Scheduler({
    appendTo : "scheduler",

    startDate : previousSunday,
    endDate   : nextSaturday,
    viewPreset : 'dayAndWeek',

    listeners : {
        dataChange: function (event) {
            updateMicrosoft(event);
          }},

    columns : [
        { text : 'Name', field : 'name', width : 160 }
    ]
});
Enter fullscreen mode Exit fullscreen mode

Here we set a listener on our Bryntum Scheduler to listen for any changes to the scheduler's data store. This will fire an event called "update" whenever a scheduler event is created or updated, and an event called "remove" whenever an event is deleted.

The event that's retrieved from the dataChange listener will also carry event data about the specific scheduler event that has been altered. We'll use the event data to identify which event is being altered and what's being changed.

Next we'll create a function called updateMicrosoft that will update Teams when the appropriate "update" or "delete" event is fired.

Add the following code below the definition of scheduler in the main.js file:

async function updateMicrosoft(event) {
    if (event.action == "update") {
        if ("name" in event.changes || "startDate" in event.changes || "endDate" in event.changes || "resourceId" in event.changes || "eventColor" in event.changes) {
            if ("resourceId" in event.changes){
                if (!("oldValue" in event.changes.resourceId)){
                    return;
                }
            } 
            if (Object.keys(event.record.data).indexOf("shiftId") == -1 && Object.keys(event.changes).indexOf("name") !== -1){
                var newShift = createShift(event.record.name, event.record.startDate, event.record.endDate, event.record.resourceId, event.record.eventColor);
                newShift.then(value => {
                    event.record.data["shiftId"] = value.id;
                  });
                scheduler.resourceStore.forEach((resource) => {
                    if (resource.id == event.record.resourceId) {
                        resource.hasEvent = "Assigned";
                    }
            });
            } else {
                if (Object.keys(event.changes).indexOf("resource") !== -1){
                    return;
                }
                updateShift(event.record.shiftId, event.record.resourceId, event.record.name, event.record.startDate, event.record.endDate, event.record.eventColor);
            }
        }
    } else if (event.action == "remove" && "name" in event.records[0].data){
        deleteShift(event.records[0].data.shiftId);
    }
}
Enter fullscreen mode Exit fullscreen mode

Here we create a function that is called on all changes to the data store of Bryntum Scheduler. The function then calls one of the Microsoft Graph CRUD functions that we defined.

On "update" we check whether the update change is valid for our changes to Teams. If the update concerns the name, startDate, endDate, resourceId, or eventColor, we exclude it when an event is generated in the scheduler, as this event will not have all the data necessary for the creation of a Teams shift.

async function updateMicrosoft(event) {
    if (event.action == "update") {
        if ("name" in event.changes || "startDate" in event.changes || "endDate" in event.changes || "resourceId" in event.changes || "eventColor" in event.changes) {
            if ("resourceId" in event.changes){
                if (!("oldValue" in event.changes.resourceId)){
                    return;
                }
Enter fullscreen mode Exit fullscreen mode

We then check if the event being updated has a shiftId; if not, it is because this is a new event and a corresponding shift needs to be created. We create the shift with createShift and assign the shifts id to the corresponding Bryntum event.

            if (Object.keys(event.record.data).indexOf("shiftId") == -1 && Object.keys(event.changes).indexOf("name") !== -1){
                var newShift = createShift(event.record.name, event.record.startDate, event.record.endDate, event.record.resourceId, event.record.eventColor);
                newShift.then(value => {
                    event.record.data["shiftId"] = value.id;
                  });
                scheduler.resourceStore.forEach((resource) => {
                    if (resource.id == event.record.resourceId) {
                        resource.hasEvent = "Assigned";
                    }
            });
            }
Enter fullscreen mode Exit fullscreen mode

If the event has a shiftId already, this means there is already a corresponding shift in Teams and this shift needs to be updated.

            else {
                if (Object.keys(event.changes).indexOf("resource") !== -1){
                    return;
                }
                updateShift(event.record.shiftId, event.record.resourceId, event.record.name, event.record.startDate, event.record.endDate, event.record.eventColor);
            }
Enter fullscreen mode Exit fullscreen mode

Finally, if the dataChange event is a "remove" event, then we delete the matching Teams event using the deleteShift function.

    else if (event.action == "remove" && "name" in event.records[0].data){
        deleteShift(event.records[0].data.shiftId);
    }
Enter fullscreen mode Exit fullscreen mode

Now try to create, update, delete, and edit an event in Bryntum Scheduler. You'll see the changes reflected in Teams.

Updating Outlook scheduler using CRUD

Add styling

If you would like your Bryntum Scheduler UI to look a lot more like the Teams Shifts UI, then replace the scheduler with the following code:

const scheduler = new Scheduler({
    appendTo : "scheduler",

    resourceImagePath : 'images/users/',
    eventStyle: 'colored',
    showEventCount : true,
    resourceMargin: 0,

    startDate : previousSunday,
    endDate   : nextSaturday,
    viewPreset : 'dayAndWeek',

    listeners : {
        dataChange: function (event) {
            updateMicrosoft(event);
          }},

    columns : [
        { type : 'resourceInfo', text : 'Name', field : 'name', width : 160 }
    ],

    features : {
        group : 'hasEvent',
        eventEdit : {
            items : {
                // Key to use as fields ref (for easier retrieval later)
                color : {
                    type  : 'combo',
                    label : 'Color',
                    items : ['gray', 'blue', 'purple', 'green', 'pink', 'yellow'],
                    // name will be used to link to a field in the event record when loading and saving in the editor
                    name  : 'eventColor'
                },
                icon : {
                    type  : 'combo',
                    label : 'Icon',

                    items: [
                        { text: 'None', value: '' },
                        { text: 'Door', value: 'b-fa b-fa-door-open' },
                        { text: 'Car', value: 'b-fa b-fa-car' },
                        { text: 'Coffee', value: 'b-fa b-fa-coffee' },
                        { text: 'Envelope', value: 'b-fa b-fa-envelope' },
                    ],

                    name  : 'iconCls' 
                }
            }
        },
    },

    // Custom event renderer, simple version
    eventRenderer({
            eventRecord
        }) {
            if (eventRecord.name == "Open") {
                eventRecord.iconCls = "b-fa b-fa-door-open";
                return `${eventRecord.name}`;
            } else if (eventRecord.name == "Vacation"){
                eventRecord.iconCls = "b-fa b-fa-sun";
                return `${eventRecord.name}`;
            } else if (eventRecord.name == "Second shift"){
                eventRecord.iconCls = "b-fa b-fa-moon";
                return `${eventRecord.name}`;
            } else {
                return `${eventRecord.name}`;
            }
        }
});
Enter fullscreen mode Exit fullscreen mode

Here we do a few things to the styling of our scheduler.

    resourceImagePath : 'images/users/',
    eventStyle: 'colored',
    showEventCount : true,
    resourceMargin: 0,
Enter fullscreen mode Exit fullscreen mode

These four lines add user profile pictures, which you can add to a folder called users in the images folder. These profile pictures should have the following file name structure to relate to the members within the team: first-name last-name.jpg. If a profile picture cannot be found for a user, their initial will be used instead.

We also color and size the shifts similarly to Teams with eventStyle and resourceMargin.

The showEventCount will show how many events each member has alongside their name and profile picture.

The following code lets the user pick a color and icon for their shifts in the event editor:

features : {
        group : 'hasEvent',
        eventEdit : {
            items : {
                // Key to use as fields ref (for easier retrieval later)
                color : {
                    type  : 'combo',
                    label : 'Color',
                    items : ['gray', 'blue', 'purple', 'green', 'pink', 'yellow'],
                    // name will be used to link to a field in the event record when loading and saving in the editor
                    name  : 'eventColor'
                },
                icon : {
                    type  : 'combo',
                    label : 'Icon',

                    items: [
                        { text: 'None', value: '' },
                        { text: 'Door', value: 'b-fa b-fa-door-open' },
                        { text: 'Car', value: 'b-fa b-fa-car' },
                        { text: 'Coffee', value: 'b-fa b-fa-coffee' },
                        { text: 'Envelope', value: 'b-fa b-fa-envelope' },
                    ],

                    name  : 'iconCls' 
                }
            }
        },
    },
Enter fullscreen mode Exit fullscreen mode

The group feature also lets us organize our team members into those who have and have not been assigned shifts.

Finally, the eventRenderer will assign a common icon to shifts that share any of the names listed, allowing similar events to be styled in the same way.

    // Custom event renderer, simple version
    eventRenderer({
            eventRecord
        }) {
            if (eventRecord.name == "Open") {
                eventRecord.iconCls = "b-fa b-fa-door-open";
                return `${eventRecord.name}`;
            } else if (eventRecord.name == "Vacation"){
                eventRecord.iconCls = "b-fa b-fa-sun";
                return `${eventRecord.name}`;
            } else if (eventRecord.name == "Second shift"){
                eventRecord.iconCls = "b-fa b-fa-moon";
                return `${eventRecord.name}`;
            } else {
                return `${eventRecord.name}`;
            }
        }
Enter fullscreen mode Exit fullscreen mode

The result is an eye-catching and intuitive UI that follows the user experience of Teams.

Styled Outlook scheduler

Next steps

This tutorial gives you a starting point for creating Bryntum Scheduler using vanilla JavaScript and syncing it with Microsoft Teams. There are many ways that you can improve Bryntum Scheduler. For example, you can add features such as resource grouping. Take a look at our demos page to see demos of the available features.

Top comments (0)