mattermost-mobile/app/components/global_threads/thread_footer/thread_footer.tsx
Dean Whillier fb8238ab0b
[MM-37553] Update default themes (#5648)
* new themes and theme type updates

* update theme processing

port newer functionality from webapp

* update theme UI

including new svg-based thumbnail

* lint fixes

* update snapshots and tests

* update theme tile border approach

* remove unused path component

* remove old variable typo

* remove old variable type from theme type

* lint and snapshot updates

* update snapshots
2021-09-03 10:50:24 -04:00

235 lines
7.2 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/theme';
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) {
const participantIds = thread.participants.flatMap((participant) => {
if (location === GLOBAL_THREADS && participant.id === threadStarter?.id) {
return [];
}
return participant.id;
}).reverse();
if (location === GLOBAL_THREADS) {
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);