Fix for LHS populating you next to current user (#2263)

* Fix for LHS populating you next to current user

* Add test cases
 * Refactor to use avaiable props conditions in component
   instead of passing flags from connector
This commit is contained in:
Sudheer 2018-10-15 21:00:11 +05:30 committed by GitHub
parent 0bc824150e
commit 1b54e1ebe3
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 642 additions and 153 deletions

View file

@ -94,14 +94,356 @@ exports[`ChannelItem should match snapshot 1`] = `
},
]
}
/>
>
display_name
</Component>
</Component>
</Component>
</TouchableHighlight>
</AnimatedComponent>
`;
exports[`ChannelItem should match snapshot for deactivated user 1`] = `null`;
exports[`ChannelItem should match snapshot for current user i.e currentUser (you) 1`] = `
<AnimatedComponent>
<TouchableHighlight
activeOpacity={0.85}
delayPressOut={100}
onLongPress={[Function]}
onPress={[Function]}
underlayColor="rgba(69,120,191,0.5)"
>
<Component
style={
Array [
Object {
"flex": 1,
"flexDirection": "row",
"height": 44,
},
undefined,
]
}
>
<Component
style={
Object {
"backgroundColor": "#579eff",
"width": 5,
}
}
/>
<Component
style={
Array [
Object {
"alignItems": "center",
"flex": 1,
"flexDirection": "row",
"paddingLeft": 16,
},
Object {
"backgroundColor": "rgba(255,255,255,0.1)",
"paddingLeft": 11,
},
]
}
>
<ChannelIcon
channelId="channel_id"
hasDraft={false}
isActive={true}
isArchived={false}
isInfo={false}
isUnread={true}
membersCount={1}
size={16}
status="online"
theme={
Object {
"awayIndicator": "#ffbc42",
"buttonBg": "#166de0",
"buttonColor": "#ffffff",
"centerChannelBg": "#ffffff",
"centerChannelColor": "#3d3c40",
"codeTheme": "github",
"dndIndicator": "#f74343",
"errorTextColor": "#fd5960",
"linkColor": "#2389d7",
"mentionBj": "#ffffff",
"mentionColor": "#145dbf",
"mentionHighlightBg": "#ffe577",
"mentionHighlightLink": "#166de0",
"newMessageSeparator": "#ff8800",
"onlineIndicator": "#06d6a0",
"sidebarBg": "#145dbf",
"sidebarHeaderBg": "#1153ab",
"sidebarHeaderTextColor": "#ffffff",
"sidebarText": "#ffffff",
"sidebarTextActiveBorder": "#579eff",
"sidebarTextActiveColor": "#ffffff",
"sidebarTextHoverBg": "#4578bf",
"sidebarUnreadText": "#ffffff",
"type": "Mattermost",
}
}
type="D"
/>
<Component
ellipsizeMode="tail"
numberOfLines={1}
style={
Array [
Object {
"color": "rgba(255,255,255,0.4)",
"flex": 1,
"fontSize": 14,
"fontWeight": "600",
"height": "100%",
"lineHeight": 44,
"paddingRight": 40,
"textAlignVertical": "center",
},
Object {
"color": "#ffffff",
},
]
}
>
{displayName} (you)
</Component>
</Component>
</Component>
</TouchableHighlight>
</AnimatedComponent>
`;
exports[`ChannelItem should match snapshot for current user i.e currentUser (you) when isSearchResult 1`] = `
<AnimatedComponent>
<TouchableHighlight
activeOpacity={0.85}
delayPressOut={100}
onLongPress={[Function]}
onPress={[Function]}
underlayColor="rgba(69,120,191,0.5)"
>
<Component
style={
Array [
Object {
"flex": 1,
"flexDirection": "row",
"height": 44,
},
undefined,
]
}
>
<Component
style={
Object {
"backgroundColor": "#579eff",
"width": 5,
}
}
/>
<Component
style={
Array [
Object {
"alignItems": "center",
"flex": 1,
"flexDirection": "row",
"paddingLeft": 16,
},
Object {
"backgroundColor": "rgba(255,255,255,0.1)",
"paddingLeft": 11,
},
]
}
>
<ChannelIcon
channelId="channel_id"
hasDraft={false}
isActive={true}
isArchived={false}
isInfo={false}
isUnread={true}
membersCount={1}
size={16}
status="online"
theme={
Object {
"awayIndicator": "#ffbc42",
"buttonBg": "#166de0",
"buttonColor": "#ffffff",
"centerChannelBg": "#ffffff",
"centerChannelColor": "#3d3c40",
"codeTheme": "github",
"dndIndicator": "#f74343",
"errorTextColor": "#fd5960",
"linkColor": "#2389d7",
"mentionBj": "#ffffff",
"mentionColor": "#145dbf",
"mentionHighlightBg": "#ffe577",
"mentionHighlightLink": "#166de0",
"newMessageSeparator": "#ff8800",
"onlineIndicator": "#06d6a0",
"sidebarBg": "#145dbf",
"sidebarHeaderBg": "#1153ab",
"sidebarHeaderTextColor": "#ffffff",
"sidebarText": "#ffffff",
"sidebarTextActiveBorder": "#579eff",
"sidebarTextActiveColor": "#ffffff",
"sidebarTextHoverBg": "#4578bf",
"sidebarUnreadText": "#ffffff",
"type": "Mattermost",
}
}
type="D"
/>
<Component
ellipsizeMode="tail"
numberOfLines={1}
style={
Array [
Object {
"color": "rgba(255,255,255,0.4)",
"flex": 1,
"fontSize": 14,
"fontWeight": "600",
"height": "100%",
"lineHeight": 44,
"paddingRight": 40,
"textAlignVertical": "center",
},
Object {
"color": "#ffffff",
},
]
}
>
{displayName} (you)
</Component>
</Component>
</Component>
</TouchableHighlight>
</AnimatedComponent>
`;
exports[`ChannelItem should match snapshot for deactivated user and is currentChannel 1`] = `
<AnimatedComponent>
<TouchableHighlight
activeOpacity={0.85}
delayPressOut={100}
onLongPress={[Function]}
onPress={[Function]}
underlayColor="rgba(69,120,191,0.5)"
>
<Component
style={
Array [
Object {
"flex": 1,
"flexDirection": "row",
"height": 44,
},
undefined,
]
}
>
<Component
style={
Object {
"backgroundColor": "#579eff",
"width": 5,
}
}
/>
<Component
style={
Array [
Object {
"alignItems": "center",
"flex": 1,
"flexDirection": "row",
"paddingLeft": 16,
},
Object {
"backgroundColor": "rgba(255,255,255,0.1)",
"paddingLeft": 11,
},
]
}
>
<ChannelIcon
channelId="channel_id"
hasDraft={false}
isActive={true}
isArchived={true}
isInfo={false}
isUnread={true}
membersCount={1}
size={16}
status="online"
theme={
Object {
"awayIndicator": "#ffbc42",
"buttonBg": "#166de0",
"buttonColor": "#ffffff",
"centerChannelBg": "#ffffff",
"centerChannelColor": "#3d3c40",
"codeTheme": "github",
"dndIndicator": "#f74343",
"errorTextColor": "#fd5960",
"linkColor": "#2389d7",
"mentionBj": "#ffffff",
"mentionColor": "#145dbf",
"mentionHighlightBg": "#ffe577",
"mentionHighlightLink": "#166de0",
"newMessageSeparator": "#ff8800",
"onlineIndicator": "#06d6a0",
"sidebarBg": "#145dbf",
"sidebarHeaderBg": "#1153ab",
"sidebarHeaderTextColor": "#ffffff",
"sidebarText": "#ffffff",
"sidebarTextActiveBorder": "#579eff",
"sidebarTextActiveColor": "#ffffff",
"sidebarTextHoverBg": "#4578bf",
"sidebarUnreadText": "#ffffff",
"type": "Mattermost",
}
}
type="D"
/>
<Component
ellipsizeMode="tail"
numberOfLines={1}
style={
Array [
Object {
"color": "rgba(255,255,255,0.4)",
"flex": 1,
"fontSize": 14,
"fontWeight": "600",
"height": "100%",
"lineHeight": 44,
"paddingRight": 40,
"textAlignVertical": "center",
},
Object {
"color": "#ffffff",
},
]
}
>
display_name
</Component>
</Component>
</Component>
</TouchableHighlight>
</AnimatedComponent>
`;
exports[`ChannelItem should match snapshot for deactivated user and is searchResult 1`] = `
<AnimatedComponent>
@ -197,126 +539,20 @@ exports[`ChannelItem should match snapshot for deactivated user and is searchRes
},
]
}
/>
>
display_name
</Component>
</Component>
</Component>
</TouchableHighlight>
</AnimatedComponent>
`;
exports[`ChannelItem should match snapshot if channel is archived 1`] = `null`;
exports[`ChannelItem should match snapshot for deactivated user and not searchResults or currentChannel 1`] = `null`;
exports[`ChannelItem should match snapshot if channel is archived and is currentChannel 1`] = `
<AnimatedComponent>
<TouchableHighlight
activeOpacity={0.85}
delayPressOut={100}
onLongPress={[Function]}
onPress={[Function]}
underlayColor="rgba(69,120,191,0.5)"
>
<Component
style={
Array [
Object {
"flex": 1,
"flexDirection": "row",
"height": 44,
},
undefined,
]
}
>
<Component
style={
Object {
"backgroundColor": "#579eff",
"width": 5,
}
}
/>
<Component
style={
Array [
Object {
"alignItems": "center",
"flex": 1,
"flexDirection": "row",
"paddingLeft": 16,
},
Object {
"backgroundColor": "rgba(255,255,255,0.1)",
"paddingLeft": 11,
},
]
}
>
<ChannelIcon
channelId="channel_id"
hasDraft={false}
isActive={true}
isArchived={true}
isInfo={false}
isUnread={true}
membersCount={1}
size={16}
status="online"
theme={
Object {
"awayIndicator": "#ffbc42",
"buttonBg": "#166de0",
"buttonColor": "#ffffff",
"centerChannelBg": "#ffffff",
"centerChannelColor": "#3d3c40",
"codeTheme": "github",
"dndIndicator": "#f74343",
"errorTextColor": "#fd5960",
"linkColor": "#2389d7",
"mentionBj": "#ffffff",
"mentionColor": "#145dbf",
"mentionHighlightBg": "#ffe577",
"mentionHighlightLink": "#166de0",
"newMessageSeparator": "#ff8800",
"onlineIndicator": "#06d6a0",
"sidebarBg": "#145dbf",
"sidebarHeaderBg": "#1153ab",
"sidebarHeaderTextColor": "#ffffff",
"sidebarText": "#ffffff",
"sidebarTextActiveBorder": "#579eff",
"sidebarTextActiveColor": "#ffffff",
"sidebarTextHoverBg": "#4578bf",
"sidebarUnreadText": "#ffffff",
"type": "Mattermost",
}
}
type="O"
/>
<Component
ellipsizeMode="tail"
numberOfLines={1}
style={
Array [
Object {
"color": "rgba(255,255,255,0.4)",
"flex": 1,
"fontSize": 14,
"fontWeight": "600",
"height": "100%",
"lineHeight": 44,
"paddingRight": 40,
"textAlignVertical": "center",
},
Object {
"color": "#ffffff",
},
]
}
/>
</Component>
</Component>
</TouchableHighlight>
</AnimatedComponent>
`;
exports[`ChannelItem should match snapshot for no displayName 1`] = `null`;
exports[`ChannelItem should match snapshot for showUnreadForMsgs 1`] = `null`;
exports[`ChannelItem should match snapshot with draft 1`] = `
<AnimatedComponent>
@ -412,6 +648,137 @@ exports[`ChannelItem should match snapshot with draft 1`] = `
},
]
}
>
display_name
</Component>
</Component>
</Component>
</TouchableHighlight>
</AnimatedComponent>
`;
exports[`ChannelItem should match snapshot with mentions and muted 1`] = `
<AnimatedComponent>
<TouchableHighlight
activeOpacity={0.85}
delayPressOut={100}
onLongPress={[Function]}
onPress={[Function]}
underlayColor="rgba(69,120,191,0.5)"
>
<Component
style={
Array [
Object {
"flex": 1,
"flexDirection": "row",
"height": 44,
},
Object {
"opacity": 0.5,
},
]
}
>
<Component
style={
Array [
Object {
"alignItems": "center",
"flex": 1,
"flexDirection": "row",
"paddingLeft": 16,
},
undefined,
]
}
>
<ChannelIcon
channelId="channel_id"
hasDraft={false}
isActive={false}
isArchived={false}
isInfo={false}
isUnread={true}
membersCount={1}
size={16}
status="online"
theme={
Object {
"awayIndicator": "#ffbc42",
"buttonBg": "#166de0",
"buttonColor": "#ffffff",
"centerChannelBg": "#ffffff",
"centerChannelColor": "#3d3c40",
"codeTheme": "github",
"dndIndicator": "#f74343",
"errorTextColor": "#fd5960",
"linkColor": "#2389d7",
"mentionBj": "#ffffff",
"mentionColor": "#145dbf",
"mentionHighlightBg": "#ffe577",
"mentionHighlightLink": "#166de0",
"newMessageSeparator": "#ff8800",
"onlineIndicator": "#06d6a0",
"sidebarBg": "#145dbf",
"sidebarHeaderBg": "#1153ab",
"sidebarHeaderTextColor": "#ffffff",
"sidebarText": "#ffffff",
"sidebarTextActiveBorder": "#579eff",
"sidebarTextActiveColor": "#ffffff",
"sidebarTextHoverBg": "#4578bf",
"sidebarUnreadText": "#ffffff",
"type": "Mattermost",
}
}
type="O"
/>
<Component
ellipsizeMode="tail"
numberOfLines={1}
style={
Array [
Object {
"color": "rgba(255,255,255,0.4)",
"flex": 1,
"fontSize": 14,
"fontWeight": "600",
"height": "100%",
"lineHeight": 44,
"paddingRight": 40,
"textAlignVertical": "center",
},
Object {
"color": "#ffffff",
},
]
}
>
display_name
</Component>
<Badge
count={1}
countStyle={
Object {
"color": "#145dbf",
"fontSize": 10,
}
}
extraPaddingHorizontal={10}
minHeight={20}
minWidth={20}
onPress={[Function]}
style={
Object {
"backgroundColor": undefined,
"borderColor": "#1153ab",
"borderRadius": 10,
"borderWidth": 1,
"padding": 3,
"position": "relative",
"right": 16,
}
}
/>
</Component>
</Component>

View file

@ -2,6 +2,8 @@
// See LICENSE.txt for license information.
import React, {PureComponent} from 'react';
import {General} from 'mattermost-redux/constants';
import PropTypes from 'prop-types';
import {
Animated,
@ -22,11 +24,11 @@ const {View: AnimatedView} = Animated;
export default class ChannelItem extends PureComponent {
static propTypes = {
channelId: PropTypes.string.isRequired,
channel: PropTypes.object,
currentChannelId: PropTypes.string.isRequired,
displayName: PropTypes.string.isRequired,
fake: PropTypes.bool,
isChannelMuted: PropTypes.bool,
isMyUser: PropTypes.bool,
currentUserId: PropTypes.string.isRequired,
isUnread: PropTypes.bool,
hasDraft: PropTypes.bool,
mentions: PropTypes.number.isRequired,
@ -34,11 +36,8 @@ export default class ChannelItem extends PureComponent {
onSelectChannel: PropTypes.func.isRequired,
shouldHideChannel: PropTypes.bool,
showUnreadForMsgs: PropTypes.bool.isRequired,
status: PropTypes.string,
type: PropTypes.string.isRequired,
theme: PropTypes.object.isRequired,
unreadMsgs: PropTypes.number.isRequired,
isArchived: PropTypes.bool.isRequired,
isSearchResult: PropTypes.bool,
};
@ -51,7 +50,8 @@ export default class ChannelItem extends PureComponent {
};
onPress = preventDoubleTap(() => {
const {channelId, currentChannelId, displayName, fake, onSelectChannel, type} = this.props;
const {channelId, currentChannelId, displayName, onSelectChannel, channel} = this.props;
const {type, fake} = channel;
requestAnimationFrame(() => {
onSelectChannel({id: channelId, display_name: displayName, fake, type}, currentChannelId);
});
@ -91,18 +91,18 @@ export default class ChannelItem extends PureComponent {
currentChannelId,
displayName,
isChannelMuted,
isMyUser,
currentUserId,
isUnread,
hasDraft,
mentions,
shouldHideChannel,
status,
theme,
type,
isArchived,
isSearchResult,
channel,
} = this.props;
const isArchived = channel.delete_at > 0;
// Only ever show an archived channel if it's the currently viewed channel.
// It should disappear as soon as one navigates to another channel.
if (isArchived && (currentChannelId !== channelId) && !isSearchResult) {
@ -120,7 +120,16 @@ export default class ChannelItem extends PureComponent {
const {intl} = this.context;
let channelDisplayName = displayName;
if (isMyUser) {
let isCurrenUser = false;
if (channel.type === General.DM_CHANNEL) {
if (isSearchResult) {
isCurrenUser = channel.id === currentUserId;
} else {
isCurrenUser = channel.teammate_id === currentUserId;
}
}
if (isCurrenUser) {
channelDisplayName = intl.formatMessage({
id: 'channel_header.directchannel.you',
defaultMessage: '{displayName} (you)',
@ -172,9 +181,9 @@ export default class ChannelItem extends PureComponent {
hasDraft={hasDraft && channelId !== currentChannelId}
membersCount={displayName.split(',').length}
size={16}
status={status}
status={channel.status}
theme={theme}
type={type}
type={channel.type}
isArchived={isArchived}
/>
);

View file

@ -3,21 +3,31 @@
import React from 'react';
import {shallow} from 'enzyme';
import {TouchableHighlight} from 'react-native';
import Preferences from 'mattermost-redux/constants/preferences';
import ChannelItem from './channel_item.js';
jest.useFakeTimers();
jest.mock('react-intl');
describe('ChannelItem', () => {
const channel = {
id: 'channel_id',
delete_at: 0,
type: 'O',
fake: false,
status: 'online',
};
const baseProps = {
channelId: 'channel_id',
channel,
currentChannelId: 'current_channel_id',
displayName: 'display_name',
fake: false,
isChannelMuted: false,
isMyUser: true,
currentUserId: 'currentUser',
isUnread: true,
hasDraft: false,
mentions: 0,
@ -25,11 +35,9 @@ describe('ChannelItem', () => {
onSelectChannel: () => {}, // eslint-disable-line no-empty-function
shouldHideChannel: false,
showUnreadForMsgs: true,
status: 'online',
type: 'O',
theme: Preferences.THEMES.default,
unreadMsgs: 1,
isArchived: false,
isSearchResult: false,
};
test('should match snapshot', () => {
@ -41,12 +49,33 @@ describe('ChannelItem', () => {
expect(wrapper.getElement()).toMatchSnapshot();
});
test('should match snapshot for deactivated user', () => {
test('should match snapshot with mentions and muted', () => {
const newProps = {
...baseProps,
type: 'D',
isArchived: true,
mentions: 1,
isChannelMuted: true,
};
const wrapper = shallow(
<ChannelItem {...newProps}/>,
{context: {intl: {formatMessage: jest.fn()}}},
);
expect(wrapper.getElement()).toMatchSnapshot();
});
test('should match snapshot for deactivated user and not searchResults or currentChannel', () => {
const channelObj = {
...channel,
type: 'D',
delete_at: 123,
};
const newProps = {
...baseProps,
channel: channelObj,
};
const wrapper = shallow(
<ChannelItem {...newProps}/>,
{context: {intl: {formatMessage: jest.fn()}}},
@ -55,12 +84,18 @@ describe('ChannelItem', () => {
});
test('should match snapshot for deactivated user and is searchResult', () => {
const channelObj = {
...channel,
type: 'D',
delete_at: 123,
};
const newProps = {
...baseProps,
type: 'D',
isArchived: true,
isSearchResult: true,
channel: channelObj,
};
const wrapper = shallow(
<ChannelItem {...newProps}/>,
{context: {intl: {formatMessage: jest.fn()}}},
@ -68,6 +103,81 @@ describe('ChannelItem', () => {
expect(wrapper.getElement()).toMatchSnapshot();
});
test('should match snapshot for deactivated user and is currentChannel', () => {
const channelObj = {
...channel,
type: 'D',
delete_at: 123,
};
const newProps = {
...baseProps,
channel: channelObj,
currentChannelId: 'channel_id',
};
const wrapper = shallow(
<ChannelItem {...newProps}/>,
{context: {intl: {formatMessage: jest.fn()}}},
);
expect(wrapper.getElement()).toMatchSnapshot();
});
test('should match snapshot for no displayName', () => {
const newProps = {
...baseProps,
displayName: '',
};
const wrapper = shallow(
<ChannelItem {...newProps}/>,
{context: {intl: {formatMessage: jest.fn()}}},
);
expect(wrapper.getElement()).toMatchSnapshot();
});
test('should match snapshot for current user i.e currentUser (you)', () => {
const channelObj = {
...channel,
type: 'D',
teammate_id: 'currentUser',
};
const newProps = {
...baseProps,
channel: channelObj,
currentChannelId: 'channel_id',
};
const wrapper = shallow(
<ChannelItem {...newProps}/>,
{context: {intl: {formatMessage: (intlId) => intlId.defaultMessage}}},
);
expect(wrapper.getElement()).toMatchSnapshot();
});
test('should match snapshot for current user i.e currentUser (you) when isSearchResult', () => {
const channelObj = {
...channel,
id: 'currentUser',
type: 'D',
teammate_id: 'somethingElse',
};
const newProps = {
...baseProps,
channel: channelObj,
currentChannelId: 'channel_id',
isSearchResult: true,
};
const wrapper = shallow(
<ChannelItem {...newProps}/>,
{context: {intl: {formatMessage: (intlId) => intlId.defaultMessage}}},
);
expect(wrapper.getElement()).toMatchSnapshot();
});
test('should match snapshot with draft', () => {
const wrapper = shallow(
<ChannelItem
@ -80,11 +190,13 @@ describe('ChannelItem', () => {
expect(wrapper.getElement()).toMatchSnapshot();
});
test('should match snapshot if channel is archived', () => {
test('should match snapshot for showUnreadForMsgs', () => {
const wrapper = shallow(
<ChannelItem
{...baseProps}
isArchived={true}
hasDraft={true}
shouldHideChannel={true}
unreadMsgs={0}
/>,
{context: {intl: {formatMessage: jest.fn()}}},
);
@ -92,16 +204,21 @@ describe('ChannelItem', () => {
expect(wrapper.getElement()).toMatchSnapshot();
});
test('should match snapshot if channel is archived and is currentChannel', () => {
test('Should call onPress', () => {
const onSelectChannel = jest.fn();
const wrapper = shallow(
<ChannelItem
{...baseProps}
isArchived={true}
currentChannelId={'channel_id'}
onSelectChannel={onSelectChannel}
/>,
{context: {intl: {formatMessage: jest.fn()}}},
);
expect(wrapper.getElement()).toMatchSnapshot();
wrapper.find(TouchableHighlight).simulate('press');
jest.runAllTimers();
const expectedChannelParams = {id: baseProps.channelId, display_name: baseProps.displayName, fake: channel.fake, type: channel.type};
expect(onSelectChannel).toHaveBeenCalledWith(expectedChannelParams, baseProps.currentChannelId);
});
});

View file

@ -28,13 +28,9 @@ function makeMapStateToProps() {
const currentUserId = getCurrentUserId(state);
const channelDraft = getDraftForChannel(state, channel.id);
let isMyUser = false;
let displayName = channel.display_name;
const isArchived = channel.delete_at > 0;
if (channel.type === General.DM_CHANNEL) {
isMyUser = channel.id === currentUserId;
if (!ownProps.isSearchResult) {
const teammate = getUser(state, channel.teammate_id);
const teammateNameDisplay = getTeammateNameDisplaySetting(state);
@ -69,18 +65,14 @@ function makeMapStateToProps() {
channel,
currentChannelId,
displayName,
fake: channel.fake,
isChannelMuted: isChannelMuted(member),
isMyUser,
currentUserId,
hasDraft: Boolean(channelDraft.draft.trim() || channelDraft.files.length),
mentions: member ? member.mention_count : 0,
shouldHideChannel,
showUnreadForMsgs,
status: channel.status,
theme: getTheme(state),
type: channel.type,
unreadMsgs,
isArchived,
};
};
}

View file

@ -67,3 +67,7 @@ jest.mock('rn-fetch-blob/fs', () => ({
CacheDir: () => jest.fn(),
},
}));
global.requestAnimationFrame = (callback) => {
setTimeout(callback, 0);
};