Office UI Fabric Persona with Skype for Business Status Integration

Today I want to show you a simple SPFx Web Part solution to connect the new Office UI Fabric React component named Persona with the status from Skype for Business (Lync).

Persona is used for rendering an individual’s avatar, user information and presence. We will use the Name.NameCtrl ActiveX component toe retreive the status of each person from Skype for Business. This ActiveX component was written by Microsoft and works only in IE because it uses the NPAPI plugins which are disabled in Chrome since 1 Sep 2015.

So, lets start.

Because the Skype for Business status is dynamic data, you have to put it into the State of your React Component.

export interface IAddressBookState {
    userPresences: {};
}

In the constructor of your React Component class you have to initialize the NameCtrl ActiveX component and append the OnStatusChange event listener method.

export default class AddressBook extends React.Component<IAddressBookProps, IAddressBookState> {
    private nameCtrl: AXO;

    constructor(props: IAddressBookProps) {
        super(props);

        this.state = {
          userPresences: {}
        };

        try {
            if ((window as any).ActiveXObject) {
                this.nameCtrl = new AXO("Name.NameCtrl");
            } else {
                this.nameCtrl = this.CreateNPApiOnWindowsPlugin("application/x-sharepoint-uc");
            }

            if (!this.nameCtrl) {
              return;
            }

            this.nameCtrl.OnStatusChange = this.OnLyncPresenceStatusChange.bind(this);
        }
        catch (ex) {
            console.log(ex);
        }
    }

    private CreateNPApiOnWindowsPlugin(b) {
        var c = null;
        try {
            c = document.getElementById(b);
            if (!Boolean(c) && this.IsNPAPIOnWinPluginInstalled(b)) {
                var a = document.createElement("object");
                a.id = b;
                a.type = b;
                a.width = "0";
                a.height = "0";
                a.style.setProperty("visibility", "hidden", "");
                document.body.appendChild(a);
                c = document.getElementById(b);
            }
        } catch (d) {
            c = null;
        }
        return c;
    }

    private IsNPAPIOnWinPluginInstalled(a) {
        return Boolean(navigator.mimeTypes) && navigator.mimeTypes[a];
    }
}

I used AXO as the ActiveX component loader. You have to install this NPM package:

npm install --save axo

In the render method for each user item you have to call the GetStatus method from the ActiveX component with user email and then you can render each person with the Persona Fabric UI Component.

private onRenderItem(props: IPickerItemProps<IPersonaProps>):JSX.Element {
    if (!this.state.userPresences[props.item.tertiaryText]) {
        if (this.nameCtrl) {
            this.nameCtrl.GetStatus(props.item.tertiaryText, "user");
        }
    }

    return (
        <div className={ "ms-FocusZone ms-PickerPersona-container personaContainer_894c3072" }>
          <div className={ "ms-PickerItem-content itemContent_894c3072" }>
            <Persona
                { ...props.item }
                size={ PersonaSize.regular }
                presence={ this.state.userPresences[props.item.tertiaryText] }
                hidePersonaDetails={ false }
                onMouseOver={ (event) => { this.showLyncPresencePopup(props.item.tertiaryText, event.currentTarget); } }
                onMouseOut={ this.hideLyncPresencePopup.bind(this) }
            />
          </div>
        </div>);
}

Next is the Presence Status Change Event Handler method for the NameCtrl ActiveX Component. This method converts status Id from ActiveX Component to PersonaPresence status for our Persona Office UI Fabric React Component and saves it into State for our React Component.

private OnLyncPresenceStatusChange(userName, status, id) {
    var tempUserPresences = this.state.userPresences;

    switch (status) {
      case 0:
          tempUserPresences[userName] = PersonaPresence.online;
          break;
      case 1:
          tempUserPresences[userName] = PersonaPresence.offline;
          break;
      case 2:
      case 4:
      case 16:
          tempUserPresences[userName] = PersonaPresence.away;
          break;
      case 3:
      case 5:
      case 6:
      case 7:
      case 8:
      case 10:
          tempUserPresences[userName] = PersonaPresence.busy;
          break;
      case 9:
      case 15:
          tempUserPresences[userName] = PersonaPresence.dnd;
          break;
      default:
          tempUserPresences[userName] = PersonaPresence.none;
    }

    this.setState({
      userPresences: tempUserPresences
    });
}

The last two methods are for showing and hiding the Lync Presence popup.

private showLyncPresencePopup(userName, target) {
    if (!this.nameCtrl) {
        return;
    }

    var eLeft = $(target).offset().left;
    var x = eLeft - $(window).scrollLeft();

    var eTop = $(target).offset().top;
    var y = eTop - $(window).scrollTop();

    this.nameCtrl.ShowOOUI(userName, 0, x, y);
}

private hideLyncPresencePopup() {
    if (!this.nameCtrl) {
        return;
    }
    this.nameCtrl.HideOOUI();
}

That’s all folks. Happy coding!

Gašper Rupnik

Author: Gašper Rupnik

Software Developer and Technology Enthusiast MS, MCPS, MCSD, MCT

Leave a Reply

Your email address will not be published. Required fields are marked *