@pnp/spfx-property-controls
Version:
Reusable property pane controls for SharePoint Framework solutions
285 lines • 12 kB
JavaScript
import * as React from 'react';
import { PrincipalType } from './IPropertyFieldPeoplePicker';
import { NormalPeoplePicker } from '@fluentui/react/lib/Pickers';
import { Label } from '@fluentui/react/lib/Label';
import { PersonaPresence, PersonaInitialsColor } from '@fluentui/react/lib/Persona';
import { Async } from '@fluentui/react/lib/Utilities';
import * as strings from 'PropertyControlStrings';
import SPPeopleSearchService from '../../services/SPPeopleSearchService';
import FieldErrorMessage from '../errorMessage/FieldErrorMessage';
import * as telemetry from '../../common/telemetry';
import { setPropertyValue } from '../../helpers/GeneralHelper';
/**
* Renders the controls for PropertyFieldPeoplePicker component
*/
export default class PropertyFieldPeoplePickerHost extends React.Component {
/**
* Constructor method
*/
constructor(props) {
super(props);
this.intialPersonas = new Array();
this.resultsPeople = new Array();
this.resultsPersonas = new Array();
this.selectedPeople = new Array();
this.selectedPersonas = new Array();
telemetry.track('PropertyFieldPeoplePicker', {
allowDuplicate: props.allowDuplicate,
principalType: props.principalType ? props.principalType.toString() : '',
disabled: props.disabled
});
this.searchService = new SPPeopleSearchService();
this.onSearchFieldChanged = this.onSearchFieldChanged.bind(this);
this.onItemChanged = this.onItemChanged.bind(this);
this.createInitialPersonas();
this.state = {
resultsPeople: this.resultsPeople,
resultsPersonas: this.resultsPersonas,
errorMessage: ''
};
this.async = new Async(this);
this.validate = this.validate.bind(this);
this.notifyAfterValidate = this.notifyAfterValidate.bind(this);
this.delayedValidate = this.async.debounce(this.validate, this.props.deferredValidationTime);
}
/**
* A search field change occured
*/
onSearchFieldChanged(searchText, currentSelected) {
if (searchText.length >= this.props.searchTextLimit) {
// Clear the suggestions list
this.setState({ resultsPeople: this.resultsPeople, resultsPersonas: this.resultsPersonas });
// Request the search service
const result = this.searchService.searchPeople(this.props.context, searchText, this.props.principalType, this.props.targetSiteUrl).then((response) => {
this.resultsPeople = [];
this.resultsPersonas = [];
// If allowDuplicate === false, so remove duplicates from results
if (this.props.allowDuplicate === false) {
response = this.removeDuplicates(response);
}
response.forEach((element, index) => {
// Fill the results Array
this.resultsPeople.push(element);
// Transform the response in IPersonaProps object
this.resultsPersonas.push(this.getPersonaFromPeople(element, index));
});
// Refresh the component's state
this.setState({ resultsPeople: this.resultsPeople, resultsPersonas: this.resultsPersonas });
return this.resultsPersonas;
});
return result;
}
else {
return [];
}
}
/**
* Remove the duplicates if property allowDuplicate equals false
*/
removeDuplicates(responsePeople) {
if (this.selectedPeople === null || this.selectedPeople.length === 0) {
return responsePeople;
}
const res = [];
for (const element of responsePeople) {
let found = false;
for (let i = 0; i < this.selectedPeople.length; i++) {
const responseItem = this.selectedPeople[i];
if (responseItem.login === element.login &&
responseItem.id === element.id) {
found = true;
break;
}
}
if (found === false) {
res.push(element);
}
}
return res;
}
/**
* Creates the collection of initial personas from initial IPropertyFieldGroupOrPerson collection
*/
createInitialPersonas() {
if (this.props.initialData === null || typeof (this.props.initialData) !== typeof Array()) {
return;
}
this.props.initialData.forEach((element, index) => {
const persona = this.getPersonaFromPeople(element, index);
this.intialPersonas.push(persona);
this.selectedPersonas.push(persona);
this.selectedPeople.push(element);
});
}
/**
* Generates a IPersonaProps object from a IPropertyFieldGroupOrPerson object
*/
getPersonaFromPeople(element, index) {
return {
primaryText: element.fullName,
secondaryText: element.jobTitle,
imageUrl: element.imageUrl,
imageInitials: element.initials,
presence: PersonaPresence.none,
initialsColor: this.getRandomInitialsColor(index)
};
}
/**
* Refreshes the web part properties
*/
refreshWebPartProperties() {
this.delayedValidate(this.selectedPeople);
}
/**
* Validates the new custom field value
*/
validate(value) {
if (this.props.onGetErrorMessage === null || this.props.onGetErrorMessage === undefined) {
this.notifyAfterValidate(this.props.initialData, value);
return;
}
const errResult = this.props.onGetErrorMessage(value || []);
if (errResult) {
if (typeof errResult === 'string') {
if (errResult === '') {
this.notifyAfterValidate(this.props.initialData, value);
}
this.setState({
errorMessage: errResult
});
}
else {
errResult.then((errorMessage) => {
if (!errorMessage) {
this.notifyAfterValidate(this.props.initialData, value);
}
this.setState({
errorMessage: errorMessage
});
}).catch(() => { });
}
}
else {
this.notifyAfterValidate(this.props.initialData, value);
this.setState({
errorMessage: null
});
}
}
/**
* Notifies the parent Web Part of a property value change
*/
notifyAfterValidate(oldValue, newValue) {
if (this.props.onPropertyChange && newValue) {
setPropertyValue(this.props.properties, this.props.targetProperty, newValue);
this.props.onPropertyChange(this.props.targetProperty, oldValue, newValue);
// Trigger the apply button
if (typeof this.props.onChange !== 'undefined' && this.props.onChange !== null) {
this.props.onChange(this.props.targetProperty, newValue);
}
}
}
/**
* Called when the component will unmount
*/
componentWillUnmount() {
this.async.dispose();
}
/**
* Find the index of the selected person
* @param selectedItem
*/
_findIndex(selectedItem) {
for (let i = 0; i < this.resultsPersonas.length; i++) {
const crntPersona = this.resultsPersonas[i];
// Check if the imageUrl, primaryText, secondaryText are equal
if (crntPersona.imageUrl === selectedItem.imageUrl &&
crntPersona.primaryText === selectedItem.primaryText &&
crntPersona.secondaryText === selectedItem.secondaryText) {
return i;
}
}
return -1;
}
/**
* Event raises when the user changed people from the PeoplePicker component
*/
onItemChanged(selectedItems) {
if (selectedItems.length > 0) {
if (selectedItems.length > this.selectedPersonas.length) {
const index = this._findIndex(selectedItems[selectedItems.length - 1]);
if (index > -1) {
const people = this.resultsPeople[index];
this.selectedPeople.push(people);
this.selectedPersonas.push(this.resultsPersonas[index]);
}
}
else {
this.selectedPersonas.forEach((person, index2) => {
const selectedItemIndex = selectedItems.indexOf(person);
if (selectedItemIndex === -1) {
this.selectedPersonas.splice(index2, 1);
this.selectedPeople.splice(index2, 1);
}
});
}
}
else {
this.selectedPersonas.splice(0, this.selectedPersonas.length);
this.selectedPeople.splice(0, this.selectedPeople.length);
}
this.refreshWebPartProperties();
}
/**
* Generate a PersonaInitialsColor from the item position in the collection
*/
getRandomInitialsColor(index) {
const num = index % 13;
switch (num) {
case 0: return PersonaInitialsColor.blue;
case 1: return PersonaInitialsColor.darkBlue;
case 2: return PersonaInitialsColor.teal;
case 3: return PersonaInitialsColor.lightGreen;
case 4: return PersonaInitialsColor.green;
case 5: return PersonaInitialsColor.darkGreen;
case 6: return PersonaInitialsColor.lightPink;
case 7: return PersonaInitialsColor.pink;
case 8: return PersonaInitialsColor.magenta;
case 9: return PersonaInitialsColor.purple;
case 10: return PersonaInitialsColor.black;
case 11: return PersonaInitialsColor.orange;
case 12: return PersonaInitialsColor.red;
case 13: return PersonaInitialsColor.darkRed;
default: return PersonaInitialsColor.blue;
}
}
/**
* Renders the PeoplePicker controls with Office UI Fabric
*/
render() {
const suggestionProps = {
suggestionsHeaderText: strings.PeoplePickerSuggestedContacts,
noResultsFoundText: strings.PeoplePickerNoResults,
loadingText: strings.PeoplePickerLoading,
};
// Check which text have to be shown
if (this.props.principalType && this.props.principalType.length > 0) {
const userType = this.props.principalType.indexOf(PrincipalType.Users) !== -1;
const groupType = this.props.principalType.indexOf(PrincipalType.SharePoint) !== -1 || this.props.principalType.indexOf(PrincipalType.Security) !== -1;
// Check if both user and group are present
if (userType && groupType) {
suggestionProps.suggestionsHeaderText = strings.PeoplePickerSuggestedCombined;
}
// If only group is active
if (!userType && groupType) {
suggestionProps.suggestionsHeaderText = strings.PeoplePickerSuggestedGroups;
}
}
// Renders content
return (React.createElement("div", null,
this.props.label && React.createElement(Label, null, this.props.label),
React.createElement(NormalPeoplePicker, { disabled: this.props.disabled, pickerSuggestionsProps: suggestionProps, onResolveSuggestions: this.onSearchFieldChanged, onChange: this.onItemChanged, defaultSelectedItems: this.intialPersonas, itemLimit: this.props.multiSelect ? undefined : 1 }),
React.createElement(FieldErrorMessage, { errorMessage: this.state.errorMessage })));
}
}
//# sourceMappingURL=PropertyFieldPeoplePickerHost.js.map