mattermost-mobile/app/components/global_threads/thread_footer/thread_footer.tsx
Anurag Shivarathri ed1cc2a51d
MM-37294 MM-37296 MM-37297 MM-37495 MM-37509 CRT fixes (#5574)
* fixes MM-37294 MM-37296 MM-37297

* Added conditions to check for post & thread existence

* Update app/mm-redux/selectors/entities/threads.ts

Co-authored-by: Kyriakos Z. <3829551+koox00@users.noreply.github.com>

* type fix

* Never disabling Mark All as unread

* Added follow/unfollow message for not yet thread posts

* Test case fix for mark all as unread enabled all the time

* Removed hardcoded condition

* Fixed MM-37509

* Updated snapshot for sidebar

Co-authored-by: Kyriakos Z. <3829551+koox00@users.noreply.github.com>
Co-authored-by: Mattermod <mattermod@users.noreply.github.com>
2021-07-30 11:14:01 +05:30

237 lines
7.3 KiB
TypeScript

// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import React from 'react';
import {injectIntl, intlShape} from 'react-intl';
import {Text, TouchableOpacity, View} from 'react-native';
import Avatars from '@components/avatars';
import CompassIcon from '@components/compass_icon';
import {GLOBAL_THREADS, CHANNEL} from '@constants/screen';
import {UserThread} from '@mm-redux/types/threads';
import {UserProfile} from '@mm-redux/types/users';
import {$ID} from '@mm-redux/types/utilities';
import {preventDoubleTap} from '@utils/tap';
import {changeOpacity, makeStyleSheetFromTheme} from '@utils/theme';
import type {Theme} from '@mm-redux/types/preferences';
export type DispatchProps = {
actions: {
setThreadFollow: (currentUserId: $ID<UserProfile>, threadId: $ID<UserThread>, newState: boolean) => void;
};
};
export type OwnProps = {
location: 'GlobalThreads' | 'Channel';
testID: string;
thread: UserThread;
threadStarter: UserProfile;
theme: Theme;
}
export type StateProps = {
currentUserId: $ID<UserProfile>;
};
export type Props = DispatchProps & OwnProps & StateProps & {
intl: typeof intlShape;
};
function ThreadFooter({actions, currentUserId, intl, location, testID, theme, thread, threadStarter}: Props) {
const style = getStyleSheet(theme);
const onUnfollow = React.useCallback(preventDoubleTap(() => {
actions.setThreadFollow(currentUserId, thread.id, false);
}), []);
const onFollow = React.useCallback(preventDoubleTap(() => {
actions.setThreadFollow(currentUserId, thread.id, true);
}), []);
let replyIcon;
let followButton;
if (location === CHANNEL) {
if (thread.reply_count) {
replyIcon = (
<View style={style.replyIconContainer}>
<CompassIcon
name='reply-outline'
size={18}
color={changeOpacity(theme.centerChannelColor, 0.64)}
/>
</View>
);
}
if (thread.is_following) {
followButton = (
<TouchableOpacity
onPress={preventDoubleTap(onUnfollow)}
style={style.followingButtonContainer}
testID={`${testID}.following`}
>
<Text style={style.following}>
{intl.formatMessage({
id: 'threads.following',
defaultMessage: 'Following',
})}
</Text>
</TouchableOpacity>
);
} else {
followButton = (
<>
<View style={style.followSeparator}/>
<TouchableOpacity
onPress={preventDoubleTap(onFollow)}
style={style.notFollowingButtonContainer}
testID={`${testID}.follow`}
>
<Text style={style.notFollowing}>
{intl.formatMessage({
id: 'threads.follow',
defaultMessage: 'Follow',
})}
</Text>
</TouchableOpacity>
</>
);
}
}
let repliesComponent;
if (location === GLOBAL_THREADS && thread.unread_replies) {
repliesComponent = (
<Text
style={style.unreadReplies}
testID={`${testID}.unread_replies`}
>
{intl.formatMessage({
id: 'threads.newReplies',
defaultMessage: '{count} new {count, plural, one {reply} other {replies}}',
}, {
count: thread.unread_replies,
})}
</Text>
);
} else if (thread.reply_count) {
repliesComponent = (
<Text
style={style.replies}
testID={`${testID}.reply_count`}
>
{intl.formatMessage({
id: 'threads.replies',
defaultMessage: '{count} {count, plural, one {reply} other {replies}}',
}, {
count: thread.reply_count,
})}
</Text>
);
}
// threadstarter should be the first one in the avatars list
const participants = React.useMemo(() => {
if (thread.participants?.length) {
let isThreadStarterFound = false;
const participantIds = thread.participants.flatMap((participant) => {
if (participant.id === threadStarter?.id) {
isThreadStarterFound = true;
return [];
}
return participant.id;
});
if (isThreadStarterFound) {
participantIds.unshift(threadStarter?.id);
}
return participantIds;
}
return [];
}, [thread.participants, threadStarter]);
let avatars;
if (participants.length) {
avatars = (
<Avatars
style={style.avatarsContainer}
userIds={participants}
/>
);
}
return (
<View style={style.container}>
{avatars}
{replyIcon}
{repliesComponent}
{followButton}
</View>
);
}
const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => {
const followingButtonContainerBase = {
justifyContent: 'center',
height: 32,
paddingHorizontal: 12,
};
return {
container: {
flexDirection: 'row',
alignItems: 'center',
minHeight: 40,
},
avatarsContainer: {
marginRight: 12,
paddingVertical: 8,
},
replyIconContainer: {
top: -1,
marginRight: 5,
},
replies: {
alignSelf: 'center',
color: changeOpacity(theme.centerChannelColor, 0.64),
fontSize: 12,
fontWeight: '600',
marginRight: 12,
},
unreadReplies: {
alignSelf: 'center',
color: theme.sidebarTextActiveBorder,
fontSize: 12,
fontWeight: '600',
marginRight: 12,
},
notFollowingButtonContainer: {
...followingButtonContainerBase,
paddingLeft: 0,
},
notFollowing: {
color: changeOpacity(theme.centerChannelColor, 0.64),
fontWeight: '600',
fontSize: 12,
},
followingButtonContainer: {
...followingButtonContainerBase,
backgroundColor: changeOpacity(theme.buttonBg, 0.08),
borderRadius: 4,
},
following: {
color: theme.buttonBg,
fontWeight: '600',
fontSize: 12,
},
followSeparator: {
backgroundColor: changeOpacity(theme.centerChannelColor, 0.16),
height: 16,
marginRight: 12,
width: 1,
},
};
});
export {ThreadFooter}; // Used for shallow render test cases
export default injectIntl(ThreadFooter);