From 97c41057ccc684ae319c9583f8691d7ca2b62b2a Mon Sep 17 00:00:00 2001 From: Anurag Shivarathri Date: Sun, 11 Sep 2022 23:15:07 +0530 Subject: [PATCH] [Gekidou MM-43992] Display message priority labels for the posts (#6620) * Displays label * feedback * import fix * Moved label colors to stylesheet --- .../post_list/post/header/header.tsx | 16 ++++- .../post_list/post/header/reply/index.tsx | 1 - app/components/post_list/post/index.ts | 3 +- app/components/post_list/post/post.tsx | 9 ++- .../post_priority/post_priority_label.tsx | 67 +++++++++++++++++++ app/constants/post.ts | 6 ++ app/queries/servers/system.ts | 11 ++- assets/base/i18n/en.json | 2 + types/api/config.d.ts | 2 + 9 files changed, 109 insertions(+), 8 deletions(-) create mode 100644 app/components/post_priority/post_priority_label.tsx diff --git a/app/components/post_list/post/header/header.tsx b/app/components/post_list/post/header/header.tsx index cc9f6f7acf..cc2bc8293b 100644 --- a/app/components/post_list/post/header/header.tsx +++ b/app/components/post_list/post/header/header.tsx @@ -6,6 +6,7 @@ import {View} from 'react-native'; import CustomStatusEmoji from '@components/custom_status/custom_status_emoji'; import FormattedTime from '@components/formatted_time'; +import PostPriorityLabel from '@components/post_priority/post_priority_label'; import {CHANNEL, THREAD} from '@constants/screens'; import {useTheme} from '@context/theme'; import {postUserDisplayName} from '@utils/post'; @@ -31,6 +32,7 @@ type HeaderProps = { isEphemeral: boolean; isMilitaryTime: boolean; isPendingOrFailed: boolean; + isPostPriorityEnabled: boolean; isSystemPost: boolean; isTimezoneEnabled: boolean; isWebHook: boolean; @@ -58,9 +60,12 @@ const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => { color: theme.centerChannelColor, marginTop: 5, opacity: 0.5, - flex: 1, ...typography('Body', 75, 'Regular'), }, + postPriority: { + alignSelf: 'center', + marginLeft: 6, + }, customStatusEmoji: { color: theme.centerChannelColor, marginRight: 4, @@ -72,7 +77,7 @@ const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => { const Header = (props: HeaderProps) => { const { author, commentCount = 0, currentUser, enablePostUsernameOverride, isAutoResponse, isCRTEnabled, - isEphemeral, isMilitaryTime, isPendingOrFailed, isSystemPost, isTimezoneEnabled, isWebHook, + isEphemeral, isMilitaryTime, isPendingOrFailed, isPostPriorityEnabled, isSystemPost, isTimezoneEnabled, isWebHook, location, post, rootPostAuthor, shouldRenderReplyButton, teammateNameDisplay, } = props; const theme = useTheme(); @@ -126,6 +131,13 @@ const Header = (props: HeaderProps) => { style={style.time} testID='post_header.date_time' /> + {Boolean(isPostPriorityEnabled && post.props?.priority) && ( + + + + )} {!isCRTEnabled && showReply && commentCount > 0 && { justifyContent: 'flex-end', minWidth: 40, paddingTop: 2, - paddingBottom: 10, flex: 1, }, replyText: { diff --git a/app/components/post_list/post/index.ts b/app/components/post_list/post/index.ts index 7642409457..5e8343b699 100644 --- a/app/components/post_list/post/index.ts +++ b/app/components/post_list/post/index.ts @@ -12,7 +12,7 @@ import {queryAllCustomEmojis} from '@queries/servers/custom_emoji'; import {queryPostsBetween} from '@queries/servers/post'; import {queryPreferencesByCategoryAndName} from '@queries/servers/preference'; import {observeCanManageChannelMembers, observePermissionForPost} from '@queries/servers/role'; -import {observeConfigBooleanValue} from '@queries/servers/system'; +import {observeIsPostPriorityEnabled, observeConfigBooleanValue} from '@queries/servers/system'; import {observeThreadById} from '@queries/servers/thread'; import {observeCurrentUser} from '@queries/servers/user'; import {hasJumboEmojiOnly} from '@utils/emoji/helpers'; @@ -168,6 +168,7 @@ const withPost = withObservables( isJumboEmoji, isLastReply, isPostAddChannelMember, + isPostPriorityEnabled: observeIsPostPriorityEnabled(database), post: post.observe(), thread: isCRTEnabled ? observeThreadById(database, post.id) : of$(undefined), hasReactions, diff --git a/app/components/post_list/post/post.tsx b/app/components/post_list/post/post.tsx index 970608cece..0035bee1cb 100644 --- a/app/components/post_list/post/post.tsx +++ b/app/components/post_list/post/post.tsx @@ -53,6 +53,7 @@ type PostProps = { isJumboEmoji: boolean; isLastReply?: boolean; isPostAddChannelMember: boolean; + isPostPriorityEnabled: boolean; location: string; post: PostModel; rootId?: string; @@ -107,7 +108,7 @@ const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => { const Post = ({ appsEnabled, canDelete, currentUser, differentThreadSequence, hasFiles, hasReplies, highlight, highlightPinnedOrSaved = true, highlightReplyBar, - isCRTEnabled, isConsecutivePost, isEphemeral, isFirstReply, isSaved, isJumboEmoji, isLastReply, isPostAddChannelMember, + isCRTEnabled, isConsecutivePost, isEphemeral, isFirstReply, isSaved, isJumboEmoji, isLastReply, isPostAddChannelMember, isPostPriorityEnabled, location, post, rootId, hasReactions, searchPatterns, shouldRenderReplyButton, skipSavedHeader, skipPinnedHeader, showAddReaction = true, style, testID, thread, previousPost, }: PostProps) => { @@ -221,8 +222,9 @@ const Post = ({ let header: ReactNode; let postAvatar: ReactNode; let consecutiveStyle: StyleProp; - const sameSecuence = hasReplies ? (hasReplies && post.rootId) : !post.rootId; - if (hasSameRoot && isConsecutivePost && sameSecuence) { + const isProrityPost = isPostPriorityEnabled && post.props.priority; + const sameSequence = hasReplies ? (hasReplies && post.rootId) : !post.rootId; + if (!isProrityPost && hasSameRoot && isConsecutivePost && sameSequence) { consecutiveStyle = styles.consective; postAvatar = ; } else { @@ -254,6 +256,7 @@ const Post = ({ differentThreadSequence={differentThreadSequence} isAutoResponse={isAutoResponder} isCRTEnabled={isCRTEnabled} + isPostPriorityEnabled={isPostPriorityEnabled} isEphemeral={isEphemeral} isPendingOrFailed={isPendingOrFailed} isSystemPost={isSystemPost} diff --git a/app/components/post_priority/post_priority_label.tsx b/app/components/post_priority/post_priority_label.tsx new file mode 100644 index 0000000000..8eb35505b1 --- /dev/null +++ b/app/components/post_priority/post_priority_label.tsx @@ -0,0 +1,67 @@ +// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. +// See LICENSE.txt for license information. + +import React from 'react'; +import {useIntl} from 'react-intl'; +import {StyleProp, StyleSheet, Text, View, ViewStyle} from 'react-native'; + +import CompassIcon from '@components/compass_icon'; +import {PostPriorityTypes} from '@constants/post'; +import {typography} from '@utils/typography'; + +const style = StyleSheet.create({ + container: { + flexDirection: 'row', + borderRadius: 4, + alignItems: 'center', + height: 16, + paddingHorizontal: 4, + }, + urgent: { + backgroundColor: '#D24B4E', + }, + important: { + backgroundColor: '#5D89EA', + }, + label: { + color: '#fff', + ...typography('Body', 25, 'SemiBold'), + }, + icon: { + color: '#fff', + fontSize: 12, + marginRight: 4, + }, +}); + +type Props = { + label: string; +}; + +const PostPriorityLabel = ({label}: Props) => { + const intl = useIntl(); + + const containerStyle: StyleProp = [style.container]; + let iconName = ''; + let labelText = ''; + if (label === PostPriorityTypes.URGENT) { + containerStyle.push(style.urgent); + iconName = 'alert-outline'; + labelText = intl.formatMessage({id: 'post_priority.label.urgent', defaultMessage: 'URGENT'}); + } else { + containerStyle.push(style.important); + iconName = 'alert-circle-outline'; + labelText = intl.formatMessage({id: 'post_priority.label.important', defaultMessage: 'IMPORTANT'}); + } + return ( + + + {labelText} + + ); +}; + +export default PostPriorityLabel; diff --git a/app/constants/post.ts b/app/constants/post.ts index bcbc86af5a..0363368581 100644 --- a/app/constants/post.ts +++ b/app/constants/post.ts @@ -34,11 +34,17 @@ export const PostTypes: Record = { CUSTOM_CALLS: 'custom_calls', }; +export const PostPriorityTypes: Record = { + URGENT: 'urgent', + IMPORTANT: 'important', +}; + export const POST_TIME_TO_FAIL = 10000; export default { POST_COLLAPSE_TIMEOUT: 1000 * 60 * 5, POST_TYPES: PostTypes, + POST_PRIORITY_TYPES: PostPriorityTypes, USER_ACTIVITY_POST_TYPES: [ PostTypes.ADD_TO_CHANNEL, PostTypes.JOIN_CHANNEL, diff --git a/app/queries/servers/system.ts b/app/queries/servers/system.ts index 62ae4faabc..1542ee7c29 100644 --- a/app/queries/servers/system.ts +++ b/app/queries/servers/system.ts @@ -5,7 +5,7 @@ import {Database, Q} from '@nozbe/watermelondb'; import {of as of$, Observable} from 'rxjs'; import {switchMap} from 'rxjs/operators'; -import {Preferences} from '@constants'; +import {Config, Preferences} from '@constants'; import {MM_TABLES, SYSTEM_IDENTIFIERS} from '@constants/database'; import {PUSH_PROXY_STATUS_UNKNOWN} from '@constants/push_proxy'; @@ -167,6 +167,15 @@ export const observeConfigIntValue = (database: Database, key: keyof ClientConfi ); }; +export const observeIsPostPriorityEnabled = (database: Database) => { + const config = observeConfig(database); + return config.pipe( + switchMap( + (cfg) => of$(cfg?.FeatureFlagPostPriority === Config.TRUE && cfg?.PostPriority === Config.TRUE), + ), + ); +}; + export const observeLicense = (database: Database): Observable => { return querySystemValue(database, SYSTEM_IDENTIFIERS.LICENSE).observe().pipe( switchMap((result) => (result.length ? result[0].observe() : of$({value: undefined}))), diff --git a/assets/base/i18n/en.json b/assets/base/i18n/en.json index 46b7f266dd..956f7520ca 100644 --- a/assets/base/i18n/en.json +++ b/assets/base/i18n/en.json @@ -701,6 +701,8 @@ "post_info.system": "System", "post_message_view.edited": "(edited)", "post.options.title": "Options", + "post_priority.label.important": "IMPORTANT", + "post_priority.label.urgent": "URGENT", "post.reactions.title": "Reactions", "posts_view.newMsg": "New Messages", "public_link_copied": "Link copied to clipboard", diff --git a/types/api/config.d.ts b/types/api/config.d.ts index 606bf272e0..277dcf31a9 100644 --- a/types/api/config.d.ts +++ b/types/api/config.d.ts @@ -119,6 +119,7 @@ interface ClientConfig { FeatureFlagAppsEnabled?: string; FeatureFlagCollapsedThreads?: string; FeatureFlagGraphQL?: string; + FeatureFlagPostPriority?: string; GfycatApiKey: string; GfycatApiSecret: string; GoogleDeveloperKey: string; @@ -151,6 +152,7 @@ interface ClientConfig { PasswordRequireUppercase: string; PluginsEnabled: string; PostEditTimeLimit: string; + PostPriority: string; PrivacyPolicyLink: string; ReportAProblemLink: string; RequireEmailVerification: string;