From 7ae0ee59c53690d3e89a94a39d2926a778379e2b Mon Sep 17 00:00:00 2001 From: tristian o'brien Date: Wed, 14 Apr 2021 15:21:44 +0100 Subject: [PATCH] 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 --- .../src/components/UserCard/UserCard.tsx | 105 ++++++++++++++++-- .../react-staffdirectory/src/entites/IUser.ts | 1 - .../src/entites/IUserBio.ts | 5 + .../src/entites/IUserExtended.ts | 3 +- .../src/hooks/useSearchUsers.ts | 29 ++++- .../StaffDirectoryWebPart.manifest.json | 6 +- .../staffDirectory/StaffDirectoryWebPart.ts | 11 +- 7 files changed, 143 insertions(+), 17 deletions(-) create mode 100644 samples/react-staffdirectory/src/entites/IUserBio.ts diff --git a/samples/react-staffdirectory/src/components/UserCard/UserCard.tsx b/samples/react-staffdirectory/src/components/UserCard/UserCard.tsx index fb59fcd2c..1ff6184a3 100644 --- a/samples/react-staffdirectory/src/components/UserCard/UserCard.tsx +++ b/samples/react-staffdirectory/src/components/UserCard/UserCard.tsx @@ -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%" }, }} > - { + 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} @@ -130,6 +136,7 @@ export const UserCard = (props: IUserCardProps) => { >
{ ); }; + + //tris added onclick event const _onRenderSecondaryText = (persona: IPersonaProps) => { return ( <> - + { + event.preventDefault(); + window.open("https://gbr.delve.office.com/?u=" + userData.id + "&v=work", "_blank"); + } + } + title={persona.secondaryText} variant="medium" block nowrap> {" "} {persona.secondaryText} @@ -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} - > + > {isDetailsOpen && ( <> @@ -707,8 +722,82 @@ export const UserCard = (props: IUserCardProps) => {
); - break; - } + break; + case "aboutMe": + return ( +
]+>/g, '').replace(/ /gi,' ') : "Not available"} + > + + + + + + {userData.aboutMe ? userData.aboutMe.replace(/<[^>]+>/g, '').replace(/ /gi,' ') : "Not available"} + +
+
+ ); + break; + case "skills": + return ( +
+ + + + + + {userData.skills.join(",") ? ( + <> + {userData.skills.join(",")} + + ) : ( + "Not available" + )} + +
+
+ ); + break; + } })} diff --git a/samples/react-staffdirectory/src/entites/IUser.ts b/samples/react-staffdirectory/src/entites/IUser.ts index 28faccfd7..b09c80298 100644 --- a/samples/react-staffdirectory/src/entites/IUser.ts +++ b/samples/react-staffdirectory/src/entites/IUser.ts @@ -15,5 +15,4 @@ export interface IUser { officeLocation: string; postalCode: string; userType: string; - } diff --git a/samples/react-staffdirectory/src/entites/IUserBio.ts b/samples/react-staffdirectory/src/entites/IUserBio.ts new file mode 100644 index 000000000..a9ca51344 --- /dev/null +++ b/samples/react-staffdirectory/src/entites/IUserBio.ts @@ -0,0 +1,5 @@ +export interface IUserBio { + id?: string; + aboutMe: string; + skills: string[]; +} \ No newline at end of file diff --git a/samples/react-staffdirectory/src/entites/IUserExtended.ts b/samples/react-staffdirectory/src/entites/IUserExtended.ts index 889c8047c..7c4d46ea2 100644 --- a/samples/react-staffdirectory/src/entites/IUserExtended.ts +++ b/samples/react-staffdirectory/src/entites/IUserExtended.ts @@ -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; } diff --git a/samples/react-staffdirectory/src/hooks/useSearchUsers.ts b/samples/react-staffdirectory/src/hooks/useSearchUsers.ts index 140aa0bba..b1920266d 100644 --- a/samples/react-staffdirectory/src/hooks/useSearchUsers.ts +++ b/samples/react-staffdirectory/src/hooks/useSearchUsers.ts @@ -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 => { + let _bio : IUserBio = await _MSGraphClient + .api("/users/{" + userObjId + "}?$select=aboutMe,skills") + .version("beta") + .get(); + return _bio; +}; + /** * Gets user photo * @param userId diff --git a/samples/react-staffdirectory/src/webparts/staffDirectory/StaffDirectoryWebPart.manifest.json b/samples/react-staffdirectory/src/webparts/staffDirectory/StaffDirectoryWebPart.manifest.json index c1c75504f..0fa5934f7 100644 --- a/samples/react-staffdirectory/src/webparts/staffDirectory/StaffDirectoryWebPart.manifest.json +++ b/samples/react-staffdirectory/src/webparts/staffDirectory/StaffDirectoryWebPart.manifest.json @@ -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, diff --git a/samples/react-staffdirectory/src/webparts/staffDirectory/StaffDirectoryWebPart.ts b/samples/react-staffdirectory/src/webparts/staffDirectory/StaffDirectoryWebPart.ts index 07c1c1149..8b9f4cc6b 100644 --- a/samples/react-staffdirectory/src/webparts/staffDirectory/StaffDirectoryWebPart.ts +++ b/samples/react-staffdirectory/src/webparts/staffDirectory/StaffDirectoryWebPart.ts @@ -42,8 +42,6 @@ export default class StaffDirectoryWebPart extends BaseClientSideWebPart { - - this._themeProvider = this.context.serviceScope.consume( ThemeProvider.serviceKey ); @@ -189,7 +187,6 @@ export default class StaffDirectoryWebPart extends BaseClientSideWebPart