From 8ab2373d7b1083f15877528d67c2944b823bc9c6 Mon Sep 17 00:00:00 2001 From: Sudheer Date: Tue, 7 Aug 2018 20:00:52 +0530 Subject: [PATCH] [MM-11051] Add a loading_palceholder when user info is loading (#1972) * MM-11051] Add a loading_palceholder when user info is loading * Update package json and lock --- .../loading_placeholder.test.js.snap | 153 +++ app/components/loading_placeholder/index.js | 28 + .../loading_placeholder.test.js | 19 + .../__snapshots__/channel_item.test.js.snap | 907 +++++++++++++++++- .../channel_item/channel_item.js | 23 +- .../channel_item/channel_item.test.js | 14 + .../main/channels_list/channel_item/index.js | 9 +- package-lock.json | 11 +- package.json | 3 +- 9 files changed, 1141 insertions(+), 26 deletions(-) create mode 100644 app/components/loading_placeholder/__snapshots__/loading_placeholder.test.js.snap create mode 100644 app/components/loading_placeholder/index.js create mode 100644 app/components/loading_placeholder/loading_placeholder.test.js diff --git a/app/components/loading_placeholder/__snapshots__/loading_placeholder.test.js.snap b/app/components/loading_placeholder/__snapshots__/loading_placeholder.test.js.snap new file mode 100644 index 000000000..f387312c0 --- /dev/null +++ b/app/components/loading_placeholder/__snapshots__/loading_placeholder.test.js.snap @@ -0,0 +1,153 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`LoadingPlaceholder should match snapshot 1`] = ` +ShallowWrapper { + "length": 1, + Symbol(enzyme.__root__): [Circular], + Symbol(enzyme.__unrendered__): , + Symbol(enzyme.__renderer__): Object { + "batchedUpdates": [Function], + "getNode": [Function], + "render": [Function], + "simulateEvent": [Function], + "unmount": [Function], + }, + Symbol(enzyme.__node__): Object { + "instance": null, + "key": undefined, + "nodeType": "class", + "props": Object { + "accessible": true, + "allowFontScaling": true, + "children": Array [ + , + , + ], + "ellipsizeMode": "tail", + }, + "ref": null, + "rendered": Array [ + Object { + "instance": null, + "key": undefined, + "nodeType": "class", + "props": Object { + "defaultMessage": "Loading", + "id": "loading_screen.loading", + }, + "ref": null, + "rendered": null, + "type": [Function], + }, + Object { + "instance": null, + "key": undefined, + "nodeType": "class", + "props": Object { + "animationDelay": 300, + "minOpacity": 0.4, + "numberOfDots": 3, + "style": Object { + "fontSize": 28, + "letterSpacing": -3, + "lineHeight": 30, + "marginLeft": 5, + }, + }, + "ref": null, + "rendered": null, + "type": [Function], + }, + ], + "type": [Function], + }, + Symbol(enzyme.__nodes__): Array [ + Object { + "instance": null, + "key": undefined, + "nodeType": "class", + "props": Object { + "accessible": true, + "allowFontScaling": true, + "children": Array [ + , + , + ], + "ellipsizeMode": "tail", + }, + "ref": null, + "rendered": Array [ + Object { + "instance": null, + "key": undefined, + "nodeType": "class", + "props": Object { + "defaultMessage": "Loading", + "id": "loading_screen.loading", + }, + "ref": null, + "rendered": null, + "type": [Function], + }, + Object { + "instance": null, + "key": undefined, + "nodeType": "class", + "props": Object { + "animationDelay": 300, + "minOpacity": 0.4, + "numberOfDots": 3, + "style": Object { + "fontSize": 28, + "letterSpacing": -3, + "lineHeight": 30, + "marginLeft": 5, + }, + }, + "ref": null, + "rendered": null, + "type": [Function], + }, + ], + "type": [Function], + }, + ], + Symbol(enzyme.__options__): Object { + "adapter": ReactSixteenAdapter { + "options": Object { + "enableComponentDidUpdateOnSetState": true, + }, + }, + }, +} +`; diff --git a/app/components/loading_placeholder/index.js b/app/components/loading_placeholder/index.js new file mode 100644 index 000000000..e2dc72fb9 --- /dev/null +++ b/app/components/loading_placeholder/index.js @@ -0,0 +1,28 @@ +// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. +// See LICENSE.txt for license information. + +import React from 'react'; +import AnimatedEllipsis from 'react-native-animated-ellipsis'; +import FormattedText from 'app/components/formatted_text'; + +import {Text} from 'react-native'; + +const LoadingPlaceholder = () => ( + + + + +); + +export default LoadingPlaceholder; diff --git a/app/components/loading_placeholder/loading_placeholder.test.js b/app/components/loading_placeholder/loading_placeholder.test.js new file mode 100644 index 000000000..96293f111 --- /dev/null +++ b/app/components/loading_placeholder/loading_placeholder.test.js @@ -0,0 +1,19 @@ +// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. +// See LICENSE.txt for license information. + +import React from 'react'; +import {configure, shallow} from 'enzyme'; +import Adapter from 'enzyme-adapter-react-16'; +configure({adapter: new Adapter()}); + +import LoadingPlaceholder from './index.js'; + +describe('LoadingPlaceholder', () => { + test('should match snapshot', () => { + const wrapper = shallow( + + ); + + expect(wrapper).toMatchSnapshot(); + }); +}); diff --git a/app/components/sidebars/main/channels_list/channel_item/__snapshots__/channel_item.test.js.snap b/app/components/sidebars/main/channels_list/channel_item/__snapshots__/channel_item.test.js.snap index 0fcd3bb59..cba55a39a 100644 --- a/app/components/sidebars/main/channels_list/channel_item/__snapshots__/channel_item.test.js.snap +++ b/app/components/sidebars/main/channels_list/channel_item/__snapshots__/channel_item.test.js.snap @@ -121,7 +121,9 @@ ShallowWrapper { }, ] } - /> + > + + , @@ -200,7 +202,9 @@ ShallowWrapper { }, ] } - /> + > + + , "delayPressOut": 100, @@ -271,7 +275,9 @@ ShallowWrapper { }, ] } - /> + > + + , ], "style": Array [ @@ -334,7 +340,9 @@ ShallowWrapper { }, ] } - />, + > + + , undefined, ], "style": Array [ @@ -382,7 +390,7 @@ ShallowWrapper { "props": Object { "accessible": true, "allowFontScaling": true, - "children": undefined, + "children": , "ellipsizeMode": "tail", "numberOfLines": 1, "style": Array [ @@ -402,7 +410,15 @@ ShallowWrapper { ], }, "ref": null, - "rendered": null, + "rendered": Object { + "instance": null, + "key": undefined, + "nodeType": "function", + "props": Object {}, + "ref": null, + "rendered": null, + "type": [Function], + }, "type": [Function], }, undefined, @@ -496,7 +512,9 @@ ShallowWrapper { }, ] } - /> + > + + , @@ -575,7 +593,9 @@ ShallowWrapper { }, ] } - /> + > + + , "delayPressOut": 100, @@ -646,7 +666,9 @@ ShallowWrapper { }, ] } - /> + > + + , ], "style": Array [ @@ -709,7 +731,9 @@ ShallowWrapper { }, ] } - />, + > + + , undefined, ], "style": Array [ @@ -757,7 +781,7 @@ ShallowWrapper { "props": Object { "accessible": true, "allowFontScaling": true, - "children": undefined, + "children": , "ellipsizeMode": "tail", "numberOfLines": 1, "style": Array [ @@ -777,7 +801,15 @@ ShallowWrapper { ], }, "ref": null, - "rendered": null, + "rendered": Object { + "instance": null, + "key": undefined, + "nodeType": "function", + "props": Object {}, + "ref": null, + "rendered": null, + "type": [Function], + }, "type": [Function], }, undefined, @@ -818,3 +850,854 @@ ShallowWrapper { }, } `; + +exports[`ChannelItem should match snapshot for no displayName 1`] = ` +ShallowWrapper { + "length": 1, + Symbol(enzyme.__root__): [Circular], + Symbol(enzyme.__unrendered__): , + Symbol(enzyme.__renderer__): Object { + "batchedUpdates": [Function], + "getNode": [Function], + "render": [Function], + "simulateEvent": [Function], + "unmount": [Function], + }, + Symbol(enzyme.__node__): Object { + "instance": null, + "key": undefined, + "nodeType": "class", + "props": Object { + "children": + + + + + + + + + , + }, + "ref": [Function], + "rendered": Object { + "instance": null, + "key": undefined, + "nodeType": "class", + "props": Object { + "activeOpacity": 0.85, + "children": + + + + + + + , + "delayPressOut": 100, + "onLongPress": [Function], + "onPress": [Function], + "underlayColor": "rgba(170,170,170,0.5)", + }, + "ref": null, + "rendered": Object { + "instance": null, + "key": undefined, + "nodeType": "class", + "props": Object { + "children": Array [ + undefined, + + + + + + , + ], + "style": Array [ + Object { + "flex": 1, + "flexDirection": "row", + "height": 44, + }, + undefined, + ], + }, + "ref": null, + "rendered": Array [ + undefined, + Object { + "instance": null, + "key": undefined, + "nodeType": "class", + "props": Object { + "children": Array [ + , + + + , + undefined, + ], + "style": Array [ + Object { + "alignItems": "center", + "flex": 1, + "flexDirection": "row", + "paddingLeft": 16, + }, + undefined, + ], + }, + "ref": null, + "rendered": Array [ + Object { + "instance": null, + "key": undefined, + "nodeType": "class", + "props": Object { + "channelId": "channel_id", + "isActive": false, + "isArchived": false, + "isInfo": false, + "isUnread": true, + "membersCount": 1, + "size": 16, + "status": "online", + "teammateDeletedAt": 0, + "theme": Object { + "sidebarText": "#aaa", + "sidebarTextActiveBorder": "#aaa", + "sidebarTextActiveColor": "#aaa", + "sidebarTextHoverBg": "#aaa", + }, + "type": "O", + }, + "ref": null, + "rendered": null, + "type": [Function], + }, + Object { + "instance": null, + "key": undefined, + "nodeType": "class", + "props": Object { + "accessible": true, + "allowFontScaling": true, + "children": , + "ellipsizeMode": "tail", + "numberOfLines": 1, + "style": Array [ + Object { + "color": "rgba(170,170,170,0.4)", + "flex": 1, + "fontSize": 14, + "fontWeight": "600", + "height": "100%", + "lineHeight": 44, + "paddingRight": 40, + "textAlignVertical": "center", + }, + Object { + "color": undefined, + }, + ], + }, + "ref": null, + "rendered": Object { + "instance": null, + "key": undefined, + "nodeType": "function", + "props": Object {}, + "ref": null, + "rendered": null, + "type": [Function], + }, + "type": [Function], + }, + undefined, + ], + "type": [Function], + }, + ], + "type": [Function], + }, + "type": [Function], + }, + "type": [Function], + }, + Symbol(enzyme.__nodes__): Array [ + Object { + "instance": null, + "key": undefined, + "nodeType": "class", + "props": Object { + "children": + + + + + + + + + , + }, + "ref": [Function], + "rendered": Object { + "instance": null, + "key": undefined, + "nodeType": "class", + "props": Object { + "activeOpacity": 0.85, + "children": + + + + + + + , + "delayPressOut": 100, + "onLongPress": [Function], + "onPress": [Function], + "underlayColor": "rgba(170,170,170,0.5)", + }, + "ref": null, + "rendered": Object { + "instance": null, + "key": undefined, + "nodeType": "class", + "props": Object { + "children": Array [ + undefined, + + + + + + , + ], + "style": Array [ + Object { + "flex": 1, + "flexDirection": "row", + "height": 44, + }, + undefined, + ], + }, + "ref": null, + "rendered": Array [ + undefined, + Object { + "instance": null, + "key": undefined, + "nodeType": "class", + "props": Object { + "children": Array [ + , + + + , + undefined, + ], + "style": Array [ + Object { + "alignItems": "center", + "flex": 1, + "flexDirection": "row", + "paddingLeft": 16, + }, + undefined, + ], + }, + "ref": null, + "rendered": Array [ + Object { + "instance": null, + "key": undefined, + "nodeType": "class", + "props": Object { + "channelId": "channel_id", + "isActive": false, + "isArchived": false, + "isInfo": false, + "isUnread": true, + "membersCount": 1, + "size": 16, + "status": "online", + "teammateDeletedAt": 0, + "theme": Object { + "sidebarText": "#aaa", + "sidebarTextActiveBorder": "#aaa", + "sidebarTextActiveColor": "#aaa", + "sidebarTextHoverBg": "#aaa", + }, + "type": "O", + }, + "ref": null, + "rendered": null, + "type": [Function], + }, + Object { + "instance": null, + "key": undefined, + "nodeType": "class", + "props": Object { + "accessible": true, + "allowFontScaling": true, + "children": , + "ellipsizeMode": "tail", + "numberOfLines": 1, + "style": Array [ + Object { + "color": "rgba(170,170,170,0.4)", + "flex": 1, + "fontSize": 14, + "fontWeight": "600", + "height": "100%", + "lineHeight": 44, + "paddingRight": 40, + "textAlignVertical": "center", + }, + Object { + "color": undefined, + }, + ], + }, + "ref": null, + "rendered": Object { + "instance": null, + "key": undefined, + "nodeType": "function", + "props": Object {}, + "ref": null, + "rendered": null, + "type": [Function], + }, + "type": [Function], + }, + undefined, + ], + "type": [Function], + }, + ], + "type": [Function], + }, + "type": [Function], + }, + "type": [Function], + }, + ], + Symbol(enzyme.__options__): Object { + "adapter": ReactSixteenAdapter { + "options": Object { + "enableComponentDidUpdateOnSetState": true, + }, + }, + "context": Object { + "intl": Object { + "formatMessage": [MockFunction] { + "calls": Array [ + Array [ + Object { + "defaultMessage": "{displayName} (you)", + "id": "channel_header.directchannel.you", + }, + Object { + "displayname": "", + }, + ], + ], + }, + }, + }, + }, +} +`; diff --git a/app/components/sidebars/main/channels_list/channel_item/channel_item.js b/app/components/sidebars/main/channels_list/channel_item/channel_item.js index c87678098..cce3eca36 100644 --- a/app/components/sidebars/main/channels_list/channel_item/channel_item.js +++ b/app/components/sidebars/main/channels_list/channel_item/channel_item.js @@ -14,6 +14,7 @@ import {intlShape} from 'react-intl'; import Badge from 'app/components/badge'; import ChannelIcon from 'app/components/channel_icon'; +import LoadingPlaceholder from 'app/components/loading_placeholder'; import {preventDoubleTap} from 'app/utils/tap'; import {changeOpacity, makeStyleSheetFromTheme} from 'app/utils/theme'; @@ -113,14 +114,6 @@ export default class ChannelItem extends PureComponent { const {intl} = this.context; - let channelDisplayName = displayName; - if (isMyUser) { - channelDisplayName = intl.formatMessage({ - id: 'channel_header.directchannel.you', - defaultMessage: '{displayName} (you)', - }, {displayname: displayName}); - } - const style = getStyleSheet(theme); const isActive = channelId === currentChannelId; @@ -140,6 +133,20 @@ export default class ChannelItem extends PureComponent { extraTextStyle = style.textUnread; } + let channelDisplayName = displayName; + if (isMyUser) { + channelDisplayName = intl.formatMessage({ + id: 'channel_header.directchannel.you', + defaultMessage: '{displayName} (you)', + }, {displayname: displayName}); + } + + if (!channelDisplayName) { + channelDisplayName = ( + + ); + } + let badge; if (mentions) { badge = ( diff --git a/app/components/sidebars/main/channels_list/channel_item/channel_item.test.js b/app/components/sidebars/main/channels_list/channel_item/channel_item.test.js index 3ce307c00..7f4bd614f 100644 --- a/app/components/sidebars/main/channels_list/channel_item/channel_item.test.js +++ b/app/components/sidebars/main/channels_list/channel_item/channel_item.test.js @@ -45,4 +45,18 @@ describe('ChannelItem', () => { expect(wrapper).toMatchSnapshot(); }); + + test('should match snapshot for no displayName', () => { + const props = { + ...baseProps, + displayName: '', + }; + + const wrapper = shallow( + , + {context: {intl: {formatMessage: jest.fn()}}}, + ); + + expect(wrapper).toMatchSnapshot(); + }); }); diff --git a/app/components/sidebars/main/channels_list/channel_item/index.js b/app/components/sidebars/main/channels_list/channel_item/index.js index 2e0e1435d..6fbd29625 100644 --- a/app/components/sidebars/main/channels_list/channel_item/index.js +++ b/app/components/sidebars/main/channels_list/channel_item/index.js @@ -10,9 +10,10 @@ import { getMyChannelMember, shouldHideDefaultChannel, } from 'mattermost-redux/selectors/entities/channels'; -import {getTheme} from 'mattermost-redux/selectors/entities/preferences'; +import {getTheme, getTeammateNameDisplaySetting} from 'mattermost-redux/selectors/entities/preferences'; import {getCurrentUserId, getUser} from 'mattermost-redux/selectors/entities/users'; import {isChannelMuted} from 'mattermost-redux/utils/channel_utils'; +import {displayUsername} from 'mattermost-redux/utils/user_utils'; import ChannelItem from './channel_item'; @@ -26,12 +27,15 @@ function makeMapStateToProps() { let isMyUser = false; let teammateDeletedAt = 0; + let displayName = channel.display_name; if (channel.type === General.DM_CHANNEL && channel.teammate_id) { isMyUser = channel.teammate_id === currentUserId; const teammate = getUser(state, channel.teammate_id); if (teammate && teammate.delete_at) { teammateDeletedAt = teammate.delete_at; } + const teammateNameDisplay = getTeammateNameDisplaySetting(state); + displayName = displayUsername(teammate, teammateNameDisplay, false); } const currentChannelId = getCurrentChannelId(state); @@ -57,10 +61,9 @@ function makeMapStateToProps() { if (member && member.notify_props) { showUnreadForMsgs = member.notify_props.mark_unread !== General.MENTION; } - return { currentChannelId, - displayName: channel.display_name, + displayName, fake: channel.fake, isChannelMuted: isChannelMuted(member), isMyUser, diff --git a/package-lock.json b/package-lock.json index ef5f3fe17..753ab065f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10108,8 +10108,8 @@ } }, "mattermost-redux": { - "version": "github:mattermost/mattermost-redux#12353bc88f20dde53b6191747790c6a82b8dd527", - "from": "github:mattermost/mattermost-redux#12353bc88f20dde53b6191747790c6a82b8dd527", + "version": "github:mattermost/mattermost-redux#f13022064f1ed24a0d1c085f433490f9d40cfc2f", + "from": "github:mattermost/mattermost-redux#f13022064f1ed24a0d1c085f433490f9d40cfc2f", "requires": { "deep-equal": "1.0.1", "eslint-plugin-header": "1.2.0", @@ -14626,6 +14626,13 @@ "prop-types": "^15.5.10" } }, + "react-native-animated-ellipsis": { + "version": "github:sudheerDev/react-native-animated-ellipsis#326167b8e0fa3b6f0422c06be412bf177b725666", + "from": "github:sudheerDev/react-native-animated-ellipsis#326167b8e0fa3b6f0422c06be412bf177b725666", + "requires": { + "prop-types": "^15.5.10" + } + }, "react-native-bottom-sheet": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/react-native-bottom-sheet/-/react-native-bottom-sheet-1.0.3.tgz", diff --git a/package.json b/package.json index 414e85b9f..0df80744e 100644 --- a/package.json +++ b/package.json @@ -15,13 +15,14 @@ "intl": "1.2.5", "jail-monkey": "1.0.0", "jsc-android": "216113.0.3", - "mattermost-redux": "github:mattermost/mattermost-redux#12353bc88f20dde53b6191747790c6a82b8dd527", + "mattermost-redux": "github:mattermost/mattermost-redux#f13022064f1ed24a0d1c085f433490f9d40cfc2f", "mime-db": "1.33.0", "prop-types": "15.6.1", "react": "16.3.2", "react-intl": "2.4.0", "react-native": "github:enahum/react-native#mm", "react-native-animatable": "1.2.4", + "react-native-animated-ellipsis": "sudheerDev/react-native-animated-ellipsis.git#326167b8e0fa3b6f0422c06be412bf177b725666", "react-native-bottom-sheet": "1.0.3", "react-native-button": "2.3.0", "react-native-circular-progress": "0.2.0",