From d201035a89483089a7015f5617f7c903415a60c8 Mon Sep 17 00:00:00 2001 From: Elias Nahum Date: Tue, 11 Oct 2022 09:18:46 -0300 Subject: [PATCH] [Gekidou] Add custom status to user profile sheet (#6670) * Add custom status to user profile sheet * add missing translations --- .../post_list/post/header/header.tsx | 5 +- app/components/post_list/post/header/index.ts | 2 + app/screens/channel/header/header.tsx | 5 +- app/screens/channel/header/index.ts | 5 +- app/screens/channel_info/extra/extra.tsx | 5 +- app/screens/channel_info/extra/index.ts | 4 + app/screens/user_profile/custom_status.tsx | 91 +++++++++++++++++++ app/screens/user_profile/index.ts | 2 + app/screens/user_profile/user_profile.tsx | 13 ++- assets/base/i18n/en.json | 3 +- 10 files changed, 125 insertions(+), 10 deletions(-) create mode 100644 app/screens/user_profile/custom_status.tsx diff --git a/app/components/post_list/post/header/header.tsx b/app/components/post_list/post/header/header.tsx index cc2bc8293..b209dba6f 100644 --- a/app/components/post_list/post/header/header.tsx +++ b/app/components/post_list/post/header/header.tsx @@ -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), ); diff --git a/app/components/post_list/post/header/index.ts b/app/components/post_list/post/header/index.ts index 145cb65cf..e03917534 100644 --- a/app/components/post_list/post/header/index.ts +++ b/app/components/post_list/post/header/index.ts @@ -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, diff --git a/app/screens/channel/header/header.tsx b/app/screens/channel/header/header.tsx index 3c410491f..b019628fb 100644 --- a/app/screens/channel/header/header.tsx +++ b/app/screens/channel/header/header.tsx @@ -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 ( - {Boolean(customStatus.emoji) && + {isCustomStatusEnabled && Boolean(customStatus.emoji) && 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, diff --git a/app/screens/channel_info/extra/extra.tsx b/app/screens/channel_info/extra/extra.tsx index ce77af454..fbb56381d 100644 --- a/app/screens/channel_info/extra/extra.tsx +++ b/app/screens/channel_info/extra/extra.tsx @@ -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 ( - {Boolean(customStatus) && + {isCustomStatusEnabled && Boolean(customStatus) && of$(checkCustomStatusIsExpired(dm) ? undefined : getUserCustomStatus(dm))), ); + const isCustomStatusEnabled = observeConfigBooleanValue(database, 'EnableCustomUserStatuses'); + return { createdAt, createdBy, customStatus, header, + isCustomStatusEnabled, }; }); diff --git a/app/screens/user_profile/custom_status.tsx b/app/screens/user_profile/custom_status.tsx new file mode 100644 index 000000000..5f6f82a33 --- /dev/null +++ b/app/screens/user_profile/custom_status.tsx @@ -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 ( + + + + {Boolean(customStatus?.duration) && + + } + + + {Boolean(customStatus.emoji) && + + } + + + + ); +}; + +export default UserProfileCustomStatus; diff --git a/app/screens/user_profile/index.ts b/app/screens/user_profile/index.ts index b3ce160b1..f03acf1eb 100644 --- a/app/screens/user_profile/index.ts +++ b/app/screens/user_profile/index.ts @@ -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, diff --git a/app/screens/user_profile/user_profile.tsx b/app/screens/user_profile/user_profile.tsx index 1e848fa8f..cd87a85a8 100644 --- a/app/screens/user_profile/user_profile.tsx +++ b/app/screens/user_profile/user_profile.tsx @@ -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 && } {Boolean(user.nickname) && !override && !user.isBot &&