[Gekidou] Add custom status to user profile sheet (#6670)

* Add custom status to user profile sheet

* add missing translations
This commit is contained in:
Elias Nahum 2022-10-11 09:18:46 -03:00 committed by GitHub
parent 3e7ebfe95c
commit d201035a89
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 125 additions and 10 deletions

View file

@ -29,6 +29,7 @@ type HeaderProps = {
enablePostUsernameOverride: boolean;
isAutoResponse: boolean;
isCRTEnabled?: boolean;
isCustomStatusEnabled: boolean;
isEphemeral: boolean;
isMilitaryTime: boolean;
isPendingOrFailed: boolean;
@ -76,7 +77,7 @@ const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => {
const Header = (props: HeaderProps) => {
const {
author, commentCount = 0, currentUser, enablePostUsernameOverride, isAutoResponse, isCRTEnabled,
author, commentCount = 0, currentUser, enablePostUsernameOverride, isAutoResponse, isCRTEnabled, isCustomStatusEnabled,
isEphemeral, isMilitaryTime, isPendingOrFailed, isPostPriorityEnabled, isSystemPost, isTimezoneEnabled, isWebHook,
location, post, rootPostAuthor, shouldRenderReplyButton, teammateNameDisplay,
} = props;
@ -90,7 +91,7 @@ const Header = (props: HeaderProps) => {
const customStatus = getUserCustomStatus(author);
const customStatusExpired = isCustomStatusExpired(author);
const showCustomStatusEmoji = Boolean(
displayName && customStatus &&
isCustomStatusEnabled && displayName && customStatus &&
!(isSystemPost || author.isBot || isAutoResponse || isWebHook),
);

View file

@ -34,6 +34,7 @@ const withHeaderProps = withObservables(
const isMilitaryTime = preferences.pipe(map((prefs) => getPreferenceAsBool(prefs, Preferences.CATEGORY_DISPLAY_SETTINGS, 'use_military_time', false)));
const teammateNameDisplay = observeTeammateNameDisplay(database);
const commentCount = queryPostReplies(database, post.rootId || post.id).observeCount();
const isCustomStatusEnabled = observeConfigBooleanValue(database, 'EnableCustomUserStatuses');
const rootPostAuthor = differentThreadSequence ? post.root.observe().pipe(switchMap((root) => {
if (root.length) {
return root[0].author.observe();
@ -46,6 +47,7 @@ const withHeaderProps = withObservables(
author,
commentCount,
enablePostUsernameOverride,
isCustomStatusEnabled,
isMilitaryTime,
isTimezoneEnabled,
rootPostAuthor,

View file

@ -31,6 +31,7 @@ type ChannelProps = {
channelId: string;
channelType: ChannelType;
customStatus?: UserCustomStatus;
isCustomStatusEnabled: boolean;
isCustomStatusExpired: boolean;
componentId?: string;
displayName: string;
@ -66,7 +67,7 @@ const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => ({
const ChannelHeader = ({
channelId, channelType, componentId, customStatus, displayName,
isCustomStatusExpired, isOwnDirectMessage, memberCount,
isCustomStatusEnabled, isCustomStatusExpired, isOwnDirectMessage, memberCount,
searchTerm, teamId, callsEnabledInChannel, callsFeatureRestricted,
}: ChannelProps) => {
const intl = useIntl();
@ -194,7 +195,7 @@ const ChannelHeader = ({
} else if (customStatus && customStatus.text) {
return (
<View style={styles.customStatusContainer}>
{Boolean(customStatus.emoji) &&
{isCustomStatusEnabled && Boolean(customStatus.emoji) &&
<CustomStatusEmoji
customStatus={customStatus}
emojiSize={13}

View file

@ -9,7 +9,7 @@ import {combineLatestWith, switchMap} from 'rxjs/operators';
import {observeIsCallsFeatureRestricted} from '@calls/observers';
import {General} from '@constants';
import {observeChannel, observeChannelInfo} from '@queries/servers/channel';
import {observeCurrentTeamId, observeCurrentUserId} from '@queries/servers/system';
import {observeConfigBooleanValue, observeCurrentTeamId, observeCurrentUserId} from '@queries/servers/system';
import {observeUser} from '@queries/servers/user';
import {
getUserCustomStatus,
@ -60,6 +60,8 @@ const enhanced = withObservables(['channelId'], ({serverUrl, channelId, database
switchMap((dm) => of$(checkCustomStatusIsExpired(dm))),
);
const isCustomStatusEnabled = observeConfigBooleanValue(database, 'EnableCustomUserStatuses');
const searchTerm = channel.pipe(
combineLatestWith(dmUser),
switchMap(([c, dm]) => {
@ -82,6 +84,7 @@ const enhanced = withObservables(['channelId'], ({serverUrl, channelId, database
channelType,
customStatus,
displayName,
isCustomStatusEnabled,
isCustomStatusExpired,
isOwnDirectMessage,
memberCount,

View file

@ -22,6 +22,7 @@ type Props = {
createdBy: string;
customStatus?: UserCustomStatus;
header?: string;
isCustomStatusEnabled: boolean;
}
const headerMetadata = {header: {width: 1, height: 1}};
@ -65,7 +66,7 @@ const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => ({
},
}));
const Extra = ({channelId, createdAt, createdBy, customStatus, header}: Props) => {
const Extra = ({channelId, createdAt, createdBy, customStatus, header, isCustomStatusEnabled}: Props) => {
const theme = useTheme();
const styles = getStyleSheet(theme);
const blockStyles = getMarkdownBlockStyles(theme);
@ -82,7 +83,7 @@ const Extra = ({channelId, createdAt, createdBy, customStatus, header}: Props) =
return (
<View style={styles.container}>
{Boolean(customStatus) &&
{isCustomStatusEnabled && Boolean(customStatus) &&
<View style={styles.item}>
<FormattedText
id='channel_info.custom_status'

View file

@ -8,6 +8,7 @@ import {combineLatestWith, switchMap} from 'rxjs/operators';
import {General} from '@constants';
import {observeChannel, observeChannelInfo} from '@queries/servers/channel';
import {observeConfigBooleanValue} from '@queries/servers/system';
import {observeCurrentUser, observeTeammateNameDisplay, observeUser} from '@queries/servers/user';
import {displayUsername, getUserCustomStatus, getUserIdFromChannelName, isCustomStatusExpired as checkCustomStatusIsExpired} from '@utils/user';
@ -48,11 +49,14 @@ const enhanced = withObservables(['channelId'], ({channelId, database}: Props) =
switchMap((dm) => of$(checkCustomStatusIsExpired(dm) ? undefined : getUserCustomStatus(dm))),
);
const isCustomStatusEnabled = observeConfigBooleanValue(database, 'EnableCustomUserStatuses');
return {
createdAt,
createdBy,
customStatus,
header,
isCustomStatusEnabled,
};
});

View file

@ -0,0 +1,91 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import moment from 'moment-timezone';
import React from 'react';
import {View} from 'react-native';
import CustomStatusEmoji from '@components/custom_status/custom_status_emoji';
import CustomStatusExpiry from '@components/custom_status/custom_status_expiry';
import CustomStatusText from '@components/custom_status/custom_status_text';
import FormattedText from '@components/formatted_text';
import {useTheme} from '@context/theme';
import {changeOpacity, makeStyleSheetFromTheme} from '@utils/theme';
import {typography} from '@utils/typography';
type Props = {
customStatus: UserCustomStatus;
};
const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => ({
container: {
marginVertical: 8,
},
row: {
flexDirection: 'row',
},
description: {
color: theme.centerChannelColor,
...typography('Body', 200),
},
title: {
color: changeOpacity(theme.centerChannelColor, 0.56),
marginBottom: 2,
...typography('Body', 50, 'SemiBold'),
},
expiry: {
color: changeOpacity(theme.centerChannelColor, 0.56),
marginLeft: 3,
marginBottom: 2,
textTransform: 'lowercase',
...typography('Body', 50, 'SemiBold'),
},
emoji: {
marginRight: 8,
},
}));
const UserProfileCustomStatus = ({customStatus}: Props) => {
const theme = useTheme();
const styles = getStyleSheet(theme);
return (
<View style={styles.container}>
<View style={styles.row}>
<FormattedText
id='user_profile.custom_status'
defaultMessage='Custom Status'
style={styles.title}
testID={'user_profile.custom_status.title'}
/>
{Boolean(customStatus?.duration) &&
<CustomStatusExpiry
time={moment(customStatus.expires_at)}
theme={theme}
textStyles={styles.expiry}
withinBrackets={true}
showPrefix={true}
testID={`user_profile.${customStatus.duration}.custom_status_expiry`}
/>
}
</View>
<View style={styles.row}>
{Boolean(customStatus.emoji) &&
<CustomStatusEmoji
customStatus={customStatus}
emojiSize={24}
testID={'user_profile.custom_status_emoji'}
style={styles.emoji}
/>
}
<CustomStatusText
text={customStatus.text}
theme={theme}
textStyle={styles.description}
/>
</View>
</View>
);
};
export default UserProfileCustomStatus;

View file

@ -40,12 +40,14 @@ const enhanced = withObservables([], ({channelId, database, userId}: EnhancedPro
const preferences = queryPreferencesByCategoryAndName(database, Preferences.CATEGORY_DISPLAY_SETTINGS).
observeWithColumns(['value']);
const isMilitaryTime = preferences.pipe(map((prefs) => getPreferenceAsBool(prefs, Preferences.CATEGORY_DISPLAY_SETTINGS, 'use_military_time', false)));
const isCustomStatusEnabled = observeConfigBooleanValue(database, 'EnableCustomUserStatuses');
return {
currentUserId,
enablePostIconOverride,
enablePostUsernameOverride,
isChannelAdmin,
isCustomStatusEnabled,
isDirectMessage,
isMilitaryTime,
isSystemAdmin: systemAdmin,

View file

@ -12,8 +12,9 @@ import {Screens} from '@constants';
import {useServerUrl} from '@context/server';
import {getLocaleFromLanguage} from '@i18n';
import BottomSheet from '@screens/bottom_sheet';
import {getUserTimezone} from '@utils/user';
import {getUserCustomStatus, getUserTimezone, isCustomStatusExpired} from '@utils/user';
import UserProfileCustomStatus from './custom_status';
import UserProfileLabel from './label';
import UserProfileOptions, {OptionsType} from './options';
import UserProfileTitle from './title';
@ -27,6 +28,7 @@ type Props = {
enablePostIconOverride: boolean;
enablePostUsernameOverride: boolean;
isChannelAdmin: boolean;
isCustomStatusEnabled: boolean;
isDirectMessage: boolean;
isMilitaryTime: boolean;
isSystemAdmin: boolean;
@ -47,7 +49,7 @@ const EXTRA_HEIGHT = 60;
const UserProfile = ({
channelId, closeButtonId, currentUserId, enablePostIconOverride, enablePostUsernameOverride,
isChannelAdmin, isDirectMessage, isMilitaryTime, isSystemAdmin, isTeamAdmin,
isChannelAdmin, isCustomStatusEnabled, isDirectMessage, isMilitaryTime, isSystemAdmin, isTeamAdmin,
location, teamId, teammateDisplayName,
user, userIconOverride, usernameOverride,
}: Props) => {
@ -58,6 +60,8 @@ const UserProfile = ({
const showOptions: OptionsType = channelContext && !user.isBot ? 'all' : 'message';
const override = Boolean(userIconOverride || usernameOverride);
const timezone = getUserTimezone(user);
const customStatus = getUserCustomStatus(user);
const showCustomStatus = isCustomStatusEnabled && Boolean(customStatus) && !user.isBot && !isCustomStatusExpired(user);
let localTime: string|undefined;
if (timezone) {
moment.locale(getLocaleFromLanguage(locale).toLowerCase());
@ -77,6 +81,10 @@ const UserProfile = ({
let labels = 0;
if (!override && !user.isBot) {
if (showCustomStatus) {
labels += 1;
}
if (user.nickname) {
labels += 1;
}
@ -125,6 +133,7 @@ const UserProfile = ({
userId={user.id}
/>
}
{showCustomStatus && <UserProfileCustomStatus customStatus={customStatus!}/>}
{Boolean(user.nickname) && !override && !user.isBot &&
<UserProfileLabel
description={user.nickname}

View file

@ -701,9 +701,9 @@
"post_info.guest": "Guest",
"post_info.system": "System",
"post_message_view.edited": "(edited)",
"post.options.title": "Options",
"post_priority.label.important": "IMPORTANT",
"post_priority.label.urgent": "URGENT",
"post.options.title": "Options",
"post.reactions.title": "Reactions",
"posts_view.newMsg": "New Messages",
"public_link_copied": "Link copied to clipboard",
@ -832,6 +832,7 @@
"unreads.empty.paragraph": "Turn off the unread filter to show all your channels.",
"unreads.empty.show_all": "Show all",
"unreads.empty.title": "No more unreads",
"user_profile.custom_status": "Custom Status",
"user.edit_profile.email.auth_service": "Login occurs through {service}. Email cannot be updated. Email address used for notifications is {email}.",
"user.edit_profile.email.web_client": "Email must be updated using a web client or desktop application.",
"user.settings.general.email": "Email",