react-intl: formatMessage for array of string - reactjs

I have several interfaces, and among these interfaces there is an interface for "displaying users", and there is a field called "Role", which represents an array of user roles,
And I want to translate this column, and it was actually translated through these lines:
tableDataMapper={(rows) => {
return rows?.map((row: any, index) => {
console.log('row: ', rows);
return {
...row,
roleNames: formatMessage({
id: formatMessage({ id: row?.roleNames }),
})
};
});
} }
But the problem is that if the array contains more than one element, it does not translate it, like this picture, it translates all lines except for the line indicated in red.
import { FunctionComponent, useContext } from 'react';
import user from '../../../../api/nuclearMedicineApi/services/User/index';
import Scaffold from '../../../common/scaffold';
import UserForm from './form/index';
import { userColumns } from './data';
import { selectMapper } from '../../../../utils/mappers';
import moment from 'moment';
import { indexFilters } from './filters';
import { useQuery } from 'react-query';
import {
AuthContext,
IAuthContext,
} from '../../../../contexts/auth-context';
import { FormattedMessage, useIntl } from 'react-intl';
interface UsersProps { }
const Users: FunctionComponent<UsersProps> = () => {
const { formatMessage } = useIntl();
const auth = useContext<IAuthContext>(AuthContext);
const filterOptionsData = useQuery('userFilterOptions', () =>
[{key: 'key', value: 0, label: 'label' }],
);
let userListColumns = userColumns;
userListColumns = auth.userData?.roleNames?.some(
(role) => role !== 'ADMIN',
)
? userListColumns.filter(
(item) => item.dataSelector !== 'roleNames',
)
: userListColumns;
return (
<>
<Scaffold
createFunc={user.userCreate}
getFunc={user.userGet}
getAllFunc={user.userGetAll}
filterColumns={indexFilters}
updateFunc={user.userUpdate}
deleteFunc={user.userCreate}
switchActivation
create
switchActivationFunc={user.userSwitchActivation}
tableColumns={userListColumns}
filterOptions={filterOptionsData.data}
dataName='user'
formContent={UserForm}
fullWidthFrom
exportToExcelFunc={user.userGetExcelReport}
defaultSizePaination={10}
pageSizeOptions={[10, 20, 50, 100]}
FormSubmitMapper={(data) => {
return {
...data,
password: data.password ?? null,
...selectMapper(['patientId', 'patient'], data),
};
} }
tableDataMapper={(rows) => {
return rows?.map((row: any) => {
console.log('row: ', rows);
return {
...row,
roleNames: formatMessage({
id: formatMessage({ id: row?.roleNames }),
})
};
});
} }
FromDataMapper={(data) => {
return {
...data,
lastModificationTime: moment(
new Date(data.lastModificationTime)
).format('YYYY-MM-DD, h:mm a'),
creationTime: moment(
new Date(data.creationTime)
).format('YYYY-MM-DD, h:mm a'),
};
} }
mainPermissionName='User' approveFunc={function (data: any): Promise<any> {
throw new Error('Function not implemented.');
} } rejectFunc={function (data: any): Promise<any> {
throw new Error('Function not implemented.');
} } />
</>
);
};
export default Users;

I assume that you want to display the translations of individual roles separated by commas (e.g if A translates to roleA and B translates to roleB, roleNames: ["A", "B"] should be displayed as "roleA, roleB").
Since you have roleNames: ["SystemAdmin", "NationalRegistry"], you could simply do roleNames.map(roleName => formatMessage({ id: roleName })).join(', ')

Related

React component data from GraphQL api result undefined

I'm working on a React component that uses gql and useQuery from GraphQL to fetch data from an API.
My problem is that the data resulting is undefined because probably the state is not handled correctly and the component didn't load the data requested to the API.
I'm new to React and cannot resolve this situation probably a way to wait until the data is loaded and become defined but I have no idea how to do it.
I was trying even to add a useEffect not present in this version but didn't give any differences :( maybe I just don't know how to use it
The component as follows
import { gql, useQuery } from '#apollo/client';
import { useConfiguration } from '#lib/hooks/useConfiguration';
import { useSetConfiguration } from '#lib/hooks/useSetConfiguration';
import { useUnSetConfiguration } from '#lib/hooks/useUnSetConfiguration';
import { FormControlLabel, FormGroup, Switch, Typography } from '#mui/material';
import { useEffect, useState } from 'react';
import { useIntl } from 'react-intl';
const QUERY = gql`
query WEB_useConfiguration($name: String!, $scope: StudyConfigurationScope) {
studyConfiguration(name: $name, filter: $scope) {
configurationOverrideChain {
value
scope
}
}
}
`;
const beforeQuery = ({ studyId }) => ({
variables: { name: 'messaging.email.sender.address', scope: { studyId } },
fetchPolicy: 'network-only',
});
const afterQuery = data => ({
studyConfigurationOverrides:
data?.studyConfiguration?.configurationOverrideChain ?? {},
});
const StudyConfiguration = ({ studyId }) => {
const intl = useIntl();
const [studyConf, setStudyConf] = useState({});
const { data } = useQuery(QUERY, beforeQuery({ studyId }));
console.log('data: ', data); // undefined
const { studyConfigurationOverrides } = afterQuery(data);
// !TODO: make one smart useConfiguration hook instead of 3
// Getting the study config
const smsEnabled = useConfiguration({
name: 'messaging.recruitment.sms.enable',
scope: { studyId },
defaultValue: false,
});
const emailSender = useConfiguration({
name: 'messaging.email.sender.address',
scope: { studyId },
});
const [valueEmailReplay, setValueEmailReplay] = useState(emailSender);
const [valueSmsConf, setValueSmsConf] = useState(smsEnabled);
useEffect(() => {
if (valueSmsConf !== smsEnabled) {
setValueSmsConf(smsEnabled);
}
}, [smsEnabled]); // eslint-disable-line react-hooks/exhaustive-deps
useEffect(() => {
if (valueEmailReplay !== emailSender) {
setValueEmailReplay(emailSender);
}
}, [emailSender]); // eslint-disable-line react-hooks/exhaustive-deps
let suffix;
const globalValue = studyConfigurationOverrides.find(
e => e.scope === 'GLOBAL',
);
const defaultValue = studyConfigurationOverrides.find(
e => e.scope === 'DEfAULT',
);
if (globalValue) {
suffix = globalValue.value;
}
if (defaultValue) {
suffix = defaultValue.value;
}
const emailDomain = suffix?.substring(suffix.indexOf('#'));
const noReplyEmail = `noreply${emailDomain}`;
// Set study config
const [setNoReplyStudyEmail] = useSetConfiguration({
name: 'messaging.email.sender.address',
value: noReplyEmail,
scope: { studyId },
});
const [setSmsMessagingDisable] = useSetConfiguration({
name: 'messaging.recruitment.sms.enable',
value: 'false',
scope: { studyId },
});
// unSet study config
const [setDefaultStudyEmail] = useUnSetConfiguration({
name: 'messaging.email.sender.address',
scope: { studyId },
});
const [setSmsMessagingDefault] = useUnSetConfiguration({
name: 'messaging.recruitment.sms.enable',
scope: { studyId },
});
const handleReplayEmailChange = async event => {
setValueEmailReplay(event.target.checked ? suffix : noReplyEmail);
event.target.checked
? await setDefaultStudyEmail()
: await setNoReplyStudyEmail();
};
const handleSmsConf = async event => {
setValueSmsConf(event.target.checked);
event.target.checked
? await setSmsMessagingDefault()
: await setSmsMessagingDisable();
};
const isEmailEnabled = emailSender === suffix;
return (
<FormGroup>
<FormControlLabel
control={
<Switch checked={isEmailEnabled} onChange={handleReplayEmailChange} />
}
label={
<Typography color="textPrimary">
{intl.formatMessage(
{
defaultMessage:
'Allow candidates to reply to emails (send from {replyEmailTxt} instead of {noReplyTxt})',
},
{ replyEmailTxt: suffix, noReplyTxt: 'noReplyEmail' },
)}
</Typography>
}
/>
<FormControlLabel
control={<Switch checked={valueSmsConf} onChange={handleSmsConf} />}
label={
<Typography color="textPrimary">
{intl.formatMessage({
defaultMessage: `SMS messaging`,
})}
</Typography>
}
/>
</FormGroup>
);
};
export default StudyConfiguration;

React.js error: The service worker navigation preload request was cancelled before 'preloadResponse' settled

I have an issue with my React application (with Redux Saga), I'm getting the console error:
The service worker navigation preload request was cancelled before 'preloadResponse' settled. If you intend to use 'preloadResponse', use waitUntil() or respondWith() to wait for the promise to settle.
I see this error on the console only on Chrome, not in Firefox or Edge.
This error does not affect my application.
The following steps reproduce the error:
1. Main page upload.
2. Go to movie details page.
3. Go back to main page.
Main.jsx
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { mainActions } from '../../store/actions/actions';
import './Main.scss';
import { MoviesList, SearchPanel } from '../../components';
const propTypes = {};
const defaultProps = {};
class Main extends Component {
constructor(props) {
super(props);
this.handleSearchTextChange = this.handleSearchTextChange.bind(this);
this.handleLoadMoreButtonClick = this.handleLoadMoreButtonClick.bind(this);
this.handleMovieClick = this.handleMovieClick.bind(this);
this.handleFavoriteMovieClick = this.handleFavoriteMovieClick.bind(this);
}
componentDidMount() {
this.handleComponentDidMount();
}
handleComponentDidMount() {
const { moviesList } = this.props;
if (!moviesList || moviesList.length <= 0) {
this.getMovies(null, false);
}
}
handleLoadMoreButtonClick() {
this.getMovies(null, false);
}
handleMovieClick(e) {
if (e.target.className === 'movie') {
this.props.history.push(`/details/${e.currentTarget.dataset.id}`);
}
}
handleSearchTextChange(e) {
const { pageNumber, favoriteMoviesList } = this.props;
this.props.onSearchTextChange({
searchText: e.target.value,
pageNumber: pageNumber,
favoriteMoviesList: favoriteMoviesList
});
}
handleFavoriteMovieClick(e) {
const { id, name, posterId } = e.currentTarget.dataset;
const { moviesList, favoriteMoviesList } = this.props;
this.props.onUpdateFavoriteMovies({
updatedMovie: { id: id, name: name, posterId: posterId },
favoriteMoviesList: favoriteMoviesList,
moviesList: moviesList
});
}
getMovies(updatedSearchText, isSearchChange) {
const { searchText, pageNumber, favoriteMoviesList } = this.props;
this.props.onLoadMovies({
pageNumber: pageNumber,
favoriteMoviesList: favoriteMoviesList,
updatedSearchText: isSearchChange ? updatedSearchText : searchText,
isSearchChange: isSearchChange
});
}
render() {
const { searchText, isLoadingMoreMovies, isPager, moviesList } = this.props;
return (
<div className="main-area">
<SearchPanel
searchText={searchText}
onSearchTextChange={this.handleSearchTextChange}
/>
<MoviesList
pageName='movies'
moviesList={moviesList}
isLoadingMoreMovies={isLoadingMoreMovies}
isPager={isPager}
onLoadMoreClick={this.handleLoadMoreButtonClick}
onMovieClick={this.handleMovieClick}
onFavoriteMovieClick={this.handleFavoriteMovieClick}
/>
</div>
);
}
}
Main.propTypes = propTypes;
Main.defaultProps = defaultProps;
const mapStateToProps = (state) => {
return {
searchText: state.main.searchText,
pageNumber: state.main.pageNumber,
isLoadingMoreMovies: state.main.isLoadingMoreMovies,
isPager: state.main.isPager,
moviesList: state.main.moviesList,
favoriteMoviesList: state.main.favoriteMoviesList
};
};
const mapDispatchToProps = (dispatch) => {
return {
onLoadMovies: (request) => dispatch(mainActions.loadMovies(request)),
onSearchTextChange: (request) => dispatch(mainActions.searchTextChange(request)),
onUpdateFavoriteMovies: (request) => dispatch(mainActions.updateFavoriteMovies(request))
};
};
export default connect(mapStateToProps, mapDispatchToProps)(Main);
Details.jsx
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { detailsActions, mainActions } from '../../store/actions/actions';
import './Details.scss';
import { ActorsList, ButtonClick, CrewsList, FeaturesList, PageTitle, ProductionsList, Rating, Trailer } from '../../components';
import movieUtils from '../../utils/movie.utils';
const propTypes = {};
const defaultProps = {};
class Details extends Component {
constructor(props) {
super(props);
this.handleBackClick = this.handleBackClick.bind(this);
this.handleFavoriteMovieClick = this.handleFavoriteMovieClick.bind(this);
this.isFavorite = false;
}
componentDidMount() {
this.handleComponentDidMount();
}
handleComponentDidMount() {
if (this.props.moviesList.length <= 0) {
this.handleBackClick();
return;
}
const movieId = this.props.match.params.id;
if (!movieId) {
this.handleBackClick();
return;
}
this.props.onLoadMovieDetails(movieId);
this.updateIsFavorite(movieId);
}
numberWithCommas(number) {
return number.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ',');
}
updateIsFavorite(movieId) {
this.isFavorite = this.props.favoriteMoviesList.findIndex(movie => parseInt(movie.id) === parseInt(movieId)) > -1;
}
handleBackClick() {
this.props.history.push(`/`);
}
handleFavoriteMovieClick() {
const { movie, moviesList, favoriteMoviesList } = this.props;
this.props.onUpdateFavoriteMovies({
updatedMovie: { id: movie.id, name: movie.title, posterId: movie.poster_path },
favoriteMoviesList: favoriteMoviesList,
moviesList: moviesList
});
this.updateIsFavorite(movie.id);
}
render() {
const { movie, youtubeKey, credits } = this.props;
if (!movie) {
return null;
}
const { adult, poster_path, budget, genres, homepage, imdb_id, original_language, original_title,
overview, popularity, production_companies, production_countries, release_date, revenue, runtime, spoken_languages,
status, tagline, title, video, vote_average, vote_count } = movie;
const genresText = genres.map(genre => genre.name).join(', ');
const countriesText = production_countries.map(country => country.name).join(', ');
const languagesText = spoken_languages.map(language => language.name).join(', ');
const featuresList = [
{ item: 'Release Date', value: release_date },
{ item: 'Budget', value: `$${this.numberWithCommas(budget)}` },
{ item: 'Revenue', value: `$${this.numberWithCommas(revenue)}` },
{ item: 'Length', value: `${runtime} minutes` },
{ item: 'Popularity', value: popularity },
{ item: 'Original Title', value: original_title },
{ item: 'For Adults', value: adult ? 'Yes' : 'No' },
{ item: 'Original Language', value: original_language },
{ item: 'Spoken Languages', value: languagesText },
{ item: 'Countries', value: countriesText },
{ item: 'Status', value: status },
{ item: 'Is Video', value: video ? 'Yes' : 'No' }
];
const linksList = [];
if (homepage) {
linksList.push({ id: 1, name: 'Homepage', url: homepage });
}
if (imdb_id) {
linksList.push({ id: 2, name: 'IMDB', url: `https://www.imdb.com/title/${imdb_id}` });
}
const actorsList = movieUtils.removeDuplicates(credits ? credits.cast ? credits.cast : null : null, 'name');
const crewsList = movieUtils.removeDuplicates(credits ? credits.crew ? credits.crew : null : null, 'name');
return (
<div>
<section className="details-area">
<PageTitle
pageName='details'
pageTitle='Details'
/>
<ul className="details-content">
<li className="details-left" style={{ backgroundImage: `url('https://image.tmdb.org/t/p/original${poster_path}')` }}></li>
<li className="details-right">
<h2>{title} ({release_date.substr(0, 4)})</h2>
<p className="genres">{genresText}</p>
<p className="description short">{tagline}</p>
<Rating
rating={vote_average}
votesCount={this.numberWithCommas(vote_count)}
/>
<p className="description full">{overview}</p>
<div className="extra">
<FeaturesList
featuresList={featuresList.slice(0, 5)}
linksList={null}
isFavorite={this.isFavorite}
onFavoriteMovieClick={this.handleFavoriteMovieClick}
/>
{youtubeKey && <Trailer
youtubeKey={youtubeKey}
/>}
</div>
</li>
<div className="extra-features">
<FeaturesList
featuresList={featuresList.slice(5, featuresList.length)}
linksList={linksList}
isFavorite={null}
onFavoriteMovieClick={null}
/>
<ProductionsList
productionsList={production_companies}
/>
</div>
</ul>
</section>
<section className="actors-area">
<PageTitle
pageName='actors'
pageTitle='Cast'
/>
<ActorsList
actorsList={actorsList}
/>
</section>
<section className="crew-area">
<PageTitle
pageName='crew'
pageTitle='Crew'
/>
<CrewsList
crewsList={crewsList}
/>
</section>
<ButtonClick
buttonText={'Back'}
buttonTitle={'Back'}
isLoading={false}
onClick={this.handleBackClick}
/>
</div>
);
}
}
Details.propTypes = propTypes;
Details.defaultProps = defaultProps;
const mapStateToProps = (state) => {
return {
movie: state.details.movie,
youtubeKey: state.details.youtubeKey,
credits: state.details.credits,
moviesList: state.main.moviesList,
favoriteMoviesList: state.main.favoriteMoviesList
};
};
const mapDispatchToProps = (dispatch) => {
return {
onLoadMovieDetails: (movieId) => dispatch(detailsActions.loadDetails(movieId)),
onUpdateFavoriteMovies: (request) => dispatch(mainActions.updateFavoriteMovies(request))
};
};
export default connect(mapStateToProps, mapDispatchToProps)(Details);
What I already looked in:
Getting The service worker navigation preload request was cancelled before 'preloadResponse' settled
https://learn.microsoft.com/en-us/answers/questions/108004/getting-the-service-worker-navigation-preload-requ.html
https://support.google.com/mail/thread/4055804?hl=en
https://love2dev.com/pwa/service-worker-preload/
I tried to put this on Details.jsx page, but it didn't work:
self.addEventListener('fetch', event => {
event.respondWith(async function () {
// Respond from the cache if we can
const cachedResponse = await caches.match(event.request);
if (cachedResponse) return cachedResponse; // Else, use the preloaded response, if it's there
const response = await event.preloadResponse;
if (response) return response; // Else try the network.
return fetch(event.request);
}());
});
self.addEventListener('activate', event => {
event.waitUntil(async function () {
// Feature-detect
if (self.registration.navigationPreload) { // Enable navigation preloads!
console.log('Enable navigation preloads!');
await self.registration.navigationPreload.enable();
} return;
})();
});
How can I solve this issue? Thanks.
Had same error, even my iframe wasn't loading..whatever video you are using from youtube use nocookie/embed in url. It's working for me.
Try changing https://www.youtube.com/watch?v=i8eBBG46H8A to
https://www.youtube-nocookie.com/embed/i8eBBG46H8A
Hope nocookie & embed helps..!!

Set Dropdown Value Back to Placeholder or Very First Option After onClick Event on a Button?

In the following code, I have a Dropdown and a Button. Once you select an option in the Dropdown and click the Button, that value will be sent to Excel in the active cell. After sending this data to Excel, can I set the Dropdown back to the placeholder? Or can I set the Dropdown to the first value (which in this case is blank)? How can I set the Dropdown value back to placeholder or blank?
import * as React from "react";
import { Dropdown, DropdownMenuItemType, IDropdownOption } from 'office-ui-fabric-react/lib/Dropdown';
import { PrimaryButton } from 'office-ui-fabric-react/lib/';
export interface ParentProps {
};
export interface ParentState {
selectedItem?: { key: string | number | undefined };
operationType?;
};
export default class ParentComponent extends React.Component<ParentProps, ParentState> {
constructor(props, context) {
super(props, context);
this.state = {
operationType: '',
};
}
addToExcel = async () => {
try {
await Excel.run(async context => {
const range = context.workbook.getSelectedRange();
range.load("address");
await context.sync();
range.values = (this.state.operationType);
});
} catch (error) {
console.error(error);
}
this.setState({
})
};
render() {
const { selectedItem } = this.state;
const options: IDropdownOption[] = [
{ key: 'blank', text: '' },
{ key: 'topLevelMake', text: 'Parents', itemType: DropdownMenuItemType.Header },
{ key: 'topLevel', text: 'TOP LEVEL' },
{ key: 'make', text: 'MAKE ITEM' },
];
return (
<div>
<Dropdown
label="Operation"
selectedKey={selectedItem ? selectedItem.key : undefined}
onChange={this._onChange}
placeholder={"Select an option"}
options={options}
styles={{ dropdown: { width: 300 } }}
/>
<p></p>
<PrimaryButton
text="Enter"
onClick={this.addToExcel}
/>
</div>
);
}
private _onChange = (e, item: IDropdownOption): void => {
this.setState({ selectedItem: item });
this.setState({ operationType: item.text })
console.log(e);
}
};
Try something like this on your addToExcel():
addToExcel = async () => {
try {
await Excel.run(async context => {
const range = context.workbook.getSelectedRange();
range.load("address");
await context.sync();
range.values = (this.state.operationType);
});
} catch (error) {
console.error(error);
}
this.setState({
selectedItem: {key:'blank'},
})
};
You should update your state after your excel operations.
addToExcel = async () => {
try {
await Excel.run(async context => {
const range = context.workbook.getSelectedRange();
range.load("address");
await context.sync();
range.values = (this.state.operationType);
});
// update state after asyn operations is done
this.setState({
selectedItem:undefined
})
} catch (error) {
console.error(error);
}
};

Office UI Fabric React people picker not populating suggested drop down

When I'm using the office ui fabric react component for people picker, it's not populating the suggested people in the dropdown.
Two errors that I'm getting are
Exception in CommandButton.render(): TypeError: Cannot read property 'palette' of undefined
and
Exception in Layer.componentDidUpdate(): Exception in CommandButton.render(): TypeError: Cannot read property 'palette' of undefined
I've only been able to find this issue on github https://github.com/OfficeDev/office-ui-fabric-react/issues/1952, but there isn't much to go on. I am using office-ui-fabric-react version 4.5.1
The query is working from what I can see because I can console.log the results and it has people in there.
Here's what it looks like right now.
import * as React from 'react';
import { css,} from 'office-ui-fabric-react';
import { IReactRequestProps } from './IReactRequestProps';
import {
CompactPeoplePicker,
IBasePickerSuggestionsProps,
ListPeoplePicker,
NormalPeoplePicker
} from 'office-ui-fabric-react/lib/Pickers';
import { IPersonaProps } from 'office-ui-fabric-react/lib/Persona';
const suggestionProps: IBasePickerSuggestionsProps = {
suggestionsHeaderText: 'Suggested People',
noResultsFoundText: 'No results found',
loadingText: 'Loading'
};
import {
BaseComponent,
assign,
autobind
} from 'office-ui-fabric-react/lib//Utilities';
import { people } from './PeoplePickerExampleData';
import { Label } from 'office-ui-fabric-react/lib/Label';
import { IPeopleDataResult } from './IPeopleDataResult';
import { IPersonaWithMenu } from 'office-ui-fabric-react/lib/components/pickers/PeoplePicker/PeoplePickerItems/PeoplePickerItem.Props';
import { IContextualMenuItem } from 'office-ui-fabric-react/lib/ContextualMenu';
import { SPHttpClient, SPHttpClientResponse } from '#microsoft/sp-http';
export interface IOfficeUiFabricPeoplePickerState {
currentPicker?: number | string;
delayResults?: boolean;
}
export interface IPeopleSearchProps {
JobTitle: string;
PictureURL: string;
PreferredName: string;
}
export default class ReactRequest extends React.Component<IReactRequestProps, IOfficeUiFabricPeoplePickerState> {
private _peopleList;
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() {
super();
this._peopleList = [];
people.forEach((persona: IPersonaProps) => {
let target: IPersonaWithMenu = {};
assign(target, persona, { menuItems: this.contextualMenuItems });
this._peopleList.push(target);
});
this.state = {
currentPicker: 1,
delayResults: false
};
}
public render(): React.ReactElement<IReactRequestProps> {
if (this.props.typePicker == "Normal") {
return (
<NormalPeoplePicker
onResolveSuggestions={this._onFilterChanged}
getTextFromItem={(persona: IPersonaProps) => persona.primaryText}
pickerSuggestionsProps={suggestionProps}
className={'ms-PeoplePicker'}
key={'normal'}
/>
);
} else {
return (
<CompactPeoplePicker
onResolveSuggestions={this._onFilterChanged}
getTextFromItem={(persona: IPersonaProps) => persona.primaryText}
pickerSuggestionsProps={suggestionProps}
className={'ms-PeoplePicker'}
key={'normal'}
/>
);
}
}
#autobind
private _onFilterChanged(filterText: string, currentPersonas: IPersonaProps[], limitResults?: number) {
if (filterText) {
if (filterText.length > 2) {
return this.searchPeople(filterText, this._peopleList);
}
} else {
return [];
}
}
private searchPeople(terms: string, results: IPersonaProps[]): IPersonaProps[] | Promise<IPersonaProps[]> {
//return new Promise<IPersonaProps[]>((resolve, reject) => setTimeout(() => resolve(results), 2000));
return new Promise<IPersonaProps[]>((resolve, reject) =>
this.props.spHttpClient.get(`${this.props.siteUrl}/_api/search/query?querytext='*${terms}*'&rowlimit=10&sourceid='b09a7990-05ea-4af9-81ef-edfab16c4e31'`,
SPHttpClient.configurations.v1,
{
headers: {
'Accept': 'application/json;odata=nometadata',
'odata-version': ''
}
})
.then((response: SPHttpClientResponse): Promise<{ PrimaryQueryResult: IPeopleDataResult }> => {
return response.json();
})
.then((response: { PrimaryQueryResult: IPeopleDataResult }): void => {
let relevantResults: any = response.PrimaryQueryResult.RelevantResults;
let resultCount: number = relevantResults.TotalRows;
let people = [];
let persona: IPersonaProps = {};
console.log(relevantResults);
console.log('really relevant');
if (resultCount > 0) {
relevantResults.Table.Rows.forEach(function (row) {
row.Cells.forEach(function (cell) {
//person[cell.Key] = cell.Value;
if (cell.Key === 'JobTitle')
persona.secondaryText = cell.Value;
if (cell.Key === 'PictureURL')
persona.imageUrl = cell.Value;
if (cell.Key === 'PreferredName')
persona.primaryText = cell.Value;
});
people.push(persona);
});
}
resolve(people);
console.log(people);
console.log("PEOPLE");
}, (error: any): void => {
reject(this._peopleList = []);
}));
}
private _filterPersonasByText(filterText: string): IPersonaProps[] {
return this._peopleList.filter(item => 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<IPersonaProps[]> {
if (this.state.delayResults) {
return this._convertResultsToPromise(personasToReturn);
} else {
return personasToReturn;
}
}
private _convertResultsToPromise(results: IPersonaProps[]): Promise<IPersonaProps[]> {
return new Promise<IPersonaProps[]>((resolve, reject) => setTimeout(() => resolve(results), 2000));
}
private _doesTextStartWith(text: string, filterText: string): boolean {
return text.toLowerCase().indexOf(filterText.toLowerCase()) === 0;
}
}
i got that error when using later versions of fabric. works fine with older versions,

Cannot Find what is causing this : Warning: setState(...): Can only update a mounted or mounting component

So after looking over many different questions asking the about this warning, I have found that there is not one single reason why this would be occurring making it difficult to infer a solution on my own code.
So here is my code incase anyone has another pair of eyes they can put on it and spot maybe why i would be getting this error.
This error occurs when not on first arrival of the component but after leaving and returning to it again.
I have a smart container and a dumb component set up so here is the container:
import React, { PropTypes } from 'react';
import { connect } from 'react-redux';
import { listOrders, listUseCases } from '../../actions/order';
import { storeWithExpiration } from '../../utils/common.js';
import OrdersIndex from './OrdersIndex';
export class OrdersIndexContainer extends React.Component {
static propTypes = {
account: PropTypes.object.isRequired,
orders: PropTypes.object.isRequired,
platformMap: PropTypes.object.isRequired,
progress: PropTypes.number,
listOrdersAction: PropTypes.func.isRequired,
listUseCasesAction: PropTypes.func.isRequired,
};
render() {
const { orders, platformMap, progress } = this.props;
return (
<div>
<OrdersIndex
orders={ orders }
platformMap={ platformMap }
progress={ progress }
/>
</div>
);
}
renderOrderIndex = () => {
}
componentWillMount = () => {
const { account, listOrdersAction, listUseCasesAction } = this.props;
const token = storeWithExpiration.get('token');
listOrdersAction(token);
listUseCasesAction(account.id, token);
}
}
function mapStateToProps(state) {
const { account, orderList, progress } = state;
const orders = orderList.get('orders');
const platformMap = orderList.get('platformMap');
return { account, platformMap, orders, progress };
}
export default connect(mapStateToProps, {
listOrdersAction: listOrders,
listUseCasesAction: listUseCases,
})(OrdersIndexContainer);
And here is the dumb component:
import React, { PropTypes } from 'react';
import { Link } from 'react-router';
import ReactDataGrid from 'react-data-grid';
import { Toolbar } from 'react-data-grid/addons';
import { Data } from 'react-data-grid/addons';
import moment from 'moment';
import { SIMPLE_DATE_FORMAT } from '../../config/app_config';
// import OrderWrapFormatter from './OrderWrapFormatter';
const TABLE_COLUMNS = [
{ key: 'cNumber', name: 'Customer #', width: 125 },
{ key: 'name', name: 'Name', width: 150 },
{ key: 'orderNumber', name: 'Order #', width: 90 },
{ key: 'platform', name: 'Platform' },
{ key: 'useCase', name: 'Use Case'/* , formatter: OrderWrapFormatter */ },
{ key: 'list', name: 'List' },
{ key: 'sku', name: 'SKU' },
{ key: 'startDate', name: 'Start Date' },
{ key: 'endDate', name: 'End Date' },
];
export default class OrdersIndex extends React.Component {
static propTypes = {
orders: PropTypes.object.isRequired,
platformMap: PropTypes.object.isRequired,
progress: PropTypes.number,
};
state = {
rows: [],
originalRows: [],
columns: TABLE_COLUMNS,
sortColumn: null,
sortDirection: null,
filters: {},
}
renderRows = (orders) => {
const _rows = [];
orders.map((o) => {
_rows.push({
key: o.order.id,
id: o.order.id,
cNumber: o.order.providerCustomerNumber,
name: o.order.company.name,
orderNumber: o.order.providerOrderNumber,
platform: o.platformUseCases[0].platform.description,
useCase: this.renderMulti(o.platformUseCases, 'useCase', 'description'),
list: this.renderMulti(o.listSKUs, 'dataSet', 'name'),
sku: this.renderMulti(o.listSKUs, 'fieldSet', 'name'),
startDate: moment(o.order.startDate).format(SIMPLE_DATE_FORMAT),
endDate: moment(o.order.endDate).format(SIMPLE_DATE_FORMAT),
});
return _rows;
});
return this.setState({
rows: _rows,
originalRows: _rows.slice(),
});
}
getRows = () => {
return Data.Selectors.getRows(this.state);
}
rowGetter = (rowIdx) => {
const rows = this.getRows();
return rows[rowIdx];
}
getSize = () => {
return this.getRows().length;
}
renderMulti = (multi, itemName, subItemName) => {
const objectArray = multi.map((object) => {
return object[itemName][subItemName];
});
return objectArray.join('\n');
}
handleGridSort = (sortColumn, sortDirection) => {
const { originalRows, rows } = this.state;
const comparer = (a, b) => {
if (sortDirection === 'ASC') {
return (a[sortColumn] > b[sortColumn]) ? 1 : -1;
}
else if (sortDirection === 'DESC') {
return (a[sortColumn] < b[sortColumn]) ? 1 : -1;
}
};
const newRows = sortDirection === 'NONE' ? originalRows.slice() : rows.sort(comparer);
this.setState({
rows: newRows,
});
}
handleRowUpdated = (e) => {
// merge updated row with current row and rerender by setting state
const { rows } = this.state;
Object.assign(rows[e.rowIdx], e.updated);
this.setState({
...rows,
});
}
handleFilterChange = (filter) => {
const { filters } = this.state;
const newFilters = Object.assign({}, filters);
if (filter.filterTerm) {
newFilters[filter.column.key] = filter;
}
else {
delete newFilters[filter.column.key];
}
this.setState({
filters: newFilters,
});
}
onClearFilters = () => {
// all filters removed
this.setState({
filters: {},
});
}
// Creates appropriate warnings to prevent entering
// the order form if the account is missing information
renderNotice = (message, buttonMessage, route) => {
return (
<div className="alert alert-warning">
<strong>Notice:</strong>
<p>{ message }</p>
<p>
<Link
to={ route }
className="btn btn-warning"
>
<i className='fa fa-plus'></i>
{ buttonMessage }
</Link>
</p>
</div>
);
}
render() {
const { platformMap, progress } = this.props;
const platformMessage = 'Your account is not associated with any platform use cases.' +
'You must select at least one use case before creating new orders.';
const platformButton = 'Add Use Cases';
const platformRoute = '/products';
return (
<div className="container">
<div className="row">
<div className="col-sm-12 col-md-8">
<h1>Orders</h1>
</div>
<div className="col-sm-12 col-md-4">
<span className="pull-right">
<Link
to="/orders/create/1"
className="btn btn-primary"
disabled
>
<i className='fa fa-plus'></i>Create New Order
</Link>
</span>
</div>
</div>
{ platformMap.size === 0 && progress === 0 ?
this.renderNotice(platformMessage, platformButton, platformRoute) : null }
<div className="row">
{ progress === 0 ?
<div className="col-md-12">
{ this.renderTable() }
</div> : null }
</div>
</div>
);
}
renderTable = () => {
const { orders } = this.props;
const { columns } = this.state;
return (
<div>
{ orders.size === 0 || orders === undefined ?
<p>Your account has no orders</p> :
<ReactDataGrid
onGridSort={ this.handleGridSort }
rowKey="key"
id="key"
columns={ columns }
rowGetter={ this.rowGetter }
rowsCount={ this.getSize() }
onRowUpdated={ this.handleRowUpdated }
toolbar={ <Toolbar enableFilter /> }
onAddFilter={ this.handleFilterChange }
onClearFilters={ this.onClearFilters }
minHeight={ 500 }
filterRowsButtonText="Search By Field"
/>
}
</div>
);
}
componentWillMount = () => {
const { orders } = this.props;
const columnArray =
TABLE_COLUMNS.map((c) => {
const copy = Object.assign({}, c);
copy.filterable = true;
copy.locked = true;
if (copy.key !== 'useCase') {
copy.sortable = true;
}
return copy;
});
this.setState({
columns: columnArray,
});
this.renderRows(orders);
}
componentWillReceiveProps = (nextProps) => {
const { orders } = nextProps;
if (orders.size > 0) {
this.renderRows(orders);
}
}
}
I understand this might be a lot but I cannot for the life of me determine what could be the cause. Thanks to anyone who takes a look.

Resources