forked from Ivasoft/mattermost-mobile
MM-39711 - Gekidou Settings - Mentions functionality [3] (#6368)
This commit is contained in:
@@ -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<TargetedEvent>) => void;
|
||||
onFocus?: (e: NativeSyntheticEvent<TargetedEvent>) => 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<FloatingTextInputRef, FloatingTextInputProps>(({
|
||||
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);
|
||||
|
||||
@@ -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'
|
||||
|
||||
@@ -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<typeof INITIAL_STATE>;
|
||||
}
|
||||
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 (
|
||||
<Block
|
||||
@@ -114,11 +165,11 @@ const MentionSettings = ({currentUser, mentionKeys}: MentionSectionProps) => {
|
||||
{ Boolean(currentUser?.firstName) && (
|
||||
<>
|
||||
<OptionItem
|
||||
action={toggleFirstNameMention}
|
||||
action={onToggleFirstName}
|
||||
containerStyle={styles.container}
|
||||
description={intl.formatMessage({id: 'notification_settings.mentions.sensitiveName', defaultMessage: 'Your case sensitive first name'})}
|
||||
label={currentUser!.firstName}
|
||||
selected={firstName}
|
||||
label={currentUser.firstName}
|
||||
selected={tglFirstName}
|
||||
type='toggle'
|
||||
/>
|
||||
<View style={styles.separator}/>
|
||||
@@ -127,30 +178,42 @@ const MentionSettings = ({currentUser, mentionKeys}: MentionSectionProps) => {
|
||||
}
|
||||
{Boolean(currentUser?.username) && (
|
||||
<OptionItem
|
||||
action={toggleUsernameMention}
|
||||
action={onToggleUserName}
|
||||
containerStyle={styles.container}
|
||||
description={intl.formatMessage({id: 'notification_settings.mentions.sensitiveUsername', defaultMessage: 'Your non-case sensitive username'})}
|
||||
label={currentUser!.username}
|
||||
selected={usernameMention}
|
||||
label={currentUser.username}
|
||||
selected={tglUserName}
|
||||
type='toggle'
|
||||
/>
|
||||
)}
|
||||
<View style={styles.separator}/>
|
||||
<OptionItem
|
||||
action={toggleChannelMentions}
|
||||
action={onToggleChannel}
|
||||
containerStyle={styles.container}
|
||||
description={intl.formatMessage({id: 'notification_settings.mentions.channelWide', defaultMessage: 'Channel-wide mentions'})}
|
||||
label='@channel, @all, @here'
|
||||
selected={channel}
|
||||
selected={tglChannel}
|
||||
type='toggle'
|
||||
/>
|
||||
<View style={styles.separator}/>
|
||||
<OptionItem
|
||||
action={goToNotificationSettingsMentionKeywords}
|
||||
containerStyle={styles.container}
|
||||
description={mentionKeys || intl.formatMessage({id: 'notification_settings.mentions.keywordsDescription', defaultMessage: 'Other words that trigger a mention'})}
|
||||
<FloatingTextInput
|
||||
allowFontScaling={true}
|
||||
autoCapitalize='none'
|
||||
autoCorrect={false}
|
||||
blurOnSubmit={true}
|
||||
containerStyle={styles.containerStyle}
|
||||
keyboardAppearance={getKeyboardAppearanceFromTheme(theme)}
|
||||
label={intl.formatMessage({id: 'notification_settings.mentions.keywords', defaultMessage: 'Keywords'})}
|
||||
type='arrow'
|
||||
multiline={true}
|
||||
onChangeText={onChangeText}
|
||||
placeholder={intl.formatMessage({id: 'notification_settings.mentions..keywordsDescription', defaultMessage: 'Other words that trigger a mention'})}
|
||||
placeholderTextColor={changeOpacity(theme.centerChannelColor, 0.4)}
|
||||
returnKeyType='done'
|
||||
textInputStyle={styles.input}
|
||||
textAlignVertical='top'
|
||||
theme={theme}
|
||||
underlineColorAndroid='transparent'
|
||||
value={mentionKeys}
|
||||
/>
|
||||
</Block>
|
||||
);
|
||||
|
||||
@@ -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}
|
||||
>
|
||||
<MentionSettings
|
||||
mentionKeys={mentionKeys}
|
||||
currentUser={currentUser}
|
||||
componentId={componentId}
|
||||
/>
|
||||
{!isCRTEnabled && (
|
||||
<ReplySettings/>
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -291,7 +291,9 @@ export function getNotificationProps(user: UserModel) {
|
||||
return user.notifyProps;
|
||||
}
|
||||
|
||||
const props: Partial<UserNotifyProps> = {
|
||||
const props: UserNotifyProps = {
|
||||
email: 'true',
|
||||
mark_unread: 'all',
|
||||
channel: 'true',
|
||||
comments: 'any',
|
||||
desktop: 'all',
|
||||
|
||||
@@ -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",
|
||||
|
||||
Reference in New Issue
Block a user