import * as React from "react"; import * as lodash from "lodash"; import IJitzSPContext from "../data/interfaces/IJitzSPContext"; import UtilityService from "../services/UtilityService"; import { CompactPeoplePicker, IBasePickerSuggestionsProps, IContextualMenuItem, IPersonaProps, NormalPeoplePicker, } from "@fluentui/react"; import { IClientPeoplePickerSearchUser, IEnsurableSharePointUser, IEnsureUser, IJitzPeoplePickerState, SharePointUserPersona, } from "../common/IObjects"; const suggestionProps: IBasePickerSuggestionsProps = { suggestionsHeaderText: "Suggested People", noResultsFoundText: "No results found", loadingText: "Loading", }; export interface IJitzPeoplePickerProps { description: string; context: IJitzSPContext; hostSiteUrl?: string; typePicker: string; disabled: boolean; principalTypeUser: boolean; principalTypeSharePointGroup: boolean; principalTypeSecurityGroup: boolean; principalTypeDistributionList: boolean; numberOfItems: number; onChange?: (items: SharePointUserPersona[]) => void; prePopulatedItems: string[]; errorMessage?: string; errorCss?: string; multiSelect: boolean; placeholderText?: string; shouldKeepItems?: boolean; } export class JitzPeoplePicker extends React.Component< IJitzPeoplePickerProps, IJitzPeoplePickerState > { private _peopleList: any; private contextualMenuItems: IContextualMenuItem[] = [ { key: "newItem", icon: "circlePlus", name: "New", }, { key: "upload", icon: "upload", name: "Upload", }, { key: "divider_1", name: "-", }, { key: "rename", name: "Rename", }, { key: "properties", name: "Properties", }, { key: "disabled", name: "Disabled item", disabled: true, }, ]; constructor(props: IJitzPeoplePickerProps) { super(props); this._peopleList = []; this.state = { currentPicker: 1, disabled: false, delayResults: false, selectedItems: [], }; } public getSelectedItems() {} public componentDidMount(): void { this.setState({ disabled: this.props.disabled }); this.prePopulate(this.props.prePopulatedItems); } public componentDidUpdate( prevProps: IJitzPeoplePickerProps, prevState: IJitzPeoplePickerState, prevContext: any ): void { //this.prePopulate(); } public componentWillReceiveProps(nextProps: IJitzPeoplePickerProps) { this.setState({ disabled: nextProps.disabled }); this.prePopulate(nextProps.prePopulatedItems); } public render(): React.ReactElement { if (this.props.typePicker == "Normal") { return ( persona.primaryText || "" } pickerSuggestionsProps={suggestionProps} selectedItems={this.state.selectedItems} className={ "ms-PeoplePicker " + (this.props.errorMessage != null && this.props.errorMessage != undefined && this.props.errorMessage.length > 0 ? this.props.errorCss : "") } key={"normal"} /> ); } else { return ( persona.primaryText || "" } pickerSuggestionsProps={suggestionProps} selectedItems={this.state.selectedItems} className={ "ms-PeoplePicker" + (this.props.errorMessage != null && this.props.errorMessage != undefined && this.props.errorMessage.length > 0 ? this.props.errorCss : "") } key={"normal"} /> ); } } private _onChange(items?: any[]) { if ( this.props.shouldKeepItems == undefined || this.props.shouldKeepItems == true ) this.setState({ selectedItems: (this.props.multiSelect ? items : items != undefined ? items.length > 0 ? [items[0]] : items : []) || [], }); if (items != undefined) { items.map((p, v) => { // console.log(p); const ensureUserUrl = `${this.props.context.siteUrl}/_api/web/ensureUser`; this.props.context.client .post(ensureUserUrl, { logonName: p.User.Key }) .then((response: any) => { var res = response.data.d; return res; }) .then((res: any) => {}); }); } if (this.props.onChange) { this.props.onChange(items || []); } } private prePopulate = (nextPrePopulatedItems: string[]) => { const ensureUserUrl = `${this.props.context.siteUrl}/_api/web/ensureUser`; if ( nextPrePopulatedItems != undefined && nextPrePopulatedItems != null && nextPrePopulatedItems[0] != null ) { nextPrePopulatedItems.map((item) => { // console.log(item); this.props.context.client .post(ensureUserUrl, { logonName: item }) .then((response: any) => { var res = response.data.d; return res; }) .then((res: any) => { var pers = new SharePointUserPersona( res as IEnsurableSharePointUser ); pers.imageUrl = UtilityService.getProfilePictureUrl( this.props.hostSiteUrl || this.props.context.siteUrl, pers.User.Email || "", "1" ); // (this.props.hostSiteUrl || this.props.context.siteUrl) + // `/_layouts/15/userphoto.aspx?size=S&accountname=${pers.User.Email}`; var prepopulatedItems = this.state.selectedItems; if ( prepopulatedItems.filter( (x: any) => x.User.LoginName == pers.User.LoginName ).length == 0 ) { prepopulatedItems.push(pers); this.setState({ selectedItems: this.props.multiSelect ? prepopulatedItems : prepopulatedItems.length > 0 ? [prepopulatedItems[0]] : prepopulatedItems, }); } if (this.props.onChange) { this.props.onChange(prepopulatedItems); } }); }); } }; private _onFilterChanged = ( filterText: string, currentPersonas?: IPersonaProps[] ): any => { if (filterText) { if (filterText.length > 2) { return this._searchPeople(filterText, this._peopleList); } } else { return []; } }; /** * @function * Returns fake people results for the Mock mode */ private searchPeopleFromMock(): IPersonaProps[] { return (this._peopleList = []); } /** * @function * Returns people results after a REST API call */ private _searchPeople( terms: string, results: IPersonaProps[] ): IPersonaProps[] | Promise { const userRequestUrl: string = `${this.props.context.siteUrl}/_api/SP.UI.ApplicationPages.ClientPeoplePickerWebServiceInterface.clientPeoplePickerSearchUser`; let principalType: number = 0; if (this.props.principalTypeUser === true) { principalType += 1; } if (this.props.principalTypeSharePointGroup === true) { principalType += 8; } if (this.props.principalTypeSecurityGroup === true) { principalType += 4; } if (this.props.principalTypeDistributionList === true) { principalType += 2; } const userQueryParams = { queryParams: { AllowEmailAddresses: true, AllowMultipleEntities: false, AllUrlZones: false, MaximumEntitySuggestions: this.props.numberOfItems, PrincipalSource: 15, // PrincipalType controls the type of entities that are returned in the results. // Choices are All - 15, Distribution List - 2 , Security Groups - 4, SharePoint Groups - 8, User - 1. // These values can be combined (example: 13 is security + SP groups + users) PrincipalType: principalType, QueryString: terms, }, }; return new Promise((resolve: any, reject: any) => this.props.context.client .post(userRequestUrl, userQueryParams) .then((response: any) => { return response.data.d; }) .then((response: { ClientPeoplePickerSearchUser: string }) => { let userQueryResults: IClientPeoplePickerSearchUser[] = JSON.parse( response.ClientPeoplePickerSearchUser ); let persons = userQueryResults.map( (p) => new SharePointUserPersona(p as IEnsurableSharePointUser) ); persons.map((p, index) => { persons[index].imageUrl = UtilityService.getProfilePictureUrl( this.props.hostSiteUrl || this.props.context.siteUrl, persons[index].User.Email || persons[index].User.Key.substr( persons[index].User.Key.lastIndexOf("|") + 1 ), "1" ); // (this.props.hostSiteUrl || this.props.context.siteUrl) + // `/_layouts/15/userphoto.aspx?size=S&accountname=${ // persons[index].User.Email || // persons[index].User.Key.substr( // persons[index].User.Key.lastIndexOf("|") + 1 // ) // }`; }); return persons; }) .then( (persons: any) => { //const batch = this.props.spHttpClient.beginBatch(); const ensureUserUrl = `${this.props.context.siteUrl}/_api/web/ensureUser`; const batchPromises: Promise[] = persons.map( (p: SharePointUserPersona) => { p.primaryText = p.User.DisplayText; p.secondaryText = p.User.EntityData.Title; var userQuery = { logonName: p.User.Key }; return ( this.props.context.client .post(ensureUserUrl, userQuery) // return this.props.spHttpClient.post(ensureUserUrl, // SPHttpClient.configurations.v1, // {body:JSON.stringify({logonName: p.User.Key})}) .then((response: any) => { return response.data.d; }) .then((json: IEnsureUser) => json) ); } ); // var users = this.props.spHttpClient.execute().then(() => ); var users = Promise.all(batchPromises).then((values: any) => { values.forEach((v: any) => { let userPersona = lodash.find( persons, (o: any) => o.User.Key == v.LoginName ); if (userPersona && userPersona.User) { let user = userPersona.User; lodash.assign(user, v); userPersona.User = user; } }); resolve(persons); }); }, (error: any): void => { reject((this._peopleList = [])); } ) ); } private _filterPersonasByText(filterText: string): IPersonaProps[] { return this._peopleList.filter((item: any) => this._doesTextStartWith(item.primaryText, filterText) ); } private _removeDuplicates( personas: IPersonaProps[], possibleDupes: IPersonaProps[] ) { return personas.filter( (persona) => !this._listContainsPersona(persona, possibleDupes) ); } private _listContainsPersona( persona: IPersonaProps, personas: IPersonaProps[] ) { if (!personas || !personas.length || personas.length === 0) { return false; } return ( personas.filter((item) => item.primaryText === persona.primaryText) .length > 0 ); } private _filterPromise( personasToReturn: IPersonaProps[] ): IPersonaProps[] | Promise { if (this.state.delayResults) { return this._convertResultsToPromise(personasToReturn); } else { return personasToReturn; } } private _convertResultsToPromise( results: IPersonaProps[] ): Promise { return new Promise((resolve: any, reject: any) => setTimeout(() => resolve(results), 2000) ); } private _doesTextStartWith(text: string, filterText: string): boolean { return text.toLowerCase().indexOf(filterText.toLowerCase()) === 0; } }