Skip to content

Commit b3ec31f

Browse files
Get data for standalone mgt-person-card (#359)
* Get data for standalone mgt-person-card * Address pr feedback * minor tweak * Adding logic to handle get email and user principal name when not present * Add logic to handle get image * Address pr comments. Update logic to show contact details. * Fix load image bug Co-authored-by: Shane Weaver <[email protected]>
1 parent 485f773 commit b3ec31f

File tree

7 files changed

+240
-86
lines changed

7 files changed

+240
-86
lines changed

.storybook/theme.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,6 @@ export default create({
3131
// inputTextColor: 'black',
3232
// inputBorderRadius: 4,
3333

34-
brandTitle: 'Microsoft Graph Toolkit',
34+
brandTitle: 'Microsoft Graph Toolkit Playground',
3535
brandUrl: 'https://aka.ms/mgt'
3636
});

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

Lines changed: 147 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,9 @@
77

88
import * as MicrosoftGraph from '@microsoft/microsoft-graph-types';
99
import { customElement, html, property, TemplateResult } from 'lit-element';
10-
import { getEmailFromGraphEntity } from '../../graph/graph.people';
10+
import { findPerson, findUserByEmail, getEmailFromGraphEntity } from '../../graph/graph.people';
11+
import { getContactPhoto, getUserPhoto, myPhoto } from '../../graph/graph.photos';
12+
import { getUser, getUserWithPhoto } from '../../graph/graph.user';
1113
import { Providers } from '../../Providers';
1214
import { ProviderState } from '../../providers/IProvider';
1315
import { getSvg, SvgIcon } from '../../utils/SvgHelper';
@@ -38,6 +40,23 @@ export class MgtPersonCard extends MgtTemplatedComponent {
3840
static get styles() {
3941
return styles;
4042
}
43+
/**
44+
* allows developer to define name of person for component
45+
* @type {string}
46+
*/
47+
@property({
48+
attribute: 'person-query'
49+
})
50+
public personQuery: string;
51+
52+
/**
53+
* user-id property allows developer to use id value for component
54+
* @type {string}
55+
*/
56+
@property({
57+
attribute: 'user-id'
58+
})
59+
public userId: string;
4160

4261
/**
4362
* Set the person details to render
@@ -110,9 +129,21 @@ export class MgtPersonCard extends MgtTemplatedComponent {
110129
public attributeChangedCallback(name: string, oldValue: string, newValue: string) {
111130
super.attributeChangedCallback(name, oldValue, newValue);
112131

113-
if (name === 'is-expanded' && oldValue !== newValue) {
132+
if (oldValue === newValue) {
133+
return;
134+
}
135+
136+
if (name === 'is-expanded') {
114137
this.isExpanded = false;
115138
}
139+
140+
switch (name) {
141+
case 'person-query':
142+
case 'user-id':
143+
this.personDetails = null;
144+
this.requestStateUpdate();
145+
break;
146+
}
116147
}
117148

118149
/**
@@ -218,7 +249,7 @@ export class MgtPersonCard extends MgtTemplatedComponent {
218249
}
219250

220251
/**
221-
* foo
252+
* Render person title.
222253
*
223254
* @protected
224255
* @param {IDynamicPerson} person
@@ -236,7 +267,7 @@ export class MgtPersonCard extends MgtTemplatedComponent {
236267
}
237268

238269
/**
239-
* foo
270+
* Render person subtitle.
240271
*
241272
* @protected
242273
* @param {IDynamicPerson} person
@@ -267,6 +298,7 @@ export class MgtPersonCard extends MgtTemplatedComponent {
267298

268299
person = person || this.personDetails;
269300
const userPerson = person as MicrosoftGraph.User;
301+
const personPerson = person as MicrosoftGraph.Person;
270302

271303
// Chat
272304
let chat: TemplateResult;
@@ -290,7 +322,10 @@ export class MgtPersonCard extends MgtTemplatedComponent {
290322

291323
// Phone
292324
let phone: TemplateResult;
293-
if (userPerson.businessPhones && userPerson.businessPhones.length > 0) {
325+
if (
326+
(userPerson.businessPhones && userPerson.businessPhones.length > 0) ||
327+
(personPerson.phones && personPerson.phones.length > 0)
328+
) {
294329
phone = html`
295330
<div class="icon" @click=${() => this.callUser()}>
296331
${getSvg(SvgIcon.Phone, '#666666')}
@@ -328,7 +363,7 @@ export class MgtPersonCard extends MgtTemplatedComponent {
328363
}
329364

330365
/**
331-
* foo
366+
* Render expanded details.
332367
*
333368
* @protected
334369
* @param {IDynamicPerson} [person]
@@ -384,6 +419,7 @@ export class MgtPersonCard extends MgtTemplatedComponent {
384419
protected renderContactDetails(person?: IDynamicPerson): TemplateResult {
385420
person = person || this.personDetails;
386421
const userPerson = person as MicrosoftGraph.User;
422+
const personPerson = person as MicrosoftGraph.Person;
387423

388424
if (this.hasTemplate('contact-details')) {
389425
return this.renderTemplate('contact-details', { userPerson });
@@ -420,6 +456,14 @@ export class MgtPersonCard extends MgtTemplatedComponent {
420456
<span class="link-subtitle data">${userPerson.businessPhones[0]}</span>
421457
</div>
422458
`;
459+
} else if (personPerson.phones && personPerson.phones.length > 0) {
460+
const businessPhones = this.getPersonBusinessPhones(personPerson);
461+
phone = html`
462+
<div class="details-icon" @click=${() => this.callUser()}>
463+
${getSvg(SvgIcon.SmallPhone, '#666666')}
464+
<span class="link-subtitle data">${businessPhones[0]}</span>
465+
</div>
466+
`;
423467
}
424468

425469
// Location
@@ -450,7 +494,31 @@ export class MgtPersonCard extends MgtTemplatedComponent {
450494
* @memberof MgtPersonCard
451495
*/
452496
protected async loadState() {
453-
if (this.inheritDetails) {
497+
const provider = Providers.globalProvider;
498+
499+
// check if user is signed in
500+
if (!provider || provider.state !== ProviderState.SignedIn) {
501+
return;
502+
}
503+
504+
const graph = provider.graph.forComponent(this);
505+
506+
// check if personDetail already populated
507+
if (this.personDetails) {
508+
const user = this.personDetails as MicrosoftGraph.User;
509+
const id = user.userPrincipalName || user.id;
510+
// if we have an id but no email, we should get data from the graph
511+
if (id && !getEmailFromGraphEntity(user)) {
512+
const person = await getUserWithPhoto(graph, id);
513+
this.personDetails = person;
514+
this.personImage = this.getImage();
515+
} else if (this.personImage === '@' && !this.personDetails.personImage) {
516+
// in some cases we might only have name or email, but need to find the image
517+
// use @ for the image value to search for an image
518+
this.loadImage();
519+
}
520+
} else if (this.inheritDetails) {
521+
// User person details inherited from parent tree
454522
let parent = this.parentElement;
455523
while (parent && parent.tagName !== 'MGT-PERSON') {
456524
parent = parent.parentElement;
@@ -460,15 +528,20 @@ export class MgtPersonCard extends MgtTemplatedComponent {
460528
this.personDetails = (parent as MgtPerson).personDetails;
461529
this.personImage = (parent as MgtPerson).personImage;
462530
}
463-
}
464-
465-
if (this.personDetails) {
466-
return;
467-
}
468-
469-
const provider = Providers.globalProvider;
470-
if (!provider || provider.state !== ProviderState.SignedIn) {
471-
return;
531+
} else if (this.userId || this.personQuery === 'me') {
532+
// Use userId or 'me' query to get the person and image
533+
const person = await getUserWithPhoto(graph, this.userId);
534+
535+
this.personDetails = person;
536+
this.personImage = this.getImage();
537+
} else if (this.personQuery) {
538+
// Use the personQuery to find our person.
539+
const people = await findPerson(graph, this.personQuery);
540+
541+
if (people && people.length) {
542+
this.personDetails = people[0];
543+
this.loadImage();
544+
}
472545
}
473546
}
474547

@@ -496,11 +569,19 @@ export class MgtPersonCard extends MgtTemplatedComponent {
496569
*/
497570
protected callUser() {
498571
const user = this.personDetails as MicrosoftGraph.User;
572+
const person = this.personDetails as microsoftgraph.Person;
573+
499574
if (user && user.businessPhones && user.businessPhones.length) {
500575
const phone = user.businessPhones[0];
501576
if (phone) {
502577
window.open('tel:' + phone, '_blank');
503578
}
579+
} else if (person && person.phones && person.phones.length) {
580+
const businessPhones = this.getPersonBusinessPhones(person);
581+
const phone = businessPhones[0];
582+
if (phone) {
583+
window.open('tel:' + phone, '_blank');
584+
}
504585
}
505586
}
506587

@@ -560,6 +641,45 @@ export class MgtPersonCard extends MgtTemplatedComponent {
560641
this.isExpanded = true;
561642
}
562643

644+
private async loadImage() {
645+
const provider = Providers.globalProvider;
646+
const graph = provider.graph.forComponent(this);
647+
const person = this.personDetails;
648+
let image: string;
649+
650+
if ((person as MicrosoftGraph.Person).userPrincipalName) {
651+
// try to find a user by userPrincipalName
652+
const userPrincipalName = (person as MicrosoftGraph.Person).userPrincipalName;
653+
image = await getUserPhoto(graph, userPrincipalName);
654+
} else {
655+
// try to find a user by e-mail
656+
const email = getEmailFromGraphEntity(person);
657+
if (email) {
658+
const users = await findUserByEmail(graph, email);
659+
if (users && users.length) {
660+
// Check for an OrganizationUser
661+
const orgUser = users.find(p => {
662+
return (p as any).personType && (p as any).personType.subclass === 'OrganizationUser';
663+
});
664+
if (orgUser) {
665+
// Lookup by userId
666+
const userId = (users[0] as MicrosoftGraph.Person).scoredEmailAddresses[0].address;
667+
image = await getUserPhoto(graph, userId);
668+
} else {
669+
// Lookup by contactId
670+
const contactId = users[0].id;
671+
image = await getContactPhoto(graph, contactId);
672+
}
673+
}
674+
}
675+
}
676+
677+
if (image) {
678+
this.personDetails.personImage = image;
679+
this.personImage = image;
680+
}
681+
}
682+
563683
private getImage(): string {
564684
if (this.personImage && this.personImage !== '@') {
565685
return this.personImage;
@@ -568,4 +688,15 @@ export class MgtPersonCard extends MgtTemplatedComponent {
568688
const person = this.personDetails;
569689
return person && person.personImage ? person.personImage : null;
570690
}
691+
692+
private getPersonBusinessPhones(person: MicrosoftGraph.Person): string[] {
693+
const phones = person.phones;
694+
const businessPhones: string[] = [];
695+
for (const p of phones) {
696+
if (p.type === 'business') {
697+
businessPhones.push(p.number);
698+
}
699+
}
700+
return businessPhones;
701+
}
571702
}

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

Lines changed: 0 additions & 42 deletions
This file was deleted.

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

Lines changed: 7 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,9 @@
88
import * as MicrosoftGraph from '@microsoft/microsoft-graph-types';
99
import { customElement, html, property, query, TemplateResult } from 'lit-element';
1010
import { classMap } from 'lit-html/directives/class-map';
11-
import { findPerson, getEmailFromGraphEntity } from '../../graph/graph.people';
12-
import { getContactPhoto, getUserPhoto } from '../../graph/graph.photos';
11+
import { findPerson, findUserByEmail, getEmailFromGraphEntity } from '../../graph/graph.people';
12+
import { getContactPhoto, getUserPhoto, myPhoto } from '../../graph/graph.photos';
13+
import { getUserWithPhoto } from '../../graph/graph.user';
1314
import { Providers } from '../../Providers';
1415
import { ProviderState } from '../../providers/IProvider';
1516
import '../../styles/fabric-icon-font';
@@ -19,7 +20,6 @@ import { MgtFlyout } from '../sub-components/mgt-flyout/mgt-flyout';
1920
import { MgtTemplatedComponent } from '../templatedComponent';
2021
import { PersonCardInteraction } from './../PersonCardInteraction';
2122
import { styles } from './mgt-person-css';
22-
import { findUserByEmail } from './mgt-person.graph';
2323

2424
/**
2525
* IDynamicPerson describes the person object we use throughout mgt-person,
@@ -480,23 +480,12 @@ export class MgtPerson extends MgtTemplatedComponent {
480480
return;
481481
}
482482

483-
// User userId or 'me' query to get the person and image
483+
// Use userId or 'me' query to get the person and image
484484
if (this.userId || this.personQuery === 'me') {
485485
const graph = provider.graph.forComponent(this);
486-
const batch = graph.createBatch();
487-
488-
if (this.userId) {
489-
batch.get('user', `/users/${this.userId}`, ['user.readbasic.all']);
490-
batch.get('photo', `users/${this.userId}/photo/$value`, ['user.readbasic.all']);
491-
} else {
492-
batch.get('user', 'me', ['user.read']);
493-
batch.get('photo', 'me/photo/$value', ['user.read']);
494-
}
495-
496-
const response = await batch.execute();
497-
this.personDetails = response.user;
498-
this.personDetails.personImage = response.photo;
486+
const person = await getUserWithPhoto(graph, this.userId);
499487

488+
this.personDetails = person;
500489
this.personImage = this.getImage();
501490
return;
502491
}
@@ -508,10 +497,7 @@ export class MgtPerson extends MgtTemplatedComponent {
508497

509498
if (people && people.length) {
510499
this.personDetails = people[0];
511-
512-
if (this.personImage === '@') {
513-
this.loadImage();
514-
}
500+
this.loadImage();
515501
}
516502
}
517503
}

0 commit comments

Comments
 (0)