Added "About me" and "Skills" to the webpart.
* add Interface for the /me/ endpoint for aboutMe and skills * add webpart properties so the "About Me" and "Skills" can be selected * enabled the display of "About Me", "Skills" with appropriate icons * enabled Name and Job Title to open a users delve page in a new browser window
This commit is contained in:
parent
19b2dece0d
commit
7ae0ee59c5
|
@ -19,7 +19,6 @@ import { IUserExtended } from "../../entites/IUserExtended";
|
|||
import { IAppContext } from "../../common/IAppContext";
|
||||
import { IUserCardProps } from "./IUserCardProps";
|
||||
|
||||
|
||||
const teamsDefaultTheme = require("../../common/TeamsDefaultTheme.json");
|
||||
const teamsDarkTheme = require("../../common/TeamsDarkTheme.json");
|
||||
const teamsContrastTheme = require("../../common/TeamsContrastTheme.json");
|
||||
|
@ -97,6 +96,7 @@ export const UserCard = (props: IUserCardProps) => {
|
|||
}
|
||||
};
|
||||
|
||||
//tris added onclick event
|
||||
const _onRenderPrimaryText = (persona: IPersonaProps) => {
|
||||
return (
|
||||
<>
|
||||
|
@ -108,7 +108,12 @@ export const UserCard = (props: IUserCardProps) => {
|
|||
root: { justifyContent: "flex-start", width: "100%" },
|
||||
}}
|
||||
>
|
||||
<Text
|
||||
<Text onClick={
|
||||
(event) => {
|
||||
event.preventDefault();
|
||||
window.open("https://gbr.delve.office.com/?u=" + userData.id + "&v=work", "_blank");
|
||||
}
|
||||
}
|
||||
variant="medium"
|
||||
block
|
||||
nowrap
|
||||
|
@ -116,8 +121,9 @@ export const UserCard = (props: IUserCardProps) => {
|
|||
width: "100%",
|
||||
fontWeight: 600,
|
||||
padding: 0,
|
||||
marginBottom: 3,
|
||||
marginBottom: 3
|
||||
}}
|
||||
title={persona.text}
|
||||
>
|
||||
{persona.text}
|
||||
</Text>
|
||||
|
@ -130,6 +136,7 @@ export const UserCard = (props: IUserCardProps) => {
|
|||
>
|
||||
<div style={{ fontSize: 12 }}>
|
||||
<ActionButton
|
||||
|
||||
styles={{
|
||||
root: {
|
||||
height: 21,
|
||||
|
@ -184,11 +191,19 @@ export const UserCard = (props: IUserCardProps) => {
|
|||
);
|
||||
};
|
||||
|
||||
|
||||
//tris added onclick event
|
||||
const _onRenderSecondaryText = (persona: IPersonaProps) => {
|
||||
return (
|
||||
<>
|
||||
<Stack verticalAlign="start" tokens={{ childrenGap: 0 }}>
|
||||
<Text title={persona.secondaryText} variant="medium" block nowrap>
|
||||
<Text onClick={
|
||||
(event) => {
|
||||
event.preventDefault();
|
||||
window.open("https://gbr.delve.office.com/?u=" + userData.id + "&v=work", "_blank");
|
||||
}
|
||||
}
|
||||
title={persona.secondaryText} variant="medium" block nowrap>
|
||||
{" "}
|
||||
{persona.secondaryText}
|
||||
</Text>
|
||||
|
@ -221,11 +236,11 @@ export const UserCard = (props: IUserCardProps) => {
|
|||
}
|
||||
text={userData.displayName}
|
||||
title={userData.displayName}
|
||||
tertiaryText={userData.mail}
|
||||
tertiaryText={userData.mail}
|
||||
secondaryText={userData.jobTitle}
|
||||
onRenderPrimaryText={_onRenderPrimaryText}
|
||||
onRenderSecondaryText={_onRenderSecondaryText}
|
||||
></Persona>
|
||||
></Persona>
|
||||
</Stack>
|
||||
{isDetailsOpen && (
|
||||
<>
|
||||
|
@ -707,8 +722,82 @@ export const UserCard = (props: IUserCardProps) => {
|
|||
<div className={styleClasses.separator}></div>
|
||||
</div>
|
||||
);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case "aboutMe":
|
||||
return (
|
||||
<div
|
||||
className={`${styleClasses.styleField}`}
|
||||
title={userData.aboutMe ? userData.aboutMe.replace(/<[^>]+>/g, '').replace(/ /gi,' ') : "Not available"}
|
||||
>
|
||||
<Stack
|
||||
horizontal={true}
|
||||
verticalAlign="center"
|
||||
tokens={{ childrenGap: 5 }}
|
||||
style={{ marginRight: 20, marginLeft: 20 }}
|
||||
>
|
||||
<FontIcon
|
||||
className={styleClasses.styleIconDetails}
|
||||
iconName="Medal"
|
||||
/>
|
||||
<Label className={styleClasses.styleFieldLabel}>
|
||||
About Me
|
||||
</Label>
|
||||
</Stack>
|
||||
<Text
|
||||
styles={styleTextField}
|
||||
variant="medium"
|
||||
block={true}
|
||||
nowrap={true}
|
||||
>
|
||||
{userData.aboutMe ? userData.aboutMe.replace(/<[^>]+>/g, '').replace(/ /gi,' ') : "Not available"}
|
||||
</Text>
|
||||
<div className={styleClasses.separator}></div>
|
||||
</div>
|
||||
);
|
||||
break;
|
||||
case "skills":
|
||||
return (
|
||||
<div
|
||||
className={`${styleClasses.styleField}`}
|
||||
title={
|
||||
userData.skills.join(",")
|
||||
? userData.skills.join(",")
|
||||
: "Not available"
|
||||
}
|
||||
>
|
||||
<Stack
|
||||
horizontal={true}
|
||||
verticalAlign="center"
|
||||
tokens={{ childrenGap: 5 }}
|
||||
style={{ marginRight: 20, marginLeft: 20 }}
|
||||
>
|
||||
<FontIcon
|
||||
className={styleClasses.styleIconDetails}
|
||||
iconName="Education"
|
||||
/>
|
||||
<Label className={styleClasses.styleFieldLabel}>
|
||||
Skills
|
||||
</Label>
|
||||
</Stack>
|
||||
<Text
|
||||
styles={styleTextField}
|
||||
variant="medium"
|
||||
block={true}
|
||||
nowrap={true}
|
||||
>
|
||||
{userData.skills.join(",") ? (
|
||||
<>
|
||||
{userData.skills.join(",")}
|
||||
</>
|
||||
) : (
|
||||
"Not available"
|
||||
)}
|
||||
</Text>
|
||||
<div className={styleClasses.separator}></div>
|
||||
</div>
|
||||
);
|
||||
break;
|
||||
}
|
||||
})}
|
||||
</Stack>
|
||||
</>
|
||||
|
|
|
@ -15,5 +15,4 @@ export interface IUser {
|
|||
officeLocation: string;
|
||||
postalCode: string;
|
||||
userType: string;
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
export interface IUserBio {
|
||||
id?: string;
|
||||
aboutMe: string;
|
||||
skills: string[];
|
||||
}
|
|
@ -1,6 +1,7 @@
|
|||
import { IUser } from "./IUser";
|
||||
import { IUserPresence } from "./IUserPresence";
|
||||
export interface IUserExtended extends IUser, IUserPresence {
|
||||
import { IUserBio } from "./IUserBio";
|
||||
export interface IUserExtended extends IUser, IUserPresence, IUserBio {
|
||||
count: number;
|
||||
pictureBase64: string;
|
||||
}
|
||||
|
|
|
@ -4,8 +4,10 @@ import "@pnp/graph/users";
|
|||
import { IUserExtended } from "../entites/IUserExtended";
|
||||
import { IUser } from "../entites/IUser";
|
||||
import { IUserPresence } from "../entites/IUserPresence";
|
||||
import { IUserBio } from "../entites/IUserBio";
|
||||
import { SPComponentLoader } from "@microsoft/sp-loader";
|
||||
import { findIndex } from "lodash";
|
||||
import { findIndex, join, values } from "lodash";
|
||||
import { DetailsRow } from "office-ui-fabric-react";
|
||||
|
||||
/*************************************************************************************/
|
||||
// Hook to search users
|
||||
|
@ -22,6 +24,7 @@ export const useSearchUsers = async (
|
|||
pageSize?: number
|
||||
): Promise<{ usersExtended: IUserExtended[]; nextPage: string }> => {
|
||||
pageSize = pageSize ? pageSize : 5;
|
||||
|
||||
const _searchResults: any = await _MSGraphClient
|
||||
.api('/users?$search="' + searchString + '"')
|
||||
.version("beta")
|
||||
|
@ -40,8 +43,11 @@ export const useSearchUsers = async (
|
|||
for (const _user of _users) {
|
||||
const _userPresence = await getUserPresence(_user.id, _MSGraphClient);
|
||||
const _pictureBase64: string = await getUserPhoto(_user.mail);
|
||||
const _userBio = await getUserBio(_user.id, _MSGraphClient);
|
||||
|
||||
_usersExtended.push({
|
||||
..._user,
|
||||
..._userBio,
|
||||
..._userPresence,
|
||||
pictureBase64: _pictureBase64,
|
||||
count: 0,
|
||||
|
@ -77,14 +83,18 @@ export const useGetUsersByDepartment = async (
|
|||
.count(true)
|
||||
.get();
|
||||
|
||||
|
||||
const _users: IUser[] = _searchResults.value;
|
||||
let _usersExtended: IUserExtended[] = [];
|
||||
|
||||
for (const _user of _users) {
|
||||
const _userPresence = await getUserPresence(_user.id, _MSGraphClient);
|
||||
const _pictureBase64: string = await getUserPhoto(_user.mail);
|
||||
const _userBio = await getUserBio(_user.id, _MSGraphClient);
|
||||
|
||||
_usersExtended.push({
|
||||
..._user,
|
||||
..._userBio,
|
||||
..._userPresence,
|
||||
pictureBase64: _pictureBase64,
|
||||
count: 0,
|
||||
|
@ -119,8 +129,10 @@ export const useGetUsersNextPage = async (
|
|||
for (const _user of _users) {
|
||||
const _userPresence = await getUserPresence(_user.id, _MSGraphClient);
|
||||
const _pictureBase64: string = await getUserPhoto(_user.mail);
|
||||
const _userBio = await getUserBio(_user.id, _MSGraphClient);
|
||||
_usersExtended.push({
|
||||
..._user,
|
||||
..._userBio,
|
||||
..._userPresence,
|
||||
pictureBase64: _pictureBase64,
|
||||
count: 0,
|
||||
|
@ -185,6 +197,21 @@ const getUserPresence = async (
|
|||
return _presence;
|
||||
};
|
||||
|
||||
//*************************************************************************************//
|
||||
// function Get Users About Me and skillz
|
||||
//*************************************************************************************//
|
||||
|
||||
const getUserBio = async (
|
||||
userObjId,
|
||||
_MSGraphClient
|
||||
): Promise<IUserBio> => {
|
||||
let _bio : IUserBio = await _MSGraphClient
|
||||
.api("/users/{" + userObjId + "}?$select=aboutMe,skills")
|
||||
.version("beta")
|
||||
.get();
|
||||
return _bio;
|
||||
};
|
||||
|
||||
/**
|
||||
* Gets user photo
|
||||
* @param userId
|
||||
|
|
|
@ -18,11 +18,11 @@
|
|||
"preconfiguredEntries": [{
|
||||
"groupId": "5c03119e-3074-46fd-976b-c60198311f70", // Other
|
||||
"group": { "default": "SPFx Custom Web Parts" },
|
||||
"title": { "default": "Search Directory" },
|
||||
"description": { "default": "Search Directory" },
|
||||
"title": { "default": "UoB Search Directory" },
|
||||
"description": { "default": "University of Brighton Search Directory" },
|
||||
"officeFabricIconFontName": "ProfileSearch",
|
||||
"properties": {
|
||||
"title": "Search Directory",
|
||||
"title": "UoB Search Directory",
|
||||
"maxHeight": 700,
|
||||
"showBox": true,
|
||||
"refreshInterval": 3,
|
||||
|
|
|
@ -42,8 +42,6 @@ export default class StaffDirectoryWebPart extends BaseClientSideWebPart<IStaffD
|
|||
|
||||
protected async onInit(): Promise<void> {
|
||||
|
||||
|
||||
|
||||
this._themeProvider = this.context.serviceScope.consume(
|
||||
ThemeProvider.serviceKey
|
||||
);
|
||||
|
@ -189,7 +187,6 @@ export default class StaffDirectoryWebPart extends BaseClientSideWebPart<IStaffD
|
|||
PropertyFieldMultiSelect('userAttributes', {
|
||||
key: 'userAttributes',
|
||||
label: strings.UserAttributesLabel,
|
||||
|
||||
options: [
|
||||
{
|
||||
key: "company",
|
||||
|
@ -223,6 +220,14 @@ export default class StaffDirectoryWebPart extends BaseClientSideWebPart<IStaffD
|
|||
key: "userType",
|
||||
text: "User Type"
|
||||
},
|
||||
{
|
||||
key: "aboutMe",
|
||||
text: "About Me"
|
||||
},
|
||||
{
|
||||
key: "skills",
|
||||
text: "Skills"
|
||||
},
|
||||
],
|
||||
selectedKeys: this.properties.userAttributes
|
||||
}),
|
||||
|
|
Loading…
Reference in New Issue