diff --git a/app/components/floating_text_input_label/index.tsx b/app/components/floating_text_input_label/index.tsx index 1b886d34af..7a788f5f32 100644 --- a/app/components/floating_text_input_label/index.tsx +++ b/app/components/floating_text_input_label/index.tsx @@ -92,44 +92,44 @@ export type FloatingTextInputRef = { type FloatingTextInputProps = TextInputProps & { containerStyle?: ViewStyle; - textInputStyle?: TextStyle; - labelTextStyle?: TextStyle; editable?: boolean; error?: string; errorIcon?: string; isKeyboardInput?: boolean; label: string; + labelTextStyle?: TextStyle; multiline?: boolean; onBlur?: (event: NativeSyntheticEvent) => void; onFocus?: (e: NativeSyntheticEvent) => void; - onPress?: (e: GestureResponderEvent) => void; onLayout?: (e: LayoutChangeEvent) => void; + onPress?: (e: GestureResponderEvent) => void; placeholder?: string; showErrorIcon?: boolean; testID?: string; + textInputStyle?: TextStyle; theme: Theme; value: string; } const FloatingTextInput = forwardRef(({ - error, containerStyle, - isKeyboardInput = true, editable = true, + error, errorIcon = 'alert-outline', + isKeyboardInput = true, label = '', - onPress = undefined, - onFocus, - onBlur, - onLayout, - showErrorIcon = true, - placeholder, + labelTextStyle, multiline, + onBlur, + onFocus, + onLayout, + onPress, + placeholder, + showErrorIcon = true, + testID, + textInputStyle, theme, value = '', - textInputStyle, - labelTextStyle, - testID, ...props }: FloatingTextInputProps, ref) => { const [focused, setIsFocused] = useState(false); diff --git a/app/screens/settings/notification_auto_responder/notification_auto_responder.tsx b/app/screens/settings/notification_auto_responder/notification_auto_responder.tsx index 247adb306c..5ba8b23552 100644 --- a/app/screens/settings/notification_auto_responder/notification_auto_responder.tsx +++ b/app/screens/settings/notification_auto_responder/notification_auto_responder.tsx @@ -49,10 +49,10 @@ const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => { }, input: { color: theme.centerChannelColor, - fontSize: 15, height: 150, paddingHorizontal: 15, paddingVertical: 10, + ...typography('Body', 200, 'Regular'), }, footer: { paddingHorizontal: 15, @@ -65,7 +65,7 @@ const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => { }, label: { color: theme.centerChannelColor, - ...typography('Body', 200, 'Regular'), + ...typography('Body', 100, 'Regular'), }, enabled: { paddingHorizontal: 8, @@ -172,7 +172,7 @@ const NotificationAutoResponder = ({currentUser, componentId}: NotificationAutoR placeholder={intl.formatMessage(headerText)} placeholderTextColor={changeOpacity(theme.centerChannelColor, 0.4)} returnKeyType='done' - style={styles.input} + textInputStyle={styles.input} textAlignVertical='top' theme={theme} underlineColorAndroid='transparent' diff --git a/app/screens/settings/notification_mention/mention_settings.tsx b/app/screens/settings/notification_mention/mention_settings.tsx index 3c9bba4c3e..d2dfa8f3b5 100644 --- a/app/screens/settings/notification_mention/mention_settings.tsx +++ b/app/screens/settings/notification_mention/mention_settings.tsx @@ -1,46 +1,32 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. -import React, {useReducer} from 'react'; +import React, {useCallback, useEffect, useMemo, useState} from 'react'; import {useIntl} from 'react-intl'; -import {Alert, View} from 'react-native'; +import {View} from 'react-native'; +import {updateMe} from '@actions/remote/user'; import Block from '@components/block'; +import FloatingTextInput from '@components/floating_text_input_label'; import OptionItem from '@components/option_item'; +import {useServerUrl} from '@context/server'; import {useTheme} from '@context/theme'; +import useAndroidHardwareBackHandler from '@hooks/android_back_handler'; +import useNavButtonPressed from '@hooks/navigation_button_pressed'; import {t} from '@i18n'; +import {popTopScreen, setButtons} from '@screens/navigation'; import UserModel from '@typings/database/models/servers/user'; -import {changeOpacity, makeStyleSheetFromTheme} from '@utils/theme'; +import {changeOpacity, getKeyboardAppearanceFromTheme, makeStyleSheetFromTheme} from '@utils/theme'; import {typography} from '@utils/typography'; - -const UPDATE_MENTION_PREF = 'UPDATE_MENTION_PREF'; -const INITIAL_STATE = { - firstName: false, - usernameMention: false, - channel: false, -}; -type Action = { - type: string; - data: Partial; -} -const reducer = (state: typeof INITIAL_STATE, action: Action) => { - switch (action.type) { - case UPDATE_MENTION_PREF: - return { - ...state, - ...action.data, - }; - - default: - return state; - } -}; +import {getNotificationProps} from '@utils/user'; const mentionHeaderText = { id: t('notification_settings.mentions.wordsTrigger'), defaultMessage: 'Words that trigger mentions', }; +const SAVE_MENTION_BUTTON_ID = 'SAVE_MENTION_BUTTON_ID'; + const getStyleSheet = makeStyleSheetFromTheme((theme) => { return { separator: { @@ -63,48 +49,113 @@ const getStyleSheet = makeStyleSheetFromTheme((theme) => { container: { paddingHorizontal: 8, }, + input: { + color: theme.centerChannelColor, + height: 150, + paddingHorizontal: 15, + ...typography('Body', 100, 'Regular'), + }, + containerStyle: { + marginTop: 30, + }, }; }); +const getMentionProps = (currentUser: UserModel) => { + const notifyProps = getNotificationProps(currentUser); + const mKeys = (notifyProps.mention_keys || '').split(','); + + const usernameMentionIndex = mKeys.indexOf(currentUser.username); + if (usernameMentionIndex > -1) { + mKeys.splice(usernameMentionIndex, 1); + } + + return { + mentionKeys: mKeys.join(','), + usernameMention: usernameMentionIndex > -1, + notifyProps, + }; +}; + type MentionSectionProps = { - currentUser?: UserModel; - mentionKeys: string; + componentId: string; + currentUser: UserModel; } -const MentionSettings = ({currentUser, mentionKeys}: MentionSectionProps) => { - const [{firstName, usernameMention, channel}, dispatch] = useReducer(reducer, INITIAL_STATE); +const MentionSettings = ({componentId, currentUser}: MentionSectionProps) => { + const serverUrl = useServerUrl(); + const mentionProps = useMemo(() => getMentionProps(currentUser), [currentUser.notifyProps]); + + const notifyProps = currentUser.notifyProps || mentionProps.notifyProps; + const [tglFirstName, setTglFirstName] = useState(notifyProps.first_name === 'true'); + const [tglChannel, setTglChannel] = useState(notifyProps.channel === 'true'); + + const [tglUserName, setTglUserName] = useState(mentionProps.usernameMention); + const [mentionKeys, setMentionKeys] = useState(mentionProps.mentionKeys); + const theme = useTheme(); const styles = getStyleSheet(theme); const intl = useIntl(); - const toggleChannelMentions = () => { - dispatch({ - type: UPDATE_MENTION_PREF, - data: { - channel: !channel, - }, - }); - }; - const toggleUsernameMention = () => { - dispatch({ - type: UPDATE_MENTION_PREF, - data: { - usernameMention: !usernameMention, - }, - }); - }; - const toggleFirstNameMention = () => { - dispatch({ - type: UPDATE_MENTION_PREF, - data: { - firstName: !firstName, - }, - }); - }; - const goToNotificationSettingsMentionKeywords = () => { - return Alert.alert( - 'The functionality you are trying to use has not yet been implemented.', - ); - }; + const saveButton = useMemo(() => { + return { + id: SAVE_MENTION_BUTTON_ID, + enabled: false, + showAsAction: 'always' as const, + testID: 'notification_settings.mentions.save.button', + color: theme.sidebarHeaderTextColor, + text: intl.formatMessage({id: 'settings.save', defaultMessage: 'Save'}), + }; + }, [theme.sidebarHeaderTextColor]); + + const close = () => popTopScreen(componentId); + + const saveMention = useCallback(() => { + const notify_props: UserNotifyProps = { + ...notifyProps, + first_name: `${tglFirstName}`, + channel: `${tglChannel}`, + mention_keys: mentionKeys}; + updateMe(serverUrl, {notify_props}); + close(); + }, [serverUrl, notifyProps, tglFirstName, tglChannel, mentionKeys]); + + const onToggleFirstName = useCallback(() => { + setTglFirstName((prev) => !prev); + }, []); + + const onToggleUserName = useCallback(() => { + setTglUserName((prev) => !prev); + }, []); + + const onToggleChannel = useCallback(() => { + setTglChannel((prev) => !prev); + }, []); + + const onChangeText = useCallback((text: string) => { + setMentionKeys(text); + }, []); + + useEffect(() => { + const fNameChanged = tglFirstName !== Boolean(notifyProps.first_name); + const channelChanged = tglChannel !== Boolean(notifyProps.channel); + + const usnChanged = tglUserName !== mentionProps.usernameMention; + const kwsChanged = mentionProps.mentionKeys !== mentionKeys; + + const enabled = fNameChanged || usnChanged || channelChanged || kwsChanged; + + const buttons = { + rightButtons: [{ + ...saveButton, + enabled, + }], + }; + setButtons(componentId, buttons); + }, [componentId, saveButton, tglFirstName, tglChannel, tglUserName, mentionKeys, notifyProps]); + + useNavButtonPressed(SAVE_MENTION_BUTTON_ID, componentId, saveMention, [saveMention]); + + useAndroidHardwareBackHandler(componentId, close); return ( { { Boolean(currentUser?.firstName) && ( <> @@ -127,30 +178,42 @@ const MentionSettings = ({currentUser, mentionKeys}: MentionSectionProps) => { } {Boolean(currentUser?.username) && ( )} - ); diff --git a/app/screens/settings/notification_mention/notification_mention.tsx b/app/screens/settings/notification_mention/notification_mention.tsx index 416175b9df..e22ca9e130 100644 --- a/app/screens/settings/notification_mention/notification_mention.tsx +++ b/app/screens/settings/notification_mention/notification_mention.tsx @@ -7,6 +7,7 @@ import {SafeAreaView} from 'react-native-safe-area-context'; import {useTheme} from '@context/theme'; import {changeOpacity, makeStyleSheetFromTheme} from '@utils/theme'; +import {typography} from '@utils/typography'; import MentionSettings from './mention_settings'; import ReplySettings from './reply_settings'; @@ -21,8 +22,8 @@ const getStyleSheet = makeStyleSheetFromTheme((theme) => { }, input: { color: theme.centerChannelColor, - fontSize: 12, height: 40, + ...typography('Body', 75, 'Regular'), }, scrollView: { flex: 1, @@ -35,11 +36,11 @@ const getStyleSheet = makeStyleSheetFromTheme((theme) => { }); type NotificationMentionProps = { - isCRTEnabled?: boolean; - currentUser?: UserModel; - mentionKeys: string; + componentId: string; + currentUser: UserModel; + isCRTEnabled: boolean; } -const NotificationMention = ({currentUser, mentionKeys, isCRTEnabled}: NotificationMentionProps) => { +const NotificationMention = ({componentId, currentUser, isCRTEnabled}: NotificationMentionProps) => { const theme = useTheme(); const styles = getStyleSheet(theme); @@ -55,8 +56,8 @@ const NotificationMention = ({currentUser, mentionKeys, isCRTEnabled}: Notificat alwaysBounceVertical={false} > {!isCRTEnabled && ( diff --git a/app/screens/settings/notification_push/push_send.tsx b/app/screens/settings/notification_push/push_send.tsx index 0c7186cb83..9c95bd521d 100644 --- a/app/screens/settings/notification_push/push_send.tsx +++ b/app/screens/settings/notification_push/push_send.tsx @@ -33,9 +33,9 @@ const getStyleSheet = makeStyleSheetFromTheme((theme) => { }, disabled: { color: theme.centerChannelColor, - fontSize: 15, paddingHorizontal: 15, paddingVertical: 10, + ...typography('Body', 200, 'Regular'), }, container: { paddingHorizontal: 8, diff --git a/app/utils/user/index.ts b/app/utils/user/index.ts index b2660ec00b..039db27f89 100644 --- a/app/utils/user/index.ts +++ b/app/utils/user/index.ts @@ -291,7 +291,9 @@ export function getNotificationProps(user: UserModel) { return user.notifyProps; } - const props: Partial = { + const props: UserNotifyProps = { + email: 'true', + mark_unread: 'all', channel: 'true', comments: 'any', desktop: 'all', diff --git a/assets/base/i18n/en.json b/assets/base/i18n/en.json index 46c20c738e..1677c43cfc 100644 --- a/assets/base/i18n/en.json +++ b/assets/base/i18n/en.json @@ -564,9 +564,9 @@ "notification_settings.mention.reply": "Send reply notifications for", "notification_settings.mentions": "Mentions", "notification_settings.mentions_replies": "Mentions and Replies", + "notification_settings.mentions..keywordsDescription": "Other words that trigger a mention", "notification_settings.mentions.channelWide": "Channel-wide mentions", "notification_settings.mentions.keywords": "Keywords", - "notification_settings.mentions.keywordsDescription": "Other words that trigger a mention", "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",