Skip to content

Commit a52538d

Browse files
authored
Add presence badge to person avatar (#399)
* Update logic to support attendee queries in mgt-agenda * Update storybook for mgt-people * Add graph call to get user presence * Add presence badge to avatar. * Add license language to types * Update based on PR comments. * Add oof dnd combination. * Update css * Address pr comments. * Address PR change * Add presence to person card. * Add avatar size as attribute * Update logic
1 parent 0ffdcee commit a52538d

File tree

11 files changed

+728
-31
lines changed

11 files changed

+728
-31
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@
7979
"@storybook/addon-knobs": "^5.3.17",
8080
"@storybook/addon-links": "^5.3.17",
8181
"@storybook/addon-storysource": "^5.3.17",
82-
"@storybook/storybook-deployer": "^2.8.1",
82+
"@storybook/storybook-deployer": "^2.8.5",
8383
"@storybook/web-components": "^5.3.17",
8484
"@types/jest": "^24.9.1",
8585
"@types/node": "12.12.22",

src/components/mgt-people/mgt-people.ts

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,11 @@
66
*/
77

88
import * as MicrosoftGraph from '@microsoft/microsoft-graph-types';
9+
import { Presence } from '@microsoft/microsoft-graph-types-beta';
910
import { customElement, html, property, TemplateResult } from 'lit-element';
1011
import { repeat } from 'lit-html/directives/repeat';
1112
import { getPeople, getPeopleFromGroup } from '../../graph/graph.people';
13+
import { getUsersPresenceByPeople } from '../../graph/graph.presence';
1214
import { getUsersForPeopleQueries, getUsersForUserIds } from '../../graph/graph.user';
1315
import { IDynamicPerson } from '../../graph/types';
1416
import { Providers } from '../../Providers';
@@ -122,6 +124,16 @@ export class MgtPeople extends MgtTemplatedComponent {
122124
})
123125
public showMax: number;
124126

127+
/**
128+
* determines if person component renders presence
129+
* @type {boolean}
130+
*/
131+
@property({
132+
attribute: 'show-presence',
133+
type: Boolean
134+
})
135+
public showPresence: boolean;
136+
125137
/**
126138
* Sets how the person-card is invoked
127139
* Set to PersonCardInteraction.none to not show the card
@@ -145,6 +157,7 @@ export class MgtPeople extends MgtTemplatedComponent {
145157
private _groupId: string;
146158
private _userIds: string[];
147159
private _peopleQueries: string[];
160+
private _peoplePresence: {};
148161

149162
constructor() {
150163
super();
@@ -250,6 +263,16 @@ export class MgtPeople extends MgtTemplatedComponent {
250263
* @memberof MgtPeople
251264
*/
252265
protected renderPerson(person: MicrosoftGraph.User | MicrosoftGraph.Person | MicrosoftGraph.Contact): TemplateResult {
266+
let personPresence = {
267+
// set up default presence
268+
activity: 'Offline',
269+
availability: 'Offline',
270+
id: null
271+
};
272+
if (this.showPresence && this._peoplePresence) {
273+
personPresence = this._peoplePresence[person.id];
274+
}
275+
const avatarSize = 'small';
253276
return (
254277
this.renderTemplate('person', { person }, person.id) ||
255278
// set image to @ to flag the mgt-person component to
@@ -258,7 +281,10 @@ export class MgtPeople extends MgtTemplatedComponent {
258281
<mgt-person
259282
.personDetails=${person}
260283
.personImage=${'@'}
284+
.avatarSize=${avatarSize}
261285
.personCardInteraction=${this.personCardInteraction}
286+
.showPresence=${this.showPresence}
287+
.personPresence=${personPresence}
262288
></mgt-person>
263289
`
264290
);
@@ -289,6 +315,7 @@ export class MgtPeople extends MgtTemplatedComponent {
289315
if (provider && provider.state === ProviderState.SignedIn) {
290316
const graph = provider.graph.forComponent(this);
291317

318+
// populate people
292319
if (this.groupId) {
293320
this.people = await getPeopleFromGroup(graph, this.groupId);
294321
} else if (this.userIds) {
@@ -298,6 +325,13 @@ export class MgtPeople extends MgtTemplatedComponent {
298325
} else {
299326
this.people = await getPeople(graph);
300327
}
328+
329+
// populate presence for people
330+
if (this.showPresence) {
331+
this._peoplePresence = await getUsersPresenceByPeople(graph, this.people);
332+
} else {
333+
this._peoplePresence = null;
334+
}
301335
}
302336
}
303337
}

src/components/mgt-person-card/mgt-person-card.scss

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ $person-card-background-color: var(--person-card-background-color, #ffffff);
3131
padding: 18px 14px;
3232

3333
mgt-person.person-image {
34-
--avatar-size-s: 75px;
34+
--avatar-size: 75px;
3535
}
3636

3737
.details {

src/components/mgt-person-card/mgt-person-card.ts

Lines changed: 60 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,11 @@
66
*/
77

88
import * as MicrosoftGraph from '@microsoft/microsoft-graph-types';
9+
import { Presence } from '@microsoft/microsoft-graph-types-beta';
910
import { customElement, html, property, TemplateResult } from 'lit-element';
1011
import { findPerson, getEmailFromGraphEntity } from '../../graph/graph.people';
1112
import { getPersonImage } from '../../graph/graph.photos';
13+
import { getUserPresence } from '../../graph/graph.presence';
1214
import { getUserWithPhoto } from '../../graph/graph.user';
1315
import { IDynamicPerson } from '../../graph/types';
1416
import { Providers } from '../../Providers';
@@ -116,6 +118,28 @@ export class MgtPersonCard extends MgtTemplatedComponent {
116118
})
117119
public inheritDetails: boolean;
118120

121+
/**
122+
* determines if person card component renders presence
123+
* @type {boolean}
124+
*/
125+
@property({
126+
attribute: 'show-presence',
127+
type: Boolean
128+
})
129+
public showPresence: boolean;
130+
131+
/**
132+
* Gets or sets presence of person
133+
*
134+
* @type {Presence}
135+
* @memberof MgtPerson
136+
*/
137+
@property({
138+
attribute: 'person-presence',
139+
type: Object
140+
})
141+
public personPresence: Presence;
142+
119143
/**
120144
* Invoked each time the custom element is appended into a document-connected element
121145
*
@@ -167,6 +191,8 @@ export class MgtPersonCard extends MgtTemplatedComponent {
167191

168192
const person = this.personDetails;
169193
const image = this.getImage();
194+
const presence = this.personPresence;
195+
const showPresence = this.showPresence;
170196

171197
// Check for a default template.
172198
// tslint:disable-next-line: no-string-literal
@@ -183,7 +209,7 @@ export class MgtPersonCard extends MgtTemplatedComponent {
183209
personImage: image
184210
});
185211
if (!personDetailsTemplate) {
186-
const personImageTemplate = this.renderPersonImage(image);
212+
const personImageTemplate = this.renderPersonImage(image, presence, showPresence);
187213
const personNameTemplate = this.renderPersonName(person);
188214
const personTitleTemplate = this.renderPersonTitle(person);
189215
const personSubtitleTemplate = this.renderPersonSubtitle(person);
@@ -234,10 +260,20 @@ export class MgtPersonCard extends MgtTemplatedComponent {
234260
* @param {*} image
235261
* @memberof MgtPersonCard
236262
*/
237-
protected renderPersonImage(imageSrc?: string): TemplateResult {
263+
protected renderPersonImage(imageSrc?: string, presence?: Presence, showPresence?: boolean): TemplateResult {
238264
imageSrc = imageSrc || this.getImage();
265+
presence = presence || this.personPresence;
266+
showPresence = showPresence || this.showPresence;
267+
const avatarSize = 'large';
239268
return html`
240-
<mgt-person class="person-image" .personDetails=${this.personDetails} .personImage=${imageSrc}></mgt-person>
269+
<mgt-person
270+
class="person-image"
271+
.personDetails=${this.personDetails}
272+
.personImage=${imageSrc}
273+
.personPresence=${presence}
274+
.showPresence=${showPresence}
275+
.avatarSize=${avatarSize}
276+
></mgt-person>
241277
`;
242278
}
243279

@@ -512,6 +548,8 @@ export class MgtPersonCard extends MgtTemplatedComponent {
512548
if (parent && (parent as MgtPerson).personDetails) {
513549
this.personDetails = (parent as MgtPerson).personDetails;
514550
this.personImage = (parent as MgtPerson).personImage;
551+
this.personPresence = (parent as MgtPerson).personPresence;
552+
this.showPresence = (parent as MgtPerson).showPresence;
515553
}
516554
}
517555

@@ -561,6 +599,25 @@ export class MgtPersonCard extends MgtTemplatedComponent {
561599
}
562600
}
563601
}
602+
603+
// populate presence
604+
const defaultPresence = {
605+
activity: 'Offline',
606+
availability: 'Offline',
607+
id: null
608+
};
609+
if (!this.personPresence && this.showPresence) {
610+
try {
611+
if (this.personDetails && this.personDetails.id) {
612+
this.personPresence = await getUserPresence(graph, this.personDetails.id);
613+
} else {
614+
this.personPresence = defaultPresence;
615+
}
616+
} catch (_) {
617+
// set up a default Presence in case beta api changes or getting error code
618+
this.personPresence = defaultPresence;
619+
}
620+
}
564621
}
565622

566623
/**

0 commit comments

Comments
 (0)