Avoid possible reading of length property on undefined (#2783)
This commit is contained in:
parent
1d6dccf0a5
commit
45e5bae8da
28 changed files with 99 additions and 12 deletions
|
|
@ -185,7 +185,7 @@ export function loadPostsIfNecessaryWithRetry(channelId) {
|
|||
// Get the first page of posts if it appears we haven't gotten it yet, like the webapp
|
||||
received = await retryGetPostsAction(getPosts(channelId), dispatch, getState);
|
||||
|
||||
if (received) {
|
||||
if (received?.order) {
|
||||
const count = received.order.length;
|
||||
loadMorePostsVisible = count >= ViewTypes.POST_VISIBILITY_CHUNK_SIZE;
|
||||
actions.push({
|
||||
|
|
@ -213,7 +213,7 @@ export function loadPostsIfNecessaryWithRetry(channelId) {
|
|||
|
||||
received = await retryGetPostsAction(getPostsSince(channelId, since), dispatch, getState);
|
||||
|
||||
if (received) {
|
||||
if (received?.order) {
|
||||
const count = received.order.length;
|
||||
loadMorePostsVisible = postsIds.length + count >= ViewTypes.POST_VISIBILITY_CHUNK_SIZE;
|
||||
actions.push({
|
||||
|
|
@ -621,7 +621,7 @@ export function increasePostVisibility(channelId, postId) {
|
|||
}];
|
||||
|
||||
let hasMorePost = false;
|
||||
if (result) {
|
||||
if (result?.order) {
|
||||
const count = result.order.length;
|
||||
hasMorePost = count >= pageSize;
|
||||
|
||||
|
|
|
|||
|
|
@ -41,6 +41,7 @@ export default class AtMention extends PureComponent {
|
|||
defaultChannel: {},
|
||||
isSearch: false,
|
||||
value: '',
|
||||
inChannel: [],
|
||||
};
|
||||
|
||||
constructor(props) {
|
||||
|
|
|
|||
|
|
@ -24,6 +24,11 @@ export default class AtMentionItem extends PureComponent {
|
|||
theme: PropTypes.object.isRequired,
|
||||
};
|
||||
|
||||
static defaultProps = {
|
||||
firstName: '',
|
||||
lastName: '',
|
||||
};
|
||||
|
||||
completeMention = () => {
|
||||
const {onPress, username} = this.props;
|
||||
onPress(username);
|
||||
|
|
|
|||
|
|
@ -44,6 +44,11 @@ export default class ChannelMention extends PureComponent {
|
|||
static defaultProps = {
|
||||
isSearch: false,
|
||||
value: '',
|
||||
publicChannels: [],
|
||||
privateChannels: [],
|
||||
directAndGroupMessages: [],
|
||||
myChannels: [],
|
||||
otherChannels: [],
|
||||
};
|
||||
|
||||
constructor(props) {
|
||||
|
|
|
|||
|
|
@ -29,6 +29,10 @@ class ChannelIntro extends PureComponent {
|
|||
theme: PropTypes.object.isRequired,
|
||||
};
|
||||
|
||||
static defaultProps = {
|
||||
currentChannelMembers: [],
|
||||
};
|
||||
|
||||
goToUserProfile = (userId) => {
|
||||
const {intl, navigator, theme} = this.props;
|
||||
const options = {
|
||||
|
|
|
|||
|
|
@ -61,6 +61,10 @@ export default class LastUsers extends React.PureComponent {
|
|||
usernames: PropTypes.array.isRequired,
|
||||
};
|
||||
|
||||
static defaultProps = {
|
||||
usernames: [],
|
||||
};
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
|
|
|
|||
|
|
@ -27,6 +27,10 @@ export default class FileUploadPreview extends PureComponent {
|
|||
theme: PropTypes.object.isRequired,
|
||||
};
|
||||
|
||||
static defaultProps = {
|
||||
files: [],
|
||||
};
|
||||
|
||||
buildFilePreviews = () => {
|
||||
return this.props.files.map((file) => {
|
||||
return (
|
||||
|
|
|
|||
|
|
@ -36,6 +36,10 @@ export default class PostAddChannelMember extends React.PureComponent {
|
|||
textStyles: PropTypes.object,
|
||||
};
|
||||
|
||||
static defaultProps = {
|
||||
usernames: [],
|
||||
};
|
||||
|
||||
static contextTypes = {
|
||||
intl: intlShape,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -77,6 +77,7 @@ export default class PostBody extends PureComponent {
|
|||
onFailedPostPress: emptyFunction,
|
||||
onPress: emptyFunction,
|
||||
replyBarStyle: [],
|
||||
message: '',
|
||||
};
|
||||
|
||||
static contextTypes = {
|
||||
|
|
|
|||
|
|
@ -74,6 +74,7 @@ export default class PostList extends PureComponent {
|
|||
refreshing: false,
|
||||
serverURL: '',
|
||||
siteURL: '',
|
||||
postIds: [],
|
||||
};
|
||||
|
||||
constructor(props) {
|
||||
|
|
|
|||
|
|
@ -19,6 +19,10 @@ export default class Typing extends PureComponent {
|
|||
typing: PropTypes.array.isRequired,
|
||||
};
|
||||
|
||||
static defaultProps = {
|
||||
typing: [],
|
||||
};
|
||||
|
||||
state = {
|
||||
typingHeight: new Animated.Value(0),
|
||||
}
|
||||
|
|
|
|||
|
|
@ -44,6 +44,7 @@ export default class List extends PureComponent {
|
|||
|
||||
static contextTypes = {
|
||||
intl: intlShape,
|
||||
unreadChannelIds: [],
|
||||
};
|
||||
|
||||
constructor(props) {
|
||||
|
|
|
|||
|
|
@ -14,6 +14,10 @@ export default class ToolTip extends PureComponent {
|
|||
actions: PropTypes.array.isRequired,
|
||||
};
|
||||
|
||||
static defaultProps = {
|
||||
actions: [],
|
||||
}
|
||||
|
||||
handleHide = () => {
|
||||
if (this.props.onHide) {
|
||||
this.props.onHide();
|
||||
|
|
|
|||
|
|
@ -29,10 +29,12 @@ const handleRedirectProtocol = (url, response) => {
|
|||
const serverUrl = Client4.getUrl();
|
||||
const parsed = urlParse(url);
|
||||
const {redirects} = response.rnfbRespInfo;
|
||||
const redirectUrl = urlParse(redirects[redirects.length - 1]);
|
||||
if (redirects) {
|
||||
const redirectUrl = urlParse(redirects[redirects.length - 1]);
|
||||
|
||||
if (serverUrl === parsed.origin && parsed.host === redirectUrl.host && parsed.protocol !== redirectUrl.protocol) {
|
||||
Client4.setUrl(serverUrl.replace(parsed.protocol, redirectUrl.protocol));
|
||||
if (serverUrl === parsed.origin && parsed.host === redirectUrl.host && parsed.protocol !== redirectUrl.protocol) {
|
||||
Client4.setUrl(serverUrl.replace(parsed.protocol, redirectUrl.protocol));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -55,6 +55,10 @@ export default class ImagePreview extends PureComponent {
|
|||
theme: PropTypes.object.isRequired,
|
||||
};
|
||||
|
||||
static defaultProps = {
|
||||
files: [],
|
||||
};
|
||||
|
||||
static contextTypes = {
|
||||
intl: intlShape,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -38,6 +38,10 @@ export default class MoreChannels extends PureComponent {
|
|||
theme: PropTypes.object.isRequired,
|
||||
};
|
||||
|
||||
static defaultProps = {
|
||||
channels: [],
|
||||
};
|
||||
|
||||
static contextTypes = {
|
||||
intl: intlShape.isRequired,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -21,6 +21,10 @@ export default class OptionsModalList extends PureComponent {
|
|||
onItemPress: PropTypes.func,
|
||||
};
|
||||
|
||||
static defaultProps = {
|
||||
items: [],
|
||||
};
|
||||
|
||||
handleCancelPress = preventDoubleTap(() => {
|
||||
if (this.props.onCancelPress) {
|
||||
this.props.onCancelPress();
|
||||
|
|
|
|||
|
|
@ -25,6 +25,10 @@ export default class OptionsModalList extends PureComponent {
|
|||
]),
|
||||
};
|
||||
|
||||
static defaultProps = {
|
||||
items: [],
|
||||
};
|
||||
|
||||
handleCancelPress = preventDoubleTap(() => {
|
||||
if (this.props.onCancelPress) {
|
||||
this.props.onCancelPress();
|
||||
|
|
|
|||
|
|
@ -35,6 +35,10 @@ export default class ReactionList extends PureComponent {
|
|||
userProfiles: PropTypes.array,
|
||||
};
|
||||
|
||||
static defaultProps = {
|
||||
userProfiles: [],
|
||||
};
|
||||
|
||||
static contextTypes = {
|
||||
intl: intlShape.isRequired,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -53,6 +53,10 @@ export default class SelectTeam extends PureComponent {
|
|||
teamsRequest: PropTypes.object.isRequired,
|
||||
};
|
||||
|
||||
static defaultProps = {
|
||||
teams: [],
|
||||
};
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
props.navigator.setOnNavigatorEvent(this.onNavigatorEvent);
|
||||
|
|
|
|||
|
|
@ -38,6 +38,11 @@ class Settings extends PureComponent {
|
|||
theme: PropTypes.object,
|
||||
};
|
||||
|
||||
static defaultProps = {
|
||||
errors: [],
|
||||
joinableTeams: [],
|
||||
};
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.props.navigator.setOnNavigatorEvent(this.onNavigatorEvent);
|
||||
|
|
|
|||
|
|
@ -17,6 +17,10 @@ export default class NotificationSettingsMentionsBase extends PureComponent {
|
|||
theme: PropTypes.object.isRequired,
|
||||
};
|
||||
|
||||
static defaultProps = {
|
||||
currentUser: {},
|
||||
};
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
|
|
|
|||
|
|
@ -284,7 +284,7 @@ class NotificationSettingsMentionsAndroid extends NotificationSettingsMentionsBa
|
|||
style={style.scrollView}
|
||||
contentContainerStyle={style.scrollViewContent}
|
||||
>
|
||||
{currentUser.first_name.length > 0 &&
|
||||
{currentUser.first_name?.length > 0 &&
|
||||
<View>
|
||||
<SectionItem
|
||||
label={(
|
||||
|
|
|
|||
|
|
@ -62,7 +62,7 @@ class NotificationSettingsMentionsIos extends NotificationSettingsMentionsBase {
|
|||
headerDefaultMessage='WORDS THAT TRIGGER MENTIONS'
|
||||
theme={theme}
|
||||
>
|
||||
{currentUser.first_name.length > 0 &&
|
||||
{currentUser.first_name?.length > 0 &&
|
||||
<View>
|
||||
<SectionItem
|
||||
label={(
|
||||
|
|
|
|||
|
|
@ -37,6 +37,10 @@ export default class Thread extends PureComponent {
|
|||
threadLoadingStatus: PropTypes.object,
|
||||
};
|
||||
|
||||
static defaultProps = {
|
||||
postIds: [],
|
||||
};
|
||||
|
||||
state = {};
|
||||
|
||||
static contextTypes = {
|
||||
|
|
|
|||
|
|
@ -36,6 +36,10 @@ export default class Timezone extends PureComponent {
|
|||
}).isRequired,
|
||||
};
|
||||
|
||||
static defaultProps = {
|
||||
timezones: [],
|
||||
};
|
||||
|
||||
static contextTypes = {
|
||||
intl: intlShape,
|
||||
};
|
||||
|
|
@ -71,7 +75,7 @@ export default class Timezone extends PureComponent {
|
|||
return;
|
||||
}
|
||||
|
||||
if (manualTimezone.length > 0) {
|
||||
if (manualTimezone?.length > 0) {
|
||||
// Preserve state change in server if manualTimezone exists
|
||||
this.submitUser({
|
||||
useAutomaticTimezone,
|
||||
|
|
|
|||
|
|
@ -228,17 +228,17 @@ export function cleanUpState(action, keepCurrent = false) {
|
|||
nextEntities.posts.postsInChannel = cleanUpPostsInChannel(payload.entities.posts.postsInChannel, lastChannelForTeam, keepCurrent ? currentChannelId : '');
|
||||
postIdsToKeep.push(...getAllFromPostsInChannel(nextEntities.posts.postsInChannel));
|
||||
|
||||
// Keep any posts that appear in search resutls
|
||||
// Keep any posts that appear in search results
|
||||
let searchResults = [];
|
||||
let flaggedPosts = [];
|
||||
if (payload.entities.search) {
|
||||
if (payload.entities.search.results.length) {
|
||||
if (payload.entities.search.results?.length) {
|
||||
const {results} = payload.entities.search;
|
||||
searchResults = results;
|
||||
postIdsToKeep.push(...results);
|
||||
}
|
||||
|
||||
if (payload.entities.search.flagged.length) {
|
||||
if (payload.entities.search.flagged?.length) {
|
||||
const {flagged} = payload.entities.search;
|
||||
flaggedPosts = flagged;
|
||||
postIdsToKeep.push(...flagged);
|
||||
|
|
|
|||
|
|
@ -86,6 +86,10 @@ describe('cleanUpState', () => {
|
|||
postsInThread: {},
|
||||
reactions: {},
|
||||
},
|
||||
search: {
|
||||
results: ['post1', 'post2'],
|
||||
flagged: ['post1', 'post2', 'post3'],
|
||||
},
|
||||
},
|
||||
views: {
|
||||
team: {
|
||||
|
|
@ -101,6 +105,8 @@ describe('cleanUpState', () => {
|
|||
expect(result.payload.entities.posts.posts.post1).toBeDefined();
|
||||
expect(result.payload.entities.posts.posts.post2).toBeUndefined();
|
||||
expect(result.payload.entities.posts.postsInChannel.channel1).toEqual([{order: ['post1'], recent: true}]);
|
||||
expect(result.payload.entities.search.results).toEqual(['post1', 'post2']);
|
||||
expect(result.payload.entities.search.flagged).toEqual(['post1', 'post2', 'post3']);
|
||||
});
|
||||
|
||||
test('should keep failed pending post', () => {
|
||||
|
|
|
|||
Loading…
Reference in a new issue