From 2d3d43c000a4521a6c9c3995fb3dd801405d73ba Mon Sep 17 00:00:00 2001 From: Avinash Lingaloo Date: Fri, 3 Jun 2022 16:02:40 +0400 Subject: [PATCH] MM-39711 - Gekidou Notification Push Notification main screen (#6312) * added chevron to menu item component * starting with the skeleton * starting with the skeleton * starting with the skeleton * starting with the skeleton * remove extra line * tested on tablets * some corrections * corrections as per review * starting with notification skeleton * attached notification settings to navigation * added auto responder * update translation * update snapshot * updated snapshot * correction after review * removed unnecessary screen * refactored * updated the testIDs * Update Package.resolved * refactor * removed Mattermost as default server name * fix ts * refactored settings constant * display settings skeleton - pending: query for allowed themes * added 'allowedThemes' query * added section item * mention screen skeleton in place * added section and sectionItem component * added reply section to the mention screen * update i18n * rename screens properly * update i18n * Refactored to MentionSettings component * Refactored to ReplySettings component * style clean up * textTransform uppercase * rename Section/SectionItem to Block/BlockItem * added mobile push notif screen - push status section * adding text to those two components * correction following review * added mobile push notification section * added mobile push notification thread section * style fix * code fix * code fix * MM-39711 - Gekidou Notification - Auto Responder main screen (#6313) * added skeleton for auto responder * code clean up * correction from peer review * correction from PR review * clean up * PR review correction * correction * clean up * clean up * code clean up * code clean up --- app/components/block_item/index.tsx | 38 +++-- app/constants/screens.ts | 4 + app/screens/index.tsx | 6 + app/screens/settings/constant.ts | 4 +- app/screens/settings/display/display.tsx | 2 +- .../notification_auto_responder/index.ts | 18 ++ .../notification_auto_responder.tsx | 154 ++++++++++++++++++ .../notification_mention/mention_settings.tsx | 97 ++++------- .../notification_mention.tsx | 2 +- .../notification_mention/reply_settings.tsx | 45 ++--- .../settings/notification_push/index.tsx | 20 +++ .../notification_push/notification_push.tsx | 89 ++++++++++ .../settings/notification_push/push_send.tsx | 102 ++++++++++++ .../notification_push/push_status.tsx | 82 ++++++++++ .../notification_push/push_thread.tsx | 78 +++++++++ .../settings/notifications/notifications.tsx | 31 +++- app/utils/user/index.ts | 19 +++ assets/base/i18n/en.json | 22 ++- types/api/users.d.ts | 8 +- types/screens/settings.d.ts | 4 + 20 files changed, 699 insertions(+), 126 deletions(-) create mode 100644 app/screens/settings/notification_auto_responder/index.ts create mode 100644 app/screens/settings/notification_auto_responder/notification_auto_responder.tsx create mode 100644 app/screens/settings/notification_push/index.tsx create mode 100644 app/screens/settings/notification_push/notification_push.tsx create mode 100644 app/screens/settings/notification_push/push_send.tsx create mode 100644 app/screens/settings/notification_push/push_status.tsx create mode 100644 app/screens/settings/notification_push/push_thread.tsx create mode 100644 types/screens/settings.d.ts diff --git a/app/components/block_item/index.tsx b/app/components/block_item/index.tsx index 1545e0311..0e4963d33 100644 --- a/app/components/block_item/index.tsx +++ b/app/components/block_item/index.tsx @@ -2,7 +2,7 @@ // See LICENSE.txt for license information. import React, {ReactElement, useCallback, useMemo} from 'react'; -import {Switch, Text, TouchableOpacity, View} from 'react-native'; +import {StyleProp, Switch, Text, TextStyle, TouchableOpacity, View, ViewStyle} from 'react-native'; import CompassIcon from '@components/compass_icon'; import {useTheme} from '@context/theme'; @@ -36,15 +36,12 @@ const getStyleSheet = makeStyleSheetFromTheme((theme) => { }, label: { color: theme.centerChannelColor, - ...typography('Body', 600, 'SemiBold'), - fontSize: 16, - lineHeight: 24, + ...typography('Body', 200, 'SemiBold'), + marginLeft: 9, }, description: { color: changeOpacity(theme.centerChannelColor, 0.6), - ...typography('Body', 400, 'Regular'), - fontSize: 12, - lineHeight: 16, + ...typography('Body', 75, 'Regular'), marginTop: 3, }, arrow: { @@ -62,14 +59,29 @@ type Props = { action: (value: string | boolean) => void; actionType: string; actionValue?: string; + containerStyle?: StyleProp; description?: string | ReactElement; + descriptionStyle?: StyleProp; icon?: string; label: string | ReactElement; + labelStyle?: StyleProp; selected?: boolean; testID?: string; } -const BlockItem = ({testID = 'sectionItem', action, actionType, actionValue, label, selected, description, icon}: Props) => { +const BlockItem = ({ + action, + actionType, + actionValue, + containerStyle, + description, + descriptionStyle, + icon, + label, + labelStyle, + selected, + testID = 'sectionItem', +}: Props) => { const theme = useTheme(); const style = getStyleSheet(theme); @@ -104,17 +116,17 @@ const BlockItem = ({testID = 'sectionItem', action, actionType, actionValue, lab action(actionValue || ''); }, [actionValue, action]); - const labelStyle = useMemo(() => { + const labelStyles = useMemo(() => { if (icon) { return [style.label, {marginLeft: 4}]; } - return style.label; + return [style.label, labelStyle]; }, [Boolean(icon), style]); const component = ( @@ -126,14 +138,14 @@ const BlockItem = ({testID = 'sectionItem', action, actionType, actionValue, lab /> )} {label} {description} diff --git a/app/constants/screens.ts b/app/constants/screens.ts index ac8c6a66f..fe5f67034 100644 --- a/app/constants/screens.ts +++ b/app/constants/screens.ts @@ -44,7 +44,9 @@ export const SERVER = 'Server'; export const SETTINGS = 'Settings'; export const SETTINGS_DISPLAY = 'SettingsDisplay'; export const SETTINGS_NOTIFICATION = 'SettingsNotification'; +export const SETTINGS_NOTIFICATION_AUTO_RESPONDER = 'SettingsNotificationAutoResponder'; export const SETTINGS_NOTIFICATION_MENTION = 'SettingsNotificationMention'; +export const SETTINGS_NOTIFICATION_PUSH = 'SettingsNotificationPush'; export const SNACK_BAR = 'SnackBar'; export const SSO = 'SSO'; export const THREAD = 'Thread'; @@ -95,7 +97,9 @@ export default { SETTINGS, SETTINGS_DISPLAY, SETTINGS_NOTIFICATION, + SETTINGS_NOTIFICATION_AUTO_RESPONDER, SETTINGS_NOTIFICATION_MENTION, + SETTINGS_NOTIFICATION_PUSH, SNACK_BAR, SSO, THREAD, diff --git a/app/screens/index.tsx b/app/screens/index.tsx index ec5a3469c..7dc16f98a 100644 --- a/app/screens/index.tsx +++ b/app/screens/index.tsx @@ -197,6 +197,12 @@ Navigation.setLazyComponentRegistrator((screenName) => { case Screens.SETTINGS_NOTIFICATION_MENTION: screen = withServerDatabase(require('@screens/settings/notification_mention').default); break; + case Screens.SETTINGS_NOTIFICATION_PUSH: + screen = withServerDatabase(require('@screens/settings/notification_push').default); + break; + case Screens.SETTINGS_NOTIFICATION_AUTO_RESPONDER: + screen = withServerDatabase(require('@screens/settings/notification_auto_responder').default); + break; } if (screen) { diff --git a/app/screens/settings/constant.ts b/app/screens/settings/constant.ts index ed59467df..d9f265c4a 100644 --- a/app/screens/settings/constant.ts +++ b/app/screens/settings/constant.ts @@ -43,13 +43,13 @@ export const NotificationsOptionConfig = { }, push_notification: { defaultMessage: 'Push Notifications', - i18nId: t('mobile.notification_settings.mobile'), + i18nId: t('notification_settings.mobile'), iconName: 'cellphone', testID: 'notification_settings.push_notification', }, automatic_dm_replies: { defaultMessage: 'Automatic Direct Message Replies', - i18nId: t('mobile.notification_settings.ooo_auto_responder'), + i18nId: t('notification_settings.ooo_auto_responder'), iconName: 'reply-outline', testID: 'notification_settings.automatic_dm_replies', }, diff --git a/app/screens/settings/display/display.tsx b/app/screens/settings/display/display.tsx index 58ab09ae1..7d84bf6d8 100644 --- a/app/screens/settings/display/display.tsx +++ b/app/screens/settings/display/display.tsx @@ -49,7 +49,7 @@ const Display = ({isTimezoneEnabled, isThemeSwitchingEnabled}: DisplayProps) => return ( { + return { + currentUser: observeCurrentUser(database), + }; +}); + +export default withDatabase(enhanced(NotificationAutoResponder)); diff --git a/app/screens/settings/notification_auto_responder/notification_auto_responder.tsx b/app/screens/settings/notification_auto_responder/notification_auto_responder.tsx new file mode 100644 index 000000000..b32a84b4f --- /dev/null +++ b/app/screens/settings/notification_auto_responder/notification_auto_responder.tsx @@ -0,0 +1,154 @@ +// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. +// See LICENSE.txt for license information. + +import React, {useCallback, useMemo, useRef, useState} from 'react'; +import {useIntl} from 'react-intl'; +import {View} from 'react-native'; +import {Edge, SafeAreaView} from 'react-native-safe-area-context'; + +import BlockItem from '@components/block_item'; +import FloatingTextInput from '@components/floating_text_input_label'; +import FormattedText from '@components/formatted_text'; +import {General} from '@constants'; +import {useTheme} from '@context/theme'; +import {t} from '@i18n'; +import {changeOpacity, makeStyleSheetFromTheme, getKeyboardAppearanceFromTheme} from '@utils/theme'; +import {typography} from '@utils/typography'; +import {getNotificationProps} from '@utils/user'; + +import type UserModel from '@typings/database/models/servers/user'; + +const headerText = { + id: t('notification_settings.auto_responder'), + defaultMessage: 'Custom message', +}; + +const OOO = { + id: t('notification_settings.auto_responder.default_message'), + defaultMessage: 'Hello, I am out of office and unable to respond to messages.', +}; + +const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => { + return { + container: { + flex: 1, + backgroundColor: theme.centerChannelBg, + }, + wrapper: { + backgroundColor: changeOpacity(theme.centerChannelColor, 0.06), + flex: 1, + paddingTop: 35, + }, + input: { + color: theme.centerChannelColor, + fontSize: 15, + height: 150, + paddingHorizontal: 15, + paddingVertical: 10, + }, + footer: { + paddingHorizontal: 15, + color: changeOpacity(theme.centerChannelColor, 0.5), + textAlign: 'justify', + ...typography('Body', 75), + }, + area: { + paddingHorizontal: 16, + }, + label: { + color: theme.centerChannelColor, + ...typography('Body', 200, 'Regular'), + }, + enabled: { + paddingHorizontal: 8, + backgroundColor: theme.centerChannelBg, + marginBottom: 16, + }, + }; +}); + +const edges: Edge[] = ['left', 'right']; +type NotificationAutoResponderProps = { + currentUser: UserModel; +} +const NotificationAutoResponder = ({currentUser}: NotificationAutoResponderProps) => { + const theme = useTheme(); + const autoresponderRef = useRef(null); + const intl = useIntl(); + const userNotifyProps = useMemo(() => getNotificationProps(currentUser), [currentUser.notifyProps]); + + const [notifyProps, setNotifyProps] = useState>({ + ...userNotifyProps, + auto_responder_active: (currentUser.status === General.OUT_OF_OFFICE && userNotifyProps.auto_responder_active) ? 'true' : 'false', + auto_responder_message: userNotifyProps.auto_responder_message || intl.formatMessage(OOO), + }); + + const styles = getStyleSheet(theme); + + const onAutoResponseToggle = useCallback((active: boolean) => { + setNotifyProps({ + ...notifyProps, + auto_responder_active: `${active}`, + }); + }, [notifyProps]); + + const onAutoResponseChangeText = useCallback((message: string) => { + setNotifyProps({ + ...notifyProps, + auto_responder_message: message, + }); + }, [notifyProps]); + + return ( + + + + } + action={onAutoResponseToggle} + actionType='toggle' + selected={notifyProps.auto_responder_active === 'true'} + /> + + {notifyProps.auto_responder_active === 'true' && ( + + )} + + + + ); +}; + +export default NotificationAutoResponder; diff --git a/app/screens/settings/notification_mention/mention_settings.tsx b/app/screens/settings/notification_mention/mention_settings.tsx index 1516062b5..0cf753411 100644 --- a/app/screens/settings/notification_mention/mention_settings.tsx +++ b/app/screens/settings/notification_mention/mention_settings.tsx @@ -2,11 +2,11 @@ // See LICENSE.txt for license information. import React, {useReducer} from 'react'; -import {Alert, Text, View} from 'react-native'; +import {useIntl} from 'react-intl'; +import {Alert, View} from 'react-native'; import Block from '@components/block'; import BlockItem from '@components/block_item'; -import FormattedText from '@components/formatted_text'; import {useTheme} from '@context/theme'; import {t} from '@i18n'; import UserModel from '@typings/database/models/servers/user'; @@ -47,19 +47,21 @@ const getStyleSheet = makeStyleSheetFromTheme((theme) => { backgroundColor: changeOpacity(theme.centerChannelColor, 0.1), flex: 1, height: 1, - marginLeft: 15, - }, - area: { - paddingHorizontal: 16, }, upperCase: { textTransform: 'uppercase', }, label: { color: theme.centerChannelColor, - ...typography('Body', 400, 'Regular'), - fontSize: 16, - lineHeight: 24, + ...typography('Body', 200, 'Regular'), + }, + desc: { + color: theme.centerChannelColor, + ...typography('Body', 100, 'Regular'), + paddingLeft: 8, + }, + container: { + paddingHorizontal: 8, }, }; }); @@ -72,18 +74,7 @@ const MentionSettings = ({currentUser, mentionKeys}: MentionSectionProps) => { const [{firstName, usernameMention, channel}, dispatch] = useReducer(reducer, INITIAL_STATE); const theme = useTheme(); const styles = getStyleSheet(theme); - - let mentionKeysComponent; - if (mentionKeys) { - mentionKeysComponent = ({mentionKeys}); - } else { - mentionKeysComponent = ( - - ); - } + const intl = useIntl(); const toggleChannelMentions = () => { dispatch({ @@ -119,24 +110,17 @@ const MentionSettings = ({currentUser, mentionKeys}: MentionSectionProps) => { { Boolean(currentUser?.firstName) && ( <> - {currentUser!.firstName} - - )} - description={( - - )} action={toggleFirstNameMention} actionType='toggle' + containerStyle={styles.container} + description={intl.formatMessage({id: 'notification_settings.mentions.sensitiveName', defaultMessage: 'Your case sensitive first name'})} + descriptionStyle={styles.desc} + label={currentUser!.firstName} + labelStyle={styles.label} selected={firstName} /> @@ -145,51 +129,36 @@ const MentionSettings = ({currentUser, mentionKeys}: MentionSectionProps) => { } {Boolean(currentUser?.username) && ( - {currentUser!.username} - - )} - description={( - - )} - selected={usernameMention} action={toggleUsernameMention} actionType='toggle' + containerStyle={styles.container} + description={intl.formatMessage({id: 'notification_settings.mentions.sensitiveUsername', defaultMessage: 'Your non-case sensitive username'})} + descriptionStyle={styles.desc} + label={currentUser!.username} + labelStyle={styles.label} + selected={usernameMention} /> )} - {'@channel, @all, @here'} - - )} - description={( - - )} action={toggleChannelMentions} actionType='toggle' + containerStyle={styles.container} + description={intl.formatMessage({id: 'notification_settings.mentions.channelWide', defaultMessage: 'Channel-wide mentions'})} + descriptionStyle={styles.desc} + label='@channel, @all, @here' + labelStyle={styles.label} selected={channel} /> - )} - description={mentionKeysComponent} action={goToNotificationSettingsMentionKeywords} actionType='arrow' + containerStyle={styles.container} + description={mentionKeys || intl.formatMessage({id: 'notification_settings.mentions.keywordsDescription', defaultMessage: 'Other words that trigger a mention'})} + descriptionStyle={styles.desc} + label={intl.formatMessage({id: 'notification_settings.mentions.keywords', defaultMessage: 'Keywords'})} + labelStyle={styles.label} /> ); diff --git a/app/screens/settings/notification_mention/notification_mention.tsx b/app/screens/settings/notification_mention/notification_mention.tsx index 28eed27db..416175b9d 100644 --- a/app/screens/settings/notification_mention/notification_mention.tsx +++ b/app/screens/settings/notification_mention/notification_mention.tsx @@ -46,7 +46,7 @@ const NotificationMention = ({currentUser, mentionKeys, isCRTEnabled}: Notificat return ( { return { - area: { - paddingHorizontal: 16, - }, separator: { backgroundColor: changeOpacity(theme.centerChannelColor, 0.1), flex: 1, height: 1, - marginLeft: 15, }, upperCase: { textTransform: 'uppercase', }, label: { color: theme.centerChannelColor, - ...typography('Body', 400, 'Regular'), - fontSize: 16, - lineHeight: 24, + ...typography('Body', 200, 'Regular'), + }, + container: { + paddingHorizontal: 8, }, }; }); @@ -44,6 +41,7 @@ const ReplySettings = () => { const [replyNotificationType, setReplyNotificationType] = useState('any'); //todo: initialize with value from db/api const theme = useTheme(); const styles = getStyleSheet(theme); + const intl = useIntl(); const setReplyNotifications = (notifType: string) => { setReplyNotificationType(notifType); @@ -52,48 +50,35 @@ const ReplySettings = () => { return ( - )} action={setReplyNotifications} actionType='select' actionValue='any' + containerStyle={styles.container} + label={intl.formatMessage({id: 'notification_settings.threads_start_participate', defaultMessage: 'Threads that I start or participate in'})} + labelStyle={styles.label} selected={replyNotificationType === 'any'} /> - )} action={setReplyNotifications} actionType='select' actionValue='root' + containerStyle={styles.container} + label={intl.formatMessage({id: 'notification_settings.threads_start', defaultMessage: 'Threads that I start'})} + labelStyle={styles.label} selected={replyNotificationType === 'root'} /> - )} action={setReplyNotifications} actionType='select' actionValue='never' + containerStyle={styles.container} + label={intl.formatMessage({id: 'notification_settings.threads_mentions', defaultMessage: 'Mentions in threads'})} + labelStyle={styles.label} selected={replyNotificationType === 'never'} /> diff --git a/app/screens/settings/notification_push/index.tsx b/app/screens/settings/notification_push/index.tsx new file mode 100644 index 000000000..9c2d921c9 --- /dev/null +++ b/app/screens/settings/notification_push/index.tsx @@ -0,0 +1,20 @@ +// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. +// See LICENSE.txt for license information. + +import {withDatabase} from '@nozbe/watermelondb/DatabaseProvider'; +import withObservables from '@nozbe/with-observables'; + +import {observeConfigBooleanValue} from '@queries/servers/system'; +import {observeIsCRTEnabled} from '@queries/servers/thread'; +import {WithDatabaseArgs} from '@typings/database/database'; + +import NotificationPush from './notification_push'; + +const enhanced = withObservables([], ({database}: WithDatabaseArgs) => { + return { + sendPushNotifications: observeConfigBooleanValue(database, 'SendPushNotifications'), + isCRTEnabled: observeIsCRTEnabled(database), + }; +}); + +export default withDatabase(enhanced(NotificationPush)); diff --git a/app/screens/settings/notification_push/notification_push.tsx b/app/screens/settings/notification_push/notification_push.tsx new file mode 100644 index 000000000..d9b291622 --- /dev/null +++ b/app/screens/settings/notification_push/notification_push.tsx @@ -0,0 +1,89 @@ +// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. +// See LICENSE.txt for license information. + +import React, {useState} from 'react'; +import {ScrollView} from 'react-native'; +import {Edge, SafeAreaView} from 'react-native-safe-area-context'; + +import {useTheme} from '@context/theme'; +import {changeOpacity, makeStyleSheetFromTheme} from '@utils/theme'; + +import MobileSendPush from './push_send'; +import MobilePushStatus from './push_status'; +import MobilePushThread from './push_thread'; + +const getStyleSheet = makeStyleSheetFromTheme((theme) => { + return { + container: { + flex: 1, + backgroundColor: theme.centerChannelBg, + }, + scrollView: { + flex: 1, + backgroundColor: changeOpacity(theme.centerChannelColor, 0.06), + }, + scrollViewContent: { + paddingVertical: 30, + }, + }; +}); +const edges: Edge[] = ['left', 'right']; + +type NotificationMobileProps = { + isCRTEnabled: boolean; + sendPushNotifications: boolean; +}; +const NotificationPush = ({isCRTEnabled, sendPushNotifications}: NotificationMobileProps) => { + const theme = useTheme(); + const [pushStatus, setPushStatus] = useState('online'); + const [pushPref, setPushPref] = useState('online'); + const [pushThread, setPushThreadPref] = useState('online'); + + const styles = getStyleSheet(theme); + + const setMobilePushStatus = (status: PushStatus) => { + setPushStatus(status); + }; + + const setMobilePushPref = (status: PushStatus) => { + setPushPref(status); + }; + + const onMobilePushThreadChanged = (status: PushStatus) => { + setPushThreadPref(status); + }; + + return ( + + + + {isCRTEnabled && pushPref === 'mention' && ( + + )} + {sendPushNotifications && pushPref !== 'none' && ( + + )} + + + ); +}; + +export default NotificationPush; diff --git a/app/screens/settings/notification_push/push_send.tsx b/app/screens/settings/notification_push/push_send.tsx new file mode 100644 index 000000000..369b7cdc2 --- /dev/null +++ b/app/screens/settings/notification_push/push_send.tsx @@ -0,0 +1,102 @@ +// 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 {View} from 'react-native'; + +import Block from '@components/block'; +import BlockItem from '@components/block_item'; +import FormattedText from '@components/formatted_text'; +import {useTheme} from '@context/theme'; +import {t} from '@i18n'; +import {changeOpacity, makeStyleSheetFromTheme} from '@utils/theme'; +import {typography} from '@utils/typography'; + +const headerText = { + id: t('notification_settings.send_notification'), + defaultMessage: 'Send notifications', +}; +const getStyleSheet = makeStyleSheetFromTheme((theme) => { + return { + upperCase: { + textTransform: 'uppercase', + }, + separator: { + backgroundColor: changeOpacity(theme.centerChannelColor, 0.1), + flex: 1, + height: 1, + }, + label: { + color: theme.centerChannelColor, + ...typography('Body', 100, 'Regular'), + }, + disabled: { + color: theme.centerChannelColor, + fontSize: 15, + paddingHorizontal: 15, + paddingVertical: 10, + }, + }; +}); + +type MobileSendPushProps = { + sendPushNotifications: boolean; + pushStatus: PushStatus; + setMobilePushPref: (status: PushStatus) => void; +} +const MobileSendPush = ({sendPushNotifications, pushStatus, setMobilePushPref}: MobileSendPushProps) => { + const theme = useTheme(); + const styles = getStyleSheet(theme); + const intl = useIntl(); + + return ( + + {sendPushNotifications && + <> + + + + + + + } + {!sendPushNotifications && + + } + + ); +}; + +export default MobileSendPush; diff --git a/app/screens/settings/notification_push/push_status.tsx b/app/screens/settings/notification_push/push_status.tsx new file mode 100644 index 000000000..7de54de17 --- /dev/null +++ b/app/screens/settings/notification_push/push_status.tsx @@ -0,0 +1,82 @@ +// 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 {View} from 'react-native'; + +import Block from '@components/block'; +import BlockItem from '@components/block_item'; +import {useTheme} from '@context/theme'; +import {t} from '@i18n'; +import {changeOpacity, makeStyleSheetFromTheme} from '@utils/theme'; +import {typography} from '@utils/typography'; + +const headerText = { + id: t('notification_settings.mobile.push_status'), + defaultMessage: 'Trigger push notifications when', +}; + +const getStyleSheet = makeStyleSheetFromTheme((theme) => { + return { + upperCase: { + textTransform: 'uppercase', + }, + separator: { + backgroundColor: changeOpacity(theme.centerChannelColor, 0.1), + flex: 1, + height: 1, + }, + label: { + color: theme.centerChannelColor, + ...typography('Body', 100, 'Regular'), + + }, + }; +}); + +type MobilePushStatusProps = { + pushStatus: PushStatus; + setMobilePushStatus: (status: PushStatus) => void; +} +const MobilePushStatus = ({pushStatus, setMobilePushStatus}: MobilePushStatusProps) => { + const theme = useTheme(); + const styles = getStyleSheet(theme); + const intl = useIntl(); + + return ( + + + + + + + + ); +}; + +export default MobilePushStatus; diff --git a/app/screens/settings/notification_push/push_thread.tsx b/app/screens/settings/notification_push/push_thread.tsx new file mode 100644 index 000000000..7a0f3275f --- /dev/null +++ b/app/screens/settings/notification_push/push_thread.tsx @@ -0,0 +1,78 @@ +// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. +// See LICENSE.txt for license information. + +import React from 'react'; +import {View} from 'react-native'; + +import Block from '@components/block'; +import BlockItem from '@components/block_item'; +import FormattedText from '@components/formatted_text'; +import {useTheme} from '@context/theme'; +import {t} from '@i18n'; +import {changeOpacity, makeStyleSheetFromTheme} from '@utils/theme'; +import {typography} from '@utils/typography'; + +const getStyleSheet = makeStyleSheetFromTheme((theme) => { + return { + upperCase: { + textTransform: 'uppercase', + }, + separator: { + backgroundColor: changeOpacity(theme.centerChannelColor, 0.1), + flex: 1, + height: 1, + marginLeft: 15, + }, + area: { + paddingHorizontal: 16, + }, + label: { + color: theme.centerChannelColor, + ...typography('Body', 100, 'Regular'), + }, + }; +}); + +const headerText = { + id: t('notification_settings.push_threads'), + defaultMessage: 'Thread reply notifications', +}; +const footerText = { + id: t('notification_settings.push_threads.info'), + defaultMessage: 'When enabled, any reply to a thread you\'re following will send a mobile push notification', +}; + +type MobilePushThreadProps = { + onMobilePushThreadChanged: (status: string) => void; + pushThread: PushStatus; +} + +const MobilePushThread = ({pushThread, onMobilePushThreadChanged}: MobilePushThreadProps) => { + const theme = useTheme(); + const styles = getStyleSheet(theme); + + return ( + + + )} + action={onMobilePushThreadChanged} + actionType='toggle' + selected={pushThread === 'all'} + /> + + + ); +}; + +export default MobilePushThread; diff --git a/app/screens/settings/notifications/notifications.tsx b/app/screens/settings/notifications/notifications.tsx index 9e8d68652..5899c6056 100644 --- a/app/screens/settings/notifications/notifications.tsx +++ b/app/screens/settings/notifications/notifications.tsx @@ -3,7 +3,7 @@ import React from 'react'; import {useIntl} from 'react-intl'; -import {Alert, Platform, ScrollView, View} from 'react-native'; +import {Platform, ScrollView, View} from 'react-native'; import {Edge, SafeAreaView} from 'react-native-safe-area-context'; import {Screens} from '@constants'; @@ -53,12 +53,6 @@ const Notifications = ({isCRTEnabled, enableAutoResponder}: NotificationsProps) mentionsI18nDefault = 'Mentions'; } - const onPressHandler = () => { - return Alert.alert( - 'The functionality you are trying to use has not yet been implemented.', - ); - }; - const goToNotificationSettingsMentions = () => { const screen = Screens.SETTINGS_NOTIFICATION_MENTION; @@ -69,6 +63,25 @@ const Notifications = ({isCRTEnabled, enableAutoResponder}: NotificationsProps) goToScreen(screen, title); }; + const goToNotificationSettingsPush = () => { + const screen = Screens.SETTINGS_NOTIFICATION_PUSH; + const title = intl.formatMessage({ + id: 'notification_settings.push_notification', + defaultMessage: 'Push Notifications', + }); + + goToScreen(screen, title); + }; + + const goToNotificationAutoResponder = () => { + const screen = Screens.SETTINGS_NOTIFICATION_AUTO_RESPONDER; + const title = intl.formatMessage({ + id: 'notification_settings.auto_responder', + defaultMessage: 'Automatic Replies', + }); + goToScreen(screen, title); + }; + return ( {enableAutoResponder && ( )} diff --git a/app/utils/user/index.ts b/app/utils/user/index.ts index 773d283d5..b2660ec00 100644 --- a/app/utils/user/index.ts +++ b/app/utils/user/index.ts @@ -285,3 +285,22 @@ export function filterProfilesMatchingTerm(users: UserProfile[], term: string): some((suggestion) => suggestion.startsWith(trimmedTerm)); }); } + +export function getNotificationProps(user: UserModel) { + if (user && user.notifyProps) { + return user.notifyProps; + } + + const props: Partial = { + channel: 'true', + comments: 'any', + desktop: 'all', + desktop_sound: 'true', + first_name: (!user || !user.firstName) ? 'false' : 'true', + mention_keys: user ? `${user.username},@${user.username}` : '', + push: 'mention', + push_status: 'online', + }; + + return props; +} diff --git a/assets/base/i18n/en.json b/assets/base/i18n/en.json index f51fa2d75..d6dd692f4 100644 --- a/assets/base/i18n/en.json +++ b/assets/base/i18n/en.json @@ -441,8 +441,6 @@ "mobile.notice_mobile_link": "mobile apps", "mobile.notice_platform_link": "server", "mobile.notice_text": "Mattermost is made possible by the open source software used in our {platform} and {mobile}.", - "mobile.notification_settings.mobile": "Push Notifications", - "mobile.notification_settings.ooo_auto_responder": "Automatic Direct Message Replies", "mobile.oauth.failed_to_login": "Your login attempt failed. Please try again.", "mobile.oauth.failed_to_open_link": "The link failed to open. Please try again.", "mobile.oauth.failed_to_open_link_no_browser": "The link failed to open. Please verify that a browser is installed on the device.", @@ -553,6 +551,11 @@ "more_messages.text": "{count} new {count, plural, one {message} other {messages}}", "msg_typing.areTyping": "{users} and {last} are typing...", "msg_typing.isTyping": "{user} is typing...", + "notification_settings.auto_responder": "Automatic Replies", + "notification_settings.auto_responder.default_message": "Hello, I am out of office and unable to respond to messages.", + "notification_settings.auto_responder.enabled": "Enabled", + "notification_settings.auto_responder.footer_message": "Set a custom message that will be automatically sent in response to Direct Messages. Mentions in Public and Private Channels will not trigger the automated reply. Enabling Automatic Replies sets your status to Out of Office and disables email and push notifications.", + "notification_settings.auto_responder.message_placeholder": "Message", "notification_settings.mention.reply": "Send reply notifications for", "notification_settings.mentions": "Mentions", "notification_settings.mentions_replies": "Mentions and Replies", @@ -562,6 +565,21 @@ "notification_settings.mentions.sensitiveName": "Your case sensitive first name", "notification_settings.mentions.sensitiveUsername": "Your non-case sensitive username", "notification_settings.mentions.wordsTrigger": "Words that trigger mentions", + "notification_settings.mobile": "Push Notifications", + "notification_settings.mobile.away": "Away or offline", + "notification_settings.mobile.offline": "Offline", + "notification_settings.mobile.online": "Online, away or offline", + "notification_settings.mobile.push_status": "Trigger push notifications when", + "notification_settings.ooo_auto_responder": "Automatic Direct Message Replies", + "notification_settings.push_notification": "Push Notifications", + "notification_settings.push_threads": "Thread reply notifications", + "notification_settings.push_threads.description": "Notify me about all replies to threads I'm following", + "notification_settings.push_threads.info": "When enabled, any reply to a thread you're following will send a mobile push notification", + "notification_settings.pushNotification.allActivity": "For all activity", + "notification_settings.pushNotification.disabled_long": "Push notifications for mobile devices have been disabled by your System Administrator.", + "notification_settings.pushNotification.never": "Never", + "notification_settings.pushNotification.onlyMentions": "Only for mentions and direct messages", + "notification_settings.send_notification": "Send notifications", "notification_settings.threads_mentions": "Mentions in threads", "notification_settings.threads_start": "Threads that I start", "notification_settings.threads_start_participate": "Threads that I start or participate in", diff --git a/types/api/users.d.ts b/types/api/users.d.ts index 413e389e2..94d5cee48 100644 --- a/types/api/users.d.ts +++ b/types/api/users.d.ts @@ -4,17 +4,17 @@ type UserNotifyProps = { auto_responder_active?: 'true' | 'false'; auto_responder_message?: string; + channel: 'true' | 'false'; + comments: 'never' | 'root' | 'any'; desktop: 'default' | 'all' | 'mention' | 'none'; desktop_notification_sound?: string; desktop_sound: 'true' | 'false'; email: 'true' | 'false'; + first_name: 'true' | 'false'; mark_unread: 'all' | 'mention'; + mention_keys: string; push: 'default' | 'all' | 'mention' | 'none'; push_status: 'ooo' | 'offline' | 'away' | 'dnd' | 'online'; - comments: 'never' | 'root' | 'any'; - first_name: 'true' | 'false'; - channel: 'true' | 'false'; - mention_keys: string; user_id?: string; }; diff --git a/types/screens/settings.d.ts b/types/screens/settings.d.ts new file mode 100644 index 000000000..a0d7a43f8 --- /dev/null +++ b/types/screens/settings.d.ts @@ -0,0 +1,4 @@ +// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. +// See LICENSE.txt for license information. + +type PushStatus = 'away' | 'online' | 'offline' | 'none' | 'mention' | 'all';