diff --git a/samples/react-directory/src/SPServices/ISPServices.ts b/samples/react-directory/src/SPServices/ISPServices.ts index bd9bfb65c..bce353464 100644 --- a/samples/react-directory/src/SPServices/ISPServices.ts +++ b/samples/react-directory/src/SPServices/ISPServices.ts @@ -1,9 +1,7 @@ import { PeoplePickerEntity } from '@pnp/sp'; export interface ISPServices { - getUserProperties(user: string): Promise; - getUserProfileProperty(user: string, property: string): Promise; - getUsers(searchUser: string): Promise; + searchUsers(searchString: string, searchFirstName: boolean); } \ No newline at end of file diff --git a/samples/react-directory/src/SPServices/MockDataSearch.json b/samples/react-directory/src/SPServices/MockDataSearch.json new file mode 100644 index 000000000..0bdd78b5f --- /dev/null +++ b/samples/react-directory/src/SPServices/MockDataSearch.json @@ -0,0 +1,210 @@ +{ + "odata.metadata": "https://contoso.sharepoint.com/_api/$metadata#Microsoft.Office.Server.Search.REST.SearchResult", + "ElapsedTime": 34, + "PrimaryQueryResult": { + "CustomResults": [], + "QueryId": "70699796-a977-4437-b771-92a074e322e6", + "QueryRuleId": "00000000-0000-0000-0000-000000000000", + "RefinementResults": null, + "RelevantResults": { + "GroupTemplateId": null, + "ItemTemplateId": null, + "Properties": [], + "ResultTitle": null, + "ResultTitleUrl": null, + "RowCount": 1, + "Table": { + "Rows": [{ + "Cells": [{ + "Key": "Rank", + "Value": "0", + "ValueType": "Edm.Double" + }, { + "Key": "DocId", + "Value": "17646696630634", + "ValueType": "Edm.Int64" + }, { + "Key": "FirstName", + "Value": "Peter Paul", + "ValueType": "Edm.String" + }, { + "Key": "LastName", + "Value": "Kirschner", + "ValueType": "Edm.String" + }, { + "Key": "PreferredName", + "Value": "Peter Paul Kirschner", + "ValueType": "Edm.String" + }, { + "Key": "WorkEmail", + "Value": "petkir@pkirschner.onmicrosoft.com", + "ValueType": "Edm.String" + }, { + "Key": "OfficeNumber", + "Value": null, + "ValueType": "Null" + }, { + "Key": "PictureURL", + "Value": "", + "ValueType": "Edm.String" + }, { + "Key": "WorkPhone", + "Value": "4250000000", + "ValueType": "Edm.String" + }, { + "Key": "MobilePhone", + "Value": null, + "ValueType": "Null" + }, { + "Key": "JobTitle", + "Value": null, + "ValueType": "Null" + }, { + "Key": "Department", + "Value": null, + "ValueType": "Null" + }, { + "Key": "Skills", + "Value": "", + "ValueType": "Edm.String" + }, { + "Key": "PastProjects", + "Value": "", + "ValueType": "Edm.String" + }, { + "Key": "BaseOfficeLocation", + "Value": null, + "ValueType": "Null" + }, { + "Key": "SPS-UserType", + "Value": "0", + "ValueType": "Edm.Int64" + }, { + "Key": "GroupId", + "Value": null, + "ValueType": "Null" + }, { + "Key": "SiteId", + "Value": null, + "ValueType": "Null" + }, { + "Key": "WebId", + "Value": null, + "ValueType": "Null" + }, { + "Key": "UniqueId", + "Value": null, + "ValueType": "Null" + }, { + "Key": "contentclass", + "Value": "urn:content-class:SPSPeople", + "ValueType": "Edm.String" + }, { + "Key": "PartitionId", + "Value": "92ab9c96-469b-4d78-8b8c-961c4df9356b", + "ValueType": "Edm.Guid" + }, { + "Key": "UrlZone", + "Value": "0", + "ValueType": "Edm.Int32" + }, { + "Key": "Culture", + "Value": "en-US", + "ValueType": "Edm.String" + }, { + "Key": "ResultTypeId", + "Value": "0", + "ValueType": "Edm.Int32" + }, { + "Key": "EditProfileUrl", + "Value": null, + "ValueType": "Null" + }, { + "Key": "ProfileViewsLastMonth", + "Value": null, + "ValueType": "Null" + }, { + "Key": "ProfileViewsLastWeek", + "Value": null, + "ValueType": "Null" + }, { + "Key": "ProfileQueriesFoundYou", + "Value": null, + "ValueType": "Null" + }, { + "Key": "RenderTemplateId", + "Value": "~sitecollection/_catalogs/masterpage/Display Templates/Search/Item_Default.js", + "ValueType": "Edm.String" + }, { + "Key": "GeoLocationSource", + "Value": "EUR", + "ValueType": "Edm.String" + }] + }] + }, + "TotalRows": 1, + "TotalRowsIncludingDuplicates": 1 + }, + "SpecialTermResults": null + }, + "Properties": [{ + "Key": "RowLimit", + "Value": "500", + "ValueType": "Edm.Int32" + }, { + "Key": "SourceId", + "Value": "b09a7990-05ea-4af9-81ef-edfab16c4e31", + "ValueType": "Edm.Guid" + }, { + "Key": "CorrelationId", + "Value": "e83b679f-b0c6-2000-3de3-321f0ebd7f6d", + "ValueType": "Edm.Guid" + }, { + "Key": "WasGroupRestricted", + "Value": "false", + "ValueType": "Edm.Boolean" + }, { + "Key": "WordBreakerLanguage", + "Value": "default", + "ValueType": "Edm.String" + }, { + "Key": "IsPartialUpnDocIdMapping", + "Value": "false", + "ValueType": "Edm.Boolean" + }, { + "Key": "EnableInterleaving", + "Value": "true", + "ValueType": "Edm.Boolean" + }, { + "Key": "IsMissingUnifiedGroups", + "Value": "false", + "ValueType": "Edm.Boolean" + }, { + "Key": "Constellation", + "Value": "i31EEE", + "ValueType": "Edm.String" + }, { + "Key": "MultiGeoSearchStatus", + "Value": "Full", + "ValueType": "Edm.String" + }, { + "Key": "HasParseException", + "Value": "false", + "ValueType": "Edm.Boolean" + }, { + "Key": "IsPartial", + "Value": "false", + "ValueType": "Edm.Boolean" + }, { + "Key": "InternalRequestId", + "Value": "e44dc9d5-b4dc-4f4e-84f1-eef4eb163ad4", + "ValueType": "Edm.String" + }, { + "Key": "SerializedQuery", + "Value": "", + "ValueType": "Edm.String" + }], + "SecondaryQueryResults": [], + "SpellingSuggestion": null, + "TriggeredRules": [] +} diff --git a/samples/react-directory/src/SPServices/spMockServices.ts b/samples/react-directory/src/SPServices/spMockServices.ts new file mode 100644 index 000000000..f57f5cfaa --- /dev/null +++ b/samples/react-directory/src/SPServices/spMockServices.ts @@ -0,0 +1,112 @@ +import { ISPServices } from "./ISPServices"; +import * as mockdata from './MockDataSearch.json'; +import { cloneDeep } from '@microsoft/sp-lodash-subset'; +interface MinimalMockUser { + FirstName: string; + LastName: string; + Department: string; + Location: string; + Title: string; + PreferredName: string; + WorkPhone: string; +} + +/* + +DisplayName: user.PreferredName, + Title: user.JobTitle, + PictureUrl: user.PictureURL, + Email: user.WorkEmail, + Department: user.Department, + WorkPhone: user.WorkPhone, + Location: user.OfficeNumber + ? user.OfficeNumber + : user.BaseOfficeLocation + */ +const sampleUserFirstNameLetter: string[] = [ + "A", + "C", + "D", + "F", + "H", + "J", + "L", + "N", + "P", + "R", + "T", + "V", + "X", + "Z", +]; +const sampleUserLastNameLetter: string[] = [ + "B", + "E", + "G", + "I", + "K", + "M", + "O", + "Q", + "S", + "U", + "W", + "Y", +]; + + +export class spMockServices implements ISPServices { + private sampleData: MinimalMockUser[] = []; + constructor() { + + sampleUserLastNameLetter.forEach(lastNameL => { + sampleUserFirstNameLetter.forEach(firstNameL => { + const usercount = Math.floor(Math.random() * (5)) + 1; + for (let i = 0; i < usercount; i++) { + this.sampleData.push({ + FirstName: `${firstNameL}FirstName${i}`, + LastName: `${lastNameL}LastName${i}`, + PreferredName: `${firstNameL}FirstName${i} ${lastNameL}LastName${i}`, + Department: i % 2 === 0 ? `${lastNameL}Department` : `${firstNameL}Department`, + Location: i % 3 === 0 ? `${lastNameL}Location` : `${firstNameL}Location`, + Title: i % 2 === 0 ? `${lastNameL}JobTitle` : `${firstNameL}JobTitle`, + WorkPhone: '' + Math.floor(Math.random() * 1234) + 54678900 + }); + } + }); + }); + } + + public async searchUsers(searchString: string, searchFirstName: boolean) { + let filtervalue = searchString.trim().toLowerCase(); + if (searchString.length > 0 && filtervalue.lastIndexOf("*") == searchString.length - 1) { + // remove last '*' + filtervalue = filtervalue.substring(0, searchString.length - 1); + } + if (!filtervalue || filtervalue.length === 0) { + throw new Error("No valid Input."); + } + + + const searchresult = !!searchFirstName ? + this.sampleData.filter(p => p.FirstName.toLowerCase().indexOf(filtervalue) === 0) : + this.sampleData.filter(p => p.LastName.toLowerCase().indexOf(filtervalue) === 0); + + const timeout = Math.floor(Math.random() * (1000)) + 1; + const resultdata = { + ElapsedTime: timeout, + RowCount: searchresult.length, + TotalRows: searchresult.length, + PrimarySearchResults: searchresult + }; + + + return new Promise((resolve) => { + setTimeout(() => { + resolve(resultdata); + }, timeout); + }); + + } + +} \ No newline at end of file diff --git a/samples/react-directory/src/SPServices/spservices.ts b/samples/react-directory/src/SPServices/spservices.ts index 38c405e08..fc101105c 100755 --- a/samples/react-directory/src/SPServices/spservices.ts +++ b/samples/react-directory/src/SPServices/spservices.ts @@ -18,51 +18,15 @@ export class spservices implements ISPServices { }); } - public async getUserProperties(user: string): Promise { - try { - let currentUserProperties: any = await sp.profiles.getPropertiesFor(user); - return currentUserProperties; - } catch (error) { - Promise.reject(error); - } - } - - /** - * async GetUserProfileProperty -user:string */ - public async getUserProfileProperty(user: string, property: string): Promise { - try { - let UserProperty: string = await sp.profiles.getUserProfilePropertyFor(user, property); - console.log(UserProperty); - return UserProperty; - } catch (error) { - Promise.reject(error); - } - } - - /** - * - * @param {string} searchUser - * @memberof spservices - */ - public async getUsers(searchUser: string): Promise { - try { - let users: PeoplePickerEntity[] = await sp.profiles.clientPeoplePickerSearchUser({ QueryString: searchUser, MaximumEntitySuggestions: 100, PrincipalType: 1 }); - return users; - } catch (error) { - Promise.reject(error); - } - } - - public async searchUsers(searchString: string, searchFirstName:boolean) { - const _search = !searchFirstName ? `LastName:${searchString}*` : `FirstName:${searchString}*` ; - const searchProperties: string[] = ["FirstName", "LastName", "PreferredName", "WorkEmail", "OfficeNumber","PictureURL", "WorkPhone", "MobilePhone", "JobTitle", "Department", "Skills", "PastProjects", "BaseOfficeLocation", "SPS-UserType","GroupId"]; + public async searchUsers(searchString: string, searchFirstName: boolean): Promise { + const _search = !searchFirstName ? `LastName:${searchString}*` : `FirstName:${searchString}*`; + const searchProperties: string[] = ["FirstName", "LastName", "PreferredName", "WorkEmail", "OfficeNumber", "PictureURL", "WorkPhone", "MobilePhone", "JobTitle", "Department", "Skills", "PastProjects", "BaseOfficeLocation", "SPS-UserType", "GroupId"]; try { if (!searchString) return undefined; let users = await sp.searchWithCaching({ Querytext: _search, - RowLimit:500, + RowLimit: 500, EnableInterleaving: true, SelectProperties: searchProperties, SourceId: 'b09a7990-05ea-4af9-81ef-edfab16c4e31', diff --git a/samples/react-directory/src/webparts/directory/components/Directory.tsx b/samples/react-directory/src/webparts/directory/components/Directory.tsx index f3d04e1c7..af8daa6b3 100755 --- a/samples/react-directory/src/webparts/directory/components/Directory.tsx +++ b/samples/react-directory/src/webparts/directory/components/Directory.tsx @@ -23,6 +23,8 @@ import { import { WebPartTitle } from "@pnp/spfx-controls-react/lib/WebPartTitle"; import { ISPServices } from "../../../SPServices/ISPServices"; +import { Environment, EnvironmentType } from "@microsoft/sp-core-library"; +import { spMockServices } from "../../../SPServices/spMockServices"; const az: string[] = [ "A", @@ -77,13 +79,16 @@ export default class Directory extends React.Component< searchString: "LastName", searchText: "" }; - + if (Environment.type === EnvironmentType.Local) { + this._services = new spMockServices(); + } else { this._services = new spservices(this.props.context); + } // Register event handlers this._searchUsers = this._searchUsers.bind(this); this._selectedIndex = this._selectedIndex.bind(this); this._sortPeople = this._sortPeople.bind(this); - this._searchBoxChanged = this._searchBoxChanged.bind(this) + this._searchBoxChanged = this._searchBoxChanged.bind(this); } /** @@ -137,7 +142,7 @@ export default class Directory extends React.Component< searchText, this.props.searchFirstName ); - +debugger; if (users && users.PrimarySearchResults.length > 0) { for (let index = 0; index < users.PrimarySearchResults.length; index++) { let user: any = users.PrimarySearchResults[index]; diff --git a/samples/react-directory/src/webparts/directory/components/PersonaCard/PersonaCard.tsx b/samples/react-directory/src/webparts/directory/components/PersonaCard/PersonaCard.tsx index bedfbc389..82209ef8d 100755 --- a/samples/react-directory/src/webparts/directory/components/PersonaCard/PersonaCard.tsx +++ b/samples/react-directory/src/webparts/directory/components/PersonaCard/PersonaCard.tsx @@ -3,7 +3,7 @@ import styles from './PersonaCard.module.scss'; import { IPersonaCardProps } from './IPersonaCardProps'; import { IPersonaCardState } from './IPersonaCardState'; import { - Log, + Log, Environment, EnvironmentType, } from '@microsoft/sp-core-library'; import { SPComponentLoader } from '@microsoft/sp-loader'; @@ -22,7 +22,7 @@ const LIVE_PERSONA_COMPONENT_ID: string = export class PersonaCard extends React.Component< IPersonaCardProps, IPersonaCardState -> { + > { constructor(props: IPersonaCardProps) { super(props); @@ -34,12 +34,14 @@ export class PersonaCard extends React.Component< * @memberof PersonaCard */ public async componentDidMount() { - const sharedLibrary = await this._loadSPComponentById( - LIVE_PERSONA_COMPONENT_ID - ); - const livePersonaCard: any = sharedLibrary.LivePersonaCard; - console.log(livePersonaCard); - this.setState({ livePersonaCard: livePersonaCard }); + if (Environment.type !== EnvironmentType.Local) { + const sharedLibrary = await this._loadSPComponentById( + LIVE_PERSONA_COMPONENT_ID + ); + const livePersonaCard: any = sharedLibrary.LivePersonaCard; + console.log(livePersonaCard); + this.setState({ livePersonaCard: livePersonaCard }); + } } /** @@ -52,7 +54,7 @@ export class PersonaCard extends React.Component< public componentDidUpdate( prevProps: IPersonaCardProps, prevState: IPersonaCardState - ): void {} + ): void { } /** * @@ -110,8 +112,8 @@ export class PersonaCard extends React.Component< ) : ( - '' - )} + '' + )} {this.props.profileProperties.Location ? (
@@ -121,8 +123,8 @@ export class PersonaCard extends React.Component<
) : ( - '' - )} + '' + )} diff --git a/samples/react-directory/tsconfig.json b/samples/react-directory/tsconfig.json index 471a0daa0..dacaaa6eb 100755 --- a/samples/react-directory/tsconfig.json +++ b/samples/react-directory/tsconfig.json @@ -5,6 +5,7 @@ "forceConsistentCasingInFileNames": true, "module": "esnext", "moduleResolution": "node", + "resolveJsonModule" : true, "jsx": "react", "declaration": true, "sourceMap": true,